From: Peter Hater <7element@mail.bg> Date: Tue, 22 Nov 2016 12:45:41 +0000 (+0000) Subject: [WSHTCPIP] Implement SIO_GET_INTERFACE_LIST by Andreas Maier aka andy-123. Thanks... X-Git-Tag: ReactOS-0.4.4-FOSDEM2017~193 X-Git-Url: https://git.reactos.org/?p=reactos.git;a=commitdiff_plain;h=2dc688c68bd4d37d4454e1d0fb4b3155c64b9ae7 [WSHTCPIP] Implement SIO_GET_INTERFACE_LIST by Andreas Maier aka andy-123. Thanks. CORE-10343 svn path=/trunk/; revision=73342 --- diff --git a/reactos/dll/win32/wshtcpip/CMakeLists.txt b/reactos/dll/win32/wshtcpip/CMakeLists.txt index 274412becbe..2c9059afbca 100644 --- a/reactos/dll/win32/wshtcpip/CMakeLists.txt +++ b/reactos/dll/win32/wshtcpip/CMakeLists.txt @@ -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 index 00000000000..6dd4b537d4a --- /dev/null +++ b/reactos/dll/win32/wshtcpip/iflist.c @@ -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 /* Declare Windows Headers like you normally would */ +#include /* Declare the NDK Headers */ +#include +#include + +#define NDEBUG +#include + + +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; +} diff --git a/reactos/dll/win32/wshtcpip/wshtcpip.c b/reactos/dll/win32/wshtcpip/wshtcpip.c index 47423f17ffb..4be7aab79d6 100644 --- a/reactos/dll/win32/wshtcpip/wshtcpip.c +++ b/reactos/dll/win32/wshtcpip/wshtcpip.c @@ -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; } diff --git a/reactos/dll/win32/wshtcpip/wshtcpip.h b/reactos/dll/win32/wshtcpip/wshtcpip.h index c25d8d244ff..7e4cfb2f928 100644 --- a/reactos/dll/win32/wshtcpip/wshtcpip.h +++ b/reactos/dll/win32/wshtcpip/wshtcpip.h @@ -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 */