reactos/dll/win32/iphlpapi/iphlpapi_main.c
Joachim Henze 845768f0a6 [0.4.9][IPHLPAPI][TCPIP][IP][LWIP][SDK][PSDK] Port back groundworks for netstat
This fixes:
CORE-15363 'netstat TCP foreign address port is wrong'
CORE-5401 'Netstat returns ERROR_NO_DATA Pipe being closed'
CORE-5126 'UNIMPLEMENTED: iphlpapi: GetExtendedUdpTable'
even without touching the netstat binary yet.
And is mostly based on work done by Pierre Schweitzer during 0.4.11-dev'ing.

by porting back:
0.4.15-dev-6231-g a5360f542f [IPHLPAPI] Formatting only, no functional change
partially 0.4.14-dev-1425-g f540b2b20c [IPHLPAPI] GetAdaptersAddresses(): Add 1 free() in ERROR_NO_DATA case (#2526) (but leave out adding the comments in .h)
0.4.12-dev-686-g 22f60faf43 [IPHLPAPI] Remove dead code to fix CID 513306, 1442673, 1442697
0.4.11-dev-880-g bf052e120b [IPHLPAPI] Reduce code duplication and use a single function for TCP and UDP enumerations + fix corruption
0.4.11-dev-867-g 159f5b676a [IPHLPAPI] Fix broken size computation leading to buffer overrun
0.4.11-dev-861-g 05657bfcfd [SDK] Add a non documenter TOIID used to query modules information
0.4.11-dev-827-g ce7f9211a0 [TCPIP] In InfoTdiQueryGetConnectionTcpTable(), only return if there's a connection
0.4.11-dev-823-g 0ec92100bc [TCPIP] Properly display local information for established connections
0.4.11-dev-819-g fbdfe7bd40 [SDK] Add GetExtendedUdpTable()
0.4.11-dev-818-g 370b03b523 [IPHLPAPI] Reimplement GetUdpTable() using GetExtendedUdpTable()
0.4.11-dev-817-g 58cef01422 [IPHLPAPI] Implement GetExtendedUdpTable() CORE-5126
0.4.11-dev-816-g 6fb6c7b50b [IPHLPAPI] Implement getOwnerUdoTable(), to get UDP connections with owner PID
0.4.11-dev-815-g 13de7f08af [TCPIP] Implement enumerating UDP connections with owner PID
0.4.11-dev-813-g 73c87d5c14 [IPHLPAPI] Reimplement GetTcpTable() using GetExtendedTcpTable()
0.4.11-dev-812-g d76ac645e8 [IPHLPAPI] Don't leak memory
0.4.11-dev-811-g c949a12506 [IPHLPAPI] Implement the IPv4 TCP_TABLE_OWNER_PID_* cases in GetExtendedTcpTable()
0.4.11-dev-810-g dca7e5689f [IPHLPAPI] Implement getOwnerTcpTable(), to get TCP connections with owner PID
0.4.11-dev-809-g 411504b5f4 [TCPIP] Implement enumerating TCP connections with owner PID
0.4.11-dev-808-g 935978ee57 [TCPIP] Store creator PID in ADDRESS_FILE
0.4.11-dev-807-g 702d44c683 [IPHLPAPI] Implement the IPv4 TCP_TABLE_BASIC_* cases in GetExtendedTcpTable()
0.4.11-dev-804-g 91b013d387 [TCPIP] When enumerating sockets, retrieve their state and return it
0.4.11-dev-803-g 738f327668 [IP] Add a TCPGetSocketStatus() wrapper around LibTCPGetSocketStatus()
0.4.11-dev-802-g 29c1510423 [LWIP] Implement a LibTCPGetSocketStatus() function in our LwIP glue
0.4.11-dev-792-g 8a98c85c1f [IPHLPAPI] Fix checking entity when enumerating TCP/UDP connections
0.4.11-dev-784-g f29016dabe [TCPIP] Properly handle listening sockets
0.4.11-dev-782-g 007f43dd56 [TCPIP] Implement returning UDP connections CORE-5401
0.4.11-dev-781-g 77d5f04f22 [TCPIP] Implement returning TCP connections CORE-5401
0.4.11-dev-799-g 500a5151ea [TCPIP] Fix returned IP address when querying TCP connections CORE-15363
0.4.11-dev-783-g d18b1fe24b [IPHLPAPI] Properly count UDP entries CORE-5401
0.4.11-dev-780-g e3cb9697a4 [IPHLPAPI] Implement getNumUdpEntries() and getUdpTable() CORE-5401
0.4.11-dev-779-g 678204790c [IPHLPAPI] Implement getNumTcpEntries() and getTcpTable() CORE-5401
----------------
Strip some DPRINTs entirely in IPHLPAPI/TCPIP in releases/0.4.7 - 0.4.10 (instead of fixing them like we did on master). Many of them had x64 issues:
This was partially *inspired* by watching the following commits:
0.4.13-dev-14-g f9a967b2ae [IPHLPAPI] Fix misc 64 bit issues (only the parts in iphlpapi_main.c with the format strings)
0.4.10-dev-409-g 0f8439aa71 [IPHLPAPI] Fix 64 bit issue, just the one within [IPHLPAPI] ifenum_reactos.c
0.4.9-dev-856-g 6c9359221c [IPHLPAPI] ipstats_reactos: Review all TRACE/WARN calls
This does not only fix the x64 incompatibilities by superseding those 3 commits but also will keep the file-sizes under control for the backports.
2023-07-03 01:51:26 +02:00

2736 lines
76 KiB
C

/*
* iphlpapi dll implementation
*
* Copyright (C) 2003 Juan Lang
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define DEBUG
#include <config.h>
#include "iphlpapi_private.h"
#include <strsafe.h>
WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
typedef struct _NAME_SERVER_LIST_CONTEXT {
ULONG uSizeAvailable;
ULONG uSizeRequired;
PIP_PER_ADAPTER_INFO pData;
UINT NumServers;
IP_ADDR_STRING *pLastAddr;
} NAME_SERVER_LIST_CONTEXT, *PNAME_SERVER_LIST_CONTEXT;
BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
switch (fdwReason) {
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls( hinstDLL );
interfaceMapInit();
break;
case DLL_PROCESS_DETACH:
interfaceMapFree();
break;
}
return TRUE;
}
/******************************************************************
* AddIPAddress (IPHLPAPI.@)
*
* PARAMS
* Address [In]
* IpMask [In]
* IfIndex [In]
* NTEContext [In/Out]
* NTEInstance [In/Out]
*
* RETURNS
* DWORD
*/
DWORD WINAPI AddIPAddress(IPAddr Address, IPMask Netmask, DWORD IfIndex, PULONG NteContext, PULONG NteInstance)
{
return RtlNtStatusToDosError(addIPAddress(Address, Netmask, IfIndex, NteContext, NteInstance));
}
DWORD getInterfaceGatewayByIndex(DWORD index)
{
DWORD ndx, retVal = 0, numRoutes = getNumRoutes();
RouteTable *table = getRouteTable();
if (!table) return 0;
for (ndx = 0; ndx < numRoutes; ndx++)
{
if ((table->routes[ndx].ifIndex == (index)) && (table->routes[ndx].dest == 0))
retVal = table->routes[ndx].gateway;
}
HeapFree(GetProcessHeap(), 0, table);
return retVal;
}
/******************************************************************
* AllocateAndGetIfTableFromStack (IPHLPAPI.@)
*
* PARAMS
* ppIfTable [Out] -- pointer into which the MIB_IFTABLE is
* allocated and returned.
* bOrder [In] -- passed to GetIfTable to order the table
* heap [In] -- heap from which the table is allocated
* flags [In] -- flags to HeapAlloc
*
* RETURNS -- ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
* GetIfTable returns otherwise
*/
DWORD WINAPI AllocateAndGetIfTableFromStack(PMIB_IFTABLE *ppIfTable,
BOOL bOrder, HANDLE heap, DWORD flags)
{
DWORD ret;
if (!ppIfTable)
ret = ERROR_INVALID_PARAMETER;
else {
DWORD dwSize = 0;
*ppIfTable = NULL;
ret = GetIfTable(*ppIfTable, &dwSize, bOrder);
if (ret == ERROR_INSUFFICIENT_BUFFER) {
*ppIfTable = (PMIB_IFTABLE)HeapAlloc(heap, flags, dwSize);
ret = GetIfTable(*ppIfTable, &dwSize, bOrder);
if (ret != NO_ERROR) {
HeapFree(heap, flags, *ppIfTable);
*ppIfTable = NULL;
}
}
}
return ret;
}
/******************************************************************
* AllocateAndGetIpAddrTableFromStack (IPHLPAPI.@)
*
* PARAMS
* ppIpAddrTable [Out]
* bOrder [In] -- passed to GetIpAddrTable to order the table
* heap [In] -- heap from which the table is allocated
* flags [In] -- flags to HeapAlloc
*
* RETURNS
* DWORD
*/
DWORD WINAPI AllocateAndGetIpAddrTableFromStack(PMIB_IPADDRTABLE *ppIpAddrTable,
BOOL bOrder, HANDLE heap, DWORD flags)
{
DWORD ret;
if (!ppIpAddrTable)
ret = ERROR_INVALID_PARAMETER;
else {
DWORD dwSize = 0;
*ppIpAddrTable = NULL;
ret = GetIpAddrTable(*ppIpAddrTable, &dwSize, bOrder);
if (ret == ERROR_INSUFFICIENT_BUFFER) {
*ppIpAddrTable = (PMIB_IPADDRTABLE)HeapAlloc(heap, flags, dwSize);
ret = GetIpAddrTable(*ppIpAddrTable, &dwSize, bOrder);
if (ret != NO_ERROR) {
HeapFree(heap, flags, *ppIpAddrTable);
*ppIpAddrTable = NULL;
}
}
}
return ret;
}
/******************************************************************
* AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
*
* ppIpForwardTable [Out] -- pointer into which the MIB_IPFORWARDTABLE is
* allocated and returned.
* bOrder [In] -- passed to GetIfTable to order the table
* heap [In] -- heap from which the table is allocated
* flags [In] -- flags to HeapAlloc
*
* RETURNS -- ERROR_INVALID_PARAMETER if ppIfTable is NULL, whatever
* GetIpForwardTable returns otherwise
*/
DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *
ppIpForwardTable, BOOL bOrder, HANDLE heap, DWORD flags)
{
DWORD ret;
if (!ppIpForwardTable)
ret = ERROR_INVALID_PARAMETER;
else {
DWORD dwSize = 0;
*ppIpForwardTable = NULL;
ret = GetIpForwardTable(*ppIpForwardTable, &dwSize, bOrder);
if (ret == ERROR_INSUFFICIENT_BUFFER) {
*ppIpForwardTable = (PMIB_IPFORWARDTABLE)HeapAlloc(heap, flags, dwSize);
ret = GetIpForwardTable(*ppIpForwardTable, &dwSize, bOrder);
if (ret != NO_ERROR) {
HeapFree(heap, flags, *ppIpForwardTable);
*ppIpForwardTable = NULL;
}
}
}
return ret;
}
/******************************************************************
* AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
*
* PARAMS
* ppIpNetTable [Out]
* bOrder [In] -- passed to GetIpNetTable to order the table
* heap [In] -- heap from which the table is allocated
* flags [In] -- flags to HeapAlloc
*
* RETURNS
* DWORD
*/
DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable,
BOOL bOrder, HANDLE heap, DWORD flags)
{
DWORD ret;
if (!ppIpNetTable)
ret = ERROR_INVALID_PARAMETER;
else {
DWORD dwSize = 0;
*ppIpNetTable = NULL;
ret = GetIpNetTable(*ppIpNetTable, &dwSize, bOrder);
if (ret == ERROR_INSUFFICIENT_BUFFER) {
*ppIpNetTable = (PMIB_IPNETTABLE)HeapAlloc(heap, flags, dwSize);
ret = GetIpNetTable(*ppIpNetTable, &dwSize, bOrder);
if (ret != NO_ERROR) {
HeapFree(heap, flags, *ppIpNetTable);
*ppIpNetTable = NULL;
}
}
}
return ret;
}
/******************************************************************
* AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
*
* PARAMS
* ppTcpTable [Out]
* bOrder [In] -- passed to GetTcpTable to order the table
* heap [In] -- heap from which the table is allocated
* flags [In] -- flags to HeapAlloc
*
* RETURNS
* DWORD
*/
DWORD WINAPI AllocateAndGetTcpTableFromStack(PMIB_TCPTABLE *ppTcpTable,
BOOL bOrder, HANDLE heap, DWORD flags)
{
DWORD ret;
if (!ppTcpTable)
ret = ERROR_INVALID_PARAMETER;
else {
DWORD dwSize = 0;
*ppTcpTable = NULL;
ret = GetTcpTable(*ppTcpTable, &dwSize, bOrder);
if (ret == ERROR_INSUFFICIENT_BUFFER) {
*ppTcpTable = (PMIB_TCPTABLE)HeapAlloc(heap, flags, dwSize);
ret = GetTcpTable(*ppTcpTable, &dwSize, bOrder);
if (ret != NO_ERROR) {
HeapFree(heap, flags, *ppTcpTable);
*ppTcpTable = NULL;
}
}
}
return ret;
}
/******************************************************************
* AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
*
* PARAMS
* ppUdpTable [Out]
* bOrder [In] -- passed to GetUdpTable to order the table
* heap [In] -- heap from which the table is allocated
* flags [In] -- flags to HeapAlloc
*
* RETURNS
* DWORD
*/
DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable,
BOOL bOrder, HANDLE heap, DWORD flags)
{
DWORD ret;
if (!ppUdpTable)
ret = ERROR_INVALID_PARAMETER;
else {
DWORD dwSize = 0;
*ppUdpTable = NULL;
ret = GetUdpTable(*ppUdpTable, &dwSize, bOrder);
if (ret == ERROR_INSUFFICIENT_BUFFER) {
*ppUdpTable = (PMIB_UDPTABLE)HeapAlloc(heap, flags, dwSize);
ret = GetUdpTable(*ppUdpTable, &dwSize, bOrder);
if (ret != NO_ERROR) {
HeapFree(heap, flags, *ppUdpTable);
*ppUdpTable = NULL;
}
}
}
return ret;
}
/******************************************************************
* CreateIpForwardEntry (IPHLPAPI.@)
*
* PARAMS
* pRoute [In/Out]
*
* RETURNS
* DWORD
*/
DWORD WINAPI CreateIpForwardEntry(PMIB_IPFORWARDROW pRoute)
{
return createIpForwardEntry( pRoute );
}
/******************************************************************
* CreateIpNetEntry (IPHLPAPI.@)
*
* PARAMS
* pArpEntry [In/Out]
*
* RETURNS
* DWORD
*/
DWORD WINAPI CreateIpNetEntry(PMIB_IPNETROW pArpEntry)
{
/* could use SIOCSARP on systems that support it, not sure I want to */
FIXME(":stub\n");
return (DWORD) 0;
}
/******************************************************************
* CreateProxyArpEntry (IPHLPAPI.@)
*
* PARAMS
* dwAddress [In]
* dwMask [In]
* dwIfIndex [In]
*
* RETURNS
* DWORD
*/
DWORD WINAPI CreateProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
{
FIXME(":stub\n");
/* marking Win2K+ functions not supported */
return ERROR_NOT_SUPPORTED;
}
/******************************************************************
* DeleteIPAddress (IPHLPAPI.@)
*
* PARAMS
* NTEContext [In]
*
* RETURNS
* DWORD
*/
DWORD WINAPI DeleteIPAddress(ULONG NTEContext)
{
TRACE("NTEContext %ld\n", NTEContext);
return RtlNtStatusToDosError(deleteIpAddress(NTEContext));
}
/******************************************************************
* DeleteIpForwardEntry (IPHLPAPI.@)
*
* PARAMS
* pRoute [In/Out]
*
* RETURNS
* DWORD
*/
DWORD WINAPI DeleteIpForwardEntry(PMIB_IPFORWARDROW pRoute)
{
return deleteIpForwardEntry( pRoute );
}
/******************************************************************
* DeleteIpNetEntry (IPHLPAPI.@)
*
* PARAMS
* pArpEntry [In/Out]
*
* RETURNS
* DWORD
*/
DWORD WINAPI DeleteIpNetEntry(PMIB_IPNETROW pArpEntry)
{
/* could use SIOCDARP on systems that support it, not sure I want to */
FIXME(":stub\n");
return (DWORD) 0;
}
/******************************************************************
* DeleteProxyArpEntry (IPHLPAPI.@)
*
* PARAMS
* dwAddress [In]
* dwMask [In]
* dwIfIndex [In]
*
* RETURNS
* DWORD
*/
DWORD WINAPI DeleteProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
{
FIXME(":stub\n");
/* marking Win2K+ functions not supported */
return ERROR_NOT_SUPPORTED;
}
/******************************************************************
* EnableRouter (IPHLPAPI.@)
*
* PARAMS
* pHandle [In/Out]
* pOverlapped [In/Out]
*
* RETURNS
* DWORD
*/
DWORD WINAPI EnableRouter(HANDLE * pHandle, OVERLAPPED * pOverlapped)
{
FIXME(":stub\n");
/* could echo "1" > /proc/net/sys/net/ipv4/ip_forward, not sure I want to
could map EACCESS to ERROR_ACCESS_DENIED, I suppose
marking Win2K+ functions not supported */
return ERROR_NOT_SUPPORTED;
}
/******************************************************************
* FlushIpNetTable (IPHLPAPI.@)
*
* PARAMS
* dwIfIndex [In]
*
* RETURNS
* DWORD
*/
DWORD WINAPI FlushIpNetTable(DWORD dwIfIndex)
{
FIXME(":stub\n");
/* this flushes the arp cache of the given index
marking Win2K+ functions not supported */
return ERROR_NOT_SUPPORTED;
}
/******************************************************************
* GetAdapterIndex (IPHLPAPI.@)
*
* PARAMS
* AdapterName [In/Out]
* IfIndex [In/Out]
*
* RETURNS
* DWORD
*/
DWORD WINAPI GetAdapterIndex(LPWSTR AdapterName, PULONG IfIndex)
{
FIXME(":stub\n");
/* marking Win2K+ functions not supported */
return ERROR_NOT_SUPPORTED;
}
/******************************************************************
* GetAdaptersInfo (IPHLPAPI.@)
*
* PARAMS
* pAdapterInfo [In/Out]
* pOutBufLen [In/Out]
*
* RETURNS
* DWORD
*/
DWORD WINAPI GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
{
DWORD ret;
BOOL dhcpEnabled;
DWORD dhcpServer;
TRACE("pAdapterInfo %p, pOutBufLen %p\n", pAdapterInfo, pOutBufLen);
if (!pOutBufLen)
ret = ERROR_INVALID_PARAMETER;
else {
DWORD numNonLoopbackInterfaces = getNumNonLoopbackInterfaces();
if (numNonLoopbackInterfaces > 0) {
/* this calculation assumes only one address in the IP_ADDR_STRING lists.
that's okay, because:
- we don't get multiple addresses per adapter anyway
- we don't know about per-adapter gateways
- DHCP and WINS servers can have max one entry per list */
ULONG size = sizeof(IP_ADAPTER_INFO) * numNonLoopbackInterfaces;
if (!pAdapterInfo || *pOutBufLen < size) {
*pOutBufLen = size;
ret = ERROR_BUFFER_OVERFLOW;
}
else {
InterfaceIndexTable *table = getNonLoopbackInterfaceIndexTable();
if (table) {
size = sizeof(IP_ADAPTER_INFO) * table->numIndexes;
if (*pOutBufLen < size) {
*pOutBufLen = size;
ret = ERROR_INSUFFICIENT_BUFFER;
}
else {
DWORD ndx;
HKEY hKey;
BOOL winsEnabled = FALSE;
IP_ADDRESS_STRING primaryWINS, secondaryWINS;
memset(pAdapterInfo, 0, size);
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"Software\\Wine\\Wine\\Config\\Network", 0, KEY_READ,
&hKey) == ERROR_SUCCESS) {
DWORD size = sizeof(primaryWINS.String);
unsigned long addr;
RegQueryValueExA(hKey, "WinsServer", NULL, NULL,
(PBYTE)primaryWINS.String, &size);
addr = inet_addr(primaryWINS.String);
if (addr != INADDR_NONE && addr != INADDR_ANY)
winsEnabled = TRUE;
size = sizeof(secondaryWINS.String);
RegQueryValueExA(hKey, "BackupWinsServer", NULL, NULL,
(PBYTE)secondaryWINS.String, &size);
addr = inet_addr(secondaryWINS.String);
if (addr != INADDR_NONE && addr != INADDR_ANY)
winsEnabled = TRUE;
RegCloseKey(hKey);
}
for (ndx = 0; ndx < table->numIndexes; ndx++) {
PIP_ADAPTER_INFO ptr = &pAdapterInfo[ndx];
DWORD addrLen = sizeof(ptr->Address), type;
const char *ifname =
getInterfaceNameByIndex(table->indexes[ndx]);
if (!ifname) {
ret = ERROR_OUTOFMEMORY;
break;
}
/* on Win98 this is left empty, but whatever */
strncpy(ptr->AdapterName,ifname,sizeof(ptr->AdapterName));
consumeInterfaceName(ifname);
ptr->AdapterName[MAX_ADAPTER_NAME_LENGTH] = '\0';
getInterfacePhysicalByIndex(table->indexes[ndx], &addrLen,
ptr->Address, &type);
/* MS defines address length and type as UINT in some places and
DWORD in others, **sigh**. Don't want to assume that PUINT and
PDWORD are equiv (64-bit?) */
ptr->AddressLength = addrLen;
ptr->Type = type;
ptr->Index = table->indexes[ndx];
toIPAddressString(getInterfaceIPAddrByIndex(table->indexes[ndx]),
ptr->IpAddressList.IpAddress.String);
toIPAddressString(getInterfaceMaskByIndex(table->indexes[ndx]),
ptr->IpAddressList.IpMask.String);
ptr->IpAddressList.Context = ptr->Index;
toIPAddressString(getInterfaceGatewayByIndex(table->indexes[ndx]),
ptr->GatewayList.IpAddress.String);
getDhcpInfoForAdapter(table->indexes[ndx], &dhcpEnabled,
&dhcpServer, &ptr->LeaseObtained,
&ptr->LeaseExpires);
ptr->DhcpEnabled = (DWORD) dhcpEnabled;
toIPAddressString(dhcpServer,
ptr->DhcpServer.IpAddress.String);
if (winsEnabled) {
ptr->HaveWins = TRUE;
memcpy(ptr->PrimaryWinsServer.IpAddress.String,
primaryWINS.String, sizeof(primaryWINS.String));
memcpy(ptr->SecondaryWinsServer.IpAddress.String,
secondaryWINS.String, sizeof(secondaryWINS.String));
}
if (ndx < table->numIndexes - 1)
ptr->Next = &pAdapterInfo[ndx + 1];
else
ptr->Next = NULL;
}
ret = NO_ERROR;
}
free(table);
}
else
ret = ERROR_OUTOFMEMORY;
}
}
else
ret = ERROR_NO_DATA;
}
TRACE("returning %ld\n", ret);
return ret;
}
/******************************************************************
* GetBestInterface (IPHLPAPI.@)
*
* PARAMS
* dwDestAddr [In]
* pdwBestIfIndex [In/Out]
*
* RETURNS
* DWORD
*/
DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
{
DWORD ret;
TRACE("dwDestAddr 0x%08lx, pdwBestIfIndex %p\n", dwDestAddr, pdwBestIfIndex);
if (!pdwBestIfIndex)
ret = ERROR_INVALID_PARAMETER;
else {
MIB_IPFORWARDROW ipRow;
ret = GetBestRoute(dwDestAddr, 0, &ipRow);
if (ret == ERROR_SUCCESS)
*pdwBestIfIndex = ipRow.dwForwardIfIndex;
}
TRACE("returning %ld\n", ret);
return ret;
}
/******************************************************************
* GetBestRoute (IPHLPAPI.@)
*
* PARAMS
* dwDestAddr [In]
* dwSourceAddr [In]
* OUT [In]
*
* RETURNS
* DWORD
*/
DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute)
{
PMIB_IPFORWARDTABLE table;
DWORD ret;
TRACE("dwDestAddr 0x%08lx, dwSourceAddr 0x%08lx, pBestRoute %p\n", dwDestAddr,
dwSourceAddr, pBestRoute);
if (!pBestRoute)
return ERROR_INVALID_PARAMETER;
AllocateAndGetIpForwardTableFromStack(&table, FALSE, GetProcessHeap(), 0);
if (table) {
DWORD ndx, minMaskSize, matchedNdx = 0;
for (ndx = 0, minMaskSize = 255; ndx < table->dwNumEntries; ndx++) {
if ((dwDestAddr & table->table[ndx].dwForwardMask) ==
(table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) {
DWORD hostMaskSize;
if (!_BitScanForward(&hostMaskSize, ntohl(table->table[ndx].dwForwardMask)))
{
hostMaskSize = 32;
}
if (hostMaskSize < minMaskSize) {
minMaskSize = hostMaskSize;
matchedNdx = ndx;
}
}
}
memcpy(pBestRoute, &table->table[matchedNdx], sizeof(MIB_IPFORWARDROW));
HeapFree(GetProcessHeap(), 0, table);
ret = ERROR_SUCCESS;
}
else
ret = ERROR_OUTOFMEMORY;
TRACE("returning %ld\n", ret);
return ret;
}
static int TcpTableSorter(const void *a, const void *b)
{
int ret;
if (a && b) {
PMIB_TCPROW rowA = (PMIB_TCPROW)a, rowB = (PMIB_TCPROW)b;
ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
if (ret == 0) {
ret = rowA->dwLocalPort - rowB->dwLocalPort;
if (ret == 0) {
ret = rowA->dwRemoteAddr - rowB->dwRemoteAddr;
if (ret == 0)
ret = rowA->dwRemotePort - rowB->dwRemotePort;
}
}
}
else
ret = 0;
return ret;
}
/******************************************************************
* GetExtendedTcpTable (IPHLPAPI.@)
*
* Get the table of TCP endpoints available to the application.
*
* PARAMS
* pTcpTable [Out] table struct with the filtered TCP endpoints available to application
* pdwSize [In/Out] estimated size of the structure returned in pTcpTable, in bytes
* bOrder [In] whether to order the table
* ulAf [in] version of IP used by the TCP endpoints
* TableClass [in] type of the TCP table structure from TCP_TABLE_CLASS
* Reserved [in] reserved - this value must be zero
*
* RETURNS
* Success: NO_ERROR
* Failure: either ERROR_INSUFFICIENT_BUFFER or ERROR_INVALID_PARAMETER
*/
DWORD WINAPI GetExtendedTcpTable(PVOID pTcpTable, PDWORD pdwSize, BOOL bOrder, ULONG ulAf, TCP_TABLE_CLASS TableClass, ULONG Reserved)
{
DWORD i, count, size;
DWORD ret = NO_ERROR;
if (!pdwSize)
return ERROR_INVALID_PARAMETER;
if (ulAf != AF_INET)
return ERROR_INVALID_PARAMETER;
switch (TableClass)
{
case TCP_TABLE_BASIC_ALL:
{
PMIB_TCPTABLE pOurTcpTable = getTcpTable(ClassBasic);
PMIB_TCPTABLE pTheirTcpTable = pTcpTable;
if (pOurTcpTable)
{
size = FIELD_OFFSET(MIB_TCPTABLE, table) + pOurTcpTable->dwNumEntries * sizeof(MIB_TCPROW);
if (size > *pdwSize || !pTheirTcpTable)
{
*pdwSize = size;
ret = ERROR_INSUFFICIENT_BUFFER;
}
else
{
memcpy(pTheirTcpTable, pOurTcpTable, size);
if (bOrder)
qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
sizeof(MIB_TCPROW), TcpTableSorter);
}
free(pOurTcpTable);
}
}
break;
case TCP_TABLE_BASIC_CONNECTIONS:
{
PMIB_TCPTABLE pOurTcpTable = getTcpTable(ClassBasic);
PMIB_TCPTABLE pTheirTcpTable = pTcpTable;
if (pOurTcpTable)
{
for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
{
if (pOurTcpTable->table[i].State != MIB_TCP_STATE_LISTEN)
++count;
}
size = FIELD_OFFSET(MIB_TCPTABLE, table) + count * sizeof(MIB_TCPROW);
if (size > *pdwSize || !pTheirTcpTable)
{
*pdwSize = size;
ret = ERROR_INSUFFICIENT_BUFFER;
}
else
{
pTheirTcpTable->dwNumEntries = count;
for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
{
if (pOurTcpTable->table[i].State != MIB_TCP_STATE_LISTEN)
{
memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW));
++count;
}
}
if (bOrder)
qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
sizeof(MIB_TCPROW), TcpTableSorter);
}
free(pOurTcpTable);
}
}
break;
case TCP_TABLE_BASIC_LISTENER:
{
PMIB_TCPTABLE pOurTcpTable = getTcpTable(ClassBasic);
PMIB_TCPTABLE pTheirTcpTable = pTcpTable;
if (pOurTcpTable)
{
for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
{
if (pOurTcpTable->table[i].State == MIB_TCP_STATE_LISTEN)
++count;
}
size = FIELD_OFFSET(MIB_TCPTABLE, table) + count * sizeof(MIB_TCPROW);
if (size > *pdwSize || !pTheirTcpTable)
{
*pdwSize = size;
ret = ERROR_INSUFFICIENT_BUFFER;
}
else
{
pTheirTcpTable->dwNumEntries = count;
for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
{
if (pOurTcpTable->table[i].State == MIB_TCP_STATE_LISTEN)
{
memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW));
++count;
}
}
if (bOrder)
qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
sizeof(MIB_TCPROW), TcpTableSorter);
}
free(pOurTcpTable);
}
}
break;
case TCP_TABLE_OWNER_PID_ALL:
{
PMIB_TCPTABLE_OWNER_PID pOurTcpTable = getTcpTable(ClassModulePid);
PMIB_TCPTABLE_OWNER_PID pTheirTcpTable = pTcpTable;
if (pOurTcpTable)
{
size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table) + pOurTcpTable->dwNumEntries * sizeof(MIB_TCPROW_OWNER_PID);
if (size > *pdwSize || !pTheirTcpTable)
{
*pdwSize = size;
ret = ERROR_INSUFFICIENT_BUFFER;
}
else
{
memcpy(pTheirTcpTable, pOurTcpTable, size);
if (bOrder)
qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
sizeof(MIB_TCPROW_OWNER_PID), TcpTableSorter);
}
free(pOurTcpTable);
}
}
break;
case TCP_TABLE_OWNER_PID_CONNECTIONS:
{
PMIB_TCPTABLE_OWNER_PID pOurTcpTable = getTcpTable(ClassModulePid);
PMIB_TCPTABLE_OWNER_PID pTheirTcpTable = pTcpTable;
if (pOurTcpTable)
{
for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
{
if (pOurTcpTable->table[i].dwState != MIB_TCP_STATE_LISTEN)
++count;
}
size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table) + count * sizeof(MIB_TCPROW_OWNER_PID);
if (size > *pdwSize || !pTheirTcpTable)
{
*pdwSize = size;
ret = ERROR_INSUFFICIENT_BUFFER;
}
else
{
pTheirTcpTable->dwNumEntries = count;
for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
{
if (pOurTcpTable->table[i].dwState != MIB_TCP_STATE_LISTEN)
{
memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW_OWNER_PID));
++count;
}
}
if (bOrder)
qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
sizeof(MIB_TCPROW_OWNER_PID), TcpTableSorter);
}
free(pOurTcpTable);
}
}
break;
case TCP_TABLE_OWNER_PID_LISTENER:
{
PMIB_TCPTABLE_OWNER_PID pOurTcpTable = getTcpTable(ClassModulePid);
PMIB_TCPTABLE_OWNER_PID pTheirTcpTable = pTcpTable;
if (pOurTcpTable)
{
for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
{
if (pOurTcpTable->table[i].dwState == MIB_TCP_STATE_LISTEN)
++count;
}
size = FIELD_OFFSET(MIB_TCPTABLE_OWNER_PID, table) + count * sizeof(MIB_TCPROW_OWNER_PID);
if (size > *pdwSize || !pTheirTcpTable)
{
*pdwSize = size;
ret = ERROR_INSUFFICIENT_BUFFER;
}
else
{
pTheirTcpTable->dwNumEntries = count;
for (i = 0, count = 0; i < pOurTcpTable->dwNumEntries; ++i)
{
if (pOurTcpTable->table[i].dwState == MIB_TCP_STATE_LISTEN)
{
memcpy(&pTheirTcpTable->table[count], &pOurTcpTable->table[i], sizeof(MIB_TCPROW_OWNER_PID));
++count;
}
}
if (bOrder)
qsort(pTheirTcpTable->table, pTheirTcpTable->dwNumEntries,
sizeof(MIB_TCPROW_OWNER_PID), TcpTableSorter);
}
free(pOurTcpTable);
}
}
break;
default:
ret = ERROR_INVALID_PARAMETER;
break;
}
return ret;
}
static int UdpTableSorter(const void *a, const void *b)
{
int ret;
if (a && b) {
PMIB_UDPROW rowA = (PMIB_UDPROW)a, rowB = (PMIB_UDPROW)b;
ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
if (ret == 0)
ret = rowA->dwLocalPort - rowB->dwLocalPort;
}
else
ret = 0;
return ret;
}
DWORD WINAPI GetExtendedUdpTable(PVOID pUdpTable, PDWORD pdwSize, BOOL bOrder, ULONG ulAf, UDP_TABLE_CLASS TableClass, ULONG Reserved)
{
DWORD size;
DWORD ret = NO_ERROR;
if (!pdwSize)
return ERROR_INVALID_PARAMETER;
if (ulAf != AF_INET)
return ERROR_INVALID_PARAMETER;
switch (TableClass)
{
case UDP_TABLE_BASIC:
{
PMIB_UDPTABLE pOurUdpTable = getUdpTable(ClassBasic);
PMIB_UDPTABLE pTheirUdpTable = pUdpTable;
if (pOurUdpTable)
{
size = FIELD_OFFSET(MIB_UDPTABLE, table) + pOurUdpTable->dwNumEntries * sizeof(MIB_UDPROW);
if (size > *pdwSize || !pTheirUdpTable)
{
*pdwSize = size;
ret = ERROR_INSUFFICIENT_BUFFER;
}
else
{
memcpy(pTheirUdpTable, pOurUdpTable, size);
if (bOrder)
qsort(pTheirUdpTable->table, pTheirUdpTable->dwNumEntries,
sizeof(MIB_UDPROW), UdpTableSorter);
}
free(pOurUdpTable);
}
}
break;
case UDP_TABLE_OWNER_PID:
{
PMIB_UDPTABLE_OWNER_PID pOurUdpTable = getUdpTable(ClassModulePid);
PMIB_UDPTABLE_OWNER_PID pTheirUdpTable = pUdpTable;
if (pOurUdpTable)
{
size = FIELD_OFFSET(MIB_UDPTABLE_OWNER_PID, table) + pOurUdpTable->dwNumEntries * sizeof(MIB_UDPROW_OWNER_PID);
if (size > *pdwSize || !pTheirUdpTable)
{
*pdwSize = size;
ret = ERROR_INSUFFICIENT_BUFFER;
}
else
{
memcpy(pTheirUdpTable, pOurUdpTable, size);
if (bOrder)
qsort(pTheirUdpTable->table, pTheirUdpTable->dwNumEntries,
sizeof(MIB_UDPROW_OWNER_PID), UdpTableSorter);
}
free(pOurUdpTable);
}
}
break;
default:
ret = ERROR_INVALID_PARAMETER;
break;
}
return ret;
}
/******************************************************************
* GetFriendlyIfIndex (IPHLPAPI.@)
*
* PARAMS
* IfIndex [In]
*
* RETURNS
* DWORD
*/
DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
{
/* windows doesn't validate these, either, just makes sure the top byte is
cleared. I assume my ifenum module never gives an index with the top
byte set. */
TRACE("returning %ld\n", IfIndex);
return IfIndex;
}
/******************************************************************
* GetIcmpStatistics (IPHLPAPI.@)
*
* PARAMS
* pStats [In/Out]
*
* RETURNS
* DWORD
*/
DWORD WINAPI GetIcmpStatistics(PMIB_ICMP pStats)
{
DWORD ret;
TRACE("pStats %p\n", pStats);
ret = getICMPStats(pStats);
TRACE("returning %ld\n", ret);
return ret;
}
/******************************************************************
* GetIfEntry (IPHLPAPI.@)
*
* PARAMS
* pIfRow [In/Out]
*
* RETURNS
* DWORD
*/
DWORD WINAPI GetIfEntry(PMIB_IFROW pIfRow)
{
DWORD ret;
const char *name;
TRACE("pIfRow %p\n", pIfRow);
if (!pIfRow)
return ERROR_INVALID_PARAMETER;
name = getInterfaceNameByIndex(pIfRow->dwIndex);
if (name) {
ret = getInterfaceEntryByIndex(pIfRow->dwIndex, pIfRow);
if (ret == NO_ERROR)
ret = getInterfaceStatsByName(name, pIfRow);
consumeInterfaceName(name);
}
else
ret = ERROR_INVALID_DATA;
TRACE("returning %ld\n", ret);
return ret;
}
static int IfTableSorter(const void *a, const void *b)
{
int ret;
if (a && b)
ret = ((PMIB_IFROW)a)->dwIndex - ((PMIB_IFROW)b)->dwIndex;
else
ret = 0;
return ret;
}
/******************************************************************
* GetIfTable (IPHLPAPI.@)
*
* PARAMS
* pIfTable [In/Out]
* pdwSize [In/Out]
* bOrder [In]
*
* RETURNS
* DWORD
*/
DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
{
DWORD ret;
TRACE("pIfTable %p, pdwSize %p, bOrder %ld\n", pdwSize, pdwSize,
(DWORD)bOrder);
if (!pdwSize)
ret = ERROR_INVALID_PARAMETER;
else {
DWORD numInterfaces = getNumInterfaces();
ULONG size;
TRACE("GetIfTable: numInterfaces = %d\n", (int)numInterfaces);
size = sizeof(MIB_IFTABLE) + (numInterfaces - 1) * sizeof(MIB_IFROW);
if (!pIfTable || *pdwSize < size) {
*pdwSize = size;
ret = ERROR_INSUFFICIENT_BUFFER;
}
else {
InterfaceIndexTable *table = getInterfaceIndexTable();
if (table) {
size = sizeof(MIB_IFTABLE) + (table->numIndexes - 1) *
sizeof(MIB_IFROW);
if (*pdwSize < size) {
*pdwSize = size;
ret = ERROR_INSUFFICIENT_BUFFER;
}
else {
DWORD ndx;
pIfTable->dwNumEntries = 0;
for (ndx = 0; ndx < table->numIndexes; ndx++) {
pIfTable->table[ndx].dwIndex = table->indexes[ndx];
GetIfEntry(&pIfTable->table[ndx]);
pIfTable->dwNumEntries++;
}
if (bOrder)
qsort(pIfTable->table, pIfTable->dwNumEntries, sizeof(MIB_IFROW),
IfTableSorter);
ret = NO_ERROR;
}
free(table);
}
else
ret = ERROR_OUTOFMEMORY;
}
}
TRACE("returning %ld\n", ret);
return ret;
}
/******************************************************************
* GetInterfaceInfo (IPHLPAPI.@)
*
* PARAMS
* pIfTable [In/Out]
* dwOutBufLen [In/Out]
*
* RETURNS
* DWORD
*/
DWORD WINAPI GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen)
{
DWORD ret;
TRACE("pIfTable %p, dwOutBufLen %p\n", pIfTable, dwOutBufLen);
if (!dwOutBufLen)
ret = ERROR_INVALID_PARAMETER;
else {
DWORD numNonLoopbackInterfaces = getNumNonLoopbackInterfaces();
ULONG size;
TRACE("numNonLoopbackInterfaces == 0x%x\n", numNonLoopbackInterfaces);
size = sizeof(IP_INTERFACE_INFO) + (numNonLoopbackInterfaces) *
sizeof(IP_ADAPTER_INDEX_MAP);
if (!pIfTable || *dwOutBufLen < size) {
*dwOutBufLen = size;
ret = ERROR_INSUFFICIENT_BUFFER;
}
else {
InterfaceIndexTable *table = getNonLoopbackInterfaceIndexTable();
if (table) {
TRACE("table->numIndexes == 0x%x\n", table->numIndexes);
size = sizeof(IP_INTERFACE_INFO) + (table->numIndexes) *
sizeof(IP_ADAPTER_INDEX_MAP);
if (*dwOutBufLen < size) {
*dwOutBufLen = size;
ret = ERROR_INSUFFICIENT_BUFFER;
}
else {
DWORD ndx;
pIfTable->NumAdapters = 0;
for (ndx = 0; ndx < table->numIndexes; ndx++) {
const char *walker, *name;
WCHAR *assigner;
pIfTable->Adapter[ndx].Index = table->indexes[ndx];
name = getInterfaceNameByIndex(table->indexes[ndx]);
for (walker = name, assigner = pIfTable->Adapter[ndx].Name;
walker && *walker &&
assigner - pIfTable->Adapter[ndx].Name < MAX_ADAPTER_NAME - 1;
walker++, assigner++)
*assigner = *walker;
*assigner = 0;
consumeInterfaceName(name);
pIfTable->NumAdapters++;
}
ret = NO_ERROR;
}
free(table);
}
else
ret = ERROR_OUTOFMEMORY;
}
}
TRACE("returning %ld\n", ret);
return ret;
}
static int IpAddrTableSorter(const void *a, const void *b)
{
int ret;
if (a && b)
ret = ((PMIB_IPADDRROW)a)->dwAddr - ((PMIB_IPADDRROW)b)->dwAddr;
else
ret = 0;
return ret;
}
/******************************************************************
* GetIpAddrTable (IPHLPAPI.@)
*
* PARAMS
* pIpAddrTable [In/Out]
* pdwSize [In/Out]
* bOrder [In]
*
* RETURNS
* DWORD
*/
DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder)
{
DWORD ret;
TRACE("pIpAddrTable %p, pdwSize %p, bOrder %ld\n", pIpAddrTable, pdwSize,
(DWORD)bOrder);
if (!pdwSize)
ret = ERROR_INVALID_PARAMETER;
else {
DWORD numInterfaces = getNumInterfaces();
ULONG size = sizeof(MIB_IPADDRTABLE) + (numInterfaces - 1) *
sizeof(MIB_IPADDRROW);
if (!pIpAddrTable || *pdwSize < size) {
*pdwSize = size;
ret = ERROR_INSUFFICIENT_BUFFER;
}
else {
InterfaceIndexTable *table = getInterfaceIndexTable();
if (table) {
size = sizeof(MIB_IPADDRTABLE) + (table->numIndexes - 1) *
sizeof(MIB_IPADDRROW);
if (*pdwSize < size) {
*pdwSize = size;
ret = ERROR_INSUFFICIENT_BUFFER;
}
else {
DWORD ndx, bcast;
pIpAddrTable->dwNumEntries = 0;
for (ndx = 0; ndx < table->numIndexes; ndx++) {
pIpAddrTable->table[ndx].dwIndex = table->indexes[ndx];
pIpAddrTable->table[ndx].dwAddr =
getInterfaceIPAddrByIndex(table->indexes[ndx]);
pIpAddrTable->table[ndx].dwMask =
getInterfaceMaskByIndex(table->indexes[ndx]);
/* the dwBCastAddr member isn't the broadcast address, it indicates
* whether the interface uses the 1's broadcast address (1) or the
* 0's broadcast address (0).
*/
bcast = getInterfaceBCastAddrByIndex(table->indexes[ndx]);
pIpAddrTable->table[ndx].dwBCastAddr =
(bcast & pIpAddrTable->table[ndx].dwMask) ? 1 : 0;
/* FIXME: hardcoded reasm size, not sure where to get it */
pIpAddrTable->table[ndx].dwReasmSize = 65535;
pIpAddrTable->table[ndx].unused1 = 0;
pIpAddrTable->table[ndx].wType = 0; /* aka unused2 */
pIpAddrTable->dwNumEntries++;
}
if (bOrder)
qsort(pIpAddrTable->table, pIpAddrTable->dwNumEntries,
sizeof(MIB_IPADDRROW), IpAddrTableSorter);
ret = NO_ERROR;
}
free(table);
}
else
ret = ERROR_OUTOFMEMORY;
}
}
TRACE("returning %ld\n", ret);
return ret;
}
static int IpForwardTableSorter(const void *a, const void *b)
{
int ret;
if (a && b) {
PMIB_IPFORWARDROW rowA = (PMIB_IPFORWARDROW)a, rowB = (PMIB_IPFORWARDROW)b;
ret = rowA->dwForwardDest - rowB->dwForwardDest;
if (ret == 0) {
ret = rowA->dwForwardProto - rowB->dwForwardProto;
if (ret == 0) {
ret = rowA->dwForwardPolicy - rowB->dwForwardPolicy;
if (ret == 0)
ret = rowA->dwForwardNextHop - rowB->dwForwardNextHop;
}
}
}
else
ret = 0;
return ret;
}
/******************************************************************
* GetIpForwardTable (IPHLPAPI.@)
*
* PARAMS
* pIpForwardTable [In/Out]
* pdwSize [In/Out]
* bOrder [In]
*
* RETURNS
* DWORD
*/
DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder)
{
DWORD ret;
TRACE("pIpForwardTable %p, pdwSize %p, bOrder %ld\n", pIpForwardTable,
pdwSize, (DWORD)bOrder);
if (!pdwSize)
ret = ERROR_INVALID_PARAMETER;
else {
DWORD numRoutes = getNumRoutes();
ULONG sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (numRoutes - 1) *
sizeof(MIB_IPFORWARDROW);
if (!pIpForwardTable || *pdwSize < sizeNeeded) {
*pdwSize = sizeNeeded;
ret = ERROR_INSUFFICIENT_BUFFER;
}
else {
RouteTable *table = getRouteTable();
if (table) {
sizeNeeded = sizeof(MIB_IPFORWARDTABLE) + (table->numRoutes - 1) *
sizeof(MIB_IPFORWARDROW);
if (*pdwSize < sizeNeeded) {
*pdwSize = sizeNeeded;
ret = ERROR_INSUFFICIENT_BUFFER;
}
else {
DWORD ndx;
pIpForwardTable->dwNumEntries = table->numRoutes;
for (ndx = 0; ndx < numRoutes; ndx++) {
pIpForwardTable->table[ndx].dwForwardIfIndex =
table->routes[ndx].ifIndex;
pIpForwardTable->table[ndx].dwForwardDest =
table->routes[ndx].dest;
pIpForwardTable->table[ndx].dwForwardMask =
table->routes[ndx].mask;
pIpForwardTable->table[ndx].dwForwardPolicy = 0;
pIpForwardTable->table[ndx].dwForwardNextHop =
table->routes[ndx].gateway;
/* FIXME: this type is appropriate for local interfaces; may not
always be appropriate */
pIpForwardTable->table[ndx].dwForwardType = MIB_IPROUTE_TYPE_DIRECT;
/* FIXME: other protos might be appropriate, e.g. the default route
is typically set with MIB_IPPROTO_NETMGMT instead */
pIpForwardTable->table[ndx].dwForwardProto = MIB_IPPROTO_LOCAL;
/* punt on age and AS */
pIpForwardTable->table[ndx].dwForwardAge = 0;
pIpForwardTable->table[ndx].dwForwardNextHopAS = 0;
pIpForwardTable->table[ndx].dwForwardMetric1 =
table->routes[ndx].metric;
/* rest of the metrics are 0.. */
pIpForwardTable->table[ndx].dwForwardMetric2 = 0;
pIpForwardTable->table[ndx].dwForwardMetric3 = 0;
pIpForwardTable->table[ndx].dwForwardMetric4 = 0;
pIpForwardTable->table[ndx].dwForwardMetric5 = 0;
}
if (bOrder)
qsort(pIpForwardTable->table, pIpForwardTable->dwNumEntries,
sizeof(MIB_IPFORWARDROW), IpForwardTableSorter);
ret = NO_ERROR;
}
HeapFree(GetProcessHeap(), 0, table);
}
else
ret = ERROR_OUTOFMEMORY;
}
}
TRACE("returning %ld\n", ret);
return ret;
}
static int IpNetTableSorter(const void *a, const void *b)
{
int ret;
if (a && b)
ret = ((PMIB_IPNETROW)a)->dwAddr - ((PMIB_IPNETROW)b)->dwAddr;
else
ret = 0;
return ret;
}
/******************************************************************
* GetIpNetTable (IPHLPAPI.@)
*
* PARAMS
* pIpNetTable [In/Out]
* pdwSize [In/Out]
* bOrder [In]
*
* RETURNS
* DWORD
*/
DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder)
{
DWORD ret = NO_ERROR;
TRACE("pIpNetTable %p, pdwSize %p, bOrder %d\n", pIpNetTable, pdwSize,
(DWORD)bOrder);
if (!pdwSize)
ret = ERROR_INVALID_PARAMETER;
else {
DWORD numEntries = getNumArpEntries();
ULONG size = sizeof(MIB_IPNETTABLE);
if (numEntries > 1)
size += (numEntries - 1) * sizeof(MIB_IPNETROW);
if (!pIpNetTable || *pdwSize < size) {
*pdwSize = size;
ret = ERROR_INSUFFICIENT_BUFFER;
}
else {
PMIB_IPNETTABLE table = getArpTable();
if (table) {
size = sizeof(MIB_IPNETTABLE);
if (table->dwNumEntries > 1)
size += (table->dwNumEntries - 1) * sizeof(MIB_IPNETROW);
if (*pdwSize < size) {
*pdwSize = size;
ret = ERROR_INSUFFICIENT_BUFFER;
}
else {
*pdwSize = size;
memcpy(pIpNetTable, table, size);
if (bOrder)
qsort(pIpNetTable->table, pIpNetTable->dwNumEntries,
sizeof(MIB_IPNETROW), IpNetTableSorter);
ret = NO_ERROR;
}
HeapFree(GetProcessHeap(), 0, table);
}
}
}
TRACE("returning %d\n", ret);
return ret;
}
/******************************************************************
* GetIpStatistics (IPHLPAPI.@)
*
* PARAMS
* pStats [In/Out]
*
* RETURNS
* DWORD
*/
DWORD WINAPI GetIpStatistics(PMIB_IPSTATS pStats)
{
return GetIpStatisticsEx(pStats, PF_INET);
}
/******************************************************************
* GetIpStatisticsEx (IPHLPAPI.@)
*
* PARAMS
* pStats [In/Out]
* dwFamily [In]
*
* RETURNS
* DWORD
*/
DWORD WINAPI GetIpStatisticsEx(PMIB_IPSTATS pStats, DWORD dwFamily)
{
DWORD ret;
TRACE("pStats %p\n", pStats);
ret = getIPStats(pStats, dwFamily);
TRACE("returning %ld\n", ret);
return ret;
}
/******************************************************************
* GetNetworkParams (IPHLPAPI.@)
*
* PARAMS
* pFixedInfo [In/Out]
* pOutBufLen [In/Out]
*
* RETURNS
* DWORD
*/
DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
{
DWORD ret, size, type;
LONG regReturn;
HKEY hKey;
PIPHLP_RES_INFO resInfo;
TRACE("pFixedInfo %p, pOutBufLen %p\n", pFixedInfo, pOutBufLen);
if (!pOutBufLen)
return ERROR_INVALID_PARAMETER;
resInfo = getResInfo();
if (!resInfo)
return ERROR_OUTOFMEMORY;
size = sizeof(FIXED_INFO) + (resInfo->riCount > 1 ? (resInfo->riCount-1) *
sizeof(IP_ADDR_STRING) : 0);
if (!pFixedInfo || *pOutBufLen < size) {
*pOutBufLen = size;
disposeResInfo( resInfo );
return ERROR_BUFFER_OVERFLOW;
}
memset(pFixedInfo, 0, size);
/* Check for DhcpHostname and DhcpDomain first */
regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
0,
KEY_READ,
&hKey);
if (regReturn == ERROR_SUCCESS) {
/* Windows doesn't honor DHCP option 12 even if RFC requires it if it is returned by DHCP server! */
#if 0
type = REG_SZ;
size = sizeof(pFixedInfo->HostName);
regReturn = RegQueryValueExA(hKey,
"DhcpHostname",
NULL,
&type,
(LPBYTE)pFixedInfo->HostName,
&size);
if (regReturn == ERROR_FILE_NOT_FOUND || (regReturn == ERROR_SUCCESS && size < 1))
{
#endif
type = REG_SZ;
size = sizeof(pFixedInfo->HostName);
regReturn = RegQueryValueExA(hKey,
"Hostname",
NULL,
&type,
(LPBYTE)pFixedInfo->HostName,
&size);
#if 0
}
#endif
type = REG_SZ;
size = sizeof(pFixedInfo->DomainName);
regReturn = RegQueryValueExA(hKey,
"DhcpDomain",
NULL,
&type,
(LPBYTE)pFixedInfo->DomainName,
&size);
if (regReturn == ERROR_FILE_NOT_FOUND || (regReturn == ERROR_SUCCESS && size < 1))
{
type = REG_SZ;
size = sizeof(pFixedInfo->DomainName);
regReturn = RegQueryValueExA(hKey,
"Domain",
NULL,
&type,
(LPBYTE)pFixedInfo->DomainName,
&size);
}
RegCloseKey(hKey);
}
TRACE("GetComputerNameExA: %s\n", pFixedInfo->DomainName);
if (resInfo->riCount > 0)
{
CopyMemory(&pFixedInfo->DnsServerList, resInfo->DnsList, sizeof(IP_ADDR_STRING));
if (resInfo->riCount > 1)
{
IP_ADDR_STRING *pSrc = resInfo->DnsList->Next;
IP_ADDR_STRING *pTarget = (struct _IP_ADDR_STRING*)((char*)pFixedInfo + sizeof(FIXED_INFO));
pFixedInfo->DnsServerList.Next = pTarget;
do
{
CopyMemory(pTarget, pSrc, sizeof(IP_ADDR_STRING));
resInfo->riCount--;
if (resInfo->riCount > 1)
{
pTarget->Next = (IP_ADDR_STRING*)((char*)pTarget + sizeof(IP_ADDR_STRING));
pTarget = pTarget->Next;
pSrc = pSrc->Next;
}
else
{
pTarget->Next = NULL;
break;
}
}
while(TRUE);
}
else
{
pFixedInfo->DnsServerList.Next = NULL;
}
}
pFixedInfo->NodeType = HYBRID_NODETYPE;
regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &hKey);
if (regReturn != ERROR_SUCCESS)
regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
"SYSTEM\\CurrentControlSet\\Services\\NetBT\\Parameters", 0, KEY_READ,
&hKey);
if (regReturn == ERROR_SUCCESS)
{
DWORD size = sizeof(pFixedInfo->ScopeId);
RegQueryValueExA(hKey, "ScopeID", NULL, NULL, (PBYTE)pFixedInfo->ScopeId, &size);
RegCloseKey(hKey);
}
disposeResInfo( resInfo );
/* FIXME: can check whether routing's enabled in /proc/sys/net/ipv4/ip_forward
I suppose could also check for a listener on port 53 to set EnableDns */
ret = NO_ERROR;
TRACE("returning %ld\n", ret);
return ret;
}
/******************************************************************
* GetNumberOfInterfaces (IPHLPAPI.@)
*
* PARAMS
* pdwNumIf [In/Out]
*
* RETURNS
* DWORD
*/
DWORD WINAPI GetNumberOfInterfaces(PDWORD pdwNumIf)
{
DWORD ret;
TRACE("pdwNumIf %p\n", pdwNumIf);
if (!pdwNumIf)
ret = ERROR_INVALID_PARAMETER;
else {
*pdwNumIf = getNumInterfaces();
ret = NO_ERROR;
}
TRACE("returning %ld\n", ret);
return ret;
}
/******************************************************************
* GetOwnerModuleFromTcpEntry (IPHLPAPI.@)
*
* Get data about the module that issued the context bind for a specific IPv4 TCP endpoint in a MIB table row
*
* PARAMS
* pTcpEntry [in] pointer to a MIB_TCPROW_OWNER_MODULE structure
* Class [in] TCPIP_OWNER_MODULE_INFO_CLASS enumeration value
* Buffer [out] pointer a buffer containing a TCPIP_OWNER_MODULE_BASIC_INFO structure with the owner module data.
* pdwSize [in, out] estimated size of the structure returned in Buffer, in bytes
*
* RETURNS
* Success: NO_ERROR
* Failure: ERROR_INSUFFICIENT_BUFFER, ERROR_INVALID_PARAMETER, ERROR_NOT_ENOUGH_MEMORY
* ERROR_NOT_FOUND or ERROR_PARTIAL_COPY
*
* NOTES
* The type of data returned in Buffer is indicated by the value of the Class parameter.
*/
DWORD WINAPI GetOwnerModuleFromTcpEntry(PMIB_TCPROW_OWNER_MODULE pTcpEntry, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
{
DWORD ret = NO_ERROR;
return ret;
}
static void CreateNameServerListEnumNamesFunc( PWCHAR Interface, PWCHAR Server, PVOID Data)
{
IP_ADDR_STRING *pNext;
PNAME_SERVER_LIST_CONTEXT Context = (PNAME_SERVER_LIST_CONTEXT)Data;
if (!Context->NumServers)
{
if (Context->uSizeAvailable >= Context->uSizeRequired)
{
WideCharToMultiByte(CP_ACP, 0, Server, -1, Context->pData->DnsServerList.IpAddress.String, 16, NULL, NULL);
Context->pData->DnsServerList.IpAddress.String[15] = '\0';
Context->pLastAddr = &Context->pData->DnsServerList;
}
}
else
{
Context->uSizeRequired += sizeof(IP_ADDR_STRING);
if (Context->uSizeAvailable >= Context->uSizeRequired)
{
pNext = (IP_ADDR_STRING*)(((char*)Context->pLastAddr) + sizeof(IP_ADDR_STRING));
WideCharToMultiByte(CP_ACP, 0, Server, -1, pNext->IpAddress.String, 16, NULL, NULL);
pNext->IpAddress.String[15] = '\0';
Context->pLastAddr->Next = pNext;
Context->pLastAddr = pNext;
pNext->Next = NULL;
}
}
Context->NumServers++;
}
/******************************************************************
* GetPerAdapterInfo (IPHLPAPI.@)
*
* PARAMS
* IfIndex [In]
* pPerAdapterInfo [In/Out]
* pOutBufLen [In/Out]
*
* RETURNS
* DWORD
*/
DWORD WINAPI GetPerAdapterInfo(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen)
{
HKEY hkey;
DWORD dwSize = 0;
const char *ifName;
NAME_SERVER_LIST_CONTEXT Context;
WCHAR keyname[200] = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
if (!pOutBufLen)
return ERROR_INVALID_PARAMETER;
if (!pPerAdapterInfo || *pOutBufLen < sizeof(IP_PER_ADAPTER_INFO))
{
*pOutBufLen = sizeof(IP_PER_ADAPTER_INFO);
return ERROR_BUFFER_OVERFLOW;
}
ifName = getInterfaceNameByIndex(IfIndex);
if (!ifName)
return ERROR_INVALID_PARAMETER;
MultiByteToWideChar(CP_ACP, 0, ifName, -1, &keyname[62], sizeof(keyname)/sizeof(WCHAR) - 63);
HeapFree(GetProcessHeap(), 0, (LPVOID)ifName);
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &hkey) != ERROR_SUCCESS)
{
return ERROR_NOT_SUPPORTED;
}
Context.NumServers = 0;
Context.uSizeAvailable = *pOutBufLen;
Context.uSizeRequired = sizeof(IP_PER_ADAPTER_INFO);
Context.pData = pPerAdapterInfo;
if (*pOutBufLen >= sizeof(IP_PER_ADAPTER_INFO))
ZeroMemory(pPerAdapterInfo, sizeof(IP_PER_ADAPTER_INFO));
EnumNameServers(hkey, &keyname[62], &Context, CreateNameServerListEnumNamesFunc);
if (Context.uSizeRequired > Context.uSizeAvailable)
{
*pOutBufLen = Context.uSizeRequired;
RegCloseKey(hkey);
return ERROR_BUFFER_OVERFLOW;
}
if(RegQueryValueExW(hkey, L"NameServer", NULL, NULL, NULL, &dwSize) == ERROR_SUCCESS)
{
pPerAdapterInfo->AutoconfigActive = FALSE;
}
else
{
pPerAdapterInfo->AutoconfigActive = TRUE;
}
RegCloseKey(hkey);
return NOERROR;
}
/******************************************************************
* GetRTTAndHopCount (IPHLPAPI.@)
*
* PARAMS
* DestIpAddress [In]
* HopCount [In/Out]
* MaxHops [In]
* RTT [In/Out]
*
* RETURNS
* BOOL
*/
BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
{
TRACE("DestIpAddress 0x%08lx, HopCount %p, MaxHops %ld, RTT %p\n",
DestIpAddress, HopCount, MaxHops, RTT);
FIXME(":stub\n");
return (BOOL) 0;
}
/******************************************************************
* GetTcpStatisticsEx (IPHLPAPI.@)
*
* PARAMS
* pStats [In/Out]
* dwFamily [In]
*
* RETURNS
* DWORD
*/
DWORD WINAPI GetTcpStatisticsEx(PMIB_TCPSTATS pStats, DWORD dwFamily)
{
DWORD ret;
TRACE("pStats %p\n", pStats);
ret = getTCPStats(pStats, dwFamily);
TRACE("returning %ld\n", ret);
return ret;
}
/******************************************************************
* GetTcpStatistics (IPHLPAPI.@)
*
* PARAMS
* pStats [In/Out]
*
* RETURNS
* DWORD
*/
DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS pStats)
{
return GetTcpStatisticsEx(pStats, PF_INET);
}
/******************************************************************
* GetTcpTable (IPHLPAPI.@)
*
* Get the table of active TCP connections.
*
* PARAMS
* pTcpTable [Out] buffer for TCP connections table
* pdwSize [In/Out] length of output buffer
* bOrder [In] whether to order the table
*
* RETURNS
* Success: NO_ERROR
* Failure: error code from winerror.h
*
* NOTES
* If pdwSize is less than required, the function will return
* ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to
* the required byte size.
* If bOrder is true, the returned table will be sorted, first by
* local address and port number, then by remote address and port
* number.
*/
DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
{
return GetExtendedTcpTable(pTcpTable, pdwSize, bOrder, AF_INET, TCP_TABLE_BASIC_ALL, 0);
}
/******************************************************************
* GetUdpStatisticsEx (IPHLPAPI.@)
*
* PARAMS
* pStats [In/Out]
* dwFamily [In]
*
* RETURNS
* DWORD
*/
DWORD WINAPI GetUdpStatisticsEx(PMIB_UDPSTATS pStats, DWORD dwFamily)
{
DWORD ret;
TRACE("pStats %p\n", pStats);
ret = getUDPStats(pStats, dwFamily);
TRACE("returning %ld\n", ret);
return ret;
}
/******************************************************************
* GetUdpStatistics (IPHLPAPI.@)
*
* PARAMS
* pStats [In/Out]
*
* RETURNS
* DWORD
*/
DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS pStats)
{
return GetUdpStatisticsEx(pStats, PF_INET);
}
/******************************************************************
* GetUdpTable (IPHLPAPI.@)
*
* PARAMS
* pUdpTable [In/Out]
* pdwSize [In/Out]
* bOrder [In]
*
* RETURNS
* DWORD
*/
DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
{
return GetExtendedUdpTable(pUdpTable, pdwSize, bOrder, AF_INET, UDP_TABLE_BASIC, 0);
}
/******************************************************************
* GetUniDirectionalAdapterInfo (IPHLPAPI.@)
*
* This is a Win98-only function to get information on "unidirectional"
* adapters. Since this is pretty nonsensical in other contexts, it
* never returns anything.
*
* PARAMS
* pIPIfInfo [Out] buffer for adapter infos
* dwOutBufLen [Out] length of the output buffer
*
* RETURNS
* Success: NO_ERROR
* Failure: error code from winerror.h
*
* FIXME
* Stub, returns ERROR_NOT_SUPPORTED.
*/
DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
{
TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
/* a unidirectional adapter?? not bloody likely! */
return ERROR_NOT_SUPPORTED;
}
/******************************************************************
* IpReleaseAddress (IPHLPAPI.@)
*
* Release an IP obtained through DHCP,
*
* PARAMS
* AdapterInfo [In] adapter to release IP address
*
* RETURNS
* Success: NO_ERROR
* Failure: error code from winerror.h
*/
DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
{
DWORD Status, Version = 0;
if (!AdapterInfo)
return ERROR_INVALID_PARAMETER;
/* Maybe we should do this in DllMain */
if (DhcpCApiInitialize(&Version) != ERROR_SUCCESS)
return ERROR_PROC_NOT_FOUND;
if (DhcpReleaseIpAddressLease(AdapterInfo->Index))
Status = ERROR_SUCCESS;
else
Status = ERROR_PROC_NOT_FOUND;
DhcpCApiCleanup();
return Status;
}
/******************************************************************
* IpRenewAddress (IPHLPAPI.@)
*
* Renew an IP obtained through DHCP.
*
* PARAMS
* AdapterInfo [In] adapter to renew IP address
*
* RETURNS
* Success: NO_ERROR
* Failure: error code from winerror.h
*/
DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
{
DWORD Status, Version = 0;
if (!AdapterInfo)
return ERROR_INVALID_PARAMETER;
/* Maybe we should do this in DllMain */
if (DhcpCApiInitialize(&Version) != ERROR_SUCCESS)
return ERROR_PROC_NOT_FOUND;
if (DhcpRenewIpAddressLease(AdapterInfo->Index))
Status = ERROR_SUCCESS;
else
Status = ERROR_PROC_NOT_FOUND;
DhcpCApiCleanup();
return Status;
}
/******************************************************************
* NotifyAddrChange (IPHLPAPI.@)
*
* Notify caller whenever the ip-interface map is changed.
*
* PARAMS
* Handle [Out] handle usable in asynchronous notification
* overlapped [In] overlapped structure that notifies the caller
*
* RETURNS
* Success: NO_ERROR
* Failure: error code from winerror.h
*
* FIXME
* Stub, returns ERROR_NOT_SUPPORTED.
*/
DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
{
FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
if (Handle) *Handle = INVALID_HANDLE_VALUE;
if (overlapped) ((IO_STATUS_BLOCK *) overlapped)->Status = STATUS_PENDING;
return ERROR_IO_PENDING;
}
/******************************************************************
* NotifyRouteChange (IPHLPAPI.@)
*
* Notify caller whenever the ip routing table is changed.
*
* PARAMS
* Handle [Out] handle usable in asynchronous notification
* overlapped [In] overlapped structure that notifies the caller
*
* RETURNS
* Success: NO_ERROR
* Failure: error code from winerror.h
*
* FIXME
* Stub, returns ERROR_NOT_SUPPORTED.
*/
DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
{
FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
return ERROR_NOT_SUPPORTED;
}
/******************************************************************
* SendARP (IPHLPAPI.@)
*
* Send an ARP request.
*
* PARAMS
* DestIP [In] attempt to obtain this IP
* SrcIP [In] optional sender IP address
* pMacAddr [Out] buffer for the mac address
* PhyAddrLen [In/Out] length of the output buffer
*
* RETURNS
* Success: NO_ERROR
* Failure: error code from winerror.h
*/
DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
{
IPAddr IPs[2];
ULONG Size;
if (IsBadWritePtr(pMacAddr, sizeof(ULONG)) || IsBadWritePtr(PhyAddrLen, sizeof(ULONG)))
return ERROR_INVALID_PARAMETER;
IPs[0] = DestIP;
IPs[1] = SrcIP;
Size = sizeof(IPs);
return TCPSendIoctl(INVALID_HANDLE_VALUE, IOCTL_QUERY_IP_HW_ADDRESS, IPs, &Size, pMacAddr, PhyAddrLen);
}
/******************************************************************
* SetIfEntry (IPHLPAPI.@)
*
* Set the administrative status of an interface.
*
* PARAMS
* pIfRow [In] dwAdminStatus member specifies the new status.
*
* RETURNS
* Success: NO_ERROR
* Failure: error code from winerror.h
*
* FIXME
* Stub, returns ERROR_NOT_SUPPORTED.
*/
DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
{
FIXME("(pIfRow %p): stub\n", pIfRow);
/* this is supposed to set an interface administratively up or down.
Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
this sort of down is indistinguishable from other sorts of down (e.g. no
link). */
return ERROR_NOT_SUPPORTED;
}
/******************************************************************
* SetIpForwardEntry (IPHLPAPI.@)
*
* Modify an existing route.
*
* PARAMS
* pRoute [In] route with the new information
*
* RETURNS
* Success: NO_ERROR
* Failure: error code from winerror.h
*/
DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
{
return setIpForwardEntry( pRoute );
}
/******************************************************************
* SetIpNetEntry (IPHLPAPI.@)
*
* Modify an existing ARP entry.
*
* PARAMS
* pArpEntry [In] ARP entry with the new information
*
* RETURNS
* Success: NO_ERROR
* Failure: error code from winerror.h
*/
DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
{
HANDLE tcpFile;
NTSTATUS status;
TCP_REQUEST_SET_INFORMATION_EX_ARP_ENTRY req =
TCP_REQUEST_SET_INFORMATION_INIT;
TDIEntityID id;
DWORD returnSize;
PMIB_IPNETROW arpBuff;
if (!pArpEntry)
return ERROR_INVALID_PARAMETER;
if (!NT_SUCCESS(openTcpFile( &tcpFile, FILE_READ_DATA | FILE_WRITE_DATA )))
return ERROR_NOT_SUPPORTED;
if (!NT_SUCCESS(getNthIpEntity( tcpFile, pArpEntry->dwIndex, &id )))
{
closeTcpFile(tcpFile);
return ERROR_INVALID_PARAMETER;
}
req.Req.ID.toi_class = INFO_CLASS_PROTOCOL;
req.Req.ID.toi_type = INFO_TYPE_PROVIDER;
req.Req.ID.toi_id = IP_MIB_ARPTABLE_ENTRY_ID;
req.Req.ID.toi_entity.tei_instance = id.tei_instance;
req.Req.ID.toi_entity.tei_entity = AT_ENTITY;
req.Req.BufferSize = sizeof(MIB_IPNETROW);
arpBuff = (PMIB_IPNETROW)&req.Req.Buffer[0];
RtlCopyMemory(arpBuff, pArpEntry, sizeof(MIB_IPNETROW));
status = DeviceIoControl( tcpFile,
IOCTL_TCP_SET_INFORMATION_EX,
&req,
sizeof(req),
NULL,
0,
&returnSize,
NULL );
closeTcpFile(tcpFile);
if (status)
return NO_ERROR;
else
return ERROR_INVALID_PARAMETER;
}
/******************************************************************
* SetIpStatistics (IPHLPAPI.@)
*
* Toggle IP forwarding and det the default TTL value.
*
* PARAMS
* pIpStats [In] IP statistics with the new information
*
* RETURNS
* Success: NO_ERROR
* Failure: error code from winerror.h
*
* FIXME
* Stub, returns NO_ERROR.
*/
DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
{
FIXME("(pIpStats %p): stub\n", pIpStats);
return 0;
}
/******************************************************************
* SetIpTTL (IPHLPAPI.@)
*
* Set the default TTL value.
*
* PARAMS
* nTTL [In] new TTL value
*
* RETURNS
* Success: NO_ERROR
* Failure: error code from winerror.h
*
* FIXME
* Stub, returns NO_ERROR.
*/
DWORD WINAPI SetIpTTL(UINT nTTL)
{
FIXME("(nTTL %d): stub\n", nTTL);
return 0;
}
/******************************************************************
* SetTcpEntry (IPHLPAPI.@)
*
* Set the state of a TCP connection.
*
* PARAMS
* pTcpRow [In] specifies connection with new state
*
* RETURNS
* Success: NO_ERROR
* Failure: error code from winerror.h
*
* FIXME
* Stub, returns NO_ERROR.
*/
DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
{
FIXME("(pTcpRow %p): stub\n", pTcpRow);
return 0;
}
/******************************************************************
* UnenableRouter (IPHLPAPI.@)
*
* Decrement the IP-forwarding reference count. Turn off IP-forwarding
* if it reaches zero.
*
* PARAMS
* pOverlapped [In/Out] should be the same as in EnableRouter()
* lpdwEnableCount [Out] optional, receives reference count
*
* RETURNS
* Success: NO_ERROR
* Failure: error code from winerror.h
*
* FIXME
* Stub, returns ERROR_NOT_SUPPORTED.
*/
DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
{
FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
lpdwEnableCount);
return ERROR_NOT_SUPPORTED;
}
/*
* @unimplemented
*/
DWORD WINAPI GetIpErrorString(IP_STATUS ErrorCode,PWCHAR Buffer,PDWORD Size)
{
FIXME(":stub\n");
return 0L;
}
/*
* @unimplemented
*/
PIP_ADAPTER_ORDER_MAP WINAPI GetAdapterOrderMap(VOID)
{
FIXME(":stub\n");
return 0L;
}
#ifdef GetAdaptersAddressesV1
DWORD WINAPI DECLSPEC_HOTPATCH GetAdaptersAddresses(ULONG Family,ULONG Flags,PVOID Reserved,PIP_ADAPTER_ADDRESSES pAdapterAddresses,PULONG pOutBufLen)
{
InterfaceIndexTable *indexTable;
IFInfo ifInfo;
int i;
ULONG ret, requiredSize = 0;
PIP_ADAPTER_ADDRESSES currentAddress;
PUCHAR currentLocation;
HANDLE tcpFile;
if (!pOutBufLen) return ERROR_INVALID_PARAMETER;
if (Reserved) return ERROR_INVALID_PARAMETER;
indexTable = getInterfaceIndexTable();
if (!indexTable)
return ERROR_NOT_ENOUGH_MEMORY;
ret = openTcpFile(&tcpFile, FILE_READ_DATA);
if (!NT_SUCCESS(ret))
{
free(indexTable);
return ERROR_NO_DATA;
}
for (i = indexTable->numIndexes; i >= 0; i--)
{
if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
NULL,
indexTable->indexes[i],
&ifInfo)))
{
/* The whole struct */
requiredSize += sizeof(IP_ADAPTER_ADDRESSES);
/* Friendly name */
if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
requiredSize += strlen((char *)ifInfo.if_info.ent.if_descr) + 1; //FIXME
/* Adapter name */
requiredSize += strlen((char *)ifInfo.if_info.ent.if_descr) + 1;
/* Unicast address */
if (!(Flags & GAA_FLAG_SKIP_UNICAST))
requiredSize += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
/* FIXME: Implement multicast, anycast, and dns server stuff */
/* FIXME: Implement dns suffix and description */
requiredSize += 2 * sizeof(WCHAR);
/* We're only going to implement what's required for XP SP0 */
}
}
TRACE("size: %d, requiredSize: %d\n", *pOutBufLen, requiredSize);
if (!pAdapterAddresses || *pOutBufLen < requiredSize)
{
*pOutBufLen = requiredSize;
closeTcpFile(tcpFile);
free(indexTable);
return ERROR_BUFFER_OVERFLOW;
}
RtlZeroMemory(pAdapterAddresses, requiredSize);
/* Let's set up the pointers */
currentAddress = pAdapterAddresses;
for (i = indexTable->numIndexes; i >= 0; i--)
{
if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
NULL,
indexTable->indexes[i],
&ifInfo)))
{
currentLocation = (PUCHAR)currentAddress + (ULONG_PTR)sizeof(IP_ADAPTER_ADDRESSES);
/* FIXME: Friendly name */
if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
{
currentAddress->FriendlyName = (PVOID)currentLocation;
currentLocation += sizeof(WCHAR);
}
/* Adapter name */
currentAddress->AdapterName = (PVOID)currentLocation;
currentLocation += strlen((char *)ifInfo.if_info.ent.if_descr) + 1;
/* Unicast address */
if (!(Flags & GAA_FLAG_SKIP_UNICAST))
{
currentAddress->FirstUnicastAddress = (PVOID)currentLocation;
currentLocation += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
currentAddress->FirstUnicastAddress->Address.lpSockaddr = (PVOID)currentLocation;
currentLocation += sizeof(struct sockaddr);
}
/* FIXME: Implement multicast, anycast, and dns server stuff */
/* FIXME: Implement dns suffix and description */
currentAddress->DnsSuffix = (PVOID)currentLocation;
currentLocation += sizeof(WCHAR);
currentAddress->Description = (PVOID)currentLocation;
currentLocation += sizeof(WCHAR);
currentAddress->Next = (PVOID)currentLocation;
/* Terminate the last address correctly */
if(i==0)
currentAddress->Next = NULL;
/* We're only going to implement what's required for XP SP0 */
currentAddress = currentAddress->Next;
}
}
/* Now again, for real this time */
currentAddress = pAdapterAddresses;
for (i = indexTable->numIndexes; i >= 0; i--)
{
if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
NULL,
indexTable->indexes[i],
&ifInfo)))
{
/* Make sure we're not looping more than we hoped for */
ASSERT(currentAddress);
/* Alignment information */
currentAddress->Length = sizeof(IP_ADAPTER_ADDRESSES);
currentAddress->IfIndex = indexTable->indexes[i];
/* Adapter name */
strcpy(currentAddress->AdapterName, (char *)ifInfo.if_info.ent.if_descr);
if (!(Flags & GAA_FLAG_SKIP_UNICAST))
{
currentAddress->FirstUnicastAddress->Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
currentAddress->FirstUnicastAddress->Flags = 0; //FIXME
currentAddress->FirstUnicastAddress->Next = NULL; //FIXME: Support more than one address per adapter
currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_family = AF_INET;
memcpy(currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_data,
&ifInfo.ip_addr.iae_addr,
sizeof(ifInfo.ip_addr.iae_addr));
currentAddress->FirstUnicastAddress->Address.iSockaddrLength = sizeof(ifInfo.ip_addr.iae_addr) + sizeof(USHORT);
currentAddress->FirstUnicastAddress->PrefixOrigin = IpPrefixOriginOther; //FIXME
currentAddress->FirstUnicastAddress->SuffixOrigin = IpPrefixOriginOther; //FIXME
currentAddress->FirstUnicastAddress->DadState = IpDadStatePreferred; //FIXME
currentAddress->FirstUnicastAddress->ValidLifetime = 0xFFFFFFFF; //FIXME
currentAddress->FirstUnicastAddress->PreferredLifetime = 0xFFFFFFFF; //FIXME
currentAddress->FirstUnicastAddress->LeaseLifetime = 0xFFFFFFFF; //FIXME
}
/* FIXME: Implement multicast, anycast, and dns server stuff */
currentAddress->FirstAnycastAddress = NULL;
currentAddress->FirstMulticastAddress = NULL;
currentAddress->FirstDnsServerAddress = NULL;
/* FIXME: Implement dns suffix, description, and friendly name */
currentAddress->DnsSuffix[0] = UNICODE_NULL;
currentAddress->Description[0] = UNICODE_NULL;
currentAddress->FriendlyName[0] = UNICODE_NULL;
/* Physical Address */
memcpy(currentAddress->PhysicalAddress, ifInfo.if_info.ent.if_physaddr, ifInfo.if_info.ent.if_physaddrlen);
currentAddress->PhysicalAddressLength = ifInfo.if_info.ent.if_physaddrlen;
/* Flags */
currentAddress->Flags = 0; //FIXME
/* MTU */
currentAddress->Mtu = ifInfo.if_info.ent.if_mtu;
/* Interface type */
currentAddress->IfType = ifInfo.if_info.ent.if_type;
/* Operational status */
if(ifInfo.if_info.ent.if_operstatus >= IF_OPER_STATUS_CONNECTING)
currentAddress->OperStatus = IfOperStatusUp;
else
currentAddress->OperStatus = IfOperStatusDown;
/* We're only going to implement what's required for XP SP0 */
/* Move to the next address */
currentAddress = currentAddress->Next;
}
}
closeTcpFile(tcpFile);
free(indexTable);
return NO_ERROR;
}
#endif
/*
* @unimplemented
*/
BOOL WINAPI CancelIPChangeNotify(LPOVERLAPPED notifyOverlapped)
{
FIXME(":stub\n");
return 0L;
}
/*
* @unimplemented
*/
DWORD WINAPI GetBestInterfaceEx(struct sockaddr *pDestAddr,PDWORD pdwBestIfIndex)
{
FIXME(":stub\n");
return 0L;
}
/*
* @unimplemented
*/
DWORD WINAPI NhpAllocateAndGetInterfaceInfoFromStack(IP_INTERFACE_NAME_INFO **ppTable,PDWORD pdwCount,BOOL bOrder,HANDLE hHeap,DWORD dwFlags)
{
FIXME(":stub\n");
return 0L;
}
/*
* @unimplemented
*/
DWORD WINAPI GetIcmpStatisticsEx(PMIB_ICMP_EX pStats,DWORD dwFamily)
{
FIXME(":stub\n");
if (!pStats)
return ERROR_INVALID_PARAMETER;
if (dwFamily != AF_INET && dwFamily != AF_INET6)
return ERROR_INVALID_PARAMETER;
return 0L;
}
DWORD WINAPI
SetIpForwardEntryToStack(PMIB_IPFORWARDROW pRoute)
{
FIXME("SetIpForwardEntryToStack() stub\n");
return 0L;
}
DWORD GetInterfaceNameInternal(_In_ const GUID * pInterfaceGUID,
_Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
_Inout_ PULONG pOutBufLen)
{
UNICODE_STRING GuidString;
DWORD result, type;
WCHAR szKeyName[2*MAX_PATH];
HRESULT hr;
HKEY hKey;
if (pInterfaceGUID == NULL || pOutBufLen == NULL)
return ERROR_INVALID_PARAMETER;
result = RtlStringFromGUID(pInterfaceGUID, &GuidString);
if (!NT_SUCCESS(result))
{
// failed to convert guid to string
return RtlNtStatusToDosError(result);
}
hr = StringCbPrintfW(szKeyName, sizeof(szKeyName), L"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection", GuidString.Buffer);
RtlFreeUnicodeString(&GuidString);
if (FAILED(hr))
{
// key name is too long
return ERROR_BUFFER_OVERFLOW;
}
result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_READ, &hKey);
if (result != ERROR_SUCCESS)
{
// failed to find adapter entry
return ERROR_NOT_FOUND;
}
result = RegQueryValueExW(hKey, L"Name", NULL, &type, (PVOID)pInterfaceName, pOutBufLen);
RegCloseKey(hKey);
if (result == ERROR_MORE_DATA)
{
*pOutBufLen = MAX_INTERFACE_NAME_LEN * 2;
return ERROR_INSUFFICIENT_BUFFER;
}
if (result != ERROR_SUCCESS || type != REG_SZ)
{
// failed to read adapter name
return ERROR_NO_DATA;
}
return ERROR_SUCCESS;
}
DWORD WINAPI
NhGetInterfaceNameFromDeviceGuid(_In_ const GUID * pInterfaceGUID,
_Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
_Inout_ PULONG pOutBufLen,
DWORD dwUnknown4,
DWORD dwUnknown5)
{
SetLastError(ERROR_SUCCESS);
if (pInterfaceName == NULL)
return ERROR_INVALID_PARAMETER;
return GetInterfaceNameInternal(pInterfaceGUID, pInterfaceName, pOutBufLen);
}
DWORD WINAPI
NhGetInterfaceNameFromGuid(_In_ const GUID * pInterfaceGUID,
_Out_writes_bytes_to_(*pOutBufLen, *pOutBufLen) PWCHAR pInterfaceName,
_Inout_ PULONG pOutBufLen,
DWORD dwUnknown4,
DWORD dwUnknown5)
{
DWORD result;
result = GetInterfaceNameInternal(pInterfaceGUID, pInterfaceName, pOutBufLen);
if (result == ERROR_NOT_FOUND)
SetLastError(ERROR_PATH_NOT_FOUND);
return result;
}