- Remove TCPSleep and TCPWakeup (we make all oskittcp sockets non-blocking)
[reactos.git] / reactos / lib / drivers / ip / transport / tcp / tcp.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
4 * FILE: transport/tcp/tcp.c
5 * PURPOSE: Transmission Control Protocol
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Art Yerkes (arty@users.sf.net)
8 * REVISIONS:
9 * CSH 01/08-2000 Created
10 * arty 12/21/2004 Added accept
11 */
12
13 #include "precomp.h"
14
15 LONG TCP_IPIdentification = 0;
16 static BOOLEAN TCPInitialized = FALSE;
17 static NPAGED_LOOKASIDE_LIST TCPSegmentList;
18 LIST_ENTRY SignalledConnectionsList;
19 KSPIN_LOCK SignalledConnectionsLock;
20 RECURSIVE_MUTEX TCPLock;
21 PORT_SET TCPPorts;
22
23 ULONG HandleSignalledConnection( PCONNECTION_ENDPOINT Connection ) {
24 NTSTATUS Status = STATUS_SUCCESS;
25 PTCP_COMPLETION_ROUTINE Complete;
26 PTDI_BUCKET Bucket;
27 PLIST_ENTRY Entry;
28 PIRP Irp;
29 PMDL Mdl;
30
31 ASSERT_LOCKED(&TCPLock);
32
33 TI_DbgPrint(MID_TRACE,("Handling signalled state on %x (%x)\n",
34 Connection, Connection->SocketContext));
35
36 if( Connection->SignalState & SEL_FIN ) {
37 TI_DbgPrint(DEBUG_TCP, ("EOF From socket\n"));
38
39 Connection->SignalState &= ~SEL_READ;
40 while ((Entry = ExInterlockedRemoveHeadList( &Connection->ReceiveRequest,
41 &Connection->Lock )) != NULL)
42 {
43 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
44 Complete = Bucket->Request.RequestNotifyObject;
45
46 Complete( Bucket->Request.RequestContext, STATUS_CANCELLED, 0 );
47
48 exFreePool(Bucket);
49 }
50
51 Connection->SignalState &= ~SEL_WRITE;
52 while ((Entry = ExInterlockedRemoveHeadList( &Connection->SendRequest,
53 &Connection->Lock )) != NULL)
54 {
55 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
56 Complete = Bucket->Request.RequestNotifyObject;
57
58 Complete( Bucket->Request.RequestContext, STATUS_CANCELLED, 0 );
59
60 exFreePool(Bucket);
61 }
62
63 Connection->SignalState &= ~SEL_ACCEPT;
64 while ((Entry = ExInterlockedRemoveHeadList( &Connection->ListenRequest,
65 &Connection->Lock )) != NULL)
66 {
67 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
68 Complete = Bucket->Request.RequestNotifyObject;
69
70 /* We have to notify oskittcp of the abortion */
71 TCPAbortListenForSocket(Connection->AddressFile->Listener,
72 Connection);
73
74 Complete( Bucket->Request.RequestContext, STATUS_CANCELLED, 0 );
75
76 exFreePool(Bucket);
77 }
78
79 Connection->SignalState &= ~SEL_CONNECT;
80 while ((Entry = ExInterlockedRemoveHeadList( &Connection->ConnectRequest,
81 &Connection->Lock )) != NULL)
82 {
83 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
84 Complete = Bucket->Request.RequestNotifyObject;
85
86 Complete( Bucket->Request.RequestContext, STATUS_CANCELLED, 0 );
87
88 exFreePool(Bucket);
89 }
90 }
91
92 /* Things that can happen when we try the initial connection */
93 if( Connection->SignalState & SEL_CONNECT ) {
94 Connection->SignalState &= ~SEL_CONNECT;
95 while( (Entry = ExInterlockedRemoveHeadList( &Connection->ConnectRequest,
96 &Connection->Lock )) != NULL ) {
97
98 TI_DbgPrint(DEBUG_TCP, ("Connect Event\n"));
99
100 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
101 Complete = Bucket->Request.RequestNotifyObject;
102 TI_DbgPrint(DEBUG_TCP,
103 ("Completing Request %x\n", Bucket->Request.RequestContext));
104
105 Complete( Bucket->Request.RequestContext, STATUS_SUCCESS, 0 );
106
107 /* Frees the bucket allocated in TCPConnect */
108 exFreePool( Bucket );
109 }
110 }
111
112 if( Connection->SignalState & SEL_ACCEPT ) {
113 /* Handle readable on a listening socket --
114 * TODO: Implement filtering
115 */
116
117 TI_DbgPrint(DEBUG_TCP,("Accepting new connection on %x (Queue: %s)\n",
118 Connection,
119 IsListEmpty(&Connection->ListenRequest) ?
120 "empty" : "nonempty"));
121
122 Connection->SignalState &= ~SEL_ACCEPT;
123 while( (Entry = ExInterlockedRemoveHeadList( &Connection->ListenRequest,
124 &Connection->Lock )) != NULL ) {
125 PIO_STACK_LOCATION IrpSp;
126
127 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
128 Complete = Bucket->Request.RequestNotifyObject;
129
130 Irp = Bucket->Request.RequestContext;
131 IrpSp = IoGetCurrentIrpStackLocation( Irp );
132
133 TI_DbgPrint(DEBUG_TCP,("Getting the socket\n"));
134 Status = TCPServiceListeningSocket
135 ( Connection->AddressFile->Listener,
136 Bucket->AssociatedEndpoint,
137 (PTDI_REQUEST_KERNEL)&IrpSp->Parameters );
138
139 TI_DbgPrint(DEBUG_TCP,("Socket: Status: %x\n"));
140
141 if( Status == STATUS_PENDING ) {
142 Connection->SignalState |= SEL_ACCEPT;
143 ExInterlockedInsertHeadList( &Connection->ListenRequest, &Bucket->Entry, &Connection->Lock );
144 break;
145 } else {
146 Complete( Bucket->Request.RequestContext, Status, 0 );
147 exFreePool( Bucket );
148 }
149 }
150 }
151
152 /* Things that happen after we're connected */
153 if( Connection->SignalState & SEL_READ ) {
154 TI_DbgPrint(DEBUG_TCP,("Readable: irp list %s\n",
155 IsListEmpty(&Connection->ReceiveRequest) ?
156 "empty" : "nonempty"));
157
158 Connection->SignalState &= ~SEL_READ;
159 while( (Entry = ExInterlockedRemoveHeadList( &Connection->ReceiveRequest,
160 &Connection->Lock )) != NULL ) {
161 OSK_UINT RecvLen = 0, Received = 0;
162 PVOID RecvBuffer = 0;
163
164 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
165 Complete = Bucket->Request.RequestNotifyObject;
166
167 Irp = Bucket->Request.RequestContext;
168 Mdl = Irp->MdlAddress;
169
170 TI_DbgPrint(DEBUG_TCP,
171 ("Getting the user buffer from %x\n", Mdl));
172
173 NdisQueryBuffer( Mdl, &RecvBuffer, &RecvLen );
174
175 TI_DbgPrint(DEBUG_TCP,
176 ("Reading %d bytes to %x\n", RecvLen, RecvBuffer));
177
178 TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
179 TI_DbgPrint
180 (DEBUG_TCP,
181 ("Connection->SocketContext: %x\n",
182 Connection->SocketContext));
183 TI_DbgPrint(DEBUG_TCP, ("RecvBuffer: %x\n", RecvBuffer));
184
185 Status = TCPTranslateError
186 ( OskitTCPRecv( Connection->SocketContext,
187 RecvBuffer,
188 RecvLen,
189 &Received,
190 0 ) );
191
192 TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Received));
193
194 if( Status == STATUS_SUCCESS ) {
195 TI_DbgPrint(DEBUG_TCP,("Received %d bytes with status %x\n",
196 Received, Status));
197
198 Complete( Bucket->Request.RequestContext,
199 STATUS_SUCCESS, Received );
200 exFreePool( Bucket );
201 } else if( Status == STATUS_PENDING ) {
202 ExInterlockedInsertHeadList
203 ( &Connection->ReceiveRequest, &Bucket->Entry, &Connection->Lock );
204 Connection->SignalState |= SEL_READ;
205 break;
206 } else {
207 TI_DbgPrint(DEBUG_TCP,
208 ("Completing Receive request: %x %x\n",
209 Bucket->Request, Status));
210 Complete( Bucket->Request.RequestContext, Status, 0 );
211 exFreePool( Bucket );
212 }
213 }
214 }
215 if( Connection->SignalState & SEL_WRITE ) {
216 TI_DbgPrint(DEBUG_TCP,("Writeable: irp list %s\n",
217 IsListEmpty(&Connection->SendRequest) ?
218 "empty" : "nonempty"));
219
220 Connection->SignalState &= ~SEL_WRITE;
221 while( (Entry = ExInterlockedRemoveHeadList( &Connection->SendRequest,
222 &Connection->Lock )) != NULL ) {
223 OSK_UINT SendLen = 0, Sent = 0;
224 PVOID SendBuffer = 0;
225
226 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
227 Complete = Bucket->Request.RequestNotifyObject;
228
229 Irp = Bucket->Request.RequestContext;
230 Mdl = Irp->MdlAddress;
231
232 TI_DbgPrint(DEBUG_TCP,
233 ("Getting the user buffer from %x\n", Mdl));
234
235 NdisQueryBuffer( Mdl, &SendBuffer, &SendLen );
236
237 TI_DbgPrint(DEBUG_TCP,
238 ("Writing %d bytes to %x\n", SendLen, SendBuffer));
239
240 TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
241 TI_DbgPrint
242 (DEBUG_TCP,
243 ("Connection->SocketContext: %x\n",
244 Connection->SocketContext));
245
246 Status = TCPTranslateError
247 ( OskitTCPSend( Connection->SocketContext,
248 SendBuffer,
249 SendLen,
250 &Sent,
251 0 ) );
252
253 TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Sent));
254
255 if( Status == STATUS_SUCCESS ) {
256 TI_DbgPrint(DEBUG_TCP,("Sent %d bytes with status %x\n",
257 Sent, Status));
258
259 Complete( Bucket->Request.RequestContext,
260 STATUS_SUCCESS, Sent );
261 exFreePool( Bucket );
262 } else if( Status == STATUS_PENDING ) {
263 ExInterlockedInsertHeadList
264 ( &Connection->SendRequest, &Bucket->Entry, &Connection->Lock );
265 Connection->SignalState |= SEL_WRITE;
266 break;
267 } else {
268 TI_DbgPrint(DEBUG_TCP,
269 ("Completing Send request: %x %x\n",
270 Bucket->Request, Status));
271 Complete( Bucket->Request.RequestContext, Status, 0 );
272 exFreePool( Bucket );
273 }
274 }
275 }
276
277 return Connection->SignalState;
278 }
279
280 static VOID DrainSignals() {
281 PCONNECTION_ENDPOINT Connection;
282 PLIST_ENTRY CurrentEntry, NextEntry;
283 ULONG NewState;
284 KIRQL OldIrql;
285
286 KeAcquireSpinLock(&SignalledConnectionsLock, &OldIrql);
287 CurrentEntry = SignalledConnectionsList.Flink;
288 while (CurrentEntry != &SignalledConnectionsList)
289 {
290 NextEntry = CurrentEntry->Flink;
291 Connection = CONTAINING_RECORD( CurrentEntry, CONNECTION_ENDPOINT,
292 SignalList );
293
294 KeReleaseSpinLock(&SignalledConnectionsLock, OldIrql);
295 NewState = HandleSignalledConnection(Connection);
296 KeAcquireSpinLock(&SignalledConnectionsLock, &OldIrql);
297
298 if (NewState == SEL_FIN || NewState == 0)
299 {
300 RemoveEntryList(CurrentEntry);
301 }
302
303 CurrentEntry = NextEntry;
304 }
305 KeReleaseSpinLock(&SignalledConnectionsLock, OldIrql);
306 }
307
308 PCONNECTION_ENDPOINT TCPAllocateConnectionEndpoint( PVOID ClientContext ) {
309 PCONNECTION_ENDPOINT Connection =
310 exAllocatePool(NonPagedPool, sizeof(CONNECTION_ENDPOINT));
311 if (!Connection)
312 return Connection;
313
314 TI_DbgPrint(DEBUG_CPOINT, ("Connection point file object allocated at (0x%X).\n", Connection));
315
316 RtlZeroMemory(Connection, sizeof(CONNECTION_ENDPOINT));
317
318 /* Initialize spin lock that protects the connection endpoint file object */
319 TcpipInitializeSpinLock(&Connection->Lock);
320 InitializeListHead(&Connection->ConnectRequest);
321 InitializeListHead(&Connection->ListenRequest);
322 InitializeListHead(&Connection->ReceiveRequest);
323 InitializeListHead(&Connection->SendRequest);
324
325 /* Save client context pointer */
326 Connection->ClientContext = ClientContext;
327
328 return Connection;
329 }
330
331 VOID TCPFreeConnectionEndpoint( PCONNECTION_ENDPOINT Connection ) {
332 TI_DbgPrint(DEBUG_TCP, ("Freeing TCP Endpoint\n"));
333 exFreePool( Connection );
334 }
335
336 NTSTATUS TCPSocket( PCONNECTION_ENDPOINT Connection,
337 UINT Family, UINT Type, UINT Proto ) {
338 NTSTATUS Status;
339
340 ASSERT_LOCKED(&TCPLock);
341
342 TI_DbgPrint(DEBUG_TCP,("Called: Connection %x, Family %d, Type %d, "
343 "Proto %d\n",
344 Connection, Family, Type, Proto));
345
346 Status = TCPTranslateError( OskitTCPSocket( Connection,
347 &Connection->SocketContext,
348 Family,
349 Type,
350 Proto ) );
351
352 ASSERT_KM_POINTER(Connection->SocketContext);
353
354 TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext %x\n",
355 Connection->SocketContext));
356
357 return Status;
358 }
359
360 VOID TCPReceive(PIP_INTERFACE Interface, PIP_PACKET IPPacket)
361 /*
362 * FUNCTION: Receives and queues TCP data
363 * ARGUMENTS:
364 * IPPacket = Pointer to an IP packet that was received
365 * NOTES:
366 * This is the low level interface for receiving TCP data
367 */
368 {
369 TI_DbgPrint(DEBUG_TCP,("Sending packet %d (%d) to oskit\n",
370 IPPacket->TotalSize,
371 IPPacket->HeaderSize));
372
373 TcpipRecursiveMutexEnter( &TCPLock, TRUE );
374
375 OskitTCPReceiveDatagram( IPPacket->Header,
376 IPPacket->TotalSize,
377 IPPacket->HeaderSize );
378
379 TcpipRecursiveMutexLeave( &TCPLock );
380 }
381
382 /* event.c */
383 int TCPSocketState( void *ClientData,
384 void *WhichSocket,
385 void *WhichConnection,
386 OSK_UINT NewState );
387
388 int TCPPacketSend( void *ClientData,
389 OSK_PCHAR Data,
390 OSK_UINT Len );
391
392 POSK_IFADDR TCPFindInterface( void *ClientData,
393 OSK_UINT AddrType,
394 OSK_UINT FindType,
395 OSK_SOCKADDR *ReqAddr );
396
397 NTSTATUS TCPMemStartup( void );
398 void *TCPMalloc( void *ClientData,
399 OSK_UINT bytes, OSK_PCHAR file, OSK_UINT line );
400 void TCPFree( void *ClientData,
401 void *data, OSK_PCHAR file, OSK_UINT line );
402 void TCPMemShutdown( void );
403
404 OSKITTCP_EVENT_HANDLERS EventHandlers = {
405 NULL, /* Client Data */
406 TCPSocketState, /* SocketState */
407 TCPPacketSend, /* PacketSend */
408 TCPFindInterface, /* FindInterface */
409 TCPMalloc, /* Malloc */
410 TCPFree, /* Free */
411 NULL, /* Sleep */
412 NULL, /* Wakeup */
413 };
414
415 static KEVENT TimerLoopEvent;
416 static HANDLE TimerThreadHandle;
417
418 /*
419 * We are running 2 timers here, one with a 200ms interval (fast) and the other
420 * with a 500ms interval (slow). So we need to time out at 200, 400, 500, 600,
421 * 800, 1000 and process the "fast" events at 200, 400, 600, 800, 1000 and the
422 * "slow" events at 500 and 1000.
423 */
424 static VOID NTAPI
425 TimerThread(PVOID Context)
426 {
427 LARGE_INTEGER Timeout;
428 NTSTATUS Status;
429 unsigned Current, NextFast, NextSlow, Next;
430
431 Current = 0;
432 Next = 0;
433 NextFast = 0;
434 NextSlow = 0;
435 while ( 1 ) {
436 if (Next == NextFast) {
437 NextFast += 2;
438 }
439 if (Next == NextSlow) {
440 NextSlow += 5;
441 }
442 Next = min(NextFast, NextSlow);
443 Timeout.QuadPart = (LONGLONG) (Next - Current) * -1000000; /* 100 ms */
444 Status = KeWaitForSingleObject(&TimerLoopEvent, Executive, KernelMode,
445 FALSE, &Timeout);
446 if (Status != STATUS_TIMEOUT) {
447 PsTerminateSystemThread(Status);
448 }
449
450 TcpipRecursiveMutexEnter( &TCPLock, TRUE );
451 TimerOskitTCP( Next == NextFast, Next == NextSlow );
452 if (Next == NextSlow) {
453 DrainSignals();
454 }
455 TcpipRecursiveMutexLeave( &TCPLock );
456
457 Current = Next;
458 if (10 <= Current) {
459 Current = 0;
460 Next = 0;
461 NextFast = 0;
462 NextSlow = 0;
463 }
464 }
465 }
466
467 static VOID
468 StartTimer(VOID)
469 {
470 KeInitializeEvent(&TimerLoopEvent, NotificationEvent, FALSE);
471 PsCreateSystemThread(&TimerThreadHandle, THREAD_ALL_ACCESS, 0, 0, 0,
472 TimerThread, NULL);
473 }
474
475
476 NTSTATUS TCPStartup(VOID)
477 /*
478 * FUNCTION: Initializes the TCP subsystem
479 * RETURNS:
480 * Status of operation
481 */
482 {
483 NTSTATUS Status;
484
485 TcpipRecursiveMutexInit( &TCPLock );
486 KeInitializeSpinLock( &SignalledConnectionsLock );
487 InitializeListHead( &SignalledConnectionsList );
488 Status = TCPMemStartup();
489 if ( ! NT_SUCCESS(Status) ) {
490 return Status;
491 }
492
493 Status = PortsStartup( &TCPPorts, 1, 0xfffe );
494 if( !NT_SUCCESS(Status) ) {
495 TCPMemShutdown();
496 return Status;
497 }
498
499 TcpipRecursiveMutexEnter(&TCPLock, TRUE);
500 RegisterOskitTCPEventHandlers( &EventHandlers );
501 InitOskitTCP();
502 TcpipRecursiveMutexLeave(&TCPLock);
503
504 /* Register this protocol with IP layer */
505 IPRegisterProtocol(IPPROTO_TCP, TCPReceive);
506
507 ExInitializeNPagedLookasideList(
508 &TCPSegmentList, /* Lookaside list */
509 NULL, /* Allocate routine */
510 NULL, /* Free routine */
511 0, /* Flags */
512 sizeof(TCP_SEGMENT), /* Size of each entry */
513 'SPCT', /* Tag */
514 0); /* Depth */
515
516 StartTimer();
517
518 TCPInitialized = TRUE;
519
520 return STATUS_SUCCESS;
521 }
522
523
524 NTSTATUS TCPShutdown(VOID)
525 /*
526 * FUNCTION: Shuts down the TCP subsystem
527 * RETURNS:
528 * Status of operation
529 */
530 {
531 LARGE_INTEGER WaitForThread;
532
533 if (!TCPInitialized)
534 return STATUS_SUCCESS;
535
536 WaitForThread.QuadPart = -2500000; /* 250 ms */
537 KeSetEvent(&TimerLoopEvent, IO_NO_INCREMENT, FALSE);
538 ZwWaitForSingleObject(TimerThreadHandle, FALSE, &WaitForThread);
539
540 /* Deregister this protocol with IP layer */
541 IPRegisterProtocol(IPPROTO_TCP, NULL);
542
543 ExDeleteNPagedLookasideList(&TCPSegmentList);
544
545 TCPInitialized = FALSE;
546
547 DeinitOskitTCP();
548
549 PortsShutdown( &TCPPorts );
550
551 TCPMemShutdown();
552
553 return STATUS_SUCCESS;
554 }
555
556 NTSTATUS TCPTranslateError( int OskitError ) {
557 NTSTATUS Status;
558
559 switch( OskitError ) {
560 case 0: Status = STATUS_SUCCESS; break;
561 case OSK_EADDRNOTAVAIL: Status = STATUS_INVALID_ADDRESS; break;
562 case OSK_EAFNOSUPPORT: Status = STATUS_INVALID_CONNECTION; break;
563 case OSK_ECONNREFUSED:
564 case OSK_ECONNRESET: Status = STATUS_REMOTE_NOT_LISTENING; break;
565 case OSK_EWOULDBLOCK:
566 case OSK_EINPROGRESS: Status = STATUS_PENDING; break;
567 case OSK_EINVAL: Status = STATUS_INVALID_PARAMETER; break;
568 case OSK_ENOMEM:
569 case OSK_ENOBUFS: Status = STATUS_INSUFFICIENT_RESOURCES; break;
570 case OSK_ESHUTDOWN: Status = STATUS_FILE_CLOSED; break;
571 case OSK_EMSGSIZE: Status = STATUS_BUFFER_TOO_SMALL; break;
572 case OSK_ETIMEDOUT: Status = STATUS_TIMEOUT; break;
573 case OSK_ENETUNREACH: Status = STATUS_NETWORK_UNREACHABLE; break;
574 case OSK_EFAULT: Status = STATUS_ACCESS_VIOLATION; break;
575 default:
576 DbgPrint("OskitTCP returned unhandled error code: %d\n", OskitError);
577 Status = STATUS_INVALID_CONNECTION;
578 break;
579 }
580
581 TI_DbgPrint(DEBUG_TCP,("Error %d -> %x\n", OskitError, Status));
582 return Status;
583 }
584
585 NTSTATUS TCPConnect
586 ( PCONNECTION_ENDPOINT Connection,
587 PTDI_CONNECTION_INFORMATION ConnInfo,
588 PTDI_CONNECTION_INFORMATION ReturnInfo,
589 PTCP_COMPLETION_ROUTINE Complete,
590 PVOID Context ) {
591 NTSTATUS Status;
592 SOCKADDR_IN AddressToConnect = { 0 }, AddressToBind = { 0 };
593 IP_ADDRESS RemoteAddress;
594 USHORT RemotePort;
595 PTDI_BUCKET Bucket;
596 PNEIGHBOR_CACHE_ENTRY NCE;
597
598 TI_DbgPrint(DEBUG_TCP,("TCPConnect: Called\n"));
599
600 ASSERT_LOCKED(&TCPLock);
601
602 Status = AddrBuildAddress
603 ((PTRANSPORT_ADDRESS)ConnInfo->RemoteAddress,
604 &RemoteAddress,
605 &RemotePort);
606
607 if (!NT_SUCCESS(Status)) {
608 TI_DbgPrint(DEBUG_TCP, ("Could not AddrBuildAddress in TCPConnect\n"));
609 return Status;
610 }
611
612 if (!(NCE = RouteGetRouteToDestination(&RemoteAddress)))
613 {
614 return STATUS_NETWORK_UNREACHABLE;
615 }
616
617 /* Freed in TCPSocketState */
618 TI_DbgPrint(DEBUG_TCP,
619 ("Connecting to address %x:%x\n",
620 RemoteAddress.Address.IPv4Address,
621 RemotePort));
622
623 AddressToConnect.sin_family = AF_INET;
624 AddressToBind = AddressToConnect;
625 AddressToBind.sin_addr.s_addr = NCE->Interface->Unicast.Address.IPv4Address;
626
627 Status = TCPTranslateError
628 ( OskitTCPBind( Connection->SocketContext,
629 &AddressToBind,
630 sizeof(AddressToBind) ) );
631
632 if (NT_SUCCESS(Status)) {
633 memcpy( &AddressToConnect.sin_addr,
634 &RemoteAddress.Address.IPv4Address,
635 sizeof(AddressToConnect.sin_addr) );
636 AddressToConnect.sin_port = RemotePort;
637
638 Status = TCPTranslateError
639 ( OskitTCPConnect( Connection->SocketContext,
640 Connection,
641 &AddressToConnect,
642 sizeof(AddressToConnect) ) );
643
644 if (Status == STATUS_PENDING)
645 {
646 Bucket = exAllocatePool( NonPagedPool, sizeof(*Bucket) );
647 if( !Bucket ) return STATUS_NO_MEMORY;
648
649 Bucket->Request.RequestNotifyObject = (PVOID)Complete;
650 Bucket->Request.RequestContext = Context;
651
652 IoMarkIrpPending((PIRP)Context);
653
654 ExInterlockedInsertTailList( &Connection->ConnectRequest, &Bucket->Entry, &Connection->Lock );
655 }
656 }
657
658 return Status;
659 }
660
661 NTSTATUS TCPDisconnect
662 ( PCONNECTION_ENDPOINT Connection,
663 UINT Flags,
664 PTDI_CONNECTION_INFORMATION ConnInfo,
665 PTDI_CONNECTION_INFORMATION ReturnInfo,
666 PTCP_COMPLETION_ROUTINE Complete,
667 PVOID Context ) {
668 NTSTATUS Status = STATUS_INVALID_PARAMETER;
669
670 ASSERT_LOCKED(&TCPLock);
671
672 TI_DbgPrint(DEBUG_TCP,("started\n"));
673
674 if (Flags & TDI_DISCONNECT_RELEASE)
675 Status = TCPTranslateError(OskitTCPDisconnect(Connection->SocketContext));
676
677 if ((Flags & TDI_DISCONNECT_ABORT) || !Flags)
678 Status = TCPTranslateError(OskitTCPShutdown(Connection->SocketContext, FWRITE | FREAD));
679
680 TI_DbgPrint(DEBUG_TCP,("finished %x\n", Status));
681
682 return Status;
683 }
684
685 NTSTATUS TCPClose
686 ( PCONNECTION_ENDPOINT Connection ) {
687 NTSTATUS Status;
688
689 TI_DbgPrint(DEBUG_TCP,("TCPClose started\n"));
690
691 ASSERT_LOCKED(&TCPLock);
692
693 /* Make our code remove all pending IRPs */
694 Connection->SignalState |= SEL_FIN;
695 HandleSignalledConnection(Connection);
696
697 Status = TCPTranslateError( OskitTCPClose( Connection->SocketContext ) );
698 if (Status == STATUS_SUCCESS)
699 Connection->SocketContext = NULL;
700
701 TI_DbgPrint(DEBUG_TCP,("TCPClose finished %x\n", Status));
702
703 return Status;
704 }
705
706 NTSTATUS TCPReceiveData
707 ( PCONNECTION_ENDPOINT Connection,
708 PNDIS_BUFFER Buffer,
709 ULONG ReceiveLength,
710 PULONG BytesReceived,
711 ULONG ReceiveFlags,
712 PTCP_COMPLETION_ROUTINE Complete,
713 PVOID Context ) {
714 PVOID DataBuffer;
715 UINT DataLen, Received = 0;
716 NTSTATUS Status;
717 PTDI_BUCKET Bucket;
718
719 TI_DbgPrint(DEBUG_TCP,("Called for %d bytes (on socket %x)\n",
720 ReceiveLength, Connection->SocketContext));
721
722 ASSERT_LOCKED(&TCPLock);
723
724 ASSERT_KM_POINTER(Connection->SocketContext);
725
726 NdisQueryBuffer( Buffer, &DataBuffer, &DataLen );
727
728 TI_DbgPrint(DEBUG_TCP,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer, DataBuffer, DataLen));
729
730 Status = TCPTranslateError
731 ( OskitTCPRecv
732 ( Connection->SocketContext,
733 DataBuffer,
734 DataLen,
735 &Received,
736 ReceiveFlags ) );
737
738 TI_DbgPrint(DEBUG_TCP,("OskitTCPReceive: %x, %d\n", Status, Received));
739
740 /* Keep this request around ... there was no data yet */
741 if( Status == STATUS_PENDING ) {
742 /* Freed in TCPSocketState */
743 Bucket = exAllocatePool( NonPagedPool, sizeof(*Bucket) );
744 if( !Bucket ) {
745 TI_DbgPrint(DEBUG_TCP,("Failed to allocate bucket\n"));
746 return STATUS_NO_MEMORY;
747 }
748
749 Bucket->Request.RequestNotifyObject = Complete;
750 Bucket->Request.RequestContext = Context;
751 *BytesReceived = 0;
752
753 IoMarkIrpPending((PIRP)Context);
754
755 ExInterlockedInsertTailList( &Connection->ReceiveRequest, &Bucket->Entry, &Connection->Lock );
756 TI_DbgPrint(DEBUG_TCP,("Queued read irp\n"));
757 } else {
758 TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, Received));
759 *BytesReceived = Received;
760 }
761
762 TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
763
764 return Status;
765 }
766
767 NTSTATUS TCPSendData
768 ( PCONNECTION_ENDPOINT Connection,
769 PCHAR BufferData,
770 ULONG SendLength,
771 PULONG BytesSent,
772 ULONG Flags,
773 PTCP_COMPLETION_ROUTINE Complete,
774 PVOID Context ) {
775 UINT Sent = 0;
776 NTSTATUS Status;
777 PTDI_BUCKET Bucket;
778
779 ASSERT_LOCKED(&TCPLock);
780
781 TI_DbgPrint(DEBUG_TCP,("Called for %d bytes (on socket %x)\n",
782 SendLength, Connection->SocketContext));
783
784 ASSERT_KM_POINTER(Connection->SocketContext);
785
786 TI_DbgPrint(DEBUG_TCP,("Connection = %x\n", Connection));
787 TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext = %x\n",
788 Connection->SocketContext));
789
790
791 Status = TCPTranslateError
792 ( OskitTCPSend( Connection->SocketContext,
793 (OSK_PCHAR)BufferData, SendLength,
794 &Sent, 0 ) );
795
796 TI_DbgPrint(DEBUG_TCP,("OskitTCPSend: %x, %d\n", Status, Sent));
797
798 /* Keep this request around ... there was no data yet */
799 if( Status == STATUS_PENDING ) {
800 /* Freed in TCPSocketState */
801 Bucket = exAllocatePool( NonPagedPool, sizeof(*Bucket) );
802 if( !Bucket ) {
803 TI_DbgPrint(DEBUG_TCP,("Failed to allocate bucket\n"));
804 return STATUS_NO_MEMORY;
805 }
806
807 Bucket->Request.RequestNotifyObject = Complete;
808 Bucket->Request.RequestContext = Context;
809 *BytesSent = 0;
810
811 IoMarkIrpPending((PIRP)Context);
812
813 ExInterlockedInsertTailList( &Connection->SendRequest, &Bucket->Entry, &Connection->Lock );
814 TI_DbgPrint(DEBUG_TCP,("Queued write irp\n"));
815 } else {
816 TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, Sent));
817 *BytesSent = Sent;
818 }
819
820 TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
821
822 return Status;
823 }
824
825 VOID TCPTimeout(VOID) {
826 /* Now handled by TimerThread */
827 }
828
829 UINT TCPAllocatePort( UINT HintPort ) {
830 if( HintPort ) {
831 if( AllocatePort( &TCPPorts, HintPort ) ) return HintPort;
832 else {
833 TI_DbgPrint
834 (MID_TRACE,("We got a hint port but couldn't allocate it\n"));
835 return (UINT)-1;
836 }
837 } else return AllocatePortFromRange( &TCPPorts, 1024, 5000 );
838 }
839
840 VOID TCPFreePort( UINT Port ) {
841 DeallocatePort( &TCPPorts, Port );
842 }
843
844 NTSTATUS TCPGetSockAddress
845 ( PCONNECTION_ENDPOINT Connection,
846 PTRANSPORT_ADDRESS Address,
847 BOOLEAN GetRemote ) {
848 OSK_UINT LocalAddress, RemoteAddress;
849 OSK_UI16 LocalPort, RemotePort;
850 PTA_IP_ADDRESS AddressIP = (PTA_IP_ADDRESS)Address;
851 NTSTATUS Status;
852
853 ASSERT_LOCKED(&TCPLock);
854
855 Status = TCPTranslateError(OskitTCPGetAddress(Connection->SocketContext,
856 &LocalAddress, &LocalPort,
857 &RemoteAddress, &RemotePort));
858 if (!NT_SUCCESS(Status))
859 return Status;
860
861 AddressIP->TAAddressCount = 1;
862 AddressIP->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
863 AddressIP->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
864 AddressIP->Address[0].Address[0].sin_port = GetRemote ? RemotePort : LocalPort;
865 AddressIP->Address[0].Address[0].in_addr = GetRemote ? RemoteAddress : LocalAddress;
866
867 return Status;
868 }
869
870 VOID TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint, PIRP Irp ) {
871 PLIST_ENTRY Entry;
872 PLIST_ENTRY ListHead[4];
873 KIRQL OldIrql;
874 PTDI_BUCKET Bucket;
875 UINT i = 0;
876
877 ListHead[0] = &Endpoint->SendRequest;
878 ListHead[1] = &Endpoint->ReceiveRequest;
879 ListHead[2] = &Endpoint->ConnectRequest;
880 ListHead[3] = &Endpoint->ListenRequest;
881
882 TcpipAcquireSpinLock( &Endpoint->Lock, &OldIrql );
883
884 for( i = 0; i < 4; i++ )
885 {
886 for( Entry = ListHead[i]->Flink;
887 Entry != ListHead[i];
888 Entry = Entry->Flink )
889 {
890 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
891 if( Bucket->Request.RequestContext == Irp )
892 {
893 RemoveEntryList( &Bucket->Entry );
894 exFreePool( Bucket );
895 break;
896 }
897 }
898 }
899
900 TcpipReleaseSpinLock( &Endpoint->Lock, OldIrql );
901 }
902
903 /* EOF */