- Revert my lib changes until I figure out some problems with them
[reactos.git] / 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 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 NTAPI
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 TcpipRecursiveMutexLeave( &TCPLock );
563 return Status;
564 }
565
566 AddressToConnect.sin_family = AF_INET;
567 AddressToBind = AddressToConnect;
568
569 OskitTCPBind( Connection->SocketContext,
570 Connection,
571 &AddressToBind,
572 sizeof(AddressToBind) );
573
574 memcpy( &AddressToConnect.sin_addr,
575 &RemoteAddress.Address.IPv4Address,
576 sizeof(AddressToConnect.sin_addr) );
577 AddressToConnect.sin_port = RemotePort;
578
579 Status = TCPTranslateError
580 ( OskitTCPConnect( Connection->SocketContext,
581 Connection,
582 &AddressToConnect,
583 sizeof(AddressToConnect) ) );
584
585 TcpipRecursiveMutexLeave( &TCPLock );
586
587 if( Status == OSK_EINPROGRESS )
588 return STATUS_PENDING;
589 else
590 return Status;
591 }
592
593 NTSTATUS TCPDisconnect
594 ( PCONNECTION_ENDPOINT Connection,
595 UINT Flags,
596 PTDI_CONNECTION_INFORMATION ConnInfo,
597 PTDI_CONNECTION_INFORMATION ReturnInfo,
598 PTCP_COMPLETION_ROUTINE Complete,
599 PVOID Context ) {
600 NTSTATUS Status;
601
602 TI_DbgPrint(DEBUG_TCP,("started\n"));
603
604 TcpipRecursiveMutexEnter( &TCPLock, TRUE );
605
606 switch( Flags & (TDI_DISCONNECT_ABORT | TDI_DISCONNECT_RELEASE) ) {
607 case 0:
608 case TDI_DISCONNECT_ABORT:
609 Flags = 0;
610 break;
611
612 case TDI_DISCONNECT_ABORT | TDI_DISCONNECT_RELEASE:
613 Flags = 2;
614 break;
615
616 case TDI_DISCONNECT_RELEASE:
617 Flags = 1;
618 break;
619 }
620
621 Status = TCPTranslateError
622 ( OskitTCPShutdown( Connection->SocketContext, Flags ) );
623
624 TcpipRecursiveMutexLeave( &TCPLock );
625
626 TI_DbgPrint(DEBUG_TCP,("finished %x\n", Status));
627
628 return Status;
629 }
630
631 NTSTATUS TCPClose
632 ( PCONNECTION_ENDPOINT Connection ) {
633 NTSTATUS Status;
634
635 TI_DbgPrint(DEBUG_TCP,("TCPClose started\n"));
636
637 TcpipRecursiveMutexEnter( &TCPLock, TRUE );
638
639 Status = TCPTranslateError( OskitTCPClose( Connection->SocketContext ) );
640
641 /* Make our code remove all pending IRPs */
642 Connection->State |= SEL_FIN;
643 DrainSignals();
644
645 TcpipRecursiveMutexLeave( &TCPLock );
646
647 TI_DbgPrint(DEBUG_TCP,("TCPClose finished %x\n", Status));
648
649 return Status;
650 }
651
652 NTSTATUS TCPReceiveData
653 ( PCONNECTION_ENDPOINT Connection,
654 PNDIS_BUFFER Buffer,
655 ULONG ReceiveLength,
656 PULONG BytesReceived,
657 ULONG ReceiveFlags,
658 PTCP_COMPLETION_ROUTINE Complete,
659 PVOID Context ) {
660 OSK_PCHAR DataBuffer;
661 UINT DataLen, Received = 0;
662 NTSTATUS Status;
663 PTDI_BUCKET Bucket;
664
665 TI_DbgPrint(DEBUG_TCP,("Called for %d bytes (on socket %x)\n",
666 ReceiveLength, Connection->SocketContext));
667
668 ASSERT_KM_POINTER(Connection->SocketContext);
669
670 TcpipRecursiveMutexEnter( &TCPLock, TRUE );
671
672 NdisQueryBuffer( Buffer, &DataBuffer, &DataLen );
673
674 TI_DbgPrint(DEBUG_TCP,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer, DataBuffer, DataLen));
675
676 Status = TCPTranslateError
677 ( OskitTCPRecv
678 ( Connection->SocketContext,
679 DataBuffer,
680 DataLen,
681 &Received,
682 ReceiveFlags ) );
683
684 TI_DbgPrint(DEBUG_TCP,("OskitTCPReceive: %x, %d\n", Status, Received));
685
686 /* Keep this request around ... there was no data yet */
687 if( Status == STATUS_PENDING ) {
688 /* Freed in TCPSocketState */
689 Bucket = ExAllocatePool( NonPagedPool, sizeof(*Bucket) );
690 if( !Bucket ) {
691 TI_DbgPrint(DEBUG_TCP,("Failed to allocate bucket\n"));
692 TcpipRecursiveMutexLeave( &TCPLock );
693 return STATUS_NO_MEMORY;
694 }
695
696 Bucket->Request.RequestNotifyObject = Complete;
697 Bucket->Request.RequestContext = Context;
698 *BytesReceived = 0;
699
700 InsertHeadList( &Connection->ReceiveRequest, &Bucket->Entry );
701 Status = STATUS_PENDING;
702 TI_DbgPrint(DEBUG_TCP,("Queued read irp\n"));
703 } else {
704 TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, Received));
705 *BytesReceived = Received;
706 }
707
708 TcpipRecursiveMutexLeave( &TCPLock );
709
710 TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
711
712 return Status;
713 }
714
715 NTSTATUS TCPSendData
716 ( PCONNECTION_ENDPOINT Connection,
717 PCHAR BufferData,
718 ULONG SendLength,
719 PULONG BytesSent,
720 ULONG Flags,
721 PTCP_COMPLETION_ROUTINE Complete,
722 PVOID Context ) {
723 UINT Sent = 0;
724 NTSTATUS Status;
725 PTDI_BUCKET Bucket;
726
727 TI_DbgPrint(DEBUG_TCP,("Called for %d bytes (on socket %x)\n",
728 SendLength, Connection->SocketContext));
729
730 ASSERT_KM_POINTER(Connection->SocketContext);
731
732 TcpipRecursiveMutexEnter( &TCPLock, TRUE );
733
734 TI_DbgPrint(DEBUG_TCP,("Connection = %x\n", Connection));
735 TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext = %x\n",
736 Connection->SocketContext));
737
738 Status = TCPTranslateError
739 ( OskitTCPSend( Connection->SocketContext,
740 (OSK_PCHAR)BufferData, SendLength,
741 &Sent, 0 ) );
742
743 TI_DbgPrint(DEBUG_TCP,("OskitTCPSend: %x, %d\n", Status, Sent));
744
745 /* Keep this request around ... there was no data yet */
746 if( Status == STATUS_PENDING ) {
747 /* Freed in TCPSocketState */
748 Bucket = ExAllocatePool( NonPagedPool, sizeof(*Bucket) );
749 if( !Bucket ) {
750 TI_DbgPrint(DEBUG_TCP,("Failed to allocate bucket\n"));
751 TcpipRecursiveMutexLeave( &TCPLock );
752 return STATUS_NO_MEMORY;
753 }
754
755 Bucket->Request.RequestNotifyObject = Complete;
756 Bucket->Request.RequestContext = Context;
757 *BytesSent = 0;
758
759 InsertHeadList( &Connection->SendRequest, &Bucket->Entry );
760 TI_DbgPrint(DEBUG_TCP,("Queued write irp\n"));
761 } else {
762 TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, Sent));
763 *BytesSent = Sent;
764 }
765
766 TcpipRecursiveMutexLeave( &TCPLock );
767
768 TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
769
770 return Status;
771 }
772
773 VOID TCPTimeout(VOID) {
774 /* Now handled by TimerThread */
775 }
776
777 UINT TCPAllocatePort( UINT HintPort ) {
778 if( HintPort ) {
779 if( AllocatePort( &TCPPorts, HintPort ) ) return HintPort;
780 else {
781 TI_DbgPrint
782 (MID_TRACE,("We got a hint port but couldn't allocate it\n"));
783 return (UINT)-1;
784 }
785 } else return AllocatePortFromRange( &TCPPorts, 1024, 5000 );
786 }
787
788 VOID TCPFreePort( UINT Port ) {
789 DeallocatePort( &TCPPorts, Port );
790 }
791
792 NTSTATUS TCPGetPeerAddress
793 ( PCONNECTION_ENDPOINT Connection,
794 PTRANSPORT_ADDRESS Address ) {
795 OSK_UINT LocalAddress, RemoteAddress;
796 OSK_UI16 LocalPort, RemotePort;
797 PTA_IP_ADDRESS AddressIP = (PTA_IP_ADDRESS)Address;
798
799 TcpipRecursiveMutexEnter( &TCPLock, TRUE );
800
801 OskitTCPGetAddress
802 ( Connection->SocketContext,
803 &LocalAddress, &LocalPort,
804 &RemoteAddress, &RemotePort );
805
806 AddressIP->TAAddressCount = 1;
807 AddressIP->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
808 AddressIP->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
809 AddressIP->Address[0].Address[0].sin_port = RemotePort;
810 AddressIP->Address[0].Address[0].in_addr = RemoteAddress;
811
812 TcpipRecursiveMutexLeave( &TCPLock );
813
814 return STATUS_SUCCESS;
815 }
816
817 VOID TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint, PIRP Irp ) {
818 PLIST_ENTRY Entry;
819 PLIST_ENTRY ListHead[4];
820 KIRQL OldIrql;
821 PTDI_BUCKET Bucket;
822 UINT i = 0;
823
824 ListHead[0] = &Endpoint->SendRequest;
825 ListHead[1] = &Endpoint->ReceiveRequest;
826 ListHead[2] = &Endpoint->ConnectRequest;
827 ListHead[3] = &Endpoint->ListenRequest;
828
829 TcpipAcquireSpinLock( &Endpoint->Lock, &OldIrql );
830
831 for( i = 0; i < sizeof( ListHead ) / sizeof( ListHead[0] ); i++ ) {
832 for( Entry = ListHead[i]->Flink;
833 Entry != ListHead[i];
834 Entry = Entry->Flink ) {
835 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
836
837 if( Bucket->Request.RequestContext == Irp ) {
838 RemoveEntryList( &Bucket->Entry );
839 break;
840 }
841 }
842 }
843
844 TcpipReleaseSpinLock( &Endpoint->Lock, OldIrql );
845 }
846
847 /* EOF */