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