8c051677353f3878ce0e2a5bdeb7d622f4bb0e88
[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 ExFreePoolWithTag(Bucket, TDI_BUCKET_TAG);
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 ExAllocatePoolWithTag(NonPagedPool, sizeof(CONNECTION_ENDPOINT),
319 CONN_ENDPT_TAG);
320 if (!Connection)
321 return Connection;
322
323 TI_DbgPrint(DEBUG_CPOINT, ("Connection point file object allocated at (0x%X).\n", Connection));
324
325 RtlZeroMemory(Connection, sizeof(CONNECTION_ENDPOINT));
326
327 /* Initialize spin lock that protects the connection endpoint file object */
328 KeInitializeSpinLock(&Connection->Lock);
329 InitializeListHead(&Connection->ConnectRequest);
330 InitializeListHead(&Connection->ListenRequest);
331 InitializeListHead(&Connection->ReceiveRequest);
332 InitializeListHead(&Connection->SendRequest);
333 InitializeListHead(&Connection->CompletionQueue);
334
335 /* Save client context pointer */
336 Connection->ClientContext = ClientContext;
337
338 /* Add connection endpoint to global list */
339 ExInterlockedInsertTailList(&ConnectionEndpointListHead,
340 &Connection->ListEntry,
341 &ConnectionEndpointListLock);
342
343 return Connection;
344 }
345
346 VOID TCPFreeConnectionEndpoint( PCONNECTION_ENDPOINT Connection ) {
347 KIRQL OldIrql;
348
349 TI_DbgPrint(DEBUG_TCP, ("Freeing TCP Endpoint\n"));
350
351 TcpipAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql);
352 RemoveEntryList(&Connection->ListEntry);
353 TcpipReleaseSpinLock(&ConnectionEndpointListLock, OldIrql);
354
355 ExFreePoolWithTag( Connection, CONN_ENDPT_TAG );
356 }
357
358 NTSTATUS TCPSocket( PCONNECTION_ENDPOINT Connection,
359 UINT Family, UINT Type, UINT Proto ) {
360 NTSTATUS Status;
361 KIRQL OldIrql;
362
363 KeAcquireSpinLock(&Connection->Lock, &OldIrql);
364
365 TI_DbgPrint(DEBUG_TCP,("Called: Connection %x, Family %d, Type %d, "
366 "Proto %d\n",
367 Connection, Family, Type, Proto));
368
369 Status = TCPTranslateError( OskitTCPSocket( Connection,
370 &Connection->SocketContext,
371 Family,
372 Type,
373 Proto ) );
374
375 ASSERT_KM_POINTER(Connection->SocketContext);
376
377 TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext %x\n",
378 Connection->SocketContext));
379
380 KeReleaseSpinLock(&Connection->Lock, OldIrql);
381
382 return Status;
383 }
384
385 VOID TCPReceive(PIP_INTERFACE Interface, PIP_PACKET IPPacket)
386 /*
387 * FUNCTION: Receives and queues TCP data
388 * ARGUMENTS:
389 * IPPacket = Pointer to an IP packet that was received
390 * NOTES:
391 * This is the low level interface for receiving TCP data
392 */
393 {
394 KIRQL OldIrql;
395
396 TI_DbgPrint(DEBUG_TCP,("Sending packet %d (%d) to oskit\n",
397 IPPacket->TotalSize,
398 IPPacket->HeaderSize));
399
400 KeAcquireSpinLock(&ClientInfo.Lock, &OldIrql);
401 ClientInfo.Unlocked = TRUE;
402
403 OskitTCPReceiveDatagram( IPPacket->Header,
404 IPPacket->TotalSize,
405 IPPacket->HeaderSize );
406
407 ClientInfo.Unlocked = FALSE;
408 KeReleaseSpinLock(&ClientInfo.Lock, OldIrql);
409 }
410
411 /* event.c */
412 int TCPSocketState( void *ClientData,
413 void *WhichSocket,
414 void *WhichConnection,
415 OSK_UINT NewState );
416
417 int TCPPacketSend( void *ClientData,
418 OSK_PCHAR Data,
419 OSK_UINT Len );
420
421 POSK_IFADDR TCPFindInterface( void *ClientData,
422 OSK_UINT AddrType,
423 OSK_UINT FindType,
424 OSK_SOCKADDR *ReqAddr );
425
426 NTSTATUS TCPMemStartup( void );
427 void *TCPMalloc( void *ClientData,
428 OSK_UINT bytes, OSK_PCHAR file, OSK_UINT line );
429 void TCPFree( void *ClientData,
430 void *data, OSK_PCHAR file, OSK_UINT line );
431 void TCPMemShutdown( void );
432
433 OSKITTCP_EVENT_HANDLERS EventHandlers = {
434 NULL, /* Client Data */
435 TCPSocketState, /* SocketState */
436 TCPPacketSend, /* PacketSend */
437 TCPFindInterface, /* FindInterface */
438 TCPMalloc, /* Malloc */
439 TCPFree, /* Free */
440 NULL, /* Sleep */
441 NULL, /* Wakeup */
442 };
443
444 static KEVENT TimerLoopEvent;
445 static HANDLE TimerThreadHandle;
446
447 /*
448 * We are running 2 timers here, one with a 200ms interval (fast) and the other
449 * with a 500ms interval (slow). So we need to time out at 200, 400, 500, 600,
450 * 800, 1000 and process the "fast" events at 200, 400, 600, 800, 1000 and the
451 * "slow" events at 500 and 1000.
452 */
453 static VOID NTAPI
454 TimerThread(PVOID Context)
455 {
456 LARGE_INTEGER Timeout;
457 NTSTATUS Status;
458 unsigned Current, NextFast, NextSlow, Next;
459
460 Current = 0;
461 Next = 0;
462 NextFast = 0;
463 NextSlow = 0;
464 while ( 1 ) {
465 if (Next == NextFast) {
466 NextFast += 2;
467 }
468 if (Next == NextSlow) {
469 NextSlow += 5;
470 }
471 Next = min(NextFast, NextSlow);
472 Timeout.QuadPart = (LONGLONG) (Next - Current) * -1000000; /* 100 ms */
473 Status = KeWaitForSingleObject(&TimerLoopEvent, Executive, KernelMode,
474 FALSE, &Timeout);
475 if (Status != STATUS_TIMEOUT) {
476 PsTerminateSystemThread(Status);
477 }
478
479 TimerOskitTCP( Next == NextFast, Next == NextSlow );
480 DrainSignals();
481
482 Current = Next;
483 if (10 <= Current) {
484 Current = 0;
485 Next = 0;
486 NextFast = 0;
487 NextSlow = 0;
488 }
489 }
490 }
491
492 static VOID
493 StartTimer(VOID)
494 {
495 KeInitializeEvent(&TimerLoopEvent, NotificationEvent, FALSE);
496 PsCreateSystemThread(&TimerThreadHandle, THREAD_ALL_ACCESS, 0, 0, 0,
497 TimerThread, NULL);
498 }
499
500 NTSTATUS TCPStartup(VOID)
501 /*
502 * FUNCTION: Initializes the TCP subsystem
503 * RETURNS:
504 * Status of operation
505 */
506 {
507 NTSTATUS Status;
508
509 Status = TCPMemStartup();
510 if ( ! NT_SUCCESS(Status) ) {
511 return Status;
512 }
513
514 Status = PortsStartup( &TCPPorts, 1, 0xfffe );
515 if( !NT_SUCCESS(Status) ) {
516 TCPMemShutdown();
517 return Status;
518 }
519
520 KeInitializeSpinLock(&ClientInfo.Lock);
521 ClientInfo.Unlocked = FALSE;
522
523 RegisterOskitTCPEventHandlers( &EventHandlers );
524 InitOskitTCP();
525
526 /* Register this protocol with IP layer */
527 IPRegisterProtocol(IPPROTO_TCP, TCPReceive);
528
529 ExInitializeNPagedLookasideList(
530 &TCPSegmentList, /* Lookaside list */
531 NULL, /* Allocate routine */
532 NULL, /* Free routine */
533 0, /* Flags */
534 sizeof(TCP_SEGMENT), /* Size of each entry */
535 'SPCT', /* Tag */
536 0); /* Depth */
537
538 StartTimer();
539
540 TCPInitialized = TRUE;
541
542 return STATUS_SUCCESS;
543 }
544
545
546 NTSTATUS TCPShutdown(VOID)
547 /*
548 * FUNCTION: Shuts down the TCP subsystem
549 * RETURNS:
550 * Status of operation
551 */
552 {
553 LARGE_INTEGER WaitForThread;
554
555 if (!TCPInitialized)
556 return STATUS_SUCCESS;
557
558 WaitForThread.QuadPart = -2500000; /* 250 ms */
559 KeSetEvent(&TimerLoopEvent, IO_NO_INCREMENT, FALSE);
560 ZwWaitForSingleObject(TimerThreadHandle, FALSE, &WaitForThread);
561
562 /* Deregister this protocol with IP layer */
563 IPRegisterProtocol(IPPROTO_TCP, NULL);
564
565 ExDeleteNPagedLookasideList(&TCPSegmentList);
566
567 TCPInitialized = FALSE;
568
569 DeinitOskitTCP();
570
571 PortsShutdown( &TCPPorts );
572
573 TCPMemShutdown();
574
575 return STATUS_SUCCESS;
576 }
577
578 NTSTATUS TCPTranslateError( int OskitError ) {
579 NTSTATUS Status;
580
581 switch( OskitError ) {
582 case 0: Status = STATUS_SUCCESS; break;
583 case OSK_EADDRNOTAVAIL: Status = STATUS_INVALID_ADDRESS; break;
584 case OSK_EAFNOSUPPORT: Status = STATUS_INVALID_CONNECTION; break;
585 case OSK_ECONNREFUSED: Status = STATUS_REMOTE_NOT_LISTENING; break;
586 case OSK_ECONNRESET:
587 case OSK_ECONNABORTED: Status = STATUS_REMOTE_DISCONNECT; break;
588 case OSK_EWOULDBLOCK:
589 case OSK_EINPROGRESS: Status = STATUS_PENDING; break;
590 case OSK_EINVAL: Status = STATUS_INVALID_PARAMETER; break;
591 case OSK_ENOMEM:
592 case OSK_ENOBUFS: Status = STATUS_INSUFFICIENT_RESOURCES; break;
593 case OSK_ESHUTDOWN: Status = STATUS_FILE_CLOSED; break;
594 case OSK_EMSGSIZE: Status = STATUS_BUFFER_TOO_SMALL; break;
595 case OSK_ETIMEDOUT: Status = STATUS_TIMEOUT; break;
596 case OSK_ENETUNREACH: Status = STATUS_NETWORK_UNREACHABLE; break;
597 case OSK_EFAULT: Status = STATUS_ACCESS_VIOLATION; break;
598 default:
599 DbgPrint("OskitTCP returned unhandled error code: %d\n", OskitError);
600 Status = STATUS_INVALID_CONNECTION;
601 break;
602 }
603
604 TI_DbgPrint(DEBUG_TCP,("Error %d -> %x\n", OskitError, Status));
605 return Status;
606 }
607
608 NTSTATUS TCPConnect
609 ( PCONNECTION_ENDPOINT Connection,
610 PTDI_CONNECTION_INFORMATION ConnInfo,
611 PTDI_CONNECTION_INFORMATION ReturnInfo,
612 PTCP_COMPLETION_ROUTINE Complete,
613 PVOID Context ) {
614 NTSTATUS Status;
615 SOCKADDR_IN AddressToConnect = { 0 }, AddressToBind = { 0 };
616 IP_ADDRESS RemoteAddress;
617 USHORT RemotePort;
618 PTDI_BUCKET Bucket;
619 PNEIGHBOR_CACHE_ENTRY NCE;
620 KIRQL OldIrql;
621
622 TI_DbgPrint(DEBUG_TCP,("TCPConnect: Called\n"));
623
624 Status = AddrBuildAddress
625 ((PTRANSPORT_ADDRESS)ConnInfo->RemoteAddress,
626 &RemoteAddress,
627 &RemotePort);
628
629 if (!NT_SUCCESS(Status)) {
630 TI_DbgPrint(DEBUG_TCP, ("Could not AddrBuildAddress in TCPConnect\n"));
631 return Status;
632 }
633
634 if (!(NCE = RouteGetRouteToDestination(&RemoteAddress)))
635 {
636 return STATUS_NETWORK_UNREACHABLE;
637 }
638
639 /* Freed in TCPSocketState */
640 TI_DbgPrint(DEBUG_TCP,
641 ("Connecting to address %x:%x\n",
642 RemoteAddress.Address.IPv4Address,
643 RemotePort));
644
645 AddressToConnect.sin_family = AF_INET;
646 AddressToBind = AddressToConnect;
647 AddressToBind.sin_addr.s_addr = NCE->Interface->Unicast.Address.IPv4Address;
648
649 KeAcquireSpinLock(&Connection->Lock, &OldIrql);
650
651 Status = TCPTranslateError
652 ( OskitTCPBind( Connection->SocketContext,
653 &AddressToBind,
654 sizeof(AddressToBind) ) );
655
656 if (NT_SUCCESS(Status)) {
657 memcpy( &AddressToConnect.sin_addr,
658 &RemoteAddress.Address.IPv4Address,
659 sizeof(AddressToConnect.sin_addr) );
660 AddressToConnect.sin_port = RemotePort;
661
662 Status = TCPTranslateError
663 ( OskitTCPConnect( Connection->SocketContext,
664 &AddressToConnect,
665 sizeof(AddressToConnect) ) );
666
667 KeReleaseSpinLock(&Connection->Lock, OldIrql);
668
669 if (Status == STATUS_PENDING)
670 {
671 Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG );
672 if( !Bucket )
673 {
674 return STATUS_NO_MEMORY;
675 }
676
677 Bucket->Request.RequestNotifyObject = (PVOID)Complete;
678 Bucket->Request.RequestContext = Context;
679
680 ExInterlockedInsertTailList( &Connection->ConnectRequest, &Bucket->Entry,
681 &Connection->Lock );
682 }
683 } else {
684 KeReleaseSpinLock(&Connection->Lock, OldIrql);
685 }
686
687 return Status;
688 }
689
690 NTSTATUS TCPDisconnect
691 ( PCONNECTION_ENDPOINT Connection,
692 UINT Flags,
693 PTDI_CONNECTION_INFORMATION ConnInfo,
694 PTDI_CONNECTION_INFORMATION ReturnInfo,
695 PTCP_COMPLETION_ROUTINE Complete,
696 PVOID Context ) {
697 NTSTATUS Status = STATUS_INVALID_PARAMETER;
698 KIRQL OldIrql;
699
700 TI_DbgPrint(DEBUG_TCP,("started\n"));
701
702 KeAcquireSpinLock(&Connection->Lock, &OldIrql);
703
704 if (Flags & TDI_DISCONNECT_RELEASE)
705 Status = TCPTranslateError(OskitTCPDisconnect(Connection->SocketContext));
706
707 if ((Flags & TDI_DISCONNECT_ABORT) || !Flags)
708 Status = TCPTranslateError(OskitTCPShutdown(Connection->SocketContext, FWRITE | FREAD));
709
710 KeReleaseSpinLock(&Connection->Lock, OldIrql);
711
712 TI_DbgPrint(DEBUG_TCP,("finished %x\n", Status));
713
714 return Status;
715 }
716
717 NTSTATUS TCPClose
718 ( PCONNECTION_ENDPOINT Connection ) {
719 NTSTATUS Status;
720 KIRQL OldIrql;
721 PVOID Socket;
722
723 TI_DbgPrint(DEBUG_TCP,("TCPClose started\n"));
724
725 KeAcquireSpinLock(&Connection->Lock, &OldIrql);
726 Socket = Connection->SocketContext;
727 Connection->SocketContext = NULL;
728 Status = TCPTranslateError( OskitTCPClose( Socket ) );
729 if (!NT_SUCCESS(Status))
730 {
731 Connection->SocketContext = Socket;
732 }
733 KeReleaseSpinLock(&Connection->Lock, OldIrql);
734
735 TI_DbgPrint(DEBUG_TCP,("TCPClose finished %x\n", Status));
736
737 return Status;
738 }
739
740 NTSTATUS TCPReceiveData
741 ( PCONNECTION_ENDPOINT Connection,
742 PNDIS_BUFFER Buffer,
743 ULONG ReceiveLength,
744 PULONG BytesReceived,
745 ULONG ReceiveFlags,
746 PTCP_COMPLETION_ROUTINE Complete,
747 PVOID Context ) {
748 PVOID DataBuffer;
749 UINT DataLen, Received = 0;
750 NTSTATUS Status;
751 PTDI_BUCKET Bucket;
752 KIRQL OldIrql;
753
754 TI_DbgPrint(DEBUG_TCP,("Called for %d bytes (on socket %x)\n",
755 ReceiveLength, Connection->SocketContext));
756
757 NdisQueryBuffer( Buffer, &DataBuffer, &DataLen );
758
759 TI_DbgPrint(DEBUG_TCP,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer, DataBuffer, DataLen));
760
761 KeAcquireSpinLock(&Connection->Lock, &OldIrql);
762
763 ASSERT_KM_POINTER(Connection->SocketContext);
764
765 Status = TCPTranslateError
766 ( OskitTCPRecv
767 ( Connection->SocketContext,
768 DataBuffer,
769 DataLen,
770 &Received,
771 ReceiveFlags ) );
772
773 KeReleaseSpinLock(&Connection->Lock, OldIrql);
774
775 TI_DbgPrint(DEBUG_TCP,("OskitTCPReceive: %x, %d\n", Status, Received));
776
777 /* Keep this request around ... there was no data yet */
778 if( Status == STATUS_PENDING ) {
779 /* Freed in TCPSocketState */
780 Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG );
781 if( !Bucket ) {
782 TI_DbgPrint(DEBUG_TCP,("Failed to allocate bucket\n"));
783 return STATUS_NO_MEMORY;
784 }
785
786 Bucket->Request.RequestNotifyObject = Complete;
787 Bucket->Request.RequestContext = Context;
788 *BytesReceived = 0;
789
790 ExInterlockedInsertTailList( &Connection->ReceiveRequest, &Bucket->Entry,
791 &Connection->Lock );
792 TI_DbgPrint(DEBUG_TCP,("Queued read irp\n"));
793 } else {
794 TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, Received));
795 *BytesReceived = Received;
796 }
797
798 TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
799
800 return Status;
801 }
802
803 NTSTATUS TCPSendData
804 ( PCONNECTION_ENDPOINT Connection,
805 PCHAR BufferData,
806 ULONG SendLength,
807 PULONG BytesSent,
808 ULONG Flags,
809 PTCP_COMPLETION_ROUTINE Complete,
810 PVOID Context ) {
811 UINT Sent = 0;
812 NTSTATUS Status;
813 PTDI_BUCKET Bucket;
814 KIRQL OldIrql;
815
816 KeAcquireSpinLock(&Connection->Lock, &OldIrql);
817
818 TI_DbgPrint(DEBUG_TCP,("Called for %d bytes (on socket %x)\n",
819 SendLength, Connection->SocketContext));
820
821 ASSERT_KM_POINTER(Connection->SocketContext);
822
823 TI_DbgPrint(DEBUG_TCP,("Connection = %x\n", Connection));
824 TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext = %x\n",
825 Connection->SocketContext));
826
827 Status = TCPTranslateError
828 ( OskitTCPSend( Connection->SocketContext,
829 (OSK_PCHAR)BufferData, SendLength,
830 &Sent, 0 ) );
831
832 KeReleaseSpinLock(&Connection->Lock, OldIrql);
833
834 TI_DbgPrint(DEBUG_TCP,("OskitTCPSend: %x, %d\n", Status, Sent));
835
836 /* Keep this request around ... there was no data yet */
837 if( Status == STATUS_PENDING ) {
838 /* Freed in TCPSocketState */
839 Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket), TDI_BUCKET_TAG );
840 if( !Bucket ) {
841 TI_DbgPrint(DEBUG_TCP,("Failed to allocate bucket\n"));
842 return STATUS_NO_MEMORY;
843 }
844
845 Bucket->Request.RequestNotifyObject = Complete;
846 Bucket->Request.RequestContext = Context;
847 *BytesSent = 0;
848
849 ExInterlockedInsertTailList( &Connection->SendRequest, &Bucket->Entry,
850 &Connection->Lock );
851 TI_DbgPrint(DEBUG_TCP,("Queued write irp\n"));
852 } else {
853 TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, Sent));
854 *BytesSent = Sent;
855 }
856
857 TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
858
859 return Status;
860 }
861
862 UINT TCPAllocatePort( UINT HintPort ) {
863 if( HintPort ) {
864 if( AllocatePort( &TCPPorts, HintPort ) ) return HintPort;
865 else {
866 TI_DbgPrint
867 (MID_TRACE,("We got a hint port but couldn't allocate it\n"));
868 return (UINT)-1;
869 }
870 } else return AllocatePortFromRange( &TCPPorts, 1024, 5000 );
871 }
872
873 VOID TCPFreePort( UINT Port ) {
874 DeallocatePort( &TCPPorts, Port );
875 }
876
877 NTSTATUS TCPGetSockAddress
878 ( PCONNECTION_ENDPOINT Connection,
879 PTRANSPORT_ADDRESS Address,
880 BOOLEAN GetRemote ) {
881 OSK_UINT LocalAddress, RemoteAddress;
882 OSK_UI16 LocalPort, RemotePort;
883 PTA_IP_ADDRESS AddressIP = (PTA_IP_ADDRESS)Address;
884 NTSTATUS Status;
885 KIRQL OldIrql;
886
887 KeAcquireSpinLock(&Connection->Lock, &OldIrql);
888
889 Status = TCPTranslateError(OskitTCPGetAddress(Connection->SocketContext,
890 &LocalAddress, &LocalPort,
891 &RemoteAddress, &RemotePort));
892
893 KeReleaseSpinLock(&Connection->Lock, OldIrql);
894
895 if (!NT_SUCCESS(Status))
896 return Status;
897
898 AddressIP->TAAddressCount = 1;
899 AddressIP->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
900 AddressIP->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
901 AddressIP->Address[0].Address[0].sin_port = GetRemote ? RemotePort : LocalPort;
902 AddressIP->Address[0].Address[0].in_addr = GetRemote ? RemoteAddress : LocalAddress;
903
904 return Status;
905 }
906
907 BOOLEAN TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint, PIRP Irp ) {
908 PLIST_ENTRY Entry;
909 PLIST_ENTRY ListHead[4];
910 KIRQL OldIrql;
911 PTDI_BUCKET Bucket;
912 UINT i = 0;
913 BOOLEAN Found = FALSE;
914
915 ListHead[0] = &Endpoint->SendRequest;
916 ListHead[1] = &Endpoint->ReceiveRequest;
917 ListHead[2] = &Endpoint->ConnectRequest;
918 ListHead[3] = &Endpoint->ListenRequest;
919
920 TcpipAcquireSpinLock( &Endpoint->Lock, &OldIrql );
921
922 for( i = 0; i < 4; i++ )
923 {
924 for( Entry = ListHead[i]->Flink;
925 Entry != ListHead[i];
926 Entry = Entry->Flink )
927 {
928 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
929 if( Bucket->Request.RequestContext == Irp )
930 {
931 RemoveEntryList( &Bucket->Entry );
932 ExFreePoolWithTag( Bucket, TDI_BUCKET_TAG );
933 Found = TRUE;
934 break;
935 }
936 }
937 }
938
939 TcpipReleaseSpinLock( &Endpoint->Lock, OldIrql );
940
941 return Found;
942 }
943
944 /* EOF */