xref: /reactos/drivers/network/tcpip/tcpip/dispatch.c (revision 40462c92)
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             if (AddrFile == NULL)
715             {
716                 TI_DbgPrint(MIN_TRACE, ("FIXME: No address file object.\n"));
717                 ASSERT(AddrFile != NULL);
718                 return STATUS_INVALID_PARAMETER;
719             }
720 
721 			Address->TAAddressCount = 1;
722 			Address->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
723 			Address->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
724 			Address->Address[0].Address[0].sin_port = AddrFile->Port;
725 			Address->Address[0].Address[0].in_addr = AddrFile->Address.Address.IPv4Address;
726 			RtlZeroMemory(
727 				&Address->Address[0].Address[0].sin_zero,
728 				sizeof(Address->Address[0].Address[0].sin_zero));
729 			return STATUS_SUCCESS;
730 
731           case TDI_CONNECTION_FILE:
732             Endpoint =
733 				(PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
734             if (Endpoint == NULL || Endpoint->AddressFile == NULL)
735             {
736                 TI_DbgPrint(MIN_TRACE, ("FIXME: No connection endpoint file object.\n"));
737                 ASSERT(Endpoint != NULL && Endpoint->AddressFile != NULL);
738                 return STATUS_INVALID_PARAMETER;
739             }
740 
741             Address->TAAddressCount = 1;
742             Address->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
743             Address->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
744             Address->Address[0].Address[0].sin_port = Endpoint->AddressFile->Port;
745             Address->Address[0].Address[0].in_addr = Endpoint->AddressFile->Address.Address.IPv4Address;
746 			RtlZeroMemory(
747 				&Address->Address[0].Address[0].sin_zero,
748 				sizeof(Address->Address[0].Address[0].sin_zero));
749             return STATUS_SUCCESS;
750 
751           default:
752             TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n"));
753             return STATUS_INVALID_PARAMETER;
754         }
755       }
756 
757     case TDI_QUERY_CONNECTION_INFO:
758       {
759         PTDI_CONNECTION_INFO ConnectionInfo;
760         //PCONNECTION_ENDPOINT Endpoint;
761 
762         if (MmGetMdlByteCount(Irp->MdlAddress) < sizeof(*ConnectionInfo)) {
763           TI_DbgPrint(MID_TRACE, ("MDL buffer too small.\n"));
764           return STATUS_BUFFER_TOO_SMALL;
765         }
766 
767         ConnectionInfo = (PTDI_CONNECTION_INFO)
768           MmGetSystemAddressForMdl(Irp->MdlAddress);
769 
770         switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {
771           case TDI_CONNECTION_FILE:
772             //Endpoint = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
773             RtlZeroMemory(ConnectionInfo, sizeof(*ConnectionInfo));
774             return STATUS_SUCCESS;
775 
776           default:
777             TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n"));
778             return STATUS_INVALID_PARAMETER;
779         }
780       }
781 
782       case TDI_QUERY_MAX_DATAGRAM_INFO:
783       {
784           PTDI_MAX_DATAGRAM_INFO MaxDatagramInfo;
785 
786           if (MmGetMdlByteCount(Irp->MdlAddress) < sizeof(*MaxDatagramInfo)) {
787               TI_DbgPrint(MID_TRACE, ("MDL buffer too small.\n"));
788               return STATUS_BUFFER_TOO_SMALL;
789           }
790 
791           MaxDatagramInfo = (PTDI_MAX_DATAGRAM_INFO)
792             MmGetSystemAddressForMdl(Irp->MdlAddress);
793 
794           MaxDatagramInfo->MaxDatagramSize = 0xFFFF;
795 
796           return STATUS_SUCCESS;
797      }
798   }
799 
800   return STATUS_NOT_IMPLEMENTED;
801 }
802 
803 
804 NTSTATUS DispTdiReceive(
805   PIRP Irp)
806 /*
807  * FUNCTION: TDI_RECEIVE handler
808  * ARGUMENTS:
809  *     Irp = Pointer to an I/O request packet
810  * RETURNS:
811  *     Status of operation
812  */
813 {
814   PIO_STACK_LOCATION IrpSp;
815   PTDI_REQUEST_KERNEL_RECEIVE ReceiveInfo;
816   PTRANSPORT_CONTEXT TranContext;
817   NTSTATUS Status;
818   ULONG BytesReceived = 0;
819 
820   TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
821 
822   IrpSp = IoGetCurrentIrpStackLocation(Irp);
823   ReceiveInfo = (PTDI_REQUEST_KERNEL_RECEIVE)&(IrpSp->Parameters);
824 
825   IoMarkIrpPending(Irp);
826 
827   TranContext = IrpSp->FileObject->FsContext;
828   if (TranContext == NULL)
829     {
830       TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
831       Status = STATUS_INVALID_PARAMETER;
832       goto done;
833     }
834 
835   if (TranContext->Handle.ConnectionContext == NULL)
836     {
837       TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
838       Status = STATUS_INVALID_PARAMETER;
839       goto done;
840     }
841 
842   /* Initialize a receive request */
843   Status = DispPrepareIrpForCancel
844       (TranContext->Handle.ConnectionContext,
845        Irp,
846        (PDRIVER_CANCEL)DispCancelRequest);
847 
848   TI_DbgPrint(MID_TRACE,("TCPIP<<< Got an MDL: %x\n", Irp->MdlAddress));
849   if (NT_SUCCESS(Status))
850     {
851       Status = TCPReceiveData(
852 	  TranContext->Handle.ConnectionContext,
853 	  (PNDIS_BUFFER)Irp->MdlAddress,
854 	  ReceiveInfo->ReceiveLength,
855 	  &BytesReceived,
856 	  ReceiveInfo->ReceiveFlags,
857 	  DispDataRequestComplete,
858 	  Irp);
859     }
860 
861 done:
862   if (Status != STATUS_PENDING) {
863       DispDataRequestComplete(Irp, Status, BytesReceived);
864   }
865 
866   TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status));
867 
868   return STATUS_PENDING;
869 }
870 
871 
872 NTSTATUS DispTdiReceiveDatagram(
873     PIRP Irp)
874 /*
875  * FUNCTION: TDI_RECEIVE_DATAGRAM handler
876  * ARGUMENTS:
877  *     Irp = Pointer to an I/O request packet
878  * RETURNS:
879  *     Status of operation
880  */
881 {
882   PIO_STACK_LOCATION IrpSp;
883   PTDI_REQUEST_KERNEL_RECEIVEDG DgramInfo;
884   PTRANSPORT_CONTEXT TranContext;
885   TDI_REQUEST Request;
886   NTSTATUS Status;
887   ULONG BytesReceived = 0;
888 
889   TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
890 
891   IrpSp     = IoGetCurrentIrpStackLocation(Irp);
892   DgramInfo = (PTDI_REQUEST_KERNEL_RECEIVEDG)&(IrpSp->Parameters);
893 
894   IoMarkIrpPending(Irp);
895 
896   TranContext = IrpSp->FileObject->FsContext;
897   if (TranContext == NULL)
898     {
899       TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
900       Status = STATUS_INVALID_PARAMETER;
901       goto done;
902     }
903 
904   /* Initialize a receive request */
905   Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;
906   Request.RequestNotifyObject  = DispDataRequestComplete;
907   Request.RequestContext       = Irp;
908 
909   Status = DispPrepareIrpForCancel(
910     IrpSp->FileObject->FsContext,
911     Irp,
912     (PDRIVER_CANCEL)DispCancelRequest);
913 
914   if (NT_SUCCESS(Status))
915     {
916 	PVOID DataBuffer;
917 	UINT BufferSize;
918 
919 	NdisQueryBuffer( (PNDIS_BUFFER)Irp->MdlAddress,
920 			 &DataBuffer,
921 			 &BufferSize );
922 
923       Status = DGReceiveDatagram(
924 	  Request.Handle.AddressHandle,
925 	  DgramInfo->ReceiveDatagramInformation,
926 	  DataBuffer,
927 	  DgramInfo->ReceiveLength,
928 	  DgramInfo->ReceiveFlags,
929 	  DgramInfo->ReturnDatagramInformation,
930 	  &BytesReceived,
931 	  (PDATAGRAM_COMPLETION_ROUTINE)DispDataRequestComplete,
932 	  Irp,
933           Irp);
934     }
935 
936 done:
937    if (Status != STATUS_PENDING) {
938        DispDataRequestComplete(Irp, Status, BytesReceived);
939    }
940 
941   TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status));
942 
943   return STATUS_PENDING;
944 }
945 
946 
947 NTSTATUS DispTdiSend(
948     PIRP Irp)
949 /*
950  * FUNCTION: TDI_SEND handler
951  * ARGUMENTS:
952  *     Irp = Pointer to an I/O request packet
953  * RETURNS:
954  *     Status of operation
955  */
956 {
957   PIO_STACK_LOCATION IrpSp;
958   PTDI_REQUEST_KERNEL_SEND SendInfo;
959   PTRANSPORT_CONTEXT TranContext;
960   NTSTATUS Status;
961   ULONG BytesSent = 0;
962 
963   TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
964 
965   IrpSp = IoGetCurrentIrpStackLocation(Irp);
966   SendInfo = (PTDI_REQUEST_KERNEL_SEND)&(IrpSp->Parameters);
967 
968   IoMarkIrpPending(Irp);
969 
970   TranContext = IrpSp->FileObject->FsContext;
971   if (TranContext == NULL)
972     {
973       TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
974       Status = STATUS_INVALID_PARAMETER;
975       goto done;
976     }
977 
978   if (TranContext->Handle.ConnectionContext == NULL)
979     {
980       TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
981       Status = STATUS_INVALID_PARAMETER;
982       goto done;
983     }
984 
985   Status = DispPrepareIrpForCancel(
986     IrpSp->FileObject->FsContext,
987     Irp,
988     (PDRIVER_CANCEL)DispCancelRequest);
989 
990   TI_DbgPrint(MID_TRACE,("TCPIP<<< Got an MDL: %x\n", Irp->MdlAddress));
991   if (NT_SUCCESS(Status))
992     {
993 	PVOID Data;
994 	UINT Len;
995 
996 	NdisQueryBuffer( Irp->MdlAddress, &Data, &Len );
997 
998 	TI_DbgPrint(MID_TRACE,("About to TCPSendData\n"));
999 	Status = TCPSendData(
1000 	    TranContext->Handle.ConnectionContext,
1001 	    Data,
1002 	    SendInfo->SendLength,
1003 	    &BytesSent,
1004 	    SendInfo->SendFlags,
1005 	    DispDataRequestComplete,
1006 	    Irp);
1007     }
1008 
1009 done:
1010    if (Status != STATUS_PENDING) {
1011        DispDataRequestComplete(Irp, Status, BytesSent);
1012    }
1013 
1014   TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status));
1015 
1016   return STATUS_PENDING;
1017 }
1018 
1019 
1020 NTSTATUS DispTdiSendDatagram(
1021     PIRP Irp)
1022 /*
1023  * FUNCTION: TDI_SEND_DATAGRAM handler
1024  * ARGUMENTS:
1025  *     Irp = Pointer to an I/O request packet
1026  * RETURNS:
1027  *     Status of operation
1028  */
1029 {
1030     PIO_STACK_LOCATION IrpSp;
1031     TDI_REQUEST Request;
1032     PTDI_REQUEST_KERNEL_SENDDG DgramInfo;
1033     PTRANSPORT_CONTEXT TranContext;
1034     NTSTATUS Status;
1035 
1036     TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
1037 
1038     IrpSp       = IoGetCurrentIrpStackLocation(Irp);
1039     DgramInfo   = (PTDI_REQUEST_KERNEL_SENDDG)&(IrpSp->Parameters);
1040 
1041     IoMarkIrpPending(Irp);
1042 
1043     TranContext = IrpSp->FileObject->FsContext;
1044     if (TranContext == NULL)
1045     {
1046       TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
1047       Status = STATUS_INVALID_PARAMETER;
1048       goto done;
1049     }
1050 
1051     /* Initialize a send request */
1052     Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;
1053     Request.RequestNotifyObject  = DispDataRequestComplete;
1054     Request.RequestContext       = Irp;
1055 
1056     Status = DispPrepareIrpForCancel(
1057         IrpSp->FileObject->FsContext,
1058         Irp,
1059         (PDRIVER_CANCEL)DispCancelRequest);
1060 
1061     if (NT_SUCCESS(Status)) {
1062 	PVOID DataBuffer;
1063 	UINT BufferSize;
1064 
1065 	TI_DbgPrint(MID_TRACE,("About to query buffer %x\n", Irp->MdlAddress));
1066 
1067 	NdisQueryBuffer( (PNDIS_BUFFER)Irp->MdlAddress,
1068 			 &DataBuffer,
1069 			 &BufferSize );
1070 
1071         /* FIXME: DgramInfo->SendDatagramInformation->RemoteAddress
1072            must be of type PTDI_ADDRESS_IP */
1073 	TI_DbgPrint(MID_TRACE,
1074 		    ("About to call send routine %x\n",
1075 		     (*((PADDRESS_FILE)Request.Handle.AddressHandle)->Send)));
1076 
1077         if( (*((PADDRESS_FILE)Request.Handle.AddressHandle)->Send != NULL) )
1078         {
1079 	        ULONG DataUsed = 0;
1080             Status = (*((PADDRESS_FILE)Request.Handle.AddressHandle)->Send)(
1081                 Request.Handle.AddressHandle,
1082                 DgramInfo->SendDatagramInformation,
1083                 DataBuffer,
1084                 BufferSize,
1085                 &DataUsed);
1086             Irp->IoStatus.Information = DataUsed;
1087         }
1088         else {
1089             Status = STATUS_UNSUCCESSFUL;
1090             ASSERT(FALSE);
1091         }
1092     }
1093 
1094 done:
1095     if (Status != STATUS_PENDING) {
1096         DispDataRequestComplete(Irp, Status, Irp->IoStatus.Information);
1097     }
1098 
1099     TI_DbgPrint(DEBUG_IRP, ("Leaving.\n"));
1100 
1101     return STATUS_PENDING;
1102 }
1103 
1104 
1105 NTSTATUS DispTdiSetEventHandler(PIRP Irp)
1106 /*
1107  * FUNCTION: TDI_SET_EVENT_HANDER handler
1108  * ARGUMENTS:
1109  *     Irp = Pointer to a I/O request packet
1110  * RETURNS:
1111  *     Status of operation
1112  */
1113 {
1114   PTDI_REQUEST_KERNEL_SET_EVENT Parameters;
1115   PTRANSPORT_CONTEXT TranContext;
1116   PIO_STACK_LOCATION IrpSp;
1117   PADDRESS_FILE AddrFile;
1118   NTSTATUS Status;
1119   KIRQL OldIrql;
1120 
1121   TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
1122 
1123   IrpSp = IoGetCurrentIrpStackLocation(Irp);
1124 
1125   /* Get associated address file object. Quit if none exists */
1126 
1127   TranContext = IrpSp->FileObject->FsContext;
1128   if (!TranContext) {
1129     TI_DbgPrint(MIN_TRACE, ("Bad transport context.\n"));
1130     return STATUS_INVALID_PARAMETER;
1131   }
1132 
1133   AddrFile = (PADDRESS_FILE)TranContext->Handle.AddressHandle;
1134   if (!AddrFile) {
1135     TI_DbgPrint(MIN_TRACE, ("No address file object.\n"));
1136     return STATUS_INVALID_PARAMETER;
1137   }
1138 
1139   Parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)&IrpSp->Parameters;
1140   Status     = STATUS_SUCCESS;
1141 
1142   LockObject(AddrFile, &OldIrql);
1143 
1144   /* Set the event handler. if an event handler is associated with
1145      a specific event, it's flag (RegisteredXxxHandler) is TRUE.
1146      If an event handler is not used it's flag is FALSE */
1147   switch (Parameters->EventType) {
1148   case TDI_EVENT_CONNECT:
1149     if (!Parameters->EventHandler) {
1150       AddrFile->ConnectHandlerContext    = NULL;
1151       AddrFile->RegisteredConnectHandler = FALSE;
1152     } else {
1153       AddrFile->ConnectHandler =
1154         (PTDI_IND_CONNECT)Parameters->EventHandler;
1155       AddrFile->ConnectHandlerContext    = Parameters->EventContext;
1156       AddrFile->RegisteredConnectHandler = TRUE;
1157     }
1158     break;
1159 
1160   case TDI_EVENT_DISCONNECT:
1161     if (!Parameters->EventHandler) {
1162       AddrFile->DisconnectHandlerContext    = NULL;
1163       AddrFile->RegisteredDisconnectHandler = FALSE;
1164     } else {
1165       AddrFile->DisconnectHandler =
1166         (PTDI_IND_DISCONNECT)Parameters->EventHandler;
1167       AddrFile->DisconnectHandlerContext    = Parameters->EventContext;
1168       AddrFile->RegisteredDisconnectHandler = TRUE;
1169     }
1170     break;
1171 
1172     case TDI_EVENT_ERROR:
1173     if (Parameters->EventHandler == NULL) {
1174       AddrFile->ErrorHandlerContext    = NULL;
1175       AddrFile->RegisteredErrorHandler = FALSE;
1176     } else {
1177       AddrFile->ErrorHandler =
1178         (PTDI_IND_ERROR)Parameters->EventHandler;
1179       AddrFile->ErrorHandlerContext    = Parameters->EventContext;
1180       AddrFile->RegisteredErrorHandler = TRUE;
1181     }
1182     break;
1183 
1184   case TDI_EVENT_RECEIVE:
1185     if (Parameters->EventHandler == NULL) {
1186       AddrFile->ReceiveHandlerContext    = NULL;
1187       AddrFile->RegisteredReceiveHandler = FALSE;
1188     } else {
1189       AddrFile->ReceiveHandler =
1190         (PTDI_IND_RECEIVE)Parameters->EventHandler;
1191       AddrFile->ReceiveHandlerContext    = Parameters->EventContext;
1192       AddrFile->RegisteredReceiveHandler = TRUE;
1193     }
1194     break;
1195 
1196   case TDI_EVENT_RECEIVE_DATAGRAM:
1197     if (Parameters->EventHandler == NULL) {
1198       AddrFile->ReceiveDatagramHandlerContext    = NULL;
1199       AddrFile->RegisteredReceiveDatagramHandler = FALSE;
1200     } else {
1201       AddrFile->ReceiveDatagramHandler =
1202         (PTDI_IND_RECEIVE_DATAGRAM)Parameters->EventHandler;
1203       AddrFile->ReceiveDatagramHandlerContext    = Parameters->EventContext;
1204       AddrFile->RegisteredReceiveDatagramHandler = TRUE;
1205     }
1206     break;
1207 
1208   case TDI_EVENT_RECEIVE_EXPEDITED:
1209     if (Parameters->EventHandler == NULL) {
1210       AddrFile->ExpeditedReceiveHandlerContext    = NULL;
1211       AddrFile->RegisteredExpeditedReceiveHandler = FALSE;
1212     } else {
1213       AddrFile->ExpeditedReceiveHandler =
1214         (PTDI_IND_RECEIVE_EXPEDITED)Parameters->EventHandler;
1215       AddrFile->ExpeditedReceiveHandlerContext    = Parameters->EventContext;
1216       AddrFile->RegisteredExpeditedReceiveHandler = TRUE;
1217     }
1218     break;
1219 
1220   case TDI_EVENT_CHAINED_RECEIVE:
1221     if (Parameters->EventHandler == NULL) {
1222       AddrFile->ChainedReceiveHandlerContext    = NULL;
1223       AddrFile->RegisteredChainedReceiveHandler = FALSE;
1224     } else {
1225       AddrFile->ChainedReceiveHandler =
1226         (PTDI_IND_CHAINED_RECEIVE)Parameters->EventHandler;
1227       AddrFile->ChainedReceiveHandlerContext    = Parameters->EventContext;
1228       AddrFile->RegisteredChainedReceiveHandler = TRUE;
1229     }
1230     break;
1231 
1232   case TDI_EVENT_CHAINED_RECEIVE_DATAGRAM:
1233     if (Parameters->EventHandler == NULL) {
1234       AddrFile->ChainedReceiveDatagramHandlerContext    = NULL;
1235       AddrFile->RegisteredChainedReceiveDatagramHandler = FALSE;
1236     } else {
1237       AddrFile->ChainedReceiveDatagramHandler =
1238         (PTDI_IND_CHAINED_RECEIVE_DATAGRAM)Parameters->EventHandler;
1239       AddrFile->ChainedReceiveDatagramHandlerContext    = Parameters->EventContext;
1240       AddrFile->RegisteredChainedReceiveDatagramHandler = TRUE;
1241     }
1242     break;
1243 
1244   case TDI_EVENT_CHAINED_RECEIVE_EXPEDITED:
1245     if (Parameters->EventHandler == NULL) {
1246       AddrFile->ChainedReceiveExpeditedHandlerContext    = NULL;
1247       AddrFile->RegisteredChainedReceiveExpeditedHandler = FALSE;
1248     } else {
1249       AddrFile->ChainedReceiveExpeditedHandler =
1250         (PTDI_IND_CHAINED_RECEIVE_EXPEDITED)Parameters->EventHandler;
1251       AddrFile->ChainedReceiveExpeditedHandlerContext    = Parameters->EventContext;
1252       AddrFile->RegisteredChainedReceiveExpeditedHandler = TRUE;
1253     }
1254     break;
1255 
1256   default:
1257     TI_DbgPrint(MIN_TRACE, ("Unknown event type (0x%X).\n",
1258       Parameters->EventType));
1259 
1260     Status = STATUS_INVALID_PARAMETER;
1261   }
1262 
1263   UnlockObject(AddrFile, OldIrql);
1264 
1265   return Status;
1266 }
1267 
1268 
1269 NTSTATUS DispTdiSetInformation(
1270     PIRP Irp)
1271 /*
1272  * FUNCTION: TDI_SET_INFORMATION handler
1273  * ARGUMENTS:
1274  *     Irp = Pointer to an I/O request packet
1275  * RETURNS:
1276  *     Status of operation
1277  */
1278 {
1279     TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
1280 
1281 	return STATUS_NOT_IMPLEMENTED;
1282 }
1283 
1284 
1285 VOID DispTdiQueryInformationExComplete(
1286     PVOID Context,
1287     ULONG Status,
1288     UINT ByteCount)
1289 /*
1290  * FUNCTION: Completes a TDI QueryInformationEx request
1291  * ARGUMENTS:
1292  *     Context   = Pointer to the IRP for the request
1293  *     Status    = TDI status of the request
1294  *     ByteCount = Number of bytes returned in output buffer
1295  */
1296 {
1297     PTI_QUERY_CONTEXT QueryContext;
1298 
1299     QueryContext = (PTI_QUERY_CONTEXT)Context;
1300     if (NT_SUCCESS(Status)) {
1301         CopyBufferToBufferChain(
1302             QueryContext->InputMdl,
1303             FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX, Context),
1304             (PCHAR)&QueryContext->QueryInfo.Context,
1305             CONTEXT_SIZE);
1306     }
1307 
1308     MmUnlockPages(QueryContext->InputMdl);
1309     IoFreeMdl(QueryContext->InputMdl);
1310     if( QueryContext->OutputMdl ) {
1311 	MmUnlockPages(QueryContext->OutputMdl);
1312 	IoFreeMdl(QueryContext->OutputMdl);
1313     }
1314 
1315     QueryContext->Irp->IoStatus.Information = ByteCount;
1316     QueryContext->Irp->IoStatus.Status      = Status;
1317 
1318     ExFreePoolWithTag(QueryContext, QUERY_CONTEXT_TAG);
1319 }
1320 
1321 
1322 NTSTATUS DispTdiQueryInformationEx(
1323     PIRP Irp,
1324     PIO_STACK_LOCATION IrpSp)
1325 /*
1326  * FUNCTION: TDI QueryInformationEx handler
1327  * ARGUMENTS:
1328  *     Irp   = Pointer to I/O request packet
1329  *     IrpSp = Pointer to current stack location of Irp
1330  * RETURNS:
1331  *     Status of operation
1332  */
1333 {
1334     PTCP_REQUEST_QUERY_INFORMATION_EX InputBuffer;
1335     PTRANSPORT_CONTEXT TranContext;
1336     PTI_QUERY_CONTEXT QueryContext;
1337     PVOID OutputBuffer;
1338     TDI_REQUEST Request;
1339     UINT Size;
1340     UINT InputBufferLength;
1341     UINT OutputBufferLength;
1342     BOOLEAN InputMdlLocked  = FALSE;
1343     BOOLEAN OutputMdlLocked = FALSE;
1344     PMDL InputMdl           = NULL;
1345     PMDL OutputMdl          = NULL;
1346     NTSTATUS Status         = STATUS_SUCCESS;
1347 
1348     TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
1349 
1350     TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
1351 
1352     switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {
1353     case TDI_TRANSPORT_ADDRESS_FILE:
1354         Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;
1355         break;
1356 
1357     case TDI_CONNECTION_FILE:
1358         Request.Handle.ConnectionContext = TranContext->Handle.ConnectionContext;
1359         break;
1360 
1361     case TDI_CONTROL_CHANNEL_FILE:
1362         Request.Handle.ControlChannel = TranContext->Handle.ControlChannel;
1363         break;
1364 
1365     default:
1366         TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n"));
1367         return STATUS_INVALID_PARAMETER;
1368     }
1369 
1370     InputBufferLength  = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
1371     OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
1372 
1373     /* Validate parameters */
1374     if ((InputBufferLength == sizeof(TCP_REQUEST_QUERY_INFORMATION_EX)) &&
1375         (OutputBufferLength != 0)) {
1376 
1377         InputBuffer = (PTCP_REQUEST_QUERY_INFORMATION_EX)
1378             IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
1379         OutputBuffer = Irp->UserBuffer;
1380 
1381         QueryContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(TI_QUERY_CONTEXT), QUERY_CONTEXT_TAG);
1382         if (QueryContext) {
1383 	    _SEH2_TRY {
1384                 InputMdl = IoAllocateMdl(InputBuffer,
1385                     sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
1386                     FALSE, TRUE, NULL);
1387 
1388                 OutputMdl = IoAllocateMdl(OutputBuffer,
1389                     OutputBufferLength, FALSE, TRUE, NULL);
1390 
1391                 if (InputMdl && OutputMdl) {
1392 
1393                     MmProbeAndLockPages(InputMdl, Irp->RequestorMode,
1394                         IoModifyAccess);
1395 
1396                     InputMdlLocked = TRUE;
1397 
1398                     MmProbeAndLockPages(OutputMdl, Irp->RequestorMode,
1399                         IoWriteAccess);
1400 
1401                     OutputMdlLocked = TRUE;
1402 
1403                     RtlCopyMemory(&QueryContext->QueryInfo,
1404                         InputBuffer, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
1405                 } else
1406                     Status = STATUS_INSUFFICIENT_RESOURCES;
1407             } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
1408                 Status = _SEH2_GetExceptionCode();
1409             } _SEH2_END;
1410 
1411             if (NT_SUCCESS(Status)) {
1412                 Size = MmGetMdlByteCount(OutputMdl);
1413 
1414                 QueryContext->Irp       = Irp;
1415                 QueryContext->InputMdl  = InputMdl;
1416                 QueryContext->OutputMdl = OutputMdl;
1417 
1418                 Request.RequestNotifyObject = DispTdiQueryInformationExComplete;
1419                 Request.RequestContext      = QueryContext;
1420                 Status = InfoTdiQueryInformationEx(&Request,
1421                     &QueryContext->QueryInfo.ID, OutputMdl,
1422                     &Size, &QueryContext->QueryInfo.Context);
1423                 DispTdiQueryInformationExComplete(QueryContext, Status, Size);
1424 
1425                 TI_DbgPrint(MAX_TRACE, ("Leaving. Status = (0x%X)\n", Status));
1426 
1427                 return Status;
1428             }
1429 
1430             /* An error occurred if we get here */
1431 
1432             if (InputMdl) {
1433                 if (InputMdlLocked)
1434                     MmUnlockPages(InputMdl);
1435                 IoFreeMdl(InputMdl);
1436             }
1437 
1438             if (OutputMdl) {
1439                 if (OutputMdlLocked)
1440                     MmUnlockPages(OutputMdl);
1441                 IoFreeMdl(OutputMdl);
1442             }
1443 
1444             ExFreePoolWithTag(QueryContext, QUERY_CONTEXT_TAG);
1445         } else
1446             Status = STATUS_INSUFFICIENT_RESOURCES;
1447     } else if( InputBufferLength ==
1448 	       sizeof(TCP_REQUEST_QUERY_INFORMATION_EX) ) {
1449 	/* Handle the case where the user is probing the buffer for length */
1450 	TI_DbgPrint(MAX_TRACE, ("InputBufferLength %d OutputBufferLength %d\n",
1451 				InputBufferLength, OutputBufferLength));
1452         InputBuffer = (PTCP_REQUEST_QUERY_INFORMATION_EX)
1453             IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
1454 
1455 	Size = 0;
1456 
1457         QueryContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(TI_QUERY_CONTEXT), QUERY_CONTEXT_TAG);
1458         if (!QueryContext) return STATUS_INSUFFICIENT_RESOURCES;
1459 
1460 	_SEH2_TRY {
1461 	    InputMdl = IoAllocateMdl(InputBuffer,
1462 				     sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
1463 				     FALSE, TRUE, NULL);
1464 
1465 	    MmProbeAndLockPages(InputMdl, Irp->RequestorMode,
1466 				IoModifyAccess);
1467 
1468 	    InputMdlLocked = TRUE;
1469 	    Status = STATUS_SUCCESS;
1470 	} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
1471 	    TI_DbgPrint(MAX_TRACE, ("Failed to acquire client buffer\n"));
1472 	    Status = _SEH2_GetExceptionCode();
1473 	} _SEH2_END;
1474 
1475 	if( !NT_SUCCESS(Status) || !InputMdl ) {
1476 	    if( InputMdl ) IoFreeMdl( InputMdl );
1477 	    ExFreePoolWithTag(QueryContext, QUERY_CONTEXT_TAG);
1478 	    return Status;
1479 	}
1480 
1481 	RtlCopyMemory(&QueryContext->QueryInfo,
1482 		      InputBuffer, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
1483 
1484 	QueryContext->Irp       = Irp;
1485 	QueryContext->InputMdl  = InputMdl;
1486 	QueryContext->OutputMdl = NULL;
1487 
1488 	Request.RequestNotifyObject = DispTdiQueryInformationExComplete;
1489 	Request.RequestContext      = QueryContext;
1490 	Status = InfoTdiQueryInformationEx(&Request,
1491 					   &QueryContext->QueryInfo.ID,
1492 					   NULL,
1493 					   &Size,
1494 					   &QueryContext->QueryInfo.Context);
1495 	DispTdiQueryInformationExComplete(QueryContext, Status, Size);
1496 	TI_DbgPrint(MAX_TRACE, ("Leaving. Status = (0x%X)\n", Status));
1497     } else Status = STATUS_INVALID_PARAMETER;
1498 
1499     TI_DbgPrint(MIN_TRACE, ("Leaving. Status = (0x%X)\n", Status));
1500 
1501     return Status;
1502 }
1503 
1504 
1505 NTSTATUS DispTdiSetInformationEx(
1506     PIRP Irp,
1507     PIO_STACK_LOCATION IrpSp)
1508 /*
1509  * FUNCTION: TDI SetInformationEx handler
1510  * ARGUMENTS:
1511  *     Irp   = Pointer to I/O request packet
1512  *     IrpSp = Pointer to current stack location of Irp
1513  * RETURNS:
1514  *     Status of operation
1515  */
1516 {
1517     PTRANSPORT_CONTEXT TranContext;
1518     PTCP_REQUEST_SET_INFORMATION_EX Info;
1519     TDI_REQUEST Request;
1520     TDI_STATUS Status;
1521 
1522     TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
1523 
1524     TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
1525     Info        = (PTCP_REQUEST_SET_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer;
1526 
1527     switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {
1528     case TDI_TRANSPORT_ADDRESS_FILE:
1529         Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;
1530         break;
1531 
1532     case TDI_CONNECTION_FILE:
1533         Request.Handle.ConnectionContext = TranContext->Handle.ConnectionContext;
1534         break;
1535 
1536     case TDI_CONTROL_CHANNEL_FILE:
1537         Request.Handle.ControlChannel = TranContext->Handle.ControlChannel;
1538         break;
1539 
1540     default:
1541         Irp->IoStatus.Status      = STATUS_INVALID_PARAMETER;
1542         Irp->IoStatus.Information = 0;
1543 
1544         TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
1545 
1546         return Irp->IoStatus.Status;
1547     }
1548 
1549     Request.RequestNotifyObject = NULL;
1550     Request.RequestContext      = NULL;
1551 
1552     Status = InfoTdiSetInformationEx(&Request, &Info->ID,
1553             &Info->Buffer, Info->BufferSize);
1554 
1555     return Status;
1556 }
1557 
1558 /* TODO: Support multiple addresses per interface.
1559  * For now just set the nte context to the interface index.
1560  *
1561  * Later on, create an NTE context and NTE instance
1562  */
1563 
1564 NTSTATUS DispTdiSetIPAddress( PIRP Irp, PIO_STACK_LOCATION IrpSp ) {
1565     NTSTATUS Status = STATUS_DEVICE_DOES_NOT_EXIST;
1566     PIP_SET_ADDRESS IpAddrChange =
1567         (PIP_SET_ADDRESS)Irp->AssociatedIrp.SystemBuffer;
1568     IF_LIST_ITER(IF);
1569 
1570     TI_DbgPrint(MID_TRACE,("Setting IP Address for adapter %d\n",
1571 			   IpAddrChange->NteIndex));
1572 
1573     ForEachInterface(IF) {
1574 	TI_DbgPrint(MID_TRACE,("Looking at adapter %d\n", IF->Index));
1575 
1576         if( IF->Unicast.Address.IPv4Address == IpAddrChange->Address ) {
1577             Status = STATUS_DUPLICATE_OBJECTID;
1578             break;
1579         }
1580         if( IF->Index == IpAddrChange->NteIndex ) {
1581             IPRemoveInterfaceRoute( IF );
1582 
1583             IF->Unicast.Type = IP_ADDRESS_V4;
1584             IF->Unicast.Address.IPv4Address = IpAddrChange->Address;
1585 
1586             IF->Netmask.Type = IP_ADDRESS_V4;
1587             IF->Netmask.Address.IPv4Address = IpAddrChange->Netmask;
1588 
1589             IF->Broadcast.Type = IP_ADDRESS_V4;
1590 	    IF->Broadcast.Address.IPv4Address =
1591 		IF->Unicast.Address.IPv4Address |
1592 		~IF->Netmask.Address.IPv4Address;
1593 
1594             TI_DbgPrint(MID_TRACE,("New Unicast Address: %x\n",
1595                                    IF->Unicast.Address.IPv4Address));
1596             TI_DbgPrint(MID_TRACE,("New Netmask        : %x\n",
1597                                    IF->Netmask.Address.IPv4Address));
1598 
1599             IPAddInterfaceRoute( IF );
1600 
1601             IpAddrChange->Address = IF->Index;
1602             Status = STATUS_SUCCESS;
1603             Irp->IoStatus.Information = IF->Index;
1604             break;
1605         }
1606     } EndFor(IF);
1607 
1608     Irp->IoStatus.Status = Status;
1609     return Status;
1610 }
1611 
1612 NTSTATUS DispTdiDeleteIPAddress( PIRP Irp, PIO_STACK_LOCATION IrpSp ) {
1613     NTSTATUS Status = STATUS_UNSUCCESSFUL;
1614     PUSHORT NteIndex = Irp->AssociatedIrp.SystemBuffer;
1615     IF_LIST_ITER(IF);
1616 
1617     ForEachInterface(IF) {
1618         if( IF->Index == *NteIndex ) {
1619             IPRemoveInterfaceRoute( IF );
1620             IF->Unicast.Type = IP_ADDRESS_V4;
1621             IF->Unicast.Address.IPv4Address = 0;
1622 
1623             IF->Netmask.Type = IP_ADDRESS_V4;
1624             IF->Netmask.Address.IPv4Address = 0;
1625 
1626             IF->Broadcast.Type = IP_ADDRESS_V4;
1627             IF->Broadcast.Address.IPv4Address = 0;
1628 
1629             Status = STATUS_SUCCESS;
1630         }
1631     } EndFor(IF);
1632 
1633     Irp->IoStatus.Status = Status;
1634     return Status;
1635 }
1636 
1637 VOID NTAPI
1638 WaitForHwAddress ( PDEVICE_OBJECT DeviceObject, PVOID Context) {
1639     PQUERY_HW_WORK_ITEM WorkItem = (PQUERY_HW_WORK_ITEM)Context;
1640     LARGE_INTEGER Now;
1641     LARGE_INTEGER Wait;
1642     IP_ADDRESS Remote;
1643     PIRP Irp;
1644     PNEIGHBOR_CACHE_ENTRY NCE = NULL;
1645     NTSTATUS Status = STATUS_UNSUCCESSFUL;
1646 
1647     IoFreeWorkItem(WorkItem->WorkItem);
1648     Irp = WorkItem->Irp;
1649     AddrInitIPv4(&Remote, WorkItem->RemoteIP);
1650     KeQuerySystemTime(&Now);
1651     while (Now.QuadPart - WorkItem->StartTime.QuadPart < 10000 * 1000 && !Irp->Cancel) {
1652         NCE = NBLocateNeighbor(&Remote, WorkItem->Interface);
1653         if (NCE && !(NCE->State & NUD_INCOMPLETE)) {
1654             break;
1655         }
1656 
1657         NCE = NULL;
1658         Wait.QuadPart = -10000;
1659         KeDelayExecutionThread(KernelMode, FALSE, &Wait);
1660         KeQuerySystemTime(&Now);
1661     }
1662 
1663     if (NCE) {
1664         PVOID OutputBuffer;
1665 
1666         if (NCE->LinkAddressLength > WorkItem->IrpSp->Parameters.DeviceIoControl.OutputBufferLength) {
1667             Status = STATUS_INSUFFICIENT_RESOURCES;
1668         } else {
1669             OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
1670             RtlCopyMemory(OutputBuffer, NCE->LinkAddress, NCE->LinkAddressLength);
1671             Irp->IoStatus.Information = NCE->LinkAddressLength;
1672             Status = STATUS_SUCCESS;
1673         }
1674     }
1675 
1676     ExFreePoolWithTag(WorkItem, QUERY_CONTEXT_TAG);
1677     if (Irp->Flags & IRP_SYNCHRONOUS_API) {
1678         Irp->IoStatus.Status = Status;
1679     } else {
1680         IRPFinish(Irp, Status);
1681     }
1682 }
1683 
1684 NTSTATUS DispTdiQueryIpHwAddress( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp ) {
1685     NTSTATUS Status;
1686     PULONG IPs;
1687     IP_ADDRESS Remote, Local;
1688     PNEIGHBOR_CACHE_ENTRY NCE;
1689     PIP_INTERFACE Interface;
1690     PQUERY_HW_WORK_ITEM WorkItem;
1691 
1692     Irp->IoStatus.Information = 0;
1693 
1694     if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < 2 * sizeof(ULONG) ||
1695         IrpSp->Parameters.DeviceIoControl.OutputBufferLength == 0) {
1696         Status = STATUS_INVALID_BUFFER_SIZE;
1697         goto Exit;
1698     }
1699 
1700     IPs = (PULONG)Irp->AssociatedIrp.SystemBuffer;
1701     AddrInitIPv4(&Remote, IPs[0]);
1702     AddrInitIPv4(&Local, IPs[1]);
1703 
1704     if (AddrIsUnspecified(&Remote)) {
1705         Status = STATUS_UNSUCCESSFUL;
1706         goto Exit;
1707     }
1708 
1709     Interface = AddrLocateInterface(&Remote);
1710     if (Interface) {
1711         PVOID OutputBuffer;
1712 
1713         if (Interface->AddressLength > IrpSp->Parameters.DeviceIoControl.OutputBufferLength) {
1714             Status = STATUS_INSUFFICIENT_RESOURCES;
1715             goto Exit;
1716         }
1717 
1718         OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
1719         RtlCopyMemory(OutputBuffer, Interface->Address, Interface->AddressLength);
1720         Irp->IoStatus.Information = Interface->AddressLength;
1721         Status = STATUS_SUCCESS;
1722         goto Exit;
1723     }
1724 
1725     if (AddrIsUnspecified(&Local)) {
1726         NCE = RouteGetRouteToDestination(&Remote);
1727         if (NCE == NULL) {
1728             Status = STATUS_NETWORK_UNREACHABLE;
1729             goto Exit;
1730         }
1731 
1732         Interface = NCE->Interface;
1733     }
1734     else {
1735         Interface = AddrLocateInterface(&Local);
1736         if (Interface == NULL) {
1737             Interface = GetDefaultInterface();
1738             if (Interface == NULL) {
1739                 Status = STATUS_NETWORK_UNREACHABLE;
1740                 goto Exit;
1741             }
1742         }
1743     }
1744 
1745     WorkItem = ExAllocatePoolWithTag(PagedPool, sizeof(QUERY_HW_WORK_ITEM), QUERY_CONTEXT_TAG);
1746     if (WorkItem == NULL) {
1747         Status = STATUS_INSUFFICIENT_RESOURCES;
1748         goto Exit;
1749     }
1750 
1751     WorkItem->WorkItem = IoAllocateWorkItem(DeviceObject);
1752     if (WorkItem->WorkItem == NULL) {
1753         ExFreePoolWithTag(WorkItem, QUERY_CONTEXT_TAG);
1754         Status = STATUS_INSUFFICIENT_RESOURCES;
1755         goto Exit;
1756     }
1757 
1758     WorkItem->Irp = Irp;
1759     WorkItem->IrpSp = IrpSp;
1760     WorkItem->Interface = Interface;
1761     WorkItem->RemoteIP = IPs[0];
1762     KeQuerySystemTime(&WorkItem->StartTime);
1763 
1764     NCE = NBLocateNeighbor(&Remote, Interface);
1765     if (NCE != NULL) {
1766         if (NCE->LinkAddressLength > IrpSp->Parameters.DeviceIoControl.OutputBufferLength) {
1767             IoFreeWorkItem(WorkItem->WorkItem);
1768             ExFreePoolWithTag(WorkItem, QUERY_CONTEXT_TAG);
1769             Status = STATUS_INVALID_BUFFER_SIZE;
1770             goto Exit;
1771         }
1772 
1773         if (!(NCE->State & NUD_INCOMPLETE)) {
1774             PVOID LinkAddress = ExAllocatePoolWithTag(PagedPool, NCE->LinkAddressLength, QUERY_CONTEXT_TAG);
1775             if (LinkAddress == NULL) {
1776                 IoFreeWorkItem(WorkItem->WorkItem);
1777                 ExFreePoolWithTag(WorkItem, QUERY_CONTEXT_TAG);
1778                 Status = STATUS_INSUFFICIENT_RESOURCES;
1779                 goto Exit;
1780             }
1781             memset(LinkAddress, 0xff, NCE->LinkAddressLength);
1782             NBUpdateNeighbor(NCE, LinkAddress, NUD_INCOMPLETE);
1783             ExFreePoolWithTag(LinkAddress, QUERY_CONTEXT_TAG);
1784         }
1785     }
1786 
1787     if (!ARPTransmit(&Remote, NULL, Interface)) {
1788         IoFreeWorkItem(WorkItem->WorkItem);
1789         ExFreePoolWithTag(WorkItem, QUERY_CONTEXT_TAG);
1790         Status = STATUS_UNSUCCESSFUL;
1791         goto Exit;
1792     }
1793 
1794     if (Irp->Flags & IRP_SYNCHRONOUS_API) {
1795         WaitForHwAddress(DeviceObject, WorkItem);
1796         Status = Irp->IoStatus.Status;
1797     } else {
1798         IoMarkIrpPending(Irp);
1799         IoQueueWorkItem(WorkItem->WorkItem, WaitForHwAddress, DelayedWorkQueue, WorkItem);
1800         Status = STATUS_PENDING;
1801     }
1802 
1803 Exit:
1804     return Status;
1805 }
1806 
1807 /* EOF */
1808