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