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