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