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