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 PORT_SET TCPPorts;
18
19 #include "lwip/pbuf.h"
20 #include "lwip/ip.h"
21 #include "lwip/init.h"
22 #include "lwip/arch.h"
23
24 #include <lwip_glue/lwip_glue.h>
25
26 NPAGED_LOOKASIDE_LIST TdiBucketLookasideList;
27
28 static
29 IO_WORKITEM_ROUTINE
30 DisconnectWorker;
31
32 _Use_decl_annotations_
33 VOID
34 NTAPI
DisconnectWorker(_Unreferenced_parameter_ PDEVICE_OBJECT DeviceObject,_In_ PVOID Context)35 DisconnectWorker(
36 _Unreferenced_parameter_ PDEVICE_OBJECT DeviceObject,
37 _In_ PVOID Context
38 )
39 {
40 PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)Context;
41 PLIST_ENTRY Entry;
42 PTDI_BUCKET Bucket;
43
44 /* We timed out waiting for pending sends so force it to shutdown */
45 TCPTranslateError(LibTCPShutdown(Connection, 0, 1));
46
47 LockObject(Connection);
48
49 while (!IsListEmpty(&Connection->SendRequest))
50 {
51 Entry = RemoveHeadList(&Connection->SendRequest);
52
53 Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
54
55 Bucket->Information = 0;
56 Bucket->Status = STATUS_FILE_CLOSED;
57
58 CompleteBucket(Connection, Bucket, FALSE);
59 }
60
61 while (!IsListEmpty(&Connection->ShutdownRequest))
62 {
63 Entry = RemoveHeadList( &Connection->ShutdownRequest );
64
65 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
66
67 Bucket->Status = STATUS_TIMEOUT;
68 Bucket->Information = 0;
69
70 CompleteBucket(Connection, Bucket, FALSE);
71 }
72
73 UnlockObject(Connection);
74
75 DereferenceObject(Connection);
76 }
77
78 VOID
79 NTAPI
DisconnectTimeoutDpc(PKDPC Dpc,PVOID DeferredContext,PVOID SystemArgument1,PVOID SystemArgument2)80 DisconnectTimeoutDpc(PKDPC Dpc,
81 PVOID DeferredContext,
82 PVOID SystemArgument1,
83 PVOID SystemArgument2)
84 {
85 PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)DeferredContext;
86
87 IoQueueWorkItem(Connection->DisconnectWorkItem, DisconnectWorker, DelayedWorkQueue, Connection);
88 }
89
ConnectionFree(PVOID Object)90 VOID ConnectionFree(PVOID Object)
91 {
92 PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)Object;
93 KIRQL OldIrql;
94
95 TI_DbgPrint(DEBUG_TCP, ("Freeing TCP Endpoint\n"));
96
97 TcpipAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql);
98 RemoveEntryList(&Connection->ListEntry);
99 TcpipReleaseSpinLock(&ConnectionEndpointListLock, OldIrql);
100
101 ExDeleteResourceLite(&Connection->Resource);
102 IoFreeWorkItem(Connection->DisconnectWorkItem);
103
104 ExFreePoolWithTag( Connection, CONN_ENDPT_TAG );
105 }
106
TCPAllocateConnectionEndpoint(PVOID ClientContext)107 PCONNECTION_ENDPOINT TCPAllocateConnectionEndpoint( PVOID ClientContext )
108 {
109 PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)
110 ExAllocatePoolWithTag(NonPagedPool, sizeof(CONNECTION_ENDPOINT), CONN_ENDPT_TAG);
111
112 if (!Connection)
113 return Connection;
114
115 TI_DbgPrint(DEBUG_CPOINT, ("Connection point file object allocated at (0x%X).\n", Connection));
116
117 RtlZeroMemory(Connection, sizeof(CONNECTION_ENDPOINT));
118
119 /* Initialize spin lock that protects the connection endpoint file object */
120 ExInitializeResourceLite(&Connection->Resource);
121 InitializeListHead(&Connection->ConnectRequest);
122 InitializeListHead(&Connection->ListenRequest);
123 InitializeListHead(&Connection->ReceiveRequest);
124 InitializeListHead(&Connection->SendRequest);
125 InitializeListHead(&Connection->ShutdownRequest);
126 InitializeListHead(&Connection->PacketQueue);
127
128 /* Initialize disconnect timer */
129 KeInitializeTimer(&Connection->DisconnectTimer);
130 KeInitializeDpc(&Connection->DisconnectDpc, DisconnectTimeoutDpc, Connection);
131 Connection->DisconnectWorkItem = IoAllocateWorkItem(TCPDeviceObject);
132 if (!Connection->DisconnectWorkItem)
133 {
134 ExDeleteResourceLite(&Connection->Resource);
135 ExFreePoolWithTag( Connection, CONN_ENDPT_TAG );
136 return NULL;
137 }
138
139 /* Save client context pointer */
140 Connection->ClientContext = ClientContext;
141
142 Connection->RefCount = 1;
143 Connection->Free = ConnectionFree;
144
145 /* Add connection endpoint to global list */
146 ExInterlockedInsertTailList(&ConnectionEndpointListHead,
147 &Connection->ListEntry,
148 &ConnectionEndpointListLock);
149
150 return Connection;
151 }
152
TCPSocket(PCONNECTION_ENDPOINT Connection,UINT Family,UINT Type,UINT Proto)153 NTSTATUS TCPSocket( PCONNECTION_ENDPOINT Connection,
154 UINT Family, UINT Type, UINT Proto )
155 {
156 NTSTATUS Status;
157
158 LockObject(Connection);
159
160 TI_DbgPrint(DEBUG_TCP,("[IP, TCPSocket] Called: Connection %x, Family %d, Type %d, "
161 "Proto %d, sizeof(CONNECTION_ENDPOINT) = %d\n",
162 Connection, Family, Type, Proto, sizeof(CONNECTION_ENDPOINT)));
163
164 Connection->SocketContext = LibTCPSocket(Connection);
165 if (Connection->SocketContext)
166 Status = STATUS_SUCCESS;
167 else
168 Status = STATUS_INSUFFICIENT_RESOURCES;
169
170 UnlockObject(Connection);
171
172 TI_DbgPrint(DEBUG_TCP,("[IP, TCPSocket] Leaving. Status = 0x%x\n", Status));
173
174 return Status;
175 }
176
TCPClose(PCONNECTION_ENDPOINT Connection)177 NTSTATUS TCPClose( PCONNECTION_ENDPOINT Connection )
178 {
179 LockObject(Connection);
180
181 FlushAllQueues(Connection, STATUS_CANCELLED);
182
183 UnlockObject(Connection);
184
185 LibTCPClose(Connection, FALSE, TRUE);
186
187 DereferenceObject(Connection);
188
189 return STATUS_SUCCESS;
190 }
191
TCPReceive(PIP_INTERFACE Interface,PIP_PACKET IPPacket)192 VOID TCPReceive(PIP_INTERFACE Interface, PIP_PACKET IPPacket)
193 /*
194 * FUNCTION: Receives and queues TCP data
195 * ARGUMENTS:
196 * IPPacket = Pointer to an IP packet that was received
197 * NOTES:
198 * This is the low level interface for receiving TCP data
199 */
200 {
201 TI_DbgPrint(DEBUG_TCP,("Sending packet %d (%d) to lwIP\n",
202 IPPacket->TotalSize,
203 IPPacket->HeaderSize));
204
205 LibIPInsertPacket(Interface->TCPContext, IPPacket->Header, IPPacket->TotalSize);
206 }
207
TCPStartup(VOID)208 NTSTATUS TCPStartup(VOID)
209 /*
210 * FUNCTION: Initializes the TCP subsystem
211 * RETURNS:
212 * Status of operation
213 */
214 {
215 NTSTATUS Status;
216
217 Status = PortsStartup(&TCPPorts, 1, 0xffff);
218 if (!NT_SUCCESS(Status))
219 {
220 return Status;
221 }
222
223 ExInitializeNPagedLookasideList(&TdiBucketLookasideList,
224 NULL,
225 NULL,
226 0,
227 sizeof(TDI_BUCKET),
228 TDI_BUCKET_TAG,
229 0);
230
231 /* Initialize our IP library */
232 LibIPInitialize();
233
234 /* Register this protocol with IP layer */
235 IPRegisterProtocol(IPPROTO_TCP, TCPReceive);
236
237 TCPInitialized = TRUE;
238
239 return STATUS_SUCCESS;
240 }
241
242
TCPShutdown(VOID)243 NTSTATUS TCPShutdown(VOID)
244 /*
245 * FUNCTION: Shuts down the TCP subsystem
246 * RETURNS:
247 * Status of operation
248 */
249 {
250 if (!TCPInitialized)
251 return STATUS_SUCCESS;
252
253 ExDeleteNPagedLookasideList(&TdiBucketLookasideList);
254
255 LibIPShutdown();
256
257 /* Deregister this protocol with IP layer */
258 IPRegisterProtocol(IPPROTO_TCP, NULL);
259
260 TCPInitialized = FALSE;
261
262 PortsShutdown( &TCPPorts );
263
264 return STATUS_SUCCESS;
265 }
266
TCPTranslateError(const err_t err)267 NTSTATUS TCPTranslateError(const err_t err)
268 {
269 NTSTATUS Status;
270
271 switch (err)
272 {
273 case ERR_OK: Status = STATUS_SUCCESS; return Status; //0
274 case ERR_MEM: Status = STATUS_INSUFFICIENT_RESOURCES; break; //-1
275 case ERR_BUF: Status = STATUS_BUFFER_TOO_SMALL; break; //-2
276 case ERR_TIMEOUT: Status = STATUS_TIMEOUT; break; // -3
277 case ERR_RTE: Status = STATUS_NETWORK_UNREACHABLE; break; //-4
278 case ERR_INPROGRESS: Status = STATUS_PENDING; return Status; //-5
279 case ERR_VAL: Status = STATUS_INVALID_PARAMETER; break; //-6
280 case ERR_WOULDBLOCK: Status = STATUS_CANT_WAIT; break; //-7
281 case ERR_USE: Status = STATUS_ADDRESS_ALREADY_EXISTS; break; //-8
282 case ERR_ISCONN: Status = STATUS_UNSUCCESSFUL; break; //-9 (FIXME)
283 case ERR_ABRT: Status = STATUS_LOCAL_DISCONNECT; break; //-10
284 case ERR_RST: Status = STATUS_REMOTE_DISCONNECT; break; //-11
285 case ERR_CLSD: Status = STATUS_FILE_CLOSED; break; //-12
286 case ERR_CONN: Status = STATUS_INVALID_CONNECTION; break; //-13
287 case ERR_ARG: Status = STATUS_INVALID_PARAMETER; break; //-14
288 case ERR_IF: Status = STATUS_UNEXPECTED_NETWORK_ERROR; break; //-15
289 default:
290 DbgPrint("Invalid error value: %d\n", err);
291 ASSERT(FALSE);
292 Status = STATUS_UNSUCCESSFUL;
293 break;
294 }
295
296 TI_DbgPrint(DEBUG_TCP,("TCP operation failed: 0x%x (%d)\n", Status, err));
297
298 return Status;
299 }
300
TCPConnect(PCONNECTION_ENDPOINT Connection,PTDI_CONNECTION_INFORMATION ConnInfo,PTDI_CONNECTION_INFORMATION ReturnInfo,PTCP_COMPLETION_ROUTINE Complete,PVOID Context)301 NTSTATUS TCPConnect
302 ( PCONNECTION_ENDPOINT Connection,
303 PTDI_CONNECTION_INFORMATION ConnInfo,
304 PTDI_CONNECTION_INFORMATION ReturnInfo,
305 PTCP_COMPLETION_ROUTINE Complete,
306 PVOID Context )
307 {
308 NTSTATUS Status;
309 ip_addr_t bindaddr, connaddr;
310 IP_ADDRESS RemoteAddress;
311 USHORT RemotePort;
312 TA_IP_ADDRESS LocalAddress;
313 PTDI_BUCKET Bucket;
314 PNEIGHBOR_CACHE_ENTRY NCE;
315
316 TI_DbgPrint(DEBUG_TCP,("[IP, TCPConnect] Called\n"));
317
318 Status = AddrBuildAddress
319 ((PTRANSPORT_ADDRESS)ConnInfo->RemoteAddress,
320 &RemoteAddress,
321 &RemotePort);
322
323 if (!NT_SUCCESS(Status))
324 {
325 TI_DbgPrint(DEBUG_TCP, ("Could not AddrBuildAddress in TCPConnect\n"));
326 return Status;
327 }
328
329 /* Freed in TCPSocketState */
330 TI_DbgPrint(DEBUG_TCP,
331 ("Connecting to address %x:%x\n",
332 RemoteAddress.Address.IPv4Address,
333 RemotePort));
334
335 LockObject(Connection);
336
337 if (!Connection->AddressFile)
338 {
339 UnlockObject(Connection);
340 return STATUS_INVALID_PARAMETER;
341 }
342
343 if (AddrIsUnspecified(&Connection->AddressFile->Address))
344 {
345 if (!(NCE = RouteGetRouteToDestination(&RemoteAddress)))
346 {
347 UnlockObject(Connection);
348 return STATUS_NETWORK_UNREACHABLE;
349 }
350
351 bindaddr.addr = NCE->Interface->Unicast.Address.IPv4Address;
352 }
353 else
354 {
355 bindaddr.addr = Connection->AddressFile->Address.Address.IPv4Address;
356 }
357
358 Status = TCPTranslateError(LibTCPBind(Connection,
359 &bindaddr,
360 Connection->AddressFile->Port));
361
362 if (!NT_SUCCESS(Status))
363 {
364 UnlockObject(Connection);
365 return Status;
366 }
367
368 /* Copy bind address into connection */
369 Connection->AddressFile->Address.Address.IPv4Address = bindaddr.addr;
370 /* Check if we had an unspecified port */
371 if (!Connection->AddressFile->Port)
372 {
373 UINT AllocatedPort;
374
375 /* We did, so we need to copy back the port */
376 Status = TCPGetSockAddress(Connection, (PTRANSPORT_ADDRESS)&LocalAddress, FALSE);
377 if (!NT_SUCCESS(Status))
378 {
379 UnlockObject(Connection);
380 return Status;
381 }
382
383 /* Allocate the port in the port bitmap */
384 AllocatedPort = TCPAllocatePort(LocalAddress.Address[0].Address[0].sin_port);
385 /* This should never fail unless all ports are in use */
386 if (AllocatedPort == (UINT) -1)
387 {
388 DbgPrint("ERR: No more ports available.\n");
389 UnlockObject(Connection);
390 return STATUS_TOO_MANY_ADDRESSES;
391 }
392 Connection->AddressFile->Port = AllocatedPort;
393 }
394
395 connaddr.addr = RemoteAddress.Address.IPv4Address;
396
397 Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
398 if (!Bucket)
399 {
400 UnlockObject(Connection);
401 return STATUS_NO_MEMORY;
402 }
403
404 Bucket->Request.RequestNotifyObject = (PVOID)Complete;
405 Bucket->Request.RequestContext = Context;
406
407 InsertTailList( &Connection->ConnectRequest, &Bucket->Entry );
408
409 UnlockObject(Connection);
410
411 Status = TCPTranslateError(LibTCPConnect(Connection,
412 &connaddr,
413 RemotePort));
414 if (!NT_SUCCESS(Status))
415 {
416 LockObject(Connection);
417 RemoveEntryList(&Bucket->Entry);
418 UnlockObject(Connection);
419 ExFreeToNPagedLookasideList(&TdiBucketLookasideList, Bucket);
420 }
421 TI_DbgPrint(DEBUG_TCP,("[IP, TCPConnect] Leaving. Status = 0x%x\n", Status));
422
423 return Status;
424 }
425
TCPDisconnect(PCONNECTION_ENDPOINT Connection,UINT Flags,PLARGE_INTEGER Timeout,PTDI_CONNECTION_INFORMATION ConnInfo,PTDI_CONNECTION_INFORMATION ReturnInfo,PTCP_COMPLETION_ROUTINE Complete,PVOID Context)426 NTSTATUS TCPDisconnect
427 ( PCONNECTION_ENDPOINT Connection,
428 UINT Flags,
429 PLARGE_INTEGER Timeout,
430 PTDI_CONNECTION_INFORMATION ConnInfo,
431 PTDI_CONNECTION_INFORMATION ReturnInfo,
432 PTCP_COMPLETION_ROUTINE Complete,
433 PVOID Context )
434 {
435 NTSTATUS Status = STATUS_INVALID_PARAMETER;
436 PTDI_BUCKET Bucket;
437 LARGE_INTEGER ActualTimeout;
438
439 TI_DbgPrint(DEBUG_TCP,("[IP, TCPDisconnect] Called\n"));
440
441 LockObject(Connection);
442
443 if (Connection->SocketContext)
444 {
445 if (Flags & TDI_DISCONNECT_RELEASE)
446 {
447 if (IsListEmpty(&Connection->SendRequest))
448 {
449 ReferenceObject(Connection);
450 UnlockObject(Connection);
451 Status = TCPTranslateError(LibTCPShutdown(Connection, 0, 1));
452 LockObject(Connection);
453 DereferenceObject(Connection);
454 }
455 else if (Timeout && Timeout->QuadPart == 0)
456 {
457 FlushSendQueue(Connection, STATUS_FILE_CLOSED);
458 ReferenceObject(Connection);
459 UnlockObject(Connection);
460 LibTCPShutdown(Connection, 0, 1);
461 LockObject(Connection);
462 DereferenceObject(Connection);
463 Status = STATUS_TIMEOUT;
464 }
465 else
466 {
467 /* Use the timeout specified or 1 second if none was specified */
468 if (Timeout)
469 {
470 ActualTimeout = *Timeout;
471 }
472 else
473 {
474 ActualTimeout.QuadPart = -1000000;
475 }
476
477 /* We couldn't complete the request now because we need to wait for outstanding I/O */
478 Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
479 if (!Bucket)
480 {
481 UnlockObject(Connection);
482 return STATUS_NO_MEMORY;
483 }
484
485 Bucket->Request.RequestNotifyObject = (PVOID)Complete;
486 Bucket->Request.RequestContext = Context;
487
488 InsertTailList(&Connection->ShutdownRequest, &Bucket->Entry);
489
490 ReferenceObject(Connection);
491 if (KeSetTimer(&Connection->DisconnectTimer, ActualTimeout, &Connection->DisconnectDpc))
492 {
493 /* Timer was already in the queue. */
494 DereferenceObject(Connection);
495 }
496
497 Status = STATUS_PENDING;
498 }
499 }
500
501 if ((Flags & TDI_DISCONNECT_ABORT) || !Flags)
502 {
503 FlushReceiveQueue(Connection, STATUS_FILE_CLOSED);
504 FlushSendQueue(Connection, STATUS_FILE_CLOSED);
505 FlushShutdownQueue(Connection, STATUS_FILE_CLOSED);
506 ReferenceObject(Connection);
507 UnlockObject(Connection);
508 Status = TCPTranslateError(LibTCPShutdown(Connection, 1, 1));
509 DereferenceObject(Connection);
510 }
511 else
512 {
513 UnlockObject(Connection);
514 }
515 }
516 else
517 {
518 UnlockObject(Connection);
519 /* We already got closed by the other side so just return success */
520 Status = STATUS_SUCCESS;
521 }
522
523 TI_DbgPrint(DEBUG_TCP,("[IP, TCPDisconnect] Leaving. Status = 0x%x\n", Status));
524
525 return Status;
526 }
527
TCPReceiveData(PCONNECTION_ENDPOINT Connection,PNDIS_BUFFER Buffer,ULONG ReceiveLength,PULONG BytesReceived,ULONG ReceiveFlags,PTCP_COMPLETION_ROUTINE Complete,PVOID Context)528 NTSTATUS TCPReceiveData
529 ( PCONNECTION_ENDPOINT Connection,
530 PNDIS_BUFFER Buffer,
531 ULONG ReceiveLength,
532 PULONG BytesReceived,
533 ULONG ReceiveFlags,
534 PTCP_COMPLETION_ROUTINE Complete,
535 PVOID Context )
536 {
537 PTDI_BUCKET Bucket;
538 PUCHAR DataBuffer;
539 UINT DataLen, Received;
540 NTSTATUS Status;
541
542 TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Called for %d bytes (on socket %x)\n",
543 ReceiveLength, Connection->SocketContext));
544
545 NdisQueryBuffer(Buffer, &DataBuffer, &DataLen);
546
547 Status = LibTCPGetDataFromConnectionQueue(Connection, DataBuffer, DataLen, &Received);
548
549 if (Status == STATUS_PENDING)
550 {
551 Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
552 if (!Bucket)
553 {
554 TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Failed to allocate bucket\n"));
555
556 return STATUS_NO_MEMORY;
557 }
558
559 Bucket->Request.RequestNotifyObject = Complete;
560 Bucket->Request.RequestContext = Context;
561
562 LockObject(Connection);
563 InsertTailList( &Connection->ReceiveRequest, &Bucket->Entry );
564 UnlockObject(Connection);
565 TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Queued read irp\n"));
566
567 TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Leaving. Status = STATUS_PENDING\n"));
568
569 (*BytesReceived) = 0;
570 }
571 else
572 {
573 (*BytesReceived) = Received;
574 }
575
576 return Status;
577 }
578
TCPSendData(PCONNECTION_ENDPOINT Connection,PCHAR BufferData,ULONG SendLength,PULONG BytesSent,ULONG Flags,PTCP_COMPLETION_ROUTINE Complete,PVOID Context)579 NTSTATUS TCPSendData
580 ( PCONNECTION_ENDPOINT Connection,
581 PCHAR BufferData,
582 ULONG SendLength,
583 PULONG BytesSent,
584 ULONG Flags,
585 PTCP_COMPLETION_ROUTINE Complete,
586 PVOID Context )
587 {
588 NTSTATUS Status;
589 PTDI_BUCKET Bucket;
590
591 ReferenceObject(Connection);
592
593 TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Called for %d bytes (on socket %x)\n",
594 SendLength, Connection->SocketContext));
595
596 TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Connection = %x\n", Connection));
597 TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Connection->SocketContext = %x\n",
598 Connection->SocketContext));
599
600 Status = TCPTranslateError(LibTCPSend(Connection,
601 BufferData,
602 SendLength,
603 BytesSent,
604 FALSE));
605
606 TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Send: %x, %d\n", Status, SendLength));
607
608 /* Keep this request around ... there was no data yet */
609 if (Status == STATUS_PENDING)
610 {
611 /* Freed in TCPSocketState */
612 Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
613 if (!Bucket)
614 {
615 DereferenceObject(Connection);
616 TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Failed to allocate bucket\n"));
617 return STATUS_NO_MEMORY;
618 }
619
620 Bucket->Request.RequestNotifyObject = Complete;
621 Bucket->Request.RequestContext = Context;
622
623 LockObject(Connection);
624 InsertTailList( &Connection->SendRequest, &Bucket->Entry );
625 TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Queued write irp\n"));
626 UnlockObject(Connection);
627 }
628
629
630 TI_DbgPrint(DEBUG_TCP, ("[IP, TCPSendData] Leaving. Status = %x\n", Status));
631 DereferenceObject(Connection);
632
633 return Status;
634 }
635
TCPAllocatePort(const UINT HintPort)636 UINT TCPAllocatePort(const UINT HintPort)
637 {
638 if (HintPort)
639 {
640 if (AllocatePort(&TCPPorts, HintPort))
641 return HintPort;
642 else
643 {
644 TI_DbgPrint(MID_TRACE,("We got a hint port but couldn't allocate it\n"));
645 return (UINT)-1;
646 }
647 }
648 else
649 return AllocatePortFromRange( &TCPPorts, 1024, 5000 );
650 }
651
TCPFreePort(const UINT Port)652 VOID TCPFreePort(const UINT Port)
653 {
654 DeallocatePort(&TCPPorts, Port);
655 }
656
TCPGetSockAddress(PCONNECTION_ENDPOINT Connection,PTRANSPORT_ADDRESS Address,BOOLEAN GetRemote)657 NTSTATUS TCPGetSockAddress
658 ( PCONNECTION_ENDPOINT Connection,
659 PTRANSPORT_ADDRESS Address,
660 BOOLEAN GetRemote )
661 {
662 PTA_IP_ADDRESS AddressIP = (PTA_IP_ADDRESS)Address;
663 ip_addr_t ipaddr;
664 NTSTATUS Status;
665
666 AddressIP->TAAddressCount = 1;
667 AddressIP->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
668 AddressIP->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
669
670 LockObject(Connection);
671
672 if (GetRemote)
673 {
674 Status = TCPTranslateError(LibTCPGetPeerName(Connection->SocketContext,
675 &ipaddr,
676 &AddressIP->Address[0].Address[0].sin_port));
677 }
678 else
679 {
680 Status = TCPTranslateError(LibTCPGetHostName(Connection->SocketContext,
681 &ipaddr,
682 &AddressIP->Address[0].Address[0].sin_port));
683 }
684
685 UnlockObject(Connection);
686
687 AddressIP->Address[0].Address[0].in_addr = ipaddr.addr;
688
689 RtlZeroMemory(&AddressIP->Address[0].Address[0].sin_zero,
690 sizeof(AddressIP->Address[0].Address[0].sin_zero));
691
692 return Status;
693 }
694
TCPRemoveIRP(PCONNECTION_ENDPOINT Endpoint,PIRP Irp)695 BOOLEAN TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint, PIRP Irp )
696 {
697 PLIST_ENTRY Entry;
698 PLIST_ENTRY ListHead[5];
699 PTDI_BUCKET Bucket;
700 UINT i = 0;
701 BOOLEAN Found = FALSE;
702
703 ListHead[0] = &Endpoint->SendRequest;
704 ListHead[1] = &Endpoint->ReceiveRequest;
705 ListHead[2] = &Endpoint->ConnectRequest;
706 ListHead[3] = &Endpoint->ListenRequest;
707 ListHead[4] = &Endpoint->ShutdownRequest;
708
709 LockObject(Endpoint);
710
711 for( i = 0; i < 5; i++ )
712 {
713 for( Entry = ListHead[i]->Flink;
714 Entry != ListHead[i];
715 Entry = Entry->Flink )
716 {
717 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
718 if( Bucket->Request.RequestContext == Irp )
719 {
720 RemoveEntryList( &Bucket->Entry );
721 ExFreeToNPagedLookasideList(&TdiBucketLookasideList, Bucket);
722 Found = TRUE;
723 break;
724 }
725 }
726 }
727
728 UnlockObject(Endpoint);
729
730 return Found;
731 }
732
733 NTSTATUS
TCPSetNoDelay(PCONNECTION_ENDPOINT Connection,BOOLEAN Set)734 TCPSetNoDelay(
735 PCONNECTION_ENDPOINT Connection,
736 BOOLEAN Set)
737 {
738 if (!Connection)
739 return STATUS_UNSUCCESSFUL;
740
741 if (Connection->SocketContext == NULL)
742 return STATUS_UNSUCCESSFUL;
743
744 LibTCPSetNoDelay(Connection->SocketContext, Set);
745 return STATUS_SUCCESS;
746 }
747
748 NTSTATUS
TCPGetSocketStatus(PCONNECTION_ENDPOINT Connection,PULONG State)749 TCPGetSocketStatus(
750 PCONNECTION_ENDPOINT Connection,
751 PULONG State)
752 {
753 if (!Connection)
754 return STATUS_UNSUCCESSFUL;
755
756 if (Connection->SocketContext == NULL)
757 return STATUS_UNSUCCESSFUL;
758
759 LibTCPGetSocketStatus(Connection->SocketContext, State);
760 return STATUS_SUCCESS;
761 }
762
763 /* EOF */
764