+ IPs = (PULONG)Irp->AssociatedIrp.SystemBuffer;
+ AddrInitIPv4(&Remote, IPs[0]);
+ AddrInitIPv4(&Local, IPs[1]);
+
+ if (AddrIsUnspecified(&Local)) {
+ NCE = RouteGetRouteToDestination(&Remote);
+ if (NCE == NULL) {
+ Status = STATUS_NETWORK_UNREACHABLE;
+ goto Exit;
+ }
+
+ Interface = NCE->Interface;
+ }
+ else {
+ Interface = FindOnLinkInterface(&Local);
+ if (Interface == NULL) {
+ Status = STATUS_NETWORK_UNREACHABLE;
+ goto Exit;
+ }
+ }
+
+ WorkItem = ExAllocatePoolWithTag(PagedPool, sizeof(QUERY_HW_WORK_ITEM), QUERY_CONTEXT_TAG);
+ if (WorkItem == NULL) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Exit;
+ }
+
+ WorkItem->WorkItem = IoAllocateWorkItem(DeviceObject);
+ if (WorkItem->WorkItem == NULL) {
+ ExFreePoolWithTag(WorkItem, QUERY_CONTEXT_TAG);
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Exit;
+ }
+
+ WorkItem->Irp = Irp;
+ WorkItem->IrpSp = IrpSp;
+ WorkItem->Interface = Interface;
+ WorkItem->RemoteIP = IPs[0];
+ KeQuerySystemTime(&WorkItem->StartTime);
+
+ NCE = NBLocateNeighbor(&Remote, Interface);
+ if (NCE != NULL) {
+ if (NCE->LinkAddressLength > IrpSp->Parameters.DeviceIoControl.OutputBufferLength) {
+ IoFreeWorkItem(WorkItem->WorkItem);
+ ExFreePoolWithTag(WorkItem, QUERY_CONTEXT_TAG);
+ Status = STATUS_INVALID_BUFFER_SIZE;
+ goto Exit;
+ }
+
+ if (!(NCE->State & NUD_INCOMPLETE)) {
+ PVOID LinkAddress = ExAllocatePoolWithTag(PagedPool, NCE->LinkAddressLength, QUERY_CONTEXT_TAG);
+ if (LinkAddress == NULL) {
+ IoFreeWorkItem(WorkItem->WorkItem);
+ ExFreePoolWithTag(WorkItem, QUERY_CONTEXT_TAG);
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto Exit;
+ }
+ memset(LinkAddress, 0xff, NCE->LinkAddressLength);
+ NBUpdateNeighbor(NCE, LinkAddress, NUD_INCOMPLETE);
+ ExFreePoolWithTag(LinkAddress, QUERY_CONTEXT_TAG);
+ }
+ }
+
+ if (!ARPTransmit(&Remote, NULL, Interface)) {
+ IoFreeWorkItem(WorkItem->WorkItem);
+ ExFreePoolWithTag(WorkItem, QUERY_CONTEXT_TAG);
+ Status = STATUS_UNSUCCESSFUL;
+ goto Exit;
+ }
+
+ if (Irp->Flags & IRP_SYNCHRONOUS_API) {
+ WaitForHwAddress(DeviceObject, WorkItem);
+ Status = Irp->IoStatus.Status;
+ } else {
+ IoMarkIrpPending(Irp);
+ IoQueueWorkItem(WorkItem->WorkItem, WaitForHwAddress, DelayedWorkQueue, WorkItem);
+ Status = STATUS_PENDING;
+ }
+