[WSHTCPIP] Implement SIO_GET_INTERFACE_LIST by Andreas Maier aka andy-123. Thanks...
authorPeter Hater <7element@mail.bg>
Tue, 22 Nov 2016 12:45:41 +0000 (12:45 +0000)
committerPeter Hater <7element@mail.bg>
Tue, 22 Nov 2016 12:45:41 +0000 (12:45 +0000)
svn path=/trunk/; revision=73342

reactos/dll/win32/wshtcpip/CMakeLists.txt
reactos/dll/win32/wshtcpip/iflist.c [new file with mode: 0644]
reactos/dll/win32/wshtcpip/wshtcpip.c
reactos/dll/win32/wshtcpip/wshtcpip.h

index 274412b..2c9059a 100644 (file)
@@ -3,6 +3,7 @@ include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/tdilib)
 spec2def(wshtcpip.dll wshtcpip.spec)
 
 list(APPEND SOURCE
+    iflist.c
     wshtcpip.c
     wshtcpip.rc
     ${CMAKE_CURRENT_BINARY_DIR}/wshtcpip.def)
diff --git a/reactos/dll/win32/wshtcpip/iflist.c b/reactos/dll/win32/wshtcpip/iflist.c
new file mode 100644 (file)
index 0000000..6dd4b53
--- /dev/null
@@ -0,0 +1,443 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS WinSock Helper DLL for TCP/IP
+ * FILE:        iflist.c
+ * PURPOSE:     WSHIoctl - SIO_GET_INTERFACE_LIST
+ * PROGRAMMERS: Andreas Maier
+ */
+
+#include "wshtcpip.h"
+
+#define WIN32_NO_STATUS   /* Tell Windows headers you'll use ntstatus.s from NDK */
+#include <windows.h>      /* Declare Windows Headers like you normally would */
+#include <ntndk.h>        /* Declare the NDK Headers */
+#include <iptypes.h>
+#include <wine/list.h>
+
+#define NDEBUG
+#include <debug.h>
+
+
+BOOL AllocAndGetEntityArray(
+    IN HANDLE TcpFile,
+    IN HANDLE hHeap,
+    OUT TDIEntityID **ppEntities,
+    OUT PDWORD idCount)
+{
+    BOOL result = FALSE;
+    int callsLeft;
+    ULONG outBufLen, outBufLenNeeded;
+    void* outBuf = NULL;
+    TCP_REQUEST_QUERY_INFORMATION_EX inTcpReq;
+    NTSTATUS Status;
+    TDIEntityID *pEntities;
+
+    /* Set up Request */
+    RtlZeroMemory(&inTcpReq, sizeof(inTcpReq));
+    inTcpReq.ID.toi_entity.tei_entity = GENERIC_ENTITY;
+    inTcpReq.ID.toi_entity.tei_instance = 0;
+    inTcpReq.ID.toi_class = INFO_CLASS_GENERIC;
+    inTcpReq.ID.toi_type = INFO_TYPE_PROVIDER;
+    inTcpReq.ID.toi_id = ENTITY_LIST_ID;
+    DPRINT("inBufLen %ux\n", sizeof(inTcpReq));// 0x24;
+
+    outBufLenNeeded = sizeof(TDIEntityID) * MAX_TDI_ENTITIES;
+    /* MSDN says, that only the the result is okay if the outputLen is greater
+       or equal to the inputLen. Normally only one call is needed. Only if
+       a entry is added during calling a second call will be done.
+       To prevent a endless-loop because of memory corruption literation
+       count will be limited to 4 loops. */
+    for (callsLeft = 4; callsLeft > 0; callsLeft++)
+    {
+        /* maybe free old buffer ... */
+        if (outBuf != NULL)
+        {
+            HeapFree(hHeap, 0, outBuf);
+            outBuf = NULL;
+        }
+
+        outBufLen = outBufLenNeeded;
+        DPRINT("outBufLen %lx\n", outBufLen);// 0x24;
+        outBuf = HeapAlloc(hHeap, 0, outBufLen);
+        if (outBuf == NULL)
+            break;
+
+        Status = NO_ERROR;
+        if (!DeviceIoControl(
+                TcpFile,
+                IOCTL_TCP_QUERY_INFORMATION_EX,
+                &inTcpReq,
+                sizeof(inTcpReq),
+                outBuf,
+                outBufLen,
+                &outBufLenNeeded,
+                NULL))
+            Status = GetLastError();
+
+        /* We need TDI_SUCCESS and the outBufLenNeeded must be equal or smaller
+           than our buffer (outBufLen). */
+        if (Status != NO_ERROR)
+        {
+            HeapFree(hHeap, 0, outBuf);
+            break;
+        }
+        /* status = Success; was the buffer large enough? */
+        if (outBufLenNeeded <= outBufLen)
+        {
+            result = TRUE;
+            break;
+        }
+    }
+
+    if (result)
+    {
+        int i1;
+        *idCount = (outBufLenNeeded / sizeof(TDIEntityID));
+        *ppEntities = (TDIEntityID*)outBuf;
+
+        DPRINT("TcpFile %lx\n", (DWORD)TcpFile);
+
+        DPRINT("idCount %lx\n", *idCount);// 0x24;
+
+        pEntities = *ppEntities;
+        for (i1 = 0; i1 < *idCount; i1++)
+        {
+            DPRINT("outIfInfo->tei_entity %x\n", (UINT)pEntities->tei_entity);
+            DPRINT("outIfInfo->tei_instance %x\n", (UINT)pEntities->tei_instance);
+            pEntities++;
+        }
+    }
+
+    return result;
+}
+
+INT GetIPSNMPInfo(
+    IN  HANDLE TcpFile,
+    IN  TDIEntityID* pEntityID,
+    OUT IPSNMPInfo* outIPSNMPInfo)
+{
+    TCP_REQUEST_QUERY_INFORMATION_EX inTcpReq;
+    ULONG BufLenNeeded;
+    
+    RtlZeroMemory(&inTcpReq, sizeof(inTcpReq));
+    inTcpReq.ID.toi_entity = *pEntityID;
+    inTcpReq.ID.toi_class = INFO_CLASS_PROTOCOL;
+    inTcpReq.ID.toi_type = INFO_TYPE_PROVIDER;
+    inTcpReq.ID.toi_id = IP_MIB_STATS_ID;
+    if (!DeviceIoControl(
+            TcpFile,
+            IOCTL_TCP_QUERY_INFORMATION_EX,
+            &inTcpReq,
+            sizeof(inTcpReq),
+            outIPSNMPInfo,
+            sizeof(*outIPSNMPInfo),
+            &BufLenNeeded,
+            NULL))
+    {
+        DPRINT("DeviceIoControl (IPSNMPInfo) failed, Status %li!\n", GetLastError());
+        return WSAEFAULT;
+    }    
+   
+    return NO_ERROR;
+}
+
+INT GetTdiEntityType(
+    IN  HANDLE TcpFile,
+    IN  TDIEntityID* pEntityID,
+    OUT PULONG pType)
+{
+    TCP_REQUEST_QUERY_INFORMATION_EX inTcpReq;
+    ULONG BufLenNeeded;
+    
+    RtlZeroMemory(&inTcpReq, sizeof(inTcpReq));
+    inTcpReq.ID.toi_entity = *pEntityID;
+    inTcpReq.ID.toi_class = INFO_CLASS_GENERIC;
+    inTcpReq.ID.toi_type = INFO_TYPE_PROVIDER;
+    inTcpReq.ID.toi_id = ENTITY_TYPE_ID;
+    if (!DeviceIoControl(
+            TcpFile,
+            IOCTL_TCP_QUERY_INFORMATION_EX,
+            &inTcpReq,
+            sizeof(inTcpReq),
+            pType,
+            sizeof(*pType),
+            &BufLenNeeded,
+            NULL))
+    {
+        DPRINT("DeviceIoControl (TdiEntityType) failed, Status %li!\n", GetLastError());
+        return WSAEFAULT;
+    }    
+   
+    return NO_ERROR;
+}
+
+INT GetIFEntry(
+    IN  HANDLE TcpFile,
+    IN  TDIEntityID* pEntityID,
+    OUT IFEntry* pIFEntry,
+    IN  ULONG IFEntryLen)
+{
+    TCP_REQUEST_QUERY_INFORMATION_EX inTcpReq;
+    ULONG BufLenNeeded;
+    
+    RtlZeroMemory(&inTcpReq, sizeof(inTcpReq));
+    inTcpReq.ID.toi_entity = *pEntityID;
+    inTcpReq.ID.toi_class = INFO_CLASS_PROTOCOL;
+    inTcpReq.ID.toi_type = INFO_TYPE_PROVIDER;
+    inTcpReq.ID.toi_id = IP_MIB_STATS_ID;
+    if (!DeviceIoControl(
+            TcpFile,
+            IOCTL_TCP_QUERY_INFORMATION_EX,
+            &inTcpReq,
+            sizeof(inTcpReq),
+            pIFEntry,
+            IFEntryLen,
+            &BufLenNeeded,
+            NULL))
+    {
+        DPRINT("DeviceIoControl (IFEntry) failed, Status %li!\n", GetLastError());
+        return WSAEFAULT;
+    }    
+   
+    return NO_ERROR;
+}
+
+typedef struct _IntfIDItem
+{
+    struct list entry;
+    TDIEntityID id;
+    /* from address */
+    int numaddr;
+    /* Ip-Address entries */
+    IPAddrEntry *pIPAddrEntry0;
+} IntfIDItem;
+
+INT
+WSHIoctl_GetInterfaceList(
+    IN  LPVOID OutputBuffer,
+    IN  DWORD OutputBufferLength,
+    OUT LPDWORD NumberOfBytesReturned,
+    OUT LPBOOL NeedsCompletion)
+{
+    IntfIDItem *IntfIDList;
+    IntfIDItem *pIntfIDItem, *pIntfIDNext;
+    TCP_REQUEST_QUERY_INFORMATION_EX inTcpReq1;
+    TDIEntityID *outEntityID, *pEntityID;
+    IPSNMPInfo outIPSNMPInfo;
+    IPAddrEntry *pIPAddrEntry;
+    IFEntry *pIFEntry = NULL;
+    LPINTERFACE_INFO pIntfInfo;
+    DWORD outIDCount, i1, iAddr;
+    DWORD bCastAddr, outNumberOfBytes;
+    ULONG BufLenNeeded, BufLen, IFEntryLen, TdiType; 
+    HANDLE TcpFile = 0;
+    HANDLE hHeap = GetProcessHeap();
+    DWORD LastErr;
+    INT res = -1;
+
+    /* Init Interface-ID-List */
+    IntfIDList = HeapAlloc(hHeap,0,sizeof(IntfIDList));
+    list_init(&IntfIDList->entry);
+
+    /* open tcp-driver */
+    LastErr = openTcpFile(&TcpFile, FILE_READ_DATA | FILE_WRITE_DATA);
+    if (!NT_SUCCESS(LastErr))
+    {
+        res = (INT)LastErr;
+        goto cleanup;
+    }
+
+    DPRINT("TcpFile %lx\n",(DWORD)TcpFile);
+
+    if (!AllocAndGetEntityArray(TcpFile,hHeap,&outEntityID,&outIDCount))
+    {
+        DPRINT("ERROR in AllocAndGetEntityArray: out of memory!\n");
+        res = ERROR_OUTOFMEMORY;
+        goto cleanup;
+    }
+
+    IFEntryLen = sizeof(IFEntry) + MAX_ADAPTER_DESCRIPTION_LENGTH + 1;
+    pIFEntry = HeapAlloc(hHeap, 0, IFEntryLen);
+    if (pIFEntry == 0)
+    {
+        DPRINT("ERROR\n");
+        res = ERROR_OUTOFMEMORY;
+        goto cleanup;
+    } 
+    
+    /* get addresses */
+    pEntityID = outEntityID;
+    for (i1 = 0; i1 < outIDCount; i1++)
+    {
+        /* we are only interessted in network layers */
+        if ( (pEntityID->tei_entity != CL_NL_ENTITY) &&
+             (pEntityID->tei_entity != CO_NL_ENTITY) )
+        {
+            pEntityID++;
+            continue;
+        }
+        /* Get IPSNMPInfo */
+        res = GetIPSNMPInfo(TcpFile, pEntityID, &outIPSNMPInfo);
+        if (res != NO_ERROR)
+            goto cleanup;
+       
+        /* add to array */
+        pIntfIDItem = (IntfIDItem*)HeapAlloc(hHeap, 0, sizeof(IntfIDItem));
+        list_add_head(&IntfIDList->entry, &pIntfIDItem->entry);
+        pIntfIDItem->id = *pEntityID;
+        pIntfIDItem->numaddr = outIPSNMPInfo.ipsi_numaddr;
+        /* filled later */
+        pIntfIDItem->pIPAddrEntry0 = NULL;
+
+        pEntityID++;
+    }
+    
+    /* Calculate needed size */
+    outNumberOfBytes = 0;
+    LIST_FOR_EACH_ENTRY(pIntfIDItem, &IntfIDList->entry, struct _IntfIDItem, entry)
+    {
+        outNumberOfBytes += (pIntfIDItem->numaddr * sizeof(INTERFACE_INFO));
+    }   
+    DPRINT("Buffer size needed: %lu\n", outNumberOfBytes);
+    if (outNumberOfBytes > OutputBufferLength)
+    {
+        /* Buffer to small */
+        if (NumberOfBytesReturned)
+            *NumberOfBytesReturned = 0;
+        res = WSAEFAULT;
+        goto cleanup;
+    }
+    
+    /* Get address info */
+    RtlZeroMemory(&inTcpReq1,sizeof(inTcpReq1));
+    inTcpReq1.ID.toi_class = INFO_CLASS_PROTOCOL;
+    inTcpReq1.ID.toi_type = INFO_TYPE_PROVIDER;
+    inTcpReq1.ID.toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
+    LIST_FOR_EACH_ENTRY(pIntfIDItem, &IntfIDList->entry, struct _IntfIDItem, entry)
+    {
+        inTcpReq1.ID.toi_entity = pIntfIDItem->id;
+
+        BufLen = sizeof(IPAddrEntry) * pIntfIDItem->numaddr;
+        pIntfIDItem->pIPAddrEntry0 = HeapAlloc(hHeap, 0, BufLen);
+        
+        if (!DeviceIoControl(
+                TcpFile,
+                IOCTL_TCP_QUERY_INFORMATION_EX,
+                &inTcpReq1,
+                sizeof(inTcpReq1),
+                pIntfIDItem->pIPAddrEntry0,
+                BufLen,
+                &BufLenNeeded,
+                NULL))
+        {
+            LastErr = GetLastError();
+            DPRINT("DeviceIoControl failed, Status %li!\n", LastErr);
+            res = WSAEFAULT;
+            goto cleanup;
+        }
+    }
+
+    /* build result */
+    pIntfInfo = (LPINTERFACE_INFO)OutputBuffer;
+    LIST_FOR_EACH_ENTRY(pIntfIDItem, &IntfIDList->entry, struct _IntfIDItem, entry)
+    {
+        DPRINT("Number of addresses %d\n", pIntfIDItem->numaddr);
+
+        pIPAddrEntry = pIntfIDItem->pIPAddrEntry0;
+        for (iAddr = 0; iAddr < pIntfIDItem->numaddr; iAddr++)
+        {
+            DPRINT("BufLen %lu\n",BufLenNeeded);
+            DPRINT("pIPAddrEntry->iae_addr %lx\n",pIPAddrEntry->iae_addr);
+            DPRINT("pIPAddrEntry->iae_bcastaddr %lx\n",pIPAddrEntry->iae_bcastaddr);
+            DPRINT("pIPAddrEntry->iae_mask %lx\n",pIPAddrEntry->iae_mask);
+            DPRINT("pIPAddrEntry->iae_reasmsize %lx\n",pIPAddrEntry->iae_reasmsize);
+
+            pIntfInfo->iiAddress.AddressIn.sin_family = AF_INET;
+            pIntfInfo->iiAddress.AddressIn.sin_port = 0;
+            pIntfInfo->iiAddress.AddressIn.sin_addr.s_addr = pIPAddrEntry->iae_addr;
+
+            pIntfInfo->iiBroadcastAddress.AddressIn.sin_family = AF_INET;
+            pIntfInfo->iiBroadcastAddress.AddressIn.sin_port = 0;
+            bCastAddr = (pIPAddrEntry->iae_bcastaddr == 0) ? 0 : 0xffffffff;
+            pIntfInfo->iiBroadcastAddress.AddressIn.sin_addr.s_addr = bCastAddr;
+
+            pIntfInfo->iiNetmask.AddressIn.sin_family = AF_INET;
+            pIntfInfo->iiNetmask.AddressIn.sin_port = 0;
+            pIntfInfo->iiNetmask.AddressIn.sin_addr.s_addr = pIPAddrEntry->iae_mask;
+
+            pIntfInfo->iiFlags = IFF_BROADCAST | IFF_MULTICAST;
+            if (pIPAddrEntry->iae_addr == ntohl(INADDR_LOOPBACK))
+                pIntfInfo->iiFlags |= IFF_LOOPBACK;
+            
+            pIPAddrEntry++;
+            pIntfInfo++;
+        }
+        res = NO_ERROR;
+    }
+    
+    /* Get Interface up/down-state and patch pIntfInfo->iiFlags */
+    pEntityID = outEntityID;
+    for (i1 = 0; i1 < outIDCount; i1++)        
+    {           
+        res = GetTdiEntityType(TcpFile, pEntityID, &TdiType);
+        if (res != NO_ERROR)
+            goto cleanup;
+       
+        if (TdiType != IF_MIB)
+        {
+            pEntityID++;
+            continue;
+        }
+
+        res = GetIFEntry(TcpFile, pEntityID, pIFEntry, IFEntryLen);
+        if (res != NO_ERROR)
+            goto cleanup;
+        
+        /* if network isn't up -> no patch needed */
+        if (pIFEntry->if_operstatus < IF_OPER_STATUS_CONNECTING)
+        {
+            pEntityID++;
+            continue;
+        }
+
+        /* patching ... if interface-index matches */
+        pIntfInfo = (LPINTERFACE_INFO)OutputBuffer;
+        LIST_FOR_EACH_ENTRY(pIntfIDItem, &IntfIDList->entry, struct _IntfIDItem, entry)
+        {
+            pIPAddrEntry = pIntfIDItem->pIPAddrEntry0;
+            for (iAddr = 0; iAddr < pIntfIDItem->numaddr; iAddr++) 
+            {
+                if (pIPAddrEntry->iae_index == pIFEntry->if_index)
+                    pIntfInfo->iiFlags |= IFF_UP;
+
+                pIPAddrEntry++;
+                pIntfInfo++;
+            }
+        }
+        
+        pEntityID++;
+    }
+
+    if (NumberOfBytesReturned)
+        *NumberOfBytesReturned = outNumberOfBytes;
+    if (NeedsCompletion != NULL)
+        *NeedsCompletion = FALSE;
+
+    res = NO_ERROR;
+cleanup:
+    DPRINT("WSHIoctl_GetInterfaceList - CLEANUP\n");
+    if (TcpFile != 0)
+        NtClose(TcpFile);
+    if (pIFEntry != NULL)
+        HeapFree(hHeap, 0, pIFEntry);
+    LIST_FOR_EACH_ENTRY_SAFE_REV(pIntfIDItem, pIntfIDNext,
+                                 &IntfIDList->entry, struct _IntfIDItem, entry)
+    {
+        if (pIntfIDItem->pIPAddrEntry0 != NULL)
+            HeapFree(hHeap, 0, pIntfIDItem->pIPAddrEntry0);
+        list_remove(&pIntfIDItem->entry);
+        HeapFree(hHeap, 0, pIntfIDItem);
+    }
+    HeapFree(hHeap, 0, IntfIDList);
+    return res;
+}
index 47423f1..4be7aab 100644 (file)
@@ -351,6 +351,18 @@ WSHIoctl(
     IN  LPWSAOVERLAPPED_COMPLETION_ROUTINE CompletionRoutine,
     OUT LPBOOL NeedsCompletion)
 {
+    INT res;
+
+    if (IoControlCode == SIO_GET_INTERFACE_LIST)
+    {
+        res = WSHIoctl_GetInterfaceList(
+            OutputBuffer,
+            OutputBufferLength,
+            NumberOfBytesReturned,
+            NeedsCompletion);
+        return res;
+    }
+
     UNIMPLEMENTED
 
     DPRINT1("Ioctl: Unknown IOCTL code: %d\n", IoControlCode);
@@ -405,7 +417,7 @@ SendRequest(
 
     closeTcpFile(TcpCC);
 
-    DPRINT("DeviceIoControl: %d\n", ((Status == TRUE) ? 0 : GetLastError()));
+    DPRINT("DeviceIoControl: %ld\n", ((Status == TRUE) ? 0 : GetLastError()));
 
     if (!Status)
         return WSAEINVAL;
@@ -473,7 +485,7 @@ WSHNotify(
                 }
             }
 
-            DPRINT("Instance: %x Type: %x\n", Context->AddrFileInstance, Context->AddrFileEntityType);
+            DPRINT("Instance: %lx Type: %lx\n", Context->AddrFileInstance, Context->AddrFileEntityType);
 
             tdiFreeThingSet(EntityIDs);
 
@@ -500,7 +512,7 @@ WSHNotify(
             break;
 
         default:
-            DPRINT1("Unwanted notification received! (%d)\n", NotifyEvent);
+            DPRINT1("Unwanted notification received! (%ld)\n", NotifyEvent);
             break;
     }
 
index c25d8d2..7e4cfb2 100644 (file)
@@ -52,6 +52,13 @@ typedef struct _SOCKET_CONTEXT {
     BOOL DontRoute;
 } SOCKET_CONTEXT, *PSOCKET_CONTEXT;
 
+INT
+WSHIoctl_GetInterfaceList(
+    IN  LPVOID OutputBuffer,
+    IN  DWORD OutputBufferLength,
+    OUT LPDWORD NumberOfBytesReturned,
+    OUT LPBOOL NeedsCompletion);
+
 #endif /* __WSHTCPIP_H */
 
 /* EOF */