Revert r64621.
[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 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 DbgPrint("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 /* Check if we had an unspecified port */
341 if (!Connection->AddressFile->Port)
342 {
343 /* We did, so we need to copy back the port */
344 Status = TCPGetSockAddress(Connection, (PTRANSPORT_ADDRESS)&LocalAddress, FALSE);
345 if (NT_SUCCESS(Status))
346 {
347 /* Allocate the port in the port bitmap */
348 Connection->AddressFile->Port = TCPAllocatePort(LocalAddress.Address[0].Address[0].sin_port);
349
350 /* This should never fail */
351 ASSERT(Connection->AddressFile->Port != 0xFFFF);
352 }
353 }
354
355 if (NT_SUCCESS(Status))
356 {
357 connaddr.addr = RemoteAddress.Address.IPv4Address;
358
359 Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
360 if (!Bucket)
361 {
362 UnlockObject(Connection, OldIrql);
363 return STATUS_NO_MEMORY;
364 }
365
366 Bucket->Request.RequestNotifyObject = (PVOID)Complete;
367 Bucket->Request.RequestContext = Context;
368
369 InsertTailList( &Connection->ConnectRequest, &Bucket->Entry );
370
371 Status = TCPTranslateError(LibTCPConnect(Connection,
372 &connaddr,
373 RemotePort));
374 }
375 }
376
377 UnlockObject(Connection, OldIrql);
378
379 TI_DbgPrint(DEBUG_TCP,("[IP, TCPConnect] Leaving. Status = 0x%x\n", Status));
380
381 return Status;
382 }
383
384 NTSTATUS TCPDisconnect
385 ( PCONNECTION_ENDPOINT Connection,
386 UINT Flags,
387 PLARGE_INTEGER Timeout,
388 PTDI_CONNECTION_INFORMATION ConnInfo,
389 PTDI_CONNECTION_INFORMATION ReturnInfo,
390 PTCP_COMPLETION_ROUTINE Complete,
391 PVOID Context )
392 {
393 NTSTATUS Status = STATUS_INVALID_PARAMETER;
394 PTDI_BUCKET Bucket;
395 KIRQL OldIrql;
396 LARGE_INTEGER ActualTimeout;
397
398 TI_DbgPrint(DEBUG_TCP,("[IP, TCPDisconnect] Called\n"));
399
400 LockObject(Connection, &OldIrql);
401
402 if (Connection->SocketContext)
403 {
404 if (Flags & TDI_DISCONNECT_RELEASE)
405 {
406 if (IsListEmpty(&Connection->SendRequest))
407 {
408 Status = TCPTranslateError(LibTCPShutdown(Connection, 0, 1));
409 }
410 else if (Timeout && Timeout->QuadPart == 0)
411 {
412 FlushSendQueue(Connection, STATUS_FILE_CLOSED, FALSE);
413 TCPTranslateError(LibTCPShutdown(Connection, 0, 1));
414 Status = STATUS_TIMEOUT;
415 }
416 else
417 {
418 /* Use the timeout specified or 1 second if none was specified */
419 if (Timeout)
420 {
421 ActualTimeout = *Timeout;
422 }
423 else
424 {
425 ActualTimeout.QuadPart = -1000000;
426 }
427
428 /* We couldn't complete the request now because we need to wait for outstanding I/O */
429 Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
430 if (!Bucket)
431 {
432 UnlockObject(Connection, OldIrql);
433 return STATUS_NO_MEMORY;
434 }
435
436 Bucket->Request.RequestNotifyObject = (PVOID)Complete;
437 Bucket->Request.RequestContext = Context;
438
439 InsertTailList(&Connection->ShutdownRequest, &Bucket->Entry);
440
441 ReferenceObject(Connection);
442 if (KeCancelTimer(&Connection->DisconnectTimer))
443 {
444 DereferenceObject(Connection);
445 }
446 KeSetTimer(&Connection->DisconnectTimer, ActualTimeout, &Connection->DisconnectDpc);
447
448 Status = STATUS_PENDING;
449 }
450 }
451
452 if ((Flags & TDI_DISCONNECT_ABORT) || !Flags)
453 {
454 FlushReceiveQueue(Connection, STATUS_FILE_CLOSED, FALSE);
455 FlushSendQueue(Connection, STATUS_FILE_CLOSED, FALSE);
456 FlushShutdownQueue(Connection, STATUS_FILE_CLOSED, FALSE);
457 Status = TCPTranslateError(LibTCPShutdown(Connection, 1, 1));
458 }
459 }
460 else
461 {
462 /* We already got closed by the other side so just return success */
463 Status = STATUS_SUCCESS;
464 }
465
466 UnlockObject(Connection, OldIrql);
467
468 TI_DbgPrint(DEBUG_TCP,("[IP, TCPDisconnect] Leaving. Status = 0x%x\n", Status));
469
470 return Status;
471 }
472
473 NTSTATUS TCPReceiveData
474 ( PCONNECTION_ENDPOINT Connection,
475 PNDIS_BUFFER Buffer,
476 ULONG ReceiveLength,
477 PULONG BytesReceived,
478 ULONG ReceiveFlags,
479 PTCP_COMPLETION_ROUTINE Complete,
480 PVOID Context )
481 {
482 PTDI_BUCKET Bucket;
483 PUCHAR DataBuffer;
484 UINT DataLen, Received;
485 NTSTATUS Status;
486
487 TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Called for %d bytes (on socket %x)\n",
488 ReceiveLength, Connection->SocketContext));
489
490 NdisQueryBuffer(Buffer, &DataBuffer, &DataLen);
491
492 Status = LibTCPGetDataFromConnectionQueue(Connection, DataBuffer, DataLen, &Received);
493
494 if (Status == STATUS_PENDING)
495 {
496 Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
497 if (!Bucket)
498 {
499 TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Failed to allocate bucket\n"));
500
501 return STATUS_NO_MEMORY;
502 }
503
504 Bucket->Request.RequestNotifyObject = Complete;
505 Bucket->Request.RequestContext = Context;
506
507 ExInterlockedInsertTailList( &Connection->ReceiveRequest, &Bucket->Entry, &Connection->Lock );
508 TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Queued read irp\n"));
509
510 TI_DbgPrint(DEBUG_TCP,("[IP, TCPReceiveData] Leaving. Status = STATUS_PENDING\n"));
511
512 (*BytesReceived) = 0;
513 }
514 else
515 {
516 (*BytesReceived) = Received;
517 }
518
519 return Status;
520 }
521
522 NTSTATUS TCPSendData
523 ( PCONNECTION_ENDPOINT Connection,
524 PCHAR BufferData,
525 ULONG SendLength,
526 PULONG BytesSent,
527 ULONG Flags,
528 PTCP_COMPLETION_ROUTINE Complete,
529 PVOID Context )
530 {
531 NTSTATUS Status;
532 PTDI_BUCKET Bucket;
533 KIRQL OldIrql;
534
535 LockObject(Connection, &OldIrql);
536
537 TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Called for %d bytes (on socket %x)\n",
538 SendLength, Connection->SocketContext));
539
540 TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Connection = %x\n", Connection));
541 TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Connection->SocketContext = %x\n",
542 Connection->SocketContext));
543
544 Status = TCPTranslateError(LibTCPSend(Connection,
545 BufferData,
546 SendLength,
547 BytesSent,
548 FALSE));
549
550 TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Send: %x, %d\n", Status, SendLength));
551
552 /* Keep this request around ... there was no data yet */
553 if (Status == STATUS_PENDING)
554 {
555 /* Freed in TCPSocketState */
556 Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList);
557 if (!Bucket)
558 {
559 UnlockObject(Connection, OldIrql);
560 TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Failed to allocate bucket\n"));
561 return STATUS_NO_MEMORY;
562 }
563
564 Bucket->Request.RequestNotifyObject = Complete;
565 Bucket->Request.RequestContext = Context;
566
567 InsertTailList( &Connection->SendRequest, &Bucket->Entry );
568 TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Queued write irp\n"));
569 }
570
571 UnlockObject(Connection, OldIrql);
572
573 TI_DbgPrint(DEBUG_TCP, ("[IP, TCPSendData] Leaving. Status = %x\n", Status));
574
575 return Status;
576 }
577
578 UINT TCPAllocatePort(const UINT HintPort)
579 {
580 if (HintPort)
581 {
582 if (AllocatePort(&TCPPorts, HintPort))
583 return HintPort;
584 else
585 {
586 TI_DbgPrint(MID_TRACE,("We got a hint port but couldn't allocate it\n"));
587 return (UINT)-1;
588 }
589 }
590 else
591 return AllocatePortFromRange( &TCPPorts, 1024, 5000 );
592 }
593
594 VOID TCPFreePort(const UINT Port)
595 {
596 DeallocatePort(&TCPPorts, Port);
597 }
598
599 NTSTATUS TCPGetSockAddress
600 ( PCONNECTION_ENDPOINT Connection,
601 PTRANSPORT_ADDRESS Address,
602 BOOLEAN GetRemote )
603 {
604 PTA_IP_ADDRESS AddressIP = (PTA_IP_ADDRESS)Address;
605 struct ip_addr ipaddr;
606 NTSTATUS Status;
607 KIRQL OldIrql;
608
609 AddressIP->TAAddressCount = 1;
610 AddressIP->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
611 AddressIP->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
612
613 LockObject(Connection, &OldIrql);
614
615 if (GetRemote)
616 {
617 Status = TCPTranslateError(LibTCPGetPeerName(Connection->SocketContext,
618 &ipaddr,
619 &AddressIP->Address[0].Address[0].sin_port));
620 }
621 else
622 {
623 Status = TCPTranslateError(LibTCPGetHostName(Connection->SocketContext,
624 &ipaddr,
625 &AddressIP->Address[0].Address[0].sin_port));
626 }
627
628 UnlockObject(Connection, OldIrql);
629
630 AddressIP->Address[0].Address[0].in_addr = ipaddr.addr;
631
632 RtlZeroMemory(&AddressIP->Address[0].Address[0].sin_zero,
633 sizeof(AddressIP->Address[0].Address[0].sin_zero));
634
635 return Status;
636 }
637
638 BOOLEAN TCPRemoveIRP( PCONNECTION_ENDPOINT Endpoint, PIRP Irp )
639 {
640 PLIST_ENTRY Entry;
641 PLIST_ENTRY ListHead[5];
642 KIRQL OldIrql;
643 PTDI_BUCKET Bucket;
644 UINT i = 0;
645 BOOLEAN Found = FALSE;
646
647 ListHead[0] = &Endpoint->SendRequest;
648 ListHead[1] = &Endpoint->ReceiveRequest;
649 ListHead[2] = &Endpoint->ConnectRequest;
650 ListHead[3] = &Endpoint->ListenRequest;
651 ListHead[4] = &Endpoint->ShutdownRequest;
652
653 LockObject(Endpoint, &OldIrql);
654
655 for( i = 0; i < 5; i++ )
656 {
657 for( Entry = ListHead[i]->Flink;
658 Entry != ListHead[i];
659 Entry = Entry->Flink )
660 {
661 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
662 if( Bucket->Request.RequestContext == Irp )
663 {
664 RemoveEntryList( &Bucket->Entry );
665 ExFreeToNPagedLookasideList(&TdiBucketLookasideList, Bucket);
666 Found = TRUE;
667 break;
668 }
669 }
670 }
671
672 UnlockObject(Endpoint, OldIrql);
673
674 return Found;
675 }
676
677 /* EOF */