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