Author: pschweitzer
Date: Sat Dec 5 10:41:56 2015
New Revision: 70269
URL:
http://svn.reactos.org/svn/reactos?rev=70269&view=rev
Log:
[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.
Modified:
trunk/reactos/drivers/network/tcpip/include/dispatch.h
trunk/reactos/drivers/network/tcpip/tcpip/dispatch.c
trunk/reactos/drivers/network/tcpip/tcpip/main.c
Modified: trunk/reactos/drivers/network/tcpip/include/dispatch.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/network/tcpip/incl…
==============================================================================
--- trunk/reactos/drivers/network/tcpip/include/dispatch.h [iso-8859-1] (original)
+++ trunk/reactos/drivers/network/tcpip/include/dispatch.h [iso-8859-1] Sat Dec 5
10:41:56 2015
@@ -70,6 +70,7 @@
PIO_STACK_LOCATION IrpSp);
NTSTATUS DispTdiQueryIpHwAddress(
+ PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PIO_STACK_LOCATION IrpSp);
Modified: trunk/reactos/drivers/network/tcpip/tcpip/dispatch.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/network/tcpip/tcpi…
==============================================================================
--- trunk/reactos/drivers/network/tcpip/tcpip/dispatch.c [iso-8859-1] (original)
+++ trunk/reactos/drivers/network/tcpip/tcpip/dispatch.c [iso-8859-1] Sat Dec 5 10:41:56
2015
@@ -14,19 +14,25 @@
#include <datagram.h>
#include <pseh/pseh2.h>
+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 @@
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;
-
- Status = STATUS_NOT_IMPLEMENTED;
+ PULONG IPs;
+ IP_ADDRESS Remote, Local;
+ PNEIGHBOR_CACHE_ENTRY NCE;
+ PIP_INTERFACE Interface;
+ PQUERY_HW_WORK_ITEM WorkItem;
+
+ Irp->IoStatus.Information = 0;
+
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;
}
Modified: trunk/reactos/drivers/network/tcpip/tcpip/main.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/network/tcpip/tcpi…
==============================================================================
--- trunk/reactos/drivers/network/tcpip/tcpip/main.c [iso-8859-1] (original)
+++ trunk/reactos/drivers/network/tcpip/tcpip/main.c [iso-8859-1] Sat Dec 5 10:41:56
2015
@@ -527,7 +527,7 @@
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: