xref: /reactos/drivers/network/tcpip/tcpip/dispatch.c (revision 4561998a)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS TCP/IP protocol driver
4  * FILE:        tcpip/dispatch.h
5  * PURPOSE:     TDI dispatch routines
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  * REVISIONS:
8  *   CSH 01/08-2000 Created
9  * TODO:        Validate device object in all dispatch routines
10  */
11 
12 #include "precomp.h"
13 
14 #include <datagram.h>
15 #include <pseh/pseh2.h>
16 
17 typedef struct _QUERY_HW_WORK_ITEM {
18     PIO_WORKITEM WorkItem;
19     PIRP Irp;
20     PIO_STACK_LOCATION IrpSp;
21     PIP_INTERFACE Interface;
22     LARGE_INTEGER StartTime;
23     ULONG RemoteIP;
24 } QUERY_HW_WORK_ITEM, *PQUERY_HW_WORK_ITEM;
25 
26 NTSTATUS IRPFinish( PIRP Irp, NTSTATUS Status ) {
27     KIRQL OldIrql;
28 
29     if (Status != STATUS_PENDING) {
30         Irp->IoStatus.Status = Status;
31         IoAcquireCancelSpinLock(&OldIrql);
32         (void)IoSetCancelRoutine( Irp, NULL );
33         IoReleaseCancelSpinLock(OldIrql);
34 
35         IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
36     }
37 
38     return Status;
39 }
40 
41 NTSTATUS DispPrepareIrpForCancel(
42     PTRANSPORT_CONTEXT Context,
43     PIRP Irp,
44     PDRIVER_CANCEL CancelRoutine)
45 /*
46  * FUNCTION: Prepare an IRP for cancellation
47  * ARGUMENTS:
48  *     Context       = Pointer to context information
49  *     Irp           = Pointer to an I/O request packet
50  *     CancelRoutine = Routine to be called when I/O request is cancelled
51  * RETURNS:
52  *     Status of operation
53  */
54 {
55     KIRQL OldIrql;
56     PIO_STACK_LOCATION IrpSp;
57     PTRANSPORT_CONTEXT TransContext;
58 
59     TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
60 
61     IrpSp       = IoGetCurrentIrpStackLocation(Irp);
62     TransContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
63 
64     IoAcquireCancelSpinLock(&OldIrql);
65 
66     if (!Irp->Cancel && !TransContext->CancelIrps) {
67         (void)IoSetCancelRoutine(Irp, CancelRoutine);
68         IoReleaseCancelSpinLock(OldIrql);
69 
70         TI_DbgPrint(DEBUG_IRP, ("Leaving (IRP at 0x%X can now be cancelled).\n", Irp));
71 
72         return STATUS_SUCCESS;
73     }
74 
75     /* IRP has already been cancelled */
76 
77     IoReleaseCancelSpinLock(OldIrql);
78 
79     Irp->IoStatus.Status      = STATUS_CANCELLED;
80     Irp->IoStatus.Information = 0;
81 
82     TI_DbgPrint(DEBUG_IRP, ("Leaving (IRP was already cancelled).\n"));
83 
84     return Irp->IoStatus.Status;
85 }
86 
87 VOID DispDataRequestComplete(
88     PVOID Context,
89     NTSTATUS Status,
90     ULONG Count)
91 /*
92  * FUNCTION: Completes a send/receive IRP
93  * ARGUMENTS:
94  *     Context = Pointer to context information (IRP)
95  *     Status  = Status of the request
96  *     Count   = Number of bytes sent or received
97  */
98 {
99     PIRP Irp = Context;
100 
101     TI_DbgPrint(DEBUG_IRP, ("Called for irp %x (%x, %d).\n",
102 			    Irp, Status, Count));
103 
104     Irp->IoStatus.Status      = Status;
105     Irp->IoStatus.Information = Count;
106 
107     TI_DbgPrint(MID_TRACE, ("Irp->IoStatus.Status = %x\n",
108 			    Irp->IoStatus.Status));
109     TI_DbgPrint(MID_TRACE, ("Irp->IoStatus.Information = %d\n",
110 			    Irp->IoStatus.Information));
111     TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
112 
113     IRPFinish(Irp, Status);
114 
115     TI_DbgPrint(DEBUG_IRP, ("Done Completing IRP\n"));
116 }
117 
118 VOID NTAPI DispCancelRequest(
119     PDEVICE_OBJECT Device,
120     PIRP Irp)
121 /*
122  * FUNCTION: Cancels an IRP
123  * ARGUMENTS:
124  *     Device = Pointer to device object
125  *     Irp    = Pointer to an I/O request packet
126  */
127 {
128     PIO_STACK_LOCATION IrpSp;
129     PTRANSPORT_CONTEXT TranContext;
130     PFILE_OBJECT FileObject;
131     UCHAR MinorFunction;
132     PCONNECTION_ENDPOINT Connection;
133     BOOLEAN DequeuedIrp = TRUE;
134 
135     IoReleaseCancelSpinLock(Irp->CancelIrql);
136 
137     TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
138 
139     IrpSp         = IoGetCurrentIrpStackLocation(Irp);
140     FileObject    = IrpSp->FileObject;
141     TranContext   = (PTRANSPORT_CONTEXT)FileObject->FsContext;
142     MinorFunction = IrpSp->MinorFunction;
143 
144     TI_DbgPrint(DEBUG_IRP, ("IRP at (0x%X)  MinorFunction (0x%X)  IrpSp (0x%X).\n", Irp, MinorFunction, IrpSp));
145 
146     Irp->IoStatus.Status = STATUS_CANCELLED;
147     Irp->IoStatus.Information = 0;
148 
149 #if DBG
150     if (!Irp->Cancel)
151         TI_DbgPrint(MIN_TRACE, ("Irp->Cancel is FALSE, should be TRUE.\n"));
152 #endif
153 
154     /* Try canceling the request */
155     switch(MinorFunction) {
156     case TDI_SEND:
157     case TDI_RECEIVE:
158 	DequeuedIrp = TCPRemoveIRP( TranContext->Handle.ConnectionContext, Irp );
159         break;
160 
161     case TDI_SEND_DATAGRAM:
162         if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
163             TI_DbgPrint(MIN_TRACE, ("TDI_SEND_DATAGRAM, but no address file.\n"));
164             break;
165         }
166 
167         DequeuedIrp = DGRemoveIRP(TranContext->Handle.AddressHandle, Irp);
168         break;
169 
170     case TDI_RECEIVE_DATAGRAM:
171         if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
172             TI_DbgPrint(MIN_TRACE, ("TDI_RECEIVE_DATAGRAM, but no address file.\n"));
173             break;
174         }
175 
176         DequeuedIrp = DGRemoveIRP(TranContext->Handle.AddressHandle, Irp);
177         break;
178 
179     case TDI_CONNECT:
180         DequeuedIrp = TCPRemoveIRP(TranContext->Handle.ConnectionContext, Irp);
181         break;
182 
183     case TDI_DISCONNECT:
184         Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
185 
186         DequeuedIrp = TCPRemoveIRP(TranContext->Handle.ConnectionContext, Irp);
187         if (DequeuedIrp)
188         {
189             if (KeCancelTimer(&Connection->DisconnectTimer))
190             {
191                 DereferenceObject(Connection);
192             }
193         }
194         break;
195 
196     default:
197         TI_DbgPrint(MIN_TRACE, ("Unknown IRP. MinorFunction (0x%X).\n", MinorFunction));
198         ASSERT(FALSE);
199         break;
200     }
201 
202     if (DequeuedIrp)
203        IRPFinish(Irp, STATUS_CANCELLED);
204 
205     TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
206 }
207 
208 
209 VOID NTAPI DispCancelListenRequest(
210     PDEVICE_OBJECT Device,
211     PIRP Irp)
212 /*
213  * FUNCTION: Cancels a listen IRP
214  * ARGUMENTS:
215  *     Device = Pointer to device object
216  *     Irp    = Pointer to an I/O request packet
217  */
218 {
219     PIO_STACK_LOCATION IrpSp;
220     PTRANSPORT_CONTEXT TranContext;
221     PFILE_OBJECT FileObject;
222     PCONNECTION_ENDPOINT Connection;
223 
224     IoReleaseCancelSpinLock(Irp->CancelIrql);
225 
226     TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
227 
228     IrpSp         = IoGetCurrentIrpStackLocation(Irp);
229     FileObject    = IrpSp->FileObject;
230     TranContext   = (PTRANSPORT_CONTEXT)FileObject->FsContext;
231     ASSERT( TDI_LISTEN == IrpSp->MinorFunction);
232 
233     TI_DbgPrint(DEBUG_IRP, ("IRP at (0x%X).\n", Irp));
234 
235 #if DBG
236     if (!Irp->Cancel)
237         TI_DbgPrint(MIN_TRACE, ("Irp->Cancel is FALSE, should be TRUE.\n"));
238 #endif
239 
240     /* Try canceling the request */
241     Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
242 
243     if (TCPAbortListenForSocket(Connection->AddressFile->Listener,
244                                 Connection))
245     {
246         Irp->IoStatus.Information = 0;
247         IRPFinish(Irp, STATUS_CANCELLED);
248     }
249 
250     TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
251 }
252 
253 
254 NTSTATUS DispTdiAccept(
255   PIRP Irp)
256 /*
257  * FUNCTION: TDI_ACCEPT handler
258  * ARGUMENTS:
259  *     Irp = Pointer to an I/O request packet
260  * RETURNS:
261  *     Status of operation
262  */
263 {
264   TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
265 
266   return STATUS_NOT_IMPLEMENTED;
267 }
268 
269 
270 NTSTATUS DispTdiAssociateAddress(
271     PIRP Irp)
272 /*
273  * FUNCTION: TDI_ASSOCIATE_ADDRESS handler
274  * ARGUMENTS:
275  *     Irp = Pointer to an I/O request packet
276  * RETURNS:
277  *     Status of operation
278  */
279 {
280   PTDI_REQUEST_KERNEL_ASSOCIATE Parameters;
281   PTRANSPORT_CONTEXT TranContext;
282   PIO_STACK_LOCATION IrpSp;
283   PCONNECTION_ENDPOINT Connection, LastConnection;
284   PFILE_OBJECT FileObject;
285   PADDRESS_FILE AddrFile = NULL;
286   NTSTATUS Status;
287   KIRQL OldIrql;
288 
289   TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
290 
291   IrpSp = IoGetCurrentIrpStackLocation(Irp);
292 
293   /* Get associated connection endpoint file object. Quit if none exists */
294 
295   TranContext = IrpSp->FileObject->FsContext;
296   if (!TranContext) {
297     TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
298     return STATUS_INVALID_PARAMETER;
299   }
300 
301   Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
302   if (!Connection) {
303     TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
304     return STATUS_INVALID_PARAMETER;
305   }
306 
307   Parameters = (PTDI_REQUEST_KERNEL_ASSOCIATE)&IrpSp->Parameters;
308 
309   Status = ObReferenceObjectByHandle(
310     Parameters->AddressHandle,
311     0,
312     *IoFileObjectType,
313     KernelMode,
314     (PVOID*)&FileObject,
315     NULL);
316   if (!NT_SUCCESS(Status)) {
317     TI_DbgPrint(MID_TRACE, ("Bad address file object handle (0x%X): %x.\n",
318       Parameters->AddressHandle, Status));
319     return STATUS_INVALID_PARAMETER;
320   }
321 
322   LockObject(Connection, &OldIrql);
323 
324   if (Connection->AddressFile) {
325     ObDereferenceObject(FileObject);
326     UnlockObject(Connection, OldIrql);
327     TI_DbgPrint(MID_TRACE, ("An address file is already associated.\n"));
328     return STATUS_INVALID_PARAMETER;
329   }
330 
331   if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
332     ObDereferenceObject(FileObject);
333     UnlockObject(Connection, OldIrql);
334     TI_DbgPrint(MID_TRACE, ("Bad address file object. Magic (0x%X).\n",
335       FileObject->FsContext2));
336     return STATUS_INVALID_PARAMETER;
337   }
338 
339   /* Get associated address file object. Quit if none exists */
340 
341   TranContext = FileObject->FsContext;
342   if (!TranContext) {
343     ObDereferenceObject(FileObject);
344     UnlockObject(Connection, OldIrql);
345     TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
346     return STATUS_INVALID_PARAMETER;
347   }
348 
349   AddrFile = (PADDRESS_FILE)TranContext->Handle.AddressHandle;
350   if (!AddrFile) {
351       UnlockObject(Connection, OldIrql);
352       ObDereferenceObject(FileObject);
353       TI_DbgPrint(MID_TRACE, ("No address file object.\n"));
354       return STATUS_INVALID_PARAMETER;
355   }
356 
357   LockObjectAtDpcLevel(AddrFile);
358 
359   ReferenceObject(AddrFile);
360   Connection->AddressFile = AddrFile;
361 
362   /* Add connection endpoint to the address file */
363   ReferenceObject(Connection);
364   if (AddrFile->Connection == NULL)
365       AddrFile->Connection = Connection;
366   else
367   {
368       LastConnection = AddrFile->Connection;
369       while (LastConnection->Next != NULL)
370          LastConnection = LastConnection->Next;
371       LastConnection->Next = Connection;
372   }
373 
374   ObDereferenceObject(FileObject);
375 
376   UnlockObjectFromDpcLevel(AddrFile);
377   UnlockObject(Connection, OldIrql);
378 
379   return STATUS_SUCCESS;
380 }
381 
382 
383 NTSTATUS DispTdiConnect(
384   PIRP Irp)
385 /*
386  * FUNCTION: TDI_CONNECT handler
387  * ARGUMENTS:
388  *     Irp = Pointer to an I/O request packet
389  * RETURNS:
390  *     Status of operation
391  */
392 {
393   PCONNECTION_ENDPOINT Connection;
394   PTDI_REQUEST_KERNEL Parameters;
395   PTRANSPORT_CONTEXT TranContext;
396   PIO_STACK_LOCATION IrpSp;
397   NTSTATUS Status;
398 
399   TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
400 
401   IrpSp = IoGetCurrentIrpStackLocation(Irp);
402 
403   IoMarkIrpPending(Irp);
404 
405   /* Get associated connection endpoint file object. Quit if none exists */
406 
407   TranContext = IrpSp->FileObject->FsContext;
408   if (!TranContext) {
409     TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
410     Status = STATUS_INVALID_PARAMETER;
411     goto done;
412   }
413 
414   Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
415   if (!Connection) {
416     TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
417     Status = STATUS_INVALID_PARAMETER;
418     goto done;
419   }
420 
421   Parameters = (PTDI_REQUEST_KERNEL)&IrpSp->Parameters;
422 
423   Status = DispPrepareIrpForCancel(TranContext->Handle.ConnectionContext,
424                                    Irp,
425                                    DispCancelRequest);
426 
427   if (NT_SUCCESS(Status)) {
428       Status = TCPConnect(
429           TranContext->Handle.ConnectionContext,
430           Parameters->RequestConnectionInformation,
431           Parameters->ReturnConnectionInformation,
432           DispDataRequestComplete,
433           Irp );
434   }
435 
436 done:
437   if (Status != STATUS_PENDING) {
438       DispDataRequestComplete(Irp, Status, 0);
439   }
440 
441   TI_DbgPrint(MAX_TRACE, ("TCP Connect returned %08x\n", Status));
442 
443   return STATUS_PENDING;
444 }
445 
446 
447 NTSTATUS DispTdiDisassociateAddress(
448   PIRP Irp)
449 /*
450  * FUNCTION: TDI_DISASSOCIATE_ADDRESS handler
451  * ARGUMENTS:
452  *     Irp = Pointer to an I/O request packet
453  * RETURNS:
454  *     Status of operation
455  */
456 {
457   PCONNECTION_ENDPOINT Connection;
458   PTRANSPORT_CONTEXT TranContext;
459   PIO_STACK_LOCATION IrpSp;
460 
461   TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
462 
463   IrpSp = IoGetCurrentIrpStackLocation(Irp);
464 
465   /* Get associated connection endpoint file object. Quit if none exists */
466 
467   TranContext = IrpSp->FileObject->FsContext;
468   if (!TranContext) {
469     TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
470     return STATUS_INVALID_PARAMETER;
471   }
472 
473   Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
474   if (!Connection) {
475     TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
476     return STATUS_INVALID_PARAMETER;
477   }
478 
479   /* NO-OP because we need the address to deallocate the port when the connection closes */
480 
481   return STATUS_SUCCESS;
482 }
483 
484 
485 NTSTATUS DispTdiDisconnect(
486   PIRP Irp)
487 /*
488  * FUNCTION: TDI_DISCONNECT handler
489  * ARGUMENTS:
490  *     Irp = Pointer to an I/O request packet
491  * RETURNS:
492  *     Status of operation
493  */
494 {
495   NTSTATUS Status;
496   PTDI_REQUEST_KERNEL_DISCONNECT DisReq;
497   PCONNECTION_ENDPOINT Connection;
498   PTRANSPORT_CONTEXT TranContext;
499   PIO_STACK_LOCATION IrpSp;
500 
501   TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
502 
503   IrpSp = IoGetCurrentIrpStackLocation(Irp);
504   DisReq = (PTDI_REQUEST_KERNEL_DISCONNECT)&IrpSp->Parameters;
505 
506   IoMarkIrpPending(Irp);
507 
508   /* Get associated connection endpoint file object. Quit if none exists */
509 
510   TranContext = IrpSp->FileObject->FsContext;
511   if (!TranContext) {
512     TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
513     Status = STATUS_INVALID_PARAMETER;
514     goto done;
515   }
516 
517   Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
518   if (!Connection) {
519     TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
520     Status = STATUS_INVALID_PARAMETER;
521     goto done;
522   }
523 
524   Status = DispPrepareIrpForCancel
525     (TranContext->Handle.ConnectionContext,
526      Irp,
527      (PDRIVER_CANCEL)DispCancelRequest);
528 
529   if (NT_SUCCESS(Status))
530   {
531       Status = TCPDisconnect(TranContext->Handle.ConnectionContext,
532                              DisReq->RequestFlags,
533                              DisReq->RequestSpecific,
534                              DisReq->RequestConnectionInformation,
535                              DisReq->ReturnConnectionInformation,
536                              DispDataRequestComplete,
537                              Irp);
538   }
539 
540 done:
541    if (Status != STATUS_PENDING) {
542        DispDataRequestComplete(Irp, Status, 0);
543    }
544 
545   TI_DbgPrint(MAX_TRACE, ("TCP Disconnect returned %08x\n", Status));
546 
547   return STATUS_PENDING;
548 }
549 
550 
551 NTSTATUS DispTdiListen(
552   PIRP Irp)
553 /*
554  * FUNCTION: TDI_LISTEN handler
555  * ARGUMENTS:
556  *     Irp = Pointer to an I/O request packet
557  * RETURNS:
558  *     Status of operation
559  */
560 {
561   PCONNECTION_ENDPOINT Connection;
562   PTDI_REQUEST_KERNEL Parameters;
563   PTRANSPORT_CONTEXT TranContext;
564   PIO_STACK_LOCATION IrpSp;
565   NTSTATUS Status = STATUS_SUCCESS;
566   KIRQL OldIrql;
567 
568   TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
569 
570   IrpSp = IoGetCurrentIrpStackLocation(Irp);
571 
572   IoMarkIrpPending(Irp);
573 
574   /* Get associated connection endpoint file object. Quit if none exists */
575 
576   TranContext = IrpSp->FileObject->FsContext;
577   if (TranContext == NULL)
578     {
579       TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
580       Status = STATUS_INVALID_PARAMETER;
581       goto done;
582     }
583 
584   Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
585   if (Connection == NULL)
586     {
587       TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
588       Status = STATUS_INVALID_PARAMETER;
589       goto done;
590     }
591 
592   Parameters = (PTDI_REQUEST_KERNEL)&IrpSp->Parameters;
593 
594   Status = DispPrepareIrpForCancel
595       (TranContext->Handle.ConnectionContext,
596        Irp,
597        (PDRIVER_CANCEL)DispCancelListenRequest);
598 
599   LockObject(Connection, &OldIrql);
600 
601   if (Connection->AddressFile == NULL)
602   {
603      TI_DbgPrint(MID_TRACE, ("No associated address file\n"));
604      UnlockObject(Connection, OldIrql);
605      Status = STATUS_INVALID_PARAMETER;
606      goto done;
607   }
608 
609   LockObjectAtDpcLevel(Connection->AddressFile);
610 
611   /* Listening will require us to create a listening socket and store it in
612    * the address file.  It will be signalled, and attempt to complete an irp
613    * when a new connection arrives. */
614   /* The important thing to note here is that the irp we'll complete belongs
615    * to the socket to be accepted onto, not the listener */
616   if( NT_SUCCESS(Status) && !Connection->AddressFile->Listener ) {
617       Connection->AddressFile->Listener =
618 	  TCPAllocateConnectionEndpoint( NULL );
619 
620       if( !Connection->AddressFile->Listener )
621 	  Status = STATUS_NO_MEMORY;
622 
623       if( NT_SUCCESS(Status) ) {
624           ReferenceObject(Connection->AddressFile);
625 	  Connection->AddressFile->Listener->AddressFile =
626 	      Connection->AddressFile;
627 
628 	  Status = TCPSocket( Connection->AddressFile->Listener,
629 			      Connection->AddressFile->Family,
630 			      SOCK_STREAM,
631 			      Connection->AddressFile->Protocol );
632       }
633 
634       if( NT_SUCCESS(Status) ) {
635 	  ReferenceObject(Connection->AddressFile->Listener);
636 	  Status = TCPListen( Connection->AddressFile->Listener, 1024 );
637 	  /* BACKLOG */
638       }
639   }
640 
641   if( NT_SUCCESS(Status) ) {
642       Status = TCPAccept
643 	  ( (PTDI_REQUEST)Parameters,
644 	    Connection->AddressFile->Listener,
645 	    Connection,
646 	    DispDataRequestComplete,
647 	    Irp );
648   }
649 
650   UnlockObjectFromDpcLevel(Connection->AddressFile);
651   UnlockObject(Connection, OldIrql);
652 
653 done:
654   if (Status != STATUS_PENDING) {
655       DispDataRequestComplete(Irp, Status, 0);
656   }
657 
658   TI_DbgPrint(MID_TRACE,("Leaving %x\n", Status));
659 
660   return STATUS_PENDING;
661 }
662 
663 
664 NTSTATUS DispTdiQueryInformation(
665   PDEVICE_OBJECT DeviceObject,
666   PIRP Irp)
667 /*
668  * FUNCTION: TDI_QUERY_INFORMATION handler
669  * ARGUMENTS:
670  *     DeviceObject = Pointer to device object structure
671  *     Irp          = Pointer to an I/O request packet
672  * RETURNS:
673  *     Status of operation
674  */
675 {
676   PTDI_REQUEST_KERNEL_QUERY_INFORMATION Parameters;
677   PTRANSPORT_CONTEXT TranContext;
678   PIO_STACK_LOCATION IrpSp;
679 
680   TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
681 
682   IrpSp = IoGetCurrentIrpStackLocation(Irp);
683   Parameters = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&IrpSp->Parameters;
684 
685   TranContext = IrpSp->FileObject->FsContext;
686   if (!TranContext) {
687     TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
688     return STATUS_INVALID_PARAMETER;
689   }
690 
691   switch (Parameters->QueryType)
692   {
693     case TDI_QUERY_ADDRESS_INFO:
694       {
695         PTDI_ADDRESS_INFO AddressInfo;
696         PADDRESS_FILE AddrFile;
697         PTA_IP_ADDRESS Address;
698         PCONNECTION_ENDPOINT Endpoint = NULL;
699 
700 
701         if (MmGetMdlByteCount(Irp->MdlAddress) <
702             (FIELD_OFFSET(TDI_ADDRESS_INFO, Address.Address[0].Address) +
703              sizeof(TDI_ADDRESS_IP))) {
704           TI_DbgPrint(MID_TRACE, ("MDL buffer too small.\n"));
705           return STATUS_BUFFER_TOO_SMALL;
706         }
707 
708         AddressInfo = (PTDI_ADDRESS_INFO)MmGetSystemAddressForMdl(Irp->MdlAddress);
709 		Address = (PTA_IP_ADDRESS)&AddressInfo->Address;
710 
711         switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {
712           case TDI_TRANSPORT_ADDRESS_FILE:
713             AddrFile = (PADDRESS_FILE)TranContext->Handle.AddressHandle;
714 
715 			Address->TAAddressCount = 1;
716 			Address->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
717 			Address->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
718 			Address->Address[0].Address[0].sin_port = AddrFile->Port;
719 			Address->Address[0].Address[0].in_addr = AddrFile->Address.Address.IPv4Address;
720 			RtlZeroMemory(
721 				&Address->Address[0].Address[0].sin_zero,
722 				sizeof(Address->Address[0].Address[0].sin_zero));
723 			return STATUS_SUCCESS;
724 
725           case TDI_CONNECTION_FILE:
726             Endpoint =
727 				(PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
728 
729             Address->TAAddressCount = 1;
730             Address->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
731             Address->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
732             Address->Address[0].Address[0].sin_port = Endpoint->AddressFile->Port;
733             Address->Address[0].Address[0].in_addr = Endpoint->AddressFile->Address.Address.IPv4Address;
734 			RtlZeroMemory(
735 				&Address->Address[0].Address[0].sin_zero,
736 				sizeof(Address->Address[0].Address[0].sin_zero));
737             return STATUS_SUCCESS;
738 
739           default:
740             TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n"));
741             return STATUS_INVALID_PARAMETER;
742         }
743       }
744 
745     case TDI_QUERY_CONNECTION_INFO:
746       {
747         PTDI_CONNECTION_INFO ConnectionInfo;
748         //PCONNECTION_ENDPOINT Endpoint;
749 
750         if (MmGetMdlByteCount(Irp->MdlAddress) < sizeof(*ConnectionInfo)) {
751           TI_DbgPrint(MID_TRACE, ("MDL buffer too small.\n"));
752           return STATUS_BUFFER_TOO_SMALL;
753         }
754 
755         ConnectionInfo = (PTDI_CONNECTION_INFO)
756           MmGetSystemAddressForMdl(Irp->MdlAddress);
757 
758         switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {
759           case TDI_CONNECTION_FILE:
760             //Endpoint = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
761             RtlZeroMemory(ConnectionInfo, sizeof(*ConnectionInfo));
762             return STATUS_SUCCESS;
763 
764           default:
765             TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n"));
766             return STATUS_INVALID_PARAMETER;
767         }
768       }
769 
770       case TDI_QUERY_MAX_DATAGRAM_INFO:
771       {
772           PTDI_MAX_DATAGRAM_INFO MaxDatagramInfo;
773 
774           if (MmGetMdlByteCount(Irp->MdlAddress) < sizeof(*MaxDatagramInfo)) {
775               TI_DbgPrint(MID_TRACE, ("MDL buffer too small.\n"));
776               return STATUS_BUFFER_TOO_SMALL;
777           }
778 
779           MaxDatagramInfo = (PTDI_MAX_DATAGRAM_INFO)
780             MmGetSystemAddressForMdl(Irp->MdlAddress);
781 
782           MaxDatagramInfo->MaxDatagramSize = 0xFFFF;
783 
784           return STATUS_SUCCESS;
785      }
786   }
787 
788   return STATUS_NOT_IMPLEMENTED;
789 }
790 
791 
792 NTSTATUS DispTdiReceive(
793   PIRP Irp)
794 /*
795  * FUNCTION: TDI_RECEIVE handler
796  * ARGUMENTS:
797  *     Irp = Pointer to an I/O request packet
798  * RETURNS:
799  *     Status of operation
800  */
801 {
802   PIO_STACK_LOCATION IrpSp;
803   PTDI_REQUEST_KERNEL_RECEIVE ReceiveInfo;
804   PTRANSPORT_CONTEXT TranContext;
805   NTSTATUS Status;
806   ULONG BytesReceived = 0;
807 
808   TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
809 
810   IrpSp = IoGetCurrentIrpStackLocation(Irp);
811   ReceiveInfo = (PTDI_REQUEST_KERNEL_RECEIVE)&(IrpSp->Parameters);
812 
813   IoMarkIrpPending(Irp);
814 
815   TranContext = IrpSp->FileObject->FsContext;
816   if (TranContext == NULL)
817     {
818       TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
819       Status = STATUS_INVALID_PARAMETER;
820       goto done;
821     }
822 
823   if (TranContext->Handle.ConnectionContext == NULL)
824     {
825       TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
826       Status = STATUS_INVALID_PARAMETER;
827       goto done;
828     }
829 
830   /* Initialize a receive request */
831   Status = DispPrepareIrpForCancel
832       (TranContext->Handle.ConnectionContext,
833        Irp,
834        (PDRIVER_CANCEL)DispCancelRequest);
835 
836   TI_DbgPrint(MID_TRACE,("TCPIP<<< Got an MDL: %x\n", Irp->MdlAddress));
837   if (NT_SUCCESS(Status))
838     {
839       Status = TCPReceiveData(
840 	  TranContext->Handle.ConnectionContext,
841 	  (PNDIS_BUFFER)Irp->MdlAddress,
842 	  ReceiveInfo->ReceiveLength,
843 	  &BytesReceived,
844 	  ReceiveInfo->ReceiveFlags,
845 	  DispDataRequestComplete,
846 	  Irp);
847     }
848 
849 done:
850   if (Status != STATUS_PENDING) {
851       DispDataRequestComplete(Irp, Status, BytesReceived);
852   }
853 
854   TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status));
855 
856   return STATUS_PENDING;
857 }
858 
859 
860 NTSTATUS DispTdiReceiveDatagram(
861     PIRP Irp)
862 /*
863  * FUNCTION: TDI_RECEIVE_DATAGRAM handler
864  * ARGUMENTS:
865  *     Irp = Pointer to an I/O request packet
866  * RETURNS:
867  *     Status of operation
868  */
869 {
870   PIO_STACK_LOCATION IrpSp;
871   PTDI_REQUEST_KERNEL_RECEIVEDG DgramInfo;
872   PTRANSPORT_CONTEXT TranContext;
873   TDI_REQUEST Request;
874   NTSTATUS Status;
875   ULONG BytesReceived = 0;
876 
877   TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
878 
879   IrpSp     = IoGetCurrentIrpStackLocation(Irp);
880   DgramInfo = (PTDI_REQUEST_KERNEL_RECEIVEDG)&(IrpSp->Parameters);
881 
882   IoMarkIrpPending(Irp);
883 
884   TranContext = IrpSp->FileObject->FsContext;
885   if (TranContext == NULL)
886     {
887       TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
888       Status = STATUS_INVALID_PARAMETER;
889       goto done;
890     }
891 
892   /* Initialize a receive request */
893   Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;
894   Request.RequestNotifyObject  = DispDataRequestComplete;
895   Request.RequestContext       = Irp;
896 
897   Status = DispPrepareIrpForCancel(
898     IrpSp->FileObject->FsContext,
899     Irp,
900     (PDRIVER_CANCEL)DispCancelRequest);
901 
902   if (NT_SUCCESS(Status))
903     {
904 	PVOID DataBuffer;
905 	UINT BufferSize;
906 
907 	NdisQueryBuffer( (PNDIS_BUFFER)Irp->MdlAddress,
908 			 &DataBuffer,
909 			 &BufferSize );
910 
911       Status = DGReceiveDatagram(
912 	  Request.Handle.AddressHandle,
913 	  DgramInfo->ReceiveDatagramInformation,
914 	  DataBuffer,
915 	  DgramInfo->ReceiveLength,
916 	  DgramInfo->ReceiveFlags,
917 	  DgramInfo->ReturnDatagramInformation,
918 	  &BytesReceived,
919 	  (PDATAGRAM_COMPLETION_ROUTINE)DispDataRequestComplete,
920 	  Irp,
921           Irp);
922     }
923 
924 done:
925    if (Status != STATUS_PENDING) {
926        DispDataRequestComplete(Irp, Status, BytesReceived);
927    }
928 
929   TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status));
930 
931   return STATUS_PENDING;
932 }
933 
934 
935 NTSTATUS DispTdiSend(
936     PIRP Irp)
937 /*
938  * FUNCTION: TDI_SEND handler
939  * ARGUMENTS:
940  *     Irp = Pointer to an I/O request packet
941  * RETURNS:
942  *     Status of operation
943  */
944 {
945   PIO_STACK_LOCATION IrpSp;
946   PTDI_REQUEST_KERNEL_SEND SendInfo;
947   PTRANSPORT_CONTEXT TranContext;
948   NTSTATUS Status;
949   ULONG BytesSent = 0;
950 
951   TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
952 
953   IrpSp = IoGetCurrentIrpStackLocation(Irp);
954   SendInfo = (PTDI_REQUEST_KERNEL_SEND)&(IrpSp->Parameters);
955 
956   IoMarkIrpPending(Irp);
957 
958   TranContext = IrpSp->FileObject->FsContext;
959   if (TranContext == NULL)
960     {
961       TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
962       Status = STATUS_INVALID_PARAMETER;
963       goto done;
964     }
965 
966   if (TranContext->Handle.ConnectionContext == NULL)
967     {
968       TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
969       Status = STATUS_INVALID_PARAMETER;
970       goto done;
971     }
972 
973   Status = DispPrepareIrpForCancel(
974     IrpSp->FileObject->FsContext,
975     Irp,
976     (PDRIVER_CANCEL)DispCancelRequest);
977 
978   TI_DbgPrint(MID_TRACE,("TCPIP<<< Got an MDL: %x\n", Irp->MdlAddress));
979   if (NT_SUCCESS(Status))
980     {
981 	PVOID Data;
982 	UINT Len;
983 
984 	NdisQueryBuffer( Irp->MdlAddress, &Data, &Len );
985 
986 	TI_DbgPrint(MID_TRACE,("About to TCPSendData\n"));
987 	Status = TCPSendData(
988 	    TranContext->Handle.ConnectionContext,
989 	    Data,
990 	    SendInfo->SendLength,
991 	    &BytesSent,
992 	    SendInfo->SendFlags,
993 	    DispDataRequestComplete,
994 	    Irp);
995     }
996 
997 done:
998    if (Status != STATUS_PENDING) {
999        DispDataRequestComplete(Irp, Status, BytesSent);
1000    }
1001 
1002   TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status));
1003 
1004   return STATUS_PENDING;
1005 }
1006 
1007 
1008 NTSTATUS DispTdiSendDatagram(
1009     PIRP Irp)
1010 /*
1011  * FUNCTION: TDI_SEND_DATAGRAM handler
1012  * ARGUMENTS:
1013  *     Irp = Pointer to an I/O request packet
1014  * RETURNS:
1015  *     Status of operation
1016  */
1017 {
1018     PIO_STACK_LOCATION IrpSp;
1019     TDI_REQUEST Request;
1020     PTDI_REQUEST_KERNEL_SENDDG DgramInfo;
1021     PTRANSPORT_CONTEXT TranContext;
1022     NTSTATUS Status;
1023 
1024     TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
1025 
1026     IrpSp       = IoGetCurrentIrpStackLocation(Irp);
1027     DgramInfo   = (PTDI_REQUEST_KERNEL_SENDDG)&(IrpSp->Parameters);
1028 
1029     IoMarkIrpPending(Irp);
1030 
1031     TranContext = IrpSp->FileObject->FsContext;
1032     if (TranContext == NULL)
1033     {
1034       TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
1035       Status = STATUS_INVALID_PARAMETER;
1036       goto done;
1037     }
1038 
1039     /* Initialize a send request */
1040     Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;
1041     Request.RequestNotifyObject  = DispDataRequestComplete;
1042     Request.RequestContext       = Irp;
1043 
1044     Status = DispPrepareIrpForCancel(
1045         IrpSp->FileObject->FsContext,
1046         Irp,
1047         (PDRIVER_CANCEL)DispCancelRequest);
1048 
1049     if (NT_SUCCESS(Status)) {
1050 	PVOID DataBuffer;
1051 	UINT BufferSize;
1052 
1053 	TI_DbgPrint(MID_TRACE,("About to query buffer %x\n", Irp->MdlAddress));
1054 
1055 	NdisQueryBuffer( (PNDIS_BUFFER)Irp->MdlAddress,
1056 			 &DataBuffer,
1057 			 &BufferSize );
1058 
1059         /* FIXME: DgramInfo->SendDatagramInformation->RemoteAddress
1060            must be of type PTDI_ADDRESS_IP */
1061 	TI_DbgPrint(MID_TRACE,
1062 		    ("About to call send routine %x\n",
1063 		     (*((PADDRESS_FILE)Request.Handle.AddressHandle)->Send)));
1064 
1065         if( (*((PADDRESS_FILE)Request.Handle.AddressHandle)->Send != NULL) )
1066         {
1067 	        ULONG DataUsed = 0;
1068             Status = (*((PADDRESS_FILE)Request.Handle.AddressHandle)->Send)(
1069                 Request.Handle.AddressHandle,
1070                 DgramInfo->SendDatagramInformation,
1071                 DataBuffer,
1072                 BufferSize,
1073                 &DataUsed);
1074             Irp->IoStatus.Information = DataUsed;
1075         }
1076         else {
1077             Status = STATUS_UNSUCCESSFUL;
1078             ASSERT(FALSE);
1079         }
1080     }
1081 
1082 done:
1083     if (Status != STATUS_PENDING) {
1084         DispDataRequestComplete(Irp, Status, Irp->IoStatus.Information);
1085     }
1086 
1087     TI_DbgPrint(DEBUG_IRP, ("Leaving.\n"));
1088 
1089     return STATUS_PENDING;
1090 }
1091 
1092 
1093 NTSTATUS DispTdiSetEventHandler(PIRP Irp)
1094 /*
1095  * FUNCTION: TDI_SET_EVENT_HANDER handler
1096  * ARGUMENTS:
1097  *     Irp = Pointer to a I/O request packet
1098  * RETURNS:
1099  *     Status of operation
1100  */
1101 {
1102   PTDI_REQUEST_KERNEL_SET_EVENT Parameters;
1103   PTRANSPORT_CONTEXT TranContext;
1104   PIO_STACK_LOCATION IrpSp;
1105   PADDRESS_FILE AddrFile;
1106   NTSTATUS Status;
1107   KIRQL OldIrql;
1108 
1109   TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
1110 
1111   IrpSp = IoGetCurrentIrpStackLocation(Irp);
1112 
1113   /* Get associated address file object. Quit if none exists */
1114 
1115   TranContext = IrpSp->FileObject->FsContext;
1116   if (!TranContext) {
1117     TI_DbgPrint(MIN_TRACE, ("Bad transport context.\n"));
1118     return STATUS_INVALID_PARAMETER;
1119   }
1120 
1121   AddrFile = (PADDRESS_FILE)TranContext->Handle.AddressHandle;
1122   if (!AddrFile) {
1123     TI_DbgPrint(MIN_TRACE, ("No address file object.\n"));
1124     return STATUS_INVALID_PARAMETER;
1125   }
1126 
1127   Parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)&IrpSp->Parameters;
1128   Status     = STATUS_SUCCESS;
1129 
1130   LockObject(AddrFile, &OldIrql);
1131 
1132   /* Set the event handler. if an event handler is associated with
1133      a specific event, it's flag (RegisteredXxxHandler) is TRUE.
1134      If an event handler is not used it's flag is FALSE */
1135   switch (Parameters->EventType) {
1136   case TDI_EVENT_CONNECT:
1137     if (!Parameters->EventHandler) {
1138       AddrFile->ConnectHandlerContext    = NULL;
1139       AddrFile->RegisteredConnectHandler = FALSE;
1140     } else {
1141       AddrFile->ConnectHandler =
1142         (PTDI_IND_CONNECT)Parameters->EventHandler;
1143       AddrFile->ConnectHandlerContext    = Parameters->EventContext;
1144       AddrFile->RegisteredConnectHandler = TRUE;
1145     }
1146     break;
1147 
1148   case TDI_EVENT_DISCONNECT:
1149     if (!Parameters->EventHandler) {
1150       AddrFile->DisconnectHandlerContext    = NULL;
1151       AddrFile->RegisteredDisconnectHandler = FALSE;
1152     } else {
1153       AddrFile->DisconnectHandler =
1154         (PTDI_IND_DISCONNECT)Parameters->EventHandler;
1155       AddrFile->DisconnectHandlerContext    = Parameters->EventContext;
1156       AddrFile->RegisteredDisconnectHandler = TRUE;
1157     }
1158     break;
1159 
1160     case TDI_EVENT_ERROR:
1161     if (Parameters->EventHandler == NULL) {
1162       AddrFile->ErrorHandlerContext    = NULL;
1163       AddrFile->RegisteredErrorHandler = FALSE;
1164     } else {
1165       AddrFile->ErrorHandler =
1166         (PTDI_IND_ERROR)Parameters->EventHandler;
1167       AddrFile->ErrorHandlerContext    = Parameters->EventContext;
1168       AddrFile->RegisteredErrorHandler = TRUE;
1169     }
1170     break;
1171 
1172   case TDI_EVENT_RECEIVE:
1173     if (Parameters->EventHandler == NULL) {
1174       AddrFile->ReceiveHandlerContext    = NULL;
1175       AddrFile->RegisteredReceiveHandler = FALSE;
1176     } else {
1177       AddrFile->ReceiveHandler =
1178         (PTDI_IND_RECEIVE)Parameters->EventHandler;
1179       AddrFile->ReceiveHandlerContext    = Parameters->EventContext;
1180       AddrFile->RegisteredReceiveHandler = TRUE;
1181     }
1182     break;
1183 
1184   case TDI_EVENT_RECEIVE_DATAGRAM:
1185     if (Parameters->EventHandler == NULL) {
1186       AddrFile->ReceiveDatagramHandlerContext    = NULL;
1187       AddrFile->RegisteredReceiveDatagramHandler = FALSE;
1188     } else {
1189       AddrFile->ReceiveDatagramHandler =
1190         (PTDI_IND_RECEIVE_DATAGRAM)Parameters->EventHandler;
1191       AddrFile->ReceiveDatagramHandlerContext    = Parameters->EventContext;
1192       AddrFile->RegisteredReceiveDatagramHandler = TRUE;
1193     }
1194     break;
1195 
1196   case TDI_EVENT_RECEIVE_EXPEDITED:
1197     if (Parameters->EventHandler == NULL) {
1198       AddrFile->ExpeditedReceiveHandlerContext    = NULL;
1199       AddrFile->RegisteredExpeditedReceiveHandler = FALSE;
1200     } else {
1201       AddrFile->ExpeditedReceiveHandler =
1202         (PTDI_IND_RECEIVE_EXPEDITED)Parameters->EventHandler;
1203       AddrFile->ExpeditedReceiveHandlerContext    = Parameters->EventContext;
1204       AddrFile->RegisteredExpeditedReceiveHandler = TRUE;
1205     }
1206     break;
1207 
1208   case TDI_EVENT_CHAINED_RECEIVE:
1209     if (Parameters->EventHandler == NULL) {
1210       AddrFile->ChainedReceiveHandlerContext    = NULL;
1211       AddrFile->RegisteredChainedReceiveHandler = FALSE;
1212     } else {
1213       AddrFile->ChainedReceiveHandler =
1214         (PTDI_IND_CHAINED_RECEIVE)Parameters->EventHandler;
1215       AddrFile->ChainedReceiveHandlerContext    = Parameters->EventContext;
1216       AddrFile->RegisteredChainedReceiveHandler = TRUE;
1217     }
1218     break;
1219 
1220   case TDI_EVENT_CHAINED_RECEIVE_DATAGRAM:
1221     if (Parameters->EventHandler == NULL) {
1222       AddrFile->ChainedReceiveDatagramHandlerContext    = NULL;
1223       AddrFile->RegisteredChainedReceiveDatagramHandler = FALSE;
1224     } else {
1225       AddrFile->ChainedReceiveDatagramHandler =
1226         (PTDI_IND_CHAINED_RECEIVE_DATAGRAM)Parameters->EventHandler;
1227       AddrFile->ChainedReceiveDatagramHandlerContext    = Parameters->EventContext;
1228       AddrFile->RegisteredChainedReceiveDatagramHandler = TRUE;
1229     }
1230     break;
1231 
1232   case TDI_EVENT_CHAINED_RECEIVE_EXPEDITED:
1233     if (Parameters->EventHandler == NULL) {
1234       AddrFile->ChainedReceiveExpeditedHandlerContext    = NULL;
1235       AddrFile->RegisteredChainedReceiveExpeditedHandler = FALSE;
1236     } else {
1237       AddrFile->ChainedReceiveExpeditedHandler =
1238         (PTDI_IND_CHAINED_RECEIVE_EXPEDITED)Parameters->EventHandler;
1239       AddrFile->ChainedReceiveExpeditedHandlerContext    = Parameters->EventContext;
1240       AddrFile->RegisteredChainedReceiveExpeditedHandler = TRUE;
1241     }
1242     break;
1243 
1244   default:
1245     TI_DbgPrint(MIN_TRACE, ("Unknown event type (0x%X).\n",
1246       Parameters->EventType));
1247 
1248     Status = STATUS_INVALID_PARAMETER;
1249   }
1250 
1251   UnlockObject(AddrFile, OldIrql);
1252 
1253   return Status;
1254 }
1255 
1256 
1257 NTSTATUS DispTdiSetInformation(
1258     PIRP Irp)
1259 /*
1260  * FUNCTION: TDI_SET_INFORMATION handler
1261  * ARGUMENTS:
1262  *     Irp = Pointer to an I/O request packet
1263  * RETURNS:
1264  *     Status of operation
1265  */
1266 {
1267     TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
1268 
1269 	return STATUS_NOT_IMPLEMENTED;
1270 }
1271 
1272 
1273 VOID DispTdiQueryInformationExComplete(
1274     PVOID Context,
1275     ULONG Status,
1276     UINT ByteCount)
1277 /*
1278  * FUNCTION: Completes a TDI QueryInformationEx request
1279  * ARGUMENTS:
1280  *     Context   = Pointer to the IRP for the request
1281  *     Status    = TDI status of the request
1282  *     ByteCount = Number of bytes returned in output buffer
1283  */
1284 {
1285     PTI_QUERY_CONTEXT QueryContext;
1286 
1287     QueryContext = (PTI_QUERY_CONTEXT)Context;
1288     if (NT_SUCCESS(Status)) {
1289         CopyBufferToBufferChain(
1290             QueryContext->InputMdl,
1291             FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX, Context),
1292             (PCHAR)&QueryContext->QueryInfo.Context,
1293             CONTEXT_SIZE);
1294     }
1295 
1296     MmUnlockPages(QueryContext->InputMdl);
1297     IoFreeMdl(QueryContext->InputMdl);
1298     if( QueryContext->OutputMdl ) {
1299 	MmUnlockPages(QueryContext->OutputMdl);
1300 	IoFreeMdl(QueryContext->OutputMdl);
1301     }
1302 
1303     QueryContext->Irp->IoStatus.Information = ByteCount;
1304     QueryContext->Irp->IoStatus.Status      = Status;
1305 
1306     ExFreePoolWithTag(QueryContext, QUERY_CONTEXT_TAG);
1307 }
1308 
1309 
1310 NTSTATUS DispTdiQueryInformationEx(
1311     PIRP Irp,
1312     PIO_STACK_LOCATION IrpSp)
1313 /*
1314  * FUNCTION: TDI QueryInformationEx handler
1315  * ARGUMENTS:
1316  *     Irp   = Pointer to I/O request packet
1317  *     IrpSp = Pointer to current stack location of Irp
1318  * RETURNS:
1319  *     Status of operation
1320  */
1321 {
1322     PTCP_REQUEST_QUERY_INFORMATION_EX InputBuffer;
1323     PTRANSPORT_CONTEXT TranContext;
1324     PTI_QUERY_CONTEXT QueryContext;
1325     PVOID OutputBuffer;
1326     TDI_REQUEST Request;
1327     UINT Size;
1328     UINT InputBufferLength;
1329     UINT OutputBufferLength;
1330     BOOLEAN InputMdlLocked  = FALSE;
1331     BOOLEAN OutputMdlLocked = FALSE;
1332     PMDL InputMdl           = NULL;
1333     PMDL OutputMdl          = NULL;
1334     NTSTATUS Status         = STATUS_SUCCESS;
1335 
1336     TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
1337 
1338     TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
1339 
1340     switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {
1341     case TDI_TRANSPORT_ADDRESS_FILE:
1342         Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;
1343         break;
1344 
1345     case TDI_CONNECTION_FILE:
1346         Request.Handle.ConnectionContext = TranContext->Handle.ConnectionContext;
1347         break;
1348 
1349     case TDI_CONTROL_CHANNEL_FILE:
1350         Request.Handle.ControlChannel = TranContext->Handle.ControlChannel;
1351         break;
1352 
1353     default:
1354         TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n"));
1355         return STATUS_INVALID_PARAMETER;
1356     }
1357 
1358     InputBufferLength  = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
1359     OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
1360 
1361     /* Validate parameters */
1362     if ((InputBufferLength == sizeof(TCP_REQUEST_QUERY_INFORMATION_EX)) &&
1363         (OutputBufferLength != 0)) {
1364 
1365         InputBuffer = (PTCP_REQUEST_QUERY_INFORMATION_EX)
1366             IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
1367         OutputBuffer = Irp->UserBuffer;
1368 
1369         QueryContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(TI_QUERY_CONTEXT), QUERY_CONTEXT_TAG);
1370         if (QueryContext) {
1371 	    _SEH2_TRY {
1372                 InputMdl = IoAllocateMdl(InputBuffer,
1373                     sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
1374                     FALSE, TRUE, NULL);
1375 
1376                 OutputMdl = IoAllocateMdl(OutputBuffer,
1377                     OutputBufferLength, FALSE, TRUE, NULL);
1378 
1379                 if (InputMdl && OutputMdl) {
1380 
1381                     MmProbeAndLockPages(InputMdl, Irp->RequestorMode,
1382                         IoModifyAccess);
1383 
1384                     InputMdlLocked = TRUE;
1385 
1386                     MmProbeAndLockPages(OutputMdl, Irp->RequestorMode,
1387                         IoWriteAccess);
1388 
1389                     OutputMdlLocked = TRUE;
1390 
1391                     RtlCopyMemory(&QueryContext->QueryInfo,
1392                         InputBuffer, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
1393                 } else
1394                     Status = STATUS_INSUFFICIENT_RESOURCES;
1395             } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
1396                 Status = _SEH2_GetExceptionCode();
1397             } _SEH2_END;
1398 
1399             if (NT_SUCCESS(Status)) {
1400                 Size = MmGetMdlByteCount(OutputMdl);
1401 
1402                 QueryContext->Irp       = Irp;
1403                 QueryContext->InputMdl  = InputMdl;
1404                 QueryContext->OutputMdl = OutputMdl;
1405 
1406                 Request.RequestNotifyObject = DispTdiQueryInformationExComplete;
1407                 Request.RequestContext      = QueryContext;
1408                 Status = InfoTdiQueryInformationEx(&Request,
1409                     &QueryContext->QueryInfo.ID, OutputMdl,
1410                     &Size, &QueryContext->QueryInfo.Context);
1411                 DispTdiQueryInformationExComplete(QueryContext, Status, Size);
1412 
1413                 TI_DbgPrint(MAX_TRACE, ("Leaving. Status = (0x%X)\n", Status));
1414 
1415                 return Status;
1416             }
1417 
1418             /* An error occurred if we get here */
1419 
1420             if (InputMdl) {
1421                 if (InputMdlLocked)
1422                     MmUnlockPages(InputMdl);
1423                 IoFreeMdl(InputMdl);
1424             }
1425 
1426             if (OutputMdl) {
1427                 if (OutputMdlLocked)
1428                     MmUnlockPages(OutputMdl);
1429                 IoFreeMdl(OutputMdl);
1430             }
1431 
1432             ExFreePoolWithTag(QueryContext, QUERY_CONTEXT_TAG);
1433         } else
1434             Status = STATUS_INSUFFICIENT_RESOURCES;
1435     } else if( InputBufferLength ==
1436 	       sizeof(TCP_REQUEST_QUERY_INFORMATION_EX) ) {
1437 	/* Handle the case where the user is probing the buffer for length */
1438 	TI_DbgPrint(MAX_TRACE, ("InputBufferLength %d OutputBufferLength %d\n",
1439 				InputBufferLength, OutputBufferLength));
1440         InputBuffer = (PTCP_REQUEST_QUERY_INFORMATION_EX)
1441             IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
1442 
1443 	Size = 0;
1444 
1445         QueryContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(TI_QUERY_CONTEXT), QUERY_CONTEXT_TAG);
1446         if (!QueryContext) return STATUS_INSUFFICIENT_RESOURCES;
1447 
1448 	_SEH2_TRY {
1449 	    InputMdl = IoAllocateMdl(InputBuffer,
1450 				     sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
1451 				     FALSE, TRUE, NULL);
1452 
1453 	    MmProbeAndLockPages(InputMdl, Irp->RequestorMode,
1454 				IoModifyAccess);
1455 
1456 	    InputMdlLocked = TRUE;
1457 	    Status = STATUS_SUCCESS;
1458 	} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
1459 	    TI_DbgPrint(MAX_TRACE, ("Failed to acquire client buffer\n"));
1460 	    Status = _SEH2_GetExceptionCode();
1461 	} _SEH2_END;
1462 
1463 	if( !NT_SUCCESS(Status) || !InputMdl ) {
1464 	    if( InputMdl ) IoFreeMdl( InputMdl );
1465 	    ExFreePoolWithTag(QueryContext, QUERY_CONTEXT_TAG);
1466 	    return Status;
1467 	}
1468 
1469 	RtlCopyMemory(&QueryContext->QueryInfo,
1470 		      InputBuffer, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
1471 
1472 	QueryContext->Irp       = Irp;
1473 	QueryContext->InputMdl  = InputMdl;
1474 	QueryContext->OutputMdl = NULL;
1475 
1476 	Request.RequestNotifyObject = DispTdiQueryInformationExComplete;
1477 	Request.RequestContext      = QueryContext;
1478 	Status = InfoTdiQueryInformationEx(&Request,
1479 					   &QueryContext->QueryInfo.ID,
1480 					   NULL,
1481 					   &Size,
1482 					   &QueryContext->QueryInfo.Context);
1483 	DispTdiQueryInformationExComplete(QueryContext, Status, Size);
1484 	TI_DbgPrint(MAX_TRACE, ("Leaving. Status = (0x%X)\n", Status));
1485     } else Status = STATUS_INVALID_PARAMETER;
1486 
1487     TI_DbgPrint(MIN_TRACE, ("Leaving. Status = (0x%X)\n", Status));
1488 
1489     return Status;
1490 }
1491 
1492 
1493 NTSTATUS DispTdiSetInformationEx(
1494     PIRP Irp,
1495     PIO_STACK_LOCATION IrpSp)
1496 /*
1497  * FUNCTION: TDI SetInformationEx handler
1498  * ARGUMENTS:
1499  *     Irp   = Pointer to I/O request packet
1500  *     IrpSp = Pointer to current stack location of Irp
1501  * RETURNS:
1502  *     Status of operation
1503  */
1504 {
1505     PTRANSPORT_CONTEXT TranContext;
1506     PTCP_REQUEST_SET_INFORMATION_EX Info;
1507     TDI_REQUEST Request;
1508     TDI_STATUS Status;
1509 
1510     TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
1511 
1512     TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
1513     Info        = (PTCP_REQUEST_SET_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer;
1514 
1515     switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {
1516     case TDI_TRANSPORT_ADDRESS_FILE:
1517         Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;
1518         break;
1519 
1520     case TDI_CONNECTION_FILE:
1521         Request.Handle.ConnectionContext = TranContext->Handle.ConnectionContext;
1522         break;
1523 
1524     case TDI_CONTROL_CHANNEL_FILE:
1525         Request.Handle.ControlChannel = TranContext->Handle.ControlChannel;
1526         break;
1527 
1528     default:
1529         Irp->IoStatus.Status      = STATUS_INVALID_PARAMETER;
1530         Irp->IoStatus.Information = 0;
1531 
1532         TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
1533 
1534         return Irp->IoStatus.Status;
1535     }
1536 
1537     Request.RequestNotifyObject = NULL;
1538     Request.RequestContext      = NULL;
1539 
1540     Status = InfoTdiSetInformationEx(&Request, &Info->ID,
1541             &Info->Buffer, Info->BufferSize);
1542 
1543     return Status;
1544 }
1545 
1546 /* TODO: Support multiple addresses per interface.
1547  * For now just set the nte context to the interface index.
1548  *
1549  * Later on, create an NTE context and NTE instance
1550  */
1551 
1552 NTSTATUS DispTdiSetIPAddress( PIRP Irp, PIO_STACK_LOCATION IrpSp ) {
1553     NTSTATUS Status = STATUS_DEVICE_DOES_NOT_EXIST;
1554     PIP_SET_ADDRESS IpAddrChange =
1555         (PIP_SET_ADDRESS)Irp->AssociatedIrp.SystemBuffer;
1556     IF_LIST_ITER(IF);
1557 
1558     TI_DbgPrint(MID_TRACE,("Setting IP Address for adapter %d\n",
1559 			   IpAddrChange->NteIndex));
1560 
1561     ForEachInterface(IF) {
1562 	TI_DbgPrint(MID_TRACE,("Looking at adapter %d\n", IF->Index));
1563 
1564         if( IF->Unicast.Address.IPv4Address == IpAddrChange->Address ) {
1565             Status = STATUS_DUPLICATE_OBJECTID;
1566             break;
1567         }
1568         if( IF->Index == IpAddrChange->NteIndex ) {
1569             IPRemoveInterfaceRoute( IF );
1570 
1571             IF->Unicast.Type = IP_ADDRESS_V4;
1572             IF->Unicast.Address.IPv4Address = IpAddrChange->Address;
1573 
1574             IF->Netmask.Type = IP_ADDRESS_V4;
1575             IF->Netmask.Address.IPv4Address = IpAddrChange->Netmask;
1576 
1577             IF->Broadcast.Type = IP_ADDRESS_V4;
1578 	    IF->Broadcast.Address.IPv4Address =
1579 		IF->Unicast.Address.IPv4Address |
1580 		~IF->Netmask.Address.IPv4Address;
1581 
1582             TI_DbgPrint(MID_TRACE,("New Unicast Address: %x\n",
1583                                    IF->Unicast.Address.IPv4Address));
1584             TI_DbgPrint(MID_TRACE,("New Netmask        : %x\n",
1585                                    IF->Netmask.Address.IPv4Address));
1586 
1587             IPAddInterfaceRoute( IF );
1588 
1589             IpAddrChange->Address = IF->Index;
1590             Status = STATUS_SUCCESS;
1591             Irp->IoStatus.Information = IF->Index;
1592             break;
1593         }
1594     } EndFor(IF);
1595 
1596     Irp->IoStatus.Status = Status;
1597     return Status;
1598 }
1599 
1600 NTSTATUS DispTdiDeleteIPAddress( PIRP Irp, PIO_STACK_LOCATION IrpSp ) {
1601     NTSTATUS Status = STATUS_UNSUCCESSFUL;
1602     PUSHORT NteIndex = Irp->AssociatedIrp.SystemBuffer;
1603     IF_LIST_ITER(IF);
1604 
1605     ForEachInterface(IF) {
1606         if( IF->Index == *NteIndex ) {
1607             IPRemoveInterfaceRoute( IF );
1608             IF->Unicast.Type = IP_ADDRESS_V4;
1609             IF->Unicast.Address.IPv4Address = 0;
1610 
1611             IF->Netmask.Type = IP_ADDRESS_V4;
1612             IF->Netmask.Address.IPv4Address = 0;
1613 
1614             IF->Broadcast.Type = IP_ADDRESS_V4;
1615             IF->Broadcast.Address.IPv4Address = 0;
1616 
1617             Status = STATUS_SUCCESS;
1618         }
1619     } EndFor(IF);
1620 
1621     Irp->IoStatus.Status = Status;
1622     return Status;
1623 }
1624 
1625 VOID NTAPI
1626 WaitForHwAddress ( PDEVICE_OBJECT DeviceObject, PVOID Context) {
1627     PQUERY_HW_WORK_ITEM WorkItem = (PQUERY_HW_WORK_ITEM)Context;
1628     LARGE_INTEGER Now;
1629     LARGE_INTEGER Wait;
1630     IP_ADDRESS Remote;
1631     PIRP Irp;
1632     PNEIGHBOR_CACHE_ENTRY NCE = NULL;
1633     NTSTATUS Status = STATUS_UNSUCCESSFUL;
1634 
1635     IoFreeWorkItem(WorkItem->WorkItem);
1636     Irp = WorkItem->Irp;
1637     AddrInitIPv4(&Remote, WorkItem->RemoteIP);
1638     KeQuerySystemTime(&Now);
1639     while (Now.QuadPart - WorkItem->StartTime.QuadPart < 10000 * 1000 && !Irp->Cancel) {
1640         NCE = NBLocateNeighbor(&Remote, WorkItem->Interface);
1641         if (NCE && !(NCE->State & NUD_INCOMPLETE)) {
1642             break;
1643         }
1644 
1645         NCE = NULL;
1646         Wait.QuadPart = -10000;
1647         KeDelayExecutionThread(KernelMode, FALSE, &Wait);
1648         KeQuerySystemTime(&Now);
1649     }
1650 
1651     if (NCE) {
1652         PVOID OutputBuffer;
1653 
1654         if (NCE->LinkAddressLength > WorkItem->IrpSp->Parameters.DeviceIoControl.OutputBufferLength) {
1655             Status = STATUS_INSUFFICIENT_RESOURCES;
1656         } else {
1657             OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
1658             RtlCopyMemory(OutputBuffer, NCE->LinkAddress, NCE->LinkAddressLength);
1659             Irp->IoStatus.Information = NCE->LinkAddressLength;
1660             Status = STATUS_SUCCESS;
1661         }
1662     }
1663 
1664     ExFreePoolWithTag(WorkItem, QUERY_CONTEXT_TAG);
1665     if (Irp->Flags & IRP_SYNCHRONOUS_API) {
1666         Irp->IoStatus.Status = Status;
1667     } else {
1668         IRPFinish(Irp, Status);
1669     }
1670 }
1671 
1672 NTSTATUS DispTdiQueryIpHwAddress( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp ) {
1673     NTSTATUS Status;
1674     PULONG IPs;
1675     IP_ADDRESS Remote, Local;
1676     PNEIGHBOR_CACHE_ENTRY NCE;
1677     PIP_INTERFACE Interface;
1678     PQUERY_HW_WORK_ITEM WorkItem;
1679 
1680     Irp->IoStatus.Information = 0;
1681 
1682     if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < 2 * sizeof(ULONG) ||
1683         IrpSp->Parameters.DeviceIoControl.OutputBufferLength == 0) {
1684         Status = STATUS_INVALID_BUFFER_SIZE;
1685         goto Exit;
1686     }
1687 
1688     IPs = (PULONG)Irp->AssociatedIrp.SystemBuffer;
1689     AddrInitIPv4(&Remote, IPs[0]);
1690     AddrInitIPv4(&Local, IPs[1]);
1691 
1692     if (AddrIsUnspecified(&Remote)) {
1693         Status = STATUS_UNSUCCESSFUL;
1694         goto Exit;
1695     }
1696 
1697     Interface = AddrLocateInterface(&Remote);
1698     if (Interface) {
1699         PVOID OutputBuffer;
1700 
1701         if (Interface->AddressLength > IrpSp->Parameters.DeviceIoControl.OutputBufferLength) {
1702             Status = STATUS_INSUFFICIENT_RESOURCES;
1703             goto Exit;
1704         }
1705 
1706         OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
1707         RtlCopyMemory(OutputBuffer, Interface->Address, Interface->AddressLength);
1708         Irp->IoStatus.Information = Interface->AddressLength;
1709         Status = STATUS_SUCCESS;
1710         goto Exit;
1711     }
1712 
1713     if (AddrIsUnspecified(&Local)) {
1714         NCE = RouteGetRouteToDestination(&Remote);
1715         if (NCE == NULL) {
1716             Status = STATUS_NETWORK_UNREACHABLE;
1717             goto Exit;
1718         }
1719 
1720         Interface = NCE->Interface;
1721     }
1722     else {
1723         Interface = AddrLocateInterface(&Local);
1724         if (Interface == NULL) {
1725             Interface = GetDefaultInterface();
1726             if (Interface == NULL) {
1727                 Status = STATUS_NETWORK_UNREACHABLE;
1728                 goto Exit;
1729             }
1730         }
1731     }
1732 
1733     WorkItem = ExAllocatePoolWithTag(PagedPool, sizeof(QUERY_HW_WORK_ITEM), QUERY_CONTEXT_TAG);
1734     if (WorkItem == NULL) {
1735         Status = STATUS_INSUFFICIENT_RESOURCES;
1736         goto Exit;
1737     }
1738 
1739     WorkItem->WorkItem = IoAllocateWorkItem(DeviceObject);
1740     if (WorkItem->WorkItem == NULL) {
1741         ExFreePoolWithTag(WorkItem, QUERY_CONTEXT_TAG);
1742         Status = STATUS_INSUFFICIENT_RESOURCES;
1743         goto Exit;
1744     }
1745 
1746     WorkItem->Irp = Irp;
1747     WorkItem->IrpSp = IrpSp;
1748     WorkItem->Interface = Interface;
1749     WorkItem->RemoteIP = IPs[0];
1750     KeQuerySystemTime(&WorkItem->StartTime);
1751 
1752     NCE = NBLocateNeighbor(&Remote, Interface);
1753     if (NCE != NULL) {
1754         if (NCE->LinkAddressLength > IrpSp->Parameters.DeviceIoControl.OutputBufferLength) {
1755             IoFreeWorkItem(WorkItem->WorkItem);
1756             ExFreePoolWithTag(WorkItem, QUERY_CONTEXT_TAG);
1757             Status = STATUS_INVALID_BUFFER_SIZE;
1758             goto Exit;
1759         }
1760 
1761         if (!(NCE->State & NUD_INCOMPLETE)) {
1762             PVOID LinkAddress = ExAllocatePoolWithTag(PagedPool, NCE->LinkAddressLength, QUERY_CONTEXT_TAG);
1763             if (LinkAddress == NULL) {
1764                 IoFreeWorkItem(WorkItem->WorkItem);
1765                 ExFreePoolWithTag(WorkItem, QUERY_CONTEXT_TAG);
1766                 Status = STATUS_INSUFFICIENT_RESOURCES;
1767                 goto Exit;
1768             }
1769             memset(LinkAddress, 0xff, NCE->LinkAddressLength);
1770             NBUpdateNeighbor(NCE, LinkAddress, NUD_INCOMPLETE);
1771             ExFreePoolWithTag(LinkAddress, QUERY_CONTEXT_TAG);
1772         }
1773     }
1774 
1775     if (!ARPTransmit(&Remote, NULL, Interface)) {
1776         IoFreeWorkItem(WorkItem->WorkItem);
1777         ExFreePoolWithTag(WorkItem, QUERY_CONTEXT_TAG);
1778         Status = STATUS_UNSUCCESSFUL;
1779         goto Exit;
1780     }
1781 
1782     if (Irp->Flags & IRP_SYNCHRONOUS_API) {
1783         WaitForHwAddress(DeviceObject, WorkItem);
1784         Status = Irp->IoStatus.Status;
1785     } else {
1786         IoMarkIrpPending(Irp);
1787         IoQueueWorkItem(WorkItem->WorkItem, WaitForHwAddress, DelayedWorkQueue, WorkItem);
1788         Status = STATUS_PENDING;
1789     }
1790 
1791 Exit:
1792     return Status;
1793 }
1794 
1795 /* EOF */
1796