From: Pierre Schweitzer Date: Sat, 5 Dec 2015 10:41:56 +0000 (+0000) Subject: [TCPIP] X-Git-Tag: ReactOS-0.4.0~59^2~52 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=626e9cdf00f9bd92b1a25b0138914d5321a9abdc [TCPIP] - Fix a bug IRPFinish(): do not touch the IRP if there's a pending return. Thanks to Thomas for his help! - Implement DispTdiQueryIpHwAddress(): the current implementation is not optimal, but works. It first reset the ARP table entry corresponding the to target host, if it exists. Then, it sends the ARP probe and wait till the ARP table is updated to return the HW link address. Could be improved, but it would require more important work in the driver, which is not a good solution when we're to release ;-). Obviously, this fixes arping not working in ReactOS: https://twitter.com/HeisSpiter/status/673088515647930368 And this fixes a few iphlpapi_apitest tests. svn path=/trunk/; revision=70269 --- diff --git a/reactos/drivers/network/tcpip/include/dispatch.h b/reactos/drivers/network/tcpip/include/dispatch.h index b1fc7e0b644..54ddc6f4bea 100644 --- a/reactos/drivers/network/tcpip/include/dispatch.h +++ b/reactos/drivers/network/tcpip/include/dispatch.h @@ -70,6 +70,7 @@ NTSTATUS DispTdiDeleteIPAddress( PIO_STACK_LOCATION IrpSp); NTSTATUS DispTdiQueryIpHwAddress( + PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp); diff --git a/reactos/drivers/network/tcpip/tcpip/dispatch.c b/reactos/drivers/network/tcpip/tcpip/dispatch.c index e8e65b8d30a..b57fbfada69 100644 --- a/reactos/drivers/network/tcpip/tcpip/dispatch.c +++ b/reactos/drivers/network/tcpip/tcpip/dispatch.c @@ -14,19 +14,25 @@ #include #include +typedef struct _QUERY_HW_WORK_ITEM { + PIO_WORKITEM WorkItem; + PIRP Irp; + PIO_STACK_LOCATION IrpSp; + PIP_INTERFACE Interface; + LARGE_INTEGER StartTime; + ULONG RemoteIP; +} QUERY_HW_WORK_ITEM, *PQUERY_HW_WORK_ITEM; + NTSTATUS IRPFinish( PIRP Irp, NTSTATUS Status ) { KIRQL OldIrql; - Irp->IoStatus.Status = Status; - - if( Status == STATUS_PENDING ) - IoMarkIrpPending( Irp ); - else { + if (Status != STATUS_PENDING) { + Irp->IoStatus.Status = Status; IoAcquireCancelSpinLock(&OldIrql); - (void)IoSetCancelRoutine( Irp, NULL ); + (void)IoSetCancelRoutine( Irp, NULL ); IoReleaseCancelSpinLock(OldIrql); - IoCompleteRequest( Irp, IO_NETWORK_INCREMENT ); + IoCompleteRequest( Irp, IO_NETWORK_INCREMENT ); } return Status; @@ -1609,17 +1615,148 @@ NTSTATUS DispTdiDeleteIPAddress( PIRP Irp, PIO_STACK_LOCATION IrpSp ) { return Status; } -NTSTATUS DispTdiQueryIpHwAddress( PIRP Irp, PIO_STACK_LOCATION IrpSp ) { +VOID NTAPI +WaitForHwAddress ( PDEVICE_OBJECT DeviceObject, PVOID Context) { + PQUERY_HW_WORK_ITEM WorkItem = (PQUERY_HW_WORK_ITEM)Context; + LARGE_INTEGER Now; + LARGE_INTEGER Wait; + IP_ADDRESS Remote; + PIRP Irp; + PNEIGHBOR_CACHE_ENTRY NCE = NULL; + NTSTATUS Status = STATUS_UNSUCCESSFUL; + + IoFreeWorkItem(WorkItem->WorkItem); + Irp = WorkItem->Irp; + AddrInitIPv4(&Remote, WorkItem->RemoteIP); + KeQuerySystemTime(&Now); + while (Now.QuadPart - WorkItem->StartTime.QuadPart < 10000 * 1000 && !Irp->Cancel) { + NCE = NBLocateNeighbor(&Remote, WorkItem->Interface); + if (NCE && !(NCE->State & NUD_INCOMPLETE)) { + break; + } + + NCE = NULL; + Wait.QuadPart = -10000; + KeDelayExecutionThread(KernelMode, FALSE, &Wait); + KeQuerySystemTime(&Now); + } + + if (NCE) { + PVOID OutputBuffer; + + if (NCE->LinkAddressLength > WorkItem->IrpSp->Parameters.DeviceIoControl.OutputBufferLength) { + Status = STATUS_INVALID_BUFFER_SIZE; + } else { + OutputBuffer = Irp->AssociatedIrp.SystemBuffer; + RtlCopyMemory(OutputBuffer, NCE->LinkAddress, NCE->LinkAddressLength); + Irp->IoStatus.Information = NCE->LinkAddressLength; + Status = STATUS_SUCCESS; + } + } + + ExFreePoolWithTag(WorkItem, QUERY_CONTEXT_TAG); + if (Irp->Flags & IRP_SYNCHRONOUS_API) { + Irp->IoStatus.Status = Status; + } else { + IRPFinish(Irp, Status); + } +} + +NTSTATUS DispTdiQueryIpHwAddress( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp ) { NTSTATUS Status; + PULONG IPs; + IP_ADDRESS Remote, Local; + PNEIGHBOR_CACHE_ENTRY NCE; + PIP_INTERFACE Interface; + PQUERY_HW_WORK_ITEM WorkItem; + + Irp->IoStatus.Information = 0; - Status = STATUS_NOT_IMPLEMENTED; if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < 2 * sizeof(ULONG)) { Status = STATUS_INVALID_BUFFER_SIZE; goto Exit; } + 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; + } + Exit: - Irp->IoStatus.Status = Status; return Status; } diff --git a/reactos/drivers/network/tcpip/tcpip/main.c b/reactos/drivers/network/tcpip/tcpip/main.c index 315d5857377..57754d67574 100644 --- a/reactos/drivers/network/tcpip/tcpip/main.c +++ b/reactos/drivers/network/tcpip/tcpip/main.c @@ -527,7 +527,7 @@ TiDispatch( case IOCTL_QUERY_IP_HW_ADDRESS: TI_DbgPrint(MIN_TRACE, ("QUERY_IP_HW_ADDRESS\n")); - Status = DispTdiQueryIpHwAddress(Irp, IrpSp); + Status = DispTdiQueryIpHwAddress(DeviceObject, Irp, IrpSp); break; default: