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