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