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