From a3ac53db3d29f8ab028ea16a418f6de4042adb29 Mon Sep 17 00:00:00 2001 From: Art Yerkes Date: Sun, 15 Feb 2004 07:17:00 +0000 Subject: [PATCH] Big merge in wine code. This merged version is far more complete than the previous one. See notes and comments by me and the original author of iphlpapi_main.c, Juan Lang. svn path=/trunk/; revision=8194 --- reactos/lib/iphlpapi/icmp.c | 117 ++ reactos/lib/iphlpapi/ifenum.h | 142 ++ reactos/lib/iphlpapi/ifenum_reactos.c | 723 ++++++++ reactos/lib/iphlpapi/iphlp_res.h | 12 + reactos/lib/iphlpapi/iphlpapi.edf | 12 +- reactos/lib/iphlpapi/iphlpapi_main.c | 2102 ++++++++++++++++++++++++ reactos/lib/iphlpapi/iphlpapiextra.h | 11 + reactos/lib/iphlpapi/iphlpv6.c | 91 + reactos/lib/iphlpapi/ipprivate.h | 97 +- reactos/lib/iphlpapi/ipregprivate.h | 10 +- reactos/lib/iphlpapi/ipstats.h | 108 ++ reactos/lib/iphlpapi/ipstats_reactos.c | 558 +++++++ reactos/lib/iphlpapi/makefile | 8 +- reactos/lib/iphlpapi/media.c | 59 + reactos/lib/iphlpapi/merge-notes.txt | 36 + reactos/lib/iphlpapi/registry.c | 32 +- reactos/lib/iphlpapi/resinfo_reactos.c | 52 + 17 files changed, 4130 insertions(+), 40 deletions(-) create mode 100644 reactos/lib/iphlpapi/icmp.c create mode 100644 reactos/lib/iphlpapi/ifenum.h create mode 100644 reactos/lib/iphlpapi/ifenum_reactos.c create mode 100644 reactos/lib/iphlpapi/iphlp_res.h create mode 100644 reactos/lib/iphlpapi/iphlpapi_main.c create mode 100644 reactos/lib/iphlpapi/iphlpapiextra.h create mode 100644 reactos/lib/iphlpapi/iphlpv6.c create mode 100644 reactos/lib/iphlpapi/ipstats.h create mode 100644 reactos/lib/iphlpapi/ipstats_reactos.c create mode 100644 reactos/lib/iphlpapi/media.c create mode 100644 reactos/lib/iphlpapi/merge-notes.txt create mode 100644 reactos/lib/iphlpapi/resinfo_reactos.c diff --git a/reactos/lib/iphlpapi/icmp.c b/reactos/lib/iphlpapi/icmp.c new file mode 100644 index 00000000000..29fa0f857a0 --- /dev/null +++ b/reactos/lib/iphlpapi/icmp.c @@ -0,0 +1,117 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#endif +#ifdef HAVE_RESOLV_H +# include +#endif + +#ifdef __REACTOS__ +# include +# include +# include +# include +# include +# include +# include +# include "iphlpapiextra.h" +#else +# include "windef.h" +# include "winbase.h" +# include "winreg.h" +#endif + +#include "iphlpapi.h" +#include "ifenum.h" +#include "ipstats.h" +#include "iphlp_res.h" +#include "wine/debug.h" + +/* + * @unimplemented + */ +DWORD +STDCALL +IcmpParseReplies( + LPVOID ReplyBuffer, + DWORD ReplySize + ) +{ + UNIMPLEMENTED + return 0L; +} + +/* + * @unimplemented + */ +HANDLE STDCALL IcmpCreateFile( + VOID + ) +{ + UNIMPLEMENTED + return 0L; +} + +/* + * @unimplemented + */ +BOOL STDCALL IcmpCloseHandle( + HANDLE IcmpHandle + ) +{ + UNIMPLEMENTED + return 0L; +} + +/* + * @unimplemented + */ +DWORD STDCALL IcmpSendEcho( + HANDLE IcmpHandle, + IPAddr DestinationAddress, + LPVOID RequestData, + WORD RequestSize, + PIP_OPTION_INFORMATION RequestOptions, + LPVOID ReplyBuffer, + DWORD ReplySize, + DWORD Timeout + ) +{ + UNIMPLEMENTED + return 0L; +} + +/* + * @unimplemented + */ +DWORD +STDCALL +IcmpSendEcho2( + HANDLE IcmpHandle, + HANDLE Event, + FARPROC ApcRoutine, + PVOID ApcContext, + IPAddr DestinationAddress, + LPVOID RequestData, + WORD RequestSize, + PIP_OPTION_INFORMATION RequestOptions, + LPVOID ReplyBuffer, + DWORD ReplySize, + DWORD Timeout + ) +{ + UNIMPLEMENTED + return 0L; +} diff --git a/reactos/lib/iphlpapi/ifenum.h b/reactos/lib/iphlpapi/ifenum.h new file mode 100644 index 00000000000..406fa0f5ada --- /dev/null +++ b/reactos/lib/iphlpapi/ifenum.h @@ -0,0 +1,142 @@ +/* ifenum.h + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This module implements functions shared by DLLs that need to enumerate + * network interfaces and addresses. It's meant to hide some problematic + * defines like socket(), as well as provide only one file + * that needs to be ported to implement these functions on different platforms, + * since the Windows API provides multiple ways to get at this info. + * + * Like Windows, it uses a numeric index to identify an interface uniquely. + * As implemented, an interface represents a UNIX network interface, virtual + * or real, and thus can have 0 or 1 IP addresses associated with it. (This + * only supports IPv4.) + * The indexes returned are not guaranteed to be contiguous, so don't call + * getNumInterfaces() and assume the values [0,getNumInterfaces() - 1] will be + * valid indexes; use getInterfaceIndexTable() instead. Non-loopback + * interfaces have lower index values than loopback interfaces, in order to + * make the indexes somewhat reusable as Netbios LANA numbers. See ifenum.c + * for more detail on this. + * + * See also the companion file, ipstats.h, for functions related to getting + * statistics. + */ +#ifndef WINE_IFENUM_H_ +#define WINE_IFENUM_H_ + +#include + +#include "windef.h" +#include "winbase.h" +#include "iprtrmib.h" + +#define MAX_INTERFACE_PHYSADDR 8 +#define MAX_INTERFACE_DESCRIPTION 256 + +/* Call before using the functions in this module */ +void interfaceMapInit(void); +/* Call to free resources allocated in interfaceMapInit() */ +void interfaceMapFree(void); + +DWORD getNumInterfaces(void); +DWORD getNumNonLoopbackInterfaces(void); + +/* A table of interface indexes, see get*InterfaceTable(). Ignore numAllocated, + * it's used during the creation of the table. + */ +typedef struct _InterfaceIndexTable { + DWORD numIndexes; + DWORD numAllocated; + DWORD indexes[1]; +} InterfaceIndexTable; + +/* Returns a table with all known interface indexes, or NULL if one could not + * be allocated. free() the returned table. + */ +InterfaceIndexTable *getInterfaceIndexTable(void); + +/* Like getInterfaceIndexTable, but filters out loopback interfaces. */ +InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void); + +/* ByName/ByIndex versions of various getter functions. */ + +/* can be used as quick check to see if you've got a valid index, returns NULL + * if not. The buffer returned may have been allocated. It should be returned + * by calling consumeInterfaceNmae. + */ +const char *getInterfaceNameByIndex(DWORD index); + +/* consume the interface name provided by getInterfaceName. */ + +void consumeInterfaceName( const char *ifname ); + +/* Fills index with the index of name, if found. Returns + * ERROR_INVALID_PARAMETER if name or index is NULL, ERROR_INVALID_DATA if name + * is not found, and NO_ERROR on success. + */ +DWORD getInterfaceIndexByName(const char *name, PDWORD index); + +/* This bunch returns IP addresses, and INADDR_ANY or INADDR_NONE if not found, + * appropriately depending on the f/n. + */ +DWORD getInterfaceIPAddrByName(const char *name); +DWORD getInterfaceIPAddrByIndex(DWORD index); +DWORD getInterfaceMaskByName(const char *name); +DWORD getInterfaceMaskByIndex(DWORD index); +DWORD getInterfaceBCastAddrByName(const char *name); +DWORD getInterfaceBCastAddrByIndex(DWORD index); + +/* Gets a few physical charactersistics of a device: MAC addr len, MAC addr, + * and type as one of the MIB_IF_TYPEs. + * len's in-out: on in, needs to say how many bytes are available in addr, + * which to be safe should be MAX_INTERFACE_PHYSADDR. On out, it's how many + * bytes were set, or how many were required if addr isn't big enough. + * Returns ERROR_INVALID_PARAMETER if name, len, addr, or type is NULL. + * Returns ERROR_INVALID_DATA if name/index isn't valid. + * Returns ERROR_INSUFFICIENT_BUFFER if addr isn't large enough for the + * physical address; *len will contain the required size. + * May return other errors, e.g. ERROR_OUTOFMEMORY or ERROR_NO_MORE_FILES, + * if internal errors occur. + * Returns NO_ERROR on success. + */ +DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr, + PDWORD type); +DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr, + PDWORD type); + +/* Get the operational status as a (MIB_)IF_OPER_STATUS type. + */ +DWORD getInterfaceStatusByName(const char *name, PDWORD status); +DWORD getInterfaceStatusByIndex(DWORD index, PDWORD status); + +DWORD getInterfaceMtuByName(const char *name, PDWORD mtu); +DWORD getInterfaceMtuByIndex(DWORD index, PDWORD mtu); + +/* Fills in the MIB_IFROW by name/index. Doesn't fill in interface statistics, + * see ipstats.h for that. + * Returns ERROR_INVALID_PARAMETER if name or entry is NULL, ERROR_INVALID_DATA + * if name/index isn't valid, and NO_ERROR otherwise. + */ +DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry); +DWORD getInterfaceEntryByIndex(DWORD index, PMIB_IFROW entry); + +/* Converts the network-order bytes in addr to a printable string. Returns + * string. + */ +char *toIPAddressString(unsigned int addr, char string[16]); + +#endif /* ndef WINE_IFENUM_H_ */ diff --git a/reactos/lib/iphlpapi/ifenum_reactos.c b/reactos/lib/iphlpapi/ifenum_reactos.c new file mode 100644 index 00000000000..9956b5e585e --- /dev/null +++ b/reactos/lib/iphlpapi/ifenum_reactos.c @@ -0,0 +1,723 @@ +/* Copyright (C) 2003 Art Yerkes + * A reimplementation of ifenum.c by 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Implementation notes + * - Our bretheren use IOCTL_TCP_QUERY_INFORMATION_EX to get information + * from tcpip.sys and IOCTL_TCP_SET_INFORMATION_EX to set info (such as + * the route table). These ioctls mirror WsControl exactly in usage. + * - This iphlpapi does not rely on any reactos-only features. + * - This implementation is meant to be largely correct. I am not, however, + * paying any attention to performance. It can be done faster, and + * someone should definately optimize this code when speed is more of a + * priority than it is now. + * + * Edited implementation notes from the original -- Basically edited to add + * information and prune things which are not accurate about this file. + * Interface index fun: + * - Windows may rely on an index being cleared in the topmost 8 bits in some + * APIs; see GetFriendlyIfIndex and the mention of "backward compatible" + * indexes. It isn't clear which APIs might fail with non-backward-compatible + * indexes, but I'll keep them bits clear just in case. + * FIXME: + * - We don't support IPv6 addresses here yet -- I moved the upper edge + * functions into iphlpv6.c (arty) + */ + +#include "ipprivate.h" +#include "ifenum.h" + +/* Globals */ +const PWCHAR TcpFileName = L"\\Device\\Tcp"; + +/* Functions */ + +void interfaceMapInit(void) +{ + /* For now, nothing */ +} + +void interfaceMapFree(void) +{ + /* Ditto. */ +} + +NTSTATUS openTcpFile(PHANDLE tcpFile) { + UNICODE_STRING fileName; + OBJECT_ATTRIBUTES objectAttributes; + IO_STATUS_BLOCK ioStatusBlock; + NTSTATUS status; + + TRACE("called.\n"); + + /* Shamelessly ripped from CreateFileW */ + RtlInitUnicodeString( &fileName, TcpFileName ); + + InitializeObjectAttributes( &objectAttributes, + &fileName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL ); + + status = NtCreateFile( tcpFile, + SYNCHRONIZE | GENERIC_EXECUTE, + &objectAttributes, + &ioStatusBlock, + NULL, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_OPEN_IF, + FILE_SYNCHRONOUS_IO_NONALERT, + 0, + 0 ); + + /* String does not need to be freed: it points to the constant + * string we provided */ + + TRACE("returning %08x\n", (int)status); + + return status; +} + +void closeTcpFile( HANDLE h ) { + TRACE("called.\n"); + NtClose( h ); +} + +/* A generic thing-getting function which interacts in the right way with + * TDI. This may seem oblique, but I'm using it to reduce code and hopefully + * make this thing easier to debug. + * + * The things returned can be any of: + * TDIEntityID + * TDIObjectID + * IFEntry + * IPSNMPInfo + * IPAddrEntry + * IPInterfaceInfo + */ +NTSTATUS tdiGetSetOfThings( HANDLE tcpFile, + DWORD toiClass, + DWORD toiType, + DWORD toiId, + DWORD teiEntity, + DWORD fixedPart, + DWORD entrySize, + PVOID *tdiEntitySet, + PDWORD numEntries ) { + TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT; + PVOID entitySet = 0; + NTSTATUS status = STATUS_SUCCESS; + DWORD allocationSizeForEntityArray = entrySize * MAX_TDI_ENTITIES, + arraySize = entrySize * MAX_TDI_ENTITIES; + + DPRINT("TdiGetSetOfThings(tcpFile %x,toiClass %x,toiType %x,toiId %x," + "teiEntity %x,fixedPart %d,entrySize %d)\n", + (int)tcpFile, + (int)toiClass, + (int)toiType, + (int)toiId, + (int)teiEntity, + (int)fixedPart, + (int)entrySize ); + + req.ID.toi_class = toiClass; + req.ID.toi_type = toiType; + req.ID.toi_id = toiId; + req.ID.toi_entity.tei_entity = teiEntity; + + /* There's a subtle problem here... + * If an interface is added at this exact instant, (as if by a PCMCIA + * card insertion), the array will still not have enough entries after + * have allocated it after the first DeviceIoControl call. + * + * We'll get around this by repeating until the number of interfaces + * stabilizes. + */ + do { + assert( !entitySet ); /* We must not have an entity set allocated */ + status = DeviceIoControl( tcpFile, + IOCTL_TCP_QUERY_INFORMATION_EX, + &req, + sizeof(req), + 0, + 0, + &allocationSizeForEntityArray, + NULL ); + + if( !NT_SUCCESS(status) ) { + DPRINT("TdiGetSetOfThings() => %08x\n", (int)status); + return status; + } + + arraySize = allocationSizeForEntityArray; + entitySet = HeapAlloc( GetProcessHeap(), 0, arraySize ); + + if( !entitySet ) { + status = STATUS_INSUFFICIENT_RESOURCES; + DPRINT("TdiGetSetOfThings() => %08x\n", (int)status); + return status; + } + + status = DeviceIoControl( tcpFile, + IOCTL_TCP_QUERY_INFORMATION_EX, + &req, + sizeof(req), + entitySet, + arraySize, + &allocationSizeForEntityArray, + NULL ); + + /* This is why we have the loop -- we might have added an adapter */ + if( arraySize == allocationSizeForEntityArray ) + break; + + HeapFree( GetProcessHeap(), 0, entitySet ); + entitySet = 0; + + if( !NT_SUCCESS(status) ) { + DPRINT("TdiGetSetOfThings() => %08x\n", (int)status); + return status; + } + + DPRINT("TdiGetSetOfThings(): Array changed size: %d -> %d.\n", + arraySize, allocationSizeForEntityArray ); + } while( TRUE ); /* We break if the array we received was the size we + * expected. Therefore, we got here because it wasn't */ + + *numEntries = (arraySize - fixedPart) / entrySize; + *tdiEntitySet = entitySet; + + DPRINT("TdiGetSetOfThings() => Success: %d things @ %08x\n", + (int)*numEntries, (int)entitySet); + + return STATUS_SUCCESS; +} + +VOID tdiFreeThingSet( PVOID things ) { + HeapFree( GetProcessHeap(), 0, things ); +} + +NTSTATUS tdiGetMibForIfEntity +( HANDLE tcpFile, DWORD entityId, IFEntrySafelySized *entry ) { + TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT; + NTSTATUS status = STATUS_SUCCESS; + DWORD returnSize; + + DPRINT("TdiGetMibForIfEntity(tcpFile %x,entityId %x)\n", + (int)tcpFile, (int)entityId); + + req.ID.toi_class = INFO_CLASS_PROTOCOL; + req.ID.toi_type = INFO_TYPE_PROVIDER; + req.ID.toi_id = IF_MIB_STATS_ID; + req.ID.toi_entity.tei_entity = IF_ENTITY; + req.ID.toi_entity.tei_instance = entityId; + + status = DeviceIoControl( tcpFile, + IOCTL_TCP_QUERY_INFORMATION_EX, + &req, + sizeof(req), + entry, + sizeof(*entry), + &returnSize, + NULL ); + + if( !NT_SUCCESS(status) ) { + TRACE("failure: %08x\n", status); + return status; + } else TRACE("Success.\n"); + + DPRINT("TdiGetMibForIfEntity() => {\n" + " if_index ....................... %x\n" + " if_type ........................ %x\n" + " if_mtu ......................... %d\n" + " if_speed ....................... %x\n" + " if_physaddrlen ................. %d\n" + " if_physaddr .................... %02x:%02x:%02x:%02x:%02x:%02x\n", + " if_descr ....................... %s\n" + "} status %08x\n", + (int)entry->offset.ent.if_index, + (int)entry->offset.ent.if_type, + (int)entry->offset.ent.if_mtu, + (int)entry->offset.ent.if_speed, + (int)entry->offset.ent.if_physaddrlen, + entry->offset.ent.if_physaddr[0] & 0xff, + entry->offset.ent.if_physaddr[1] & 0xff, + entry->offset.ent.if_physaddr[2] & 0xff, + entry->offset.ent.if_physaddr[3] & 0xff, + entry->offset.ent.if_physaddr[4] & 0xff, + entry->offset.ent.if_physaddr[5] & 0xff, + entry->offset.ent.if_descr, + (int)status); + + return status; +} + +NTSTATUS tdiGetEntityIDSet( HANDLE tcpFile, + TDIEntityID **entitySet, + PDWORD numEntities ) { + NTSTATUS status = tdiGetSetOfThings( tcpFile, + INFO_CLASS_GENERIC, + INFO_TYPE_PROVIDER, + ENTITY_LIST_ID, + GENERIC_ENTITY, + 0, + sizeof(TDIEntityID), + (PVOID *)entitySet, + numEntities ); + if( NT_SUCCESS(status) ) { + int i; + + for( i = 0; i < *numEntities; i++ ) { + DPRINT("%-4d: %04x:%08x\n", + i, + (*entitySet)[i].tei_entity, + (*entitySet)[i].tei_instance ); + } + } + + return status; +} + +static BOOL isInterface( TDIEntityID *if_maybe ) { + return + if_maybe->tei_entity == IF_ENTITY; +} + +static BOOL isLoopback( HANDLE tcpFile, TDIEntityID *loop_maybe ) { + IFEntrySafelySized entryInfo; + + tdiGetMibForIfEntity( tcpFile, + loop_maybe->tei_instance, + &entryInfo ); + + return !entryInfo.offset.ent.if_type || + entryInfo.offset.ent.if_type == IFENT_SOFTWARE_LOOPBACK; +} + +NTSTATUS tdiGetEntityType( HANDLE tcpFile, TDIEntityID *ent, PULONG type ) { + TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT; + NTSTATUS status = STATUS_SUCCESS; + DWORD returnSize; + + DPRINT("TdiGetEntityType(tcpFile %x,entityId %x)\n", + (DWORD)tcpFile, ent->tei_instance); + + req.ID.toi_class = INFO_CLASS_GENERIC; + req.ID.toi_type = INFO_TYPE_PROVIDER; + req.ID.toi_id = ENTITY_TYPE_ID; + req.ID.toi_entity.tei_entity = ent->tei_entity; + req.ID.toi_entity.tei_instance = ent->tei_instance; + + status = DeviceIoControl( tcpFile, + IOCTL_TCP_QUERY_INFORMATION_EX, + &req, + sizeof(req), + type, + sizeof(*type), + &returnSize, + NULL ); + + DPRINT("TdiGetEntityType() => %08x %08x\n", *type, status); + + return status; +} + +static DWORD getNumInterfacesInt(BOOL onlyLoopback) +{ + DWORD numEntities, numInterfaces = 0; + TDIEntityID *entitySet; + HANDLE tcpFile; + NTSTATUS status; + int i; + + status = openTcpFile( &tcpFile ); + + if( !NT_SUCCESS(status) ) { + DPRINT("getNumInterfaces: failed %08x\n", status ); + return 0; + } + + status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities ); + + if( !NT_SUCCESS(status) ) { + DPRINT("getNumInterfaces: failed %08x\n", status ); + return 0; + } + + closeTcpFile( tcpFile ); + + for( i = 0; i < numEntities; i++ ) { + if( isInterface( &entitySet[i] ) && + (!onlyLoopback || isLoopback( tcpFile, &entitySet[i] )) ) + numInterfaces++; + } + + DPRINT("getNumInterfaces: success: %d %d %08x\n", + onlyLoopback, numInterfaces, status ); + + tdiFreeThingSet( entitySet ); + + return numInterfaces; +} + +DWORD getNumInterfaces(void) +{ + return getNumInterfacesInt( FALSE ); +} + +DWORD getNumNonLoopbackInterfaces(void) +{ + return getNumInterfacesInt( TRUE ); +} + +DWORD getNthInterfaceEntity( HANDLE tcpFile, DWORD index, TDIEntityID *ent ) { + DWORD numEntities = 0; + DWORD numInterfaces = 0; + TDIEntityID *entitySet = 0; + NTSTATUS status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities ); + int i; + + if( !NT_SUCCESS(status) ) + return status; + + for( i = 0; i < numEntities; i++ ) { + if( isInterface( &entitySet[i] ) ) { + if( numInterfaces == index ) break; + else numInterfaces++; + } + } + + DPRINT("Index %d is entity #%d - %04x:%08x\n", index, i, + entitySet[i].tei_entity, entitySet[i].tei_instance ); + + if( numInterfaces == index && i < numEntities ) { + memcpy( ent, &entitySet[i], sizeof(*ent) ); + tdiFreeThingSet( entitySet ); + return STATUS_SUCCESS; + } else { + tdiFreeThingSet( entitySet ); + return STATUS_UNSUCCESSFUL; + } +} + +/* Note that the result of this operation must be freed later */ + +const char *getInterfaceNameByIndex(DWORD index) +{ + TDIEntityID ent; + IFEntrySafelySized entityInfo; + HANDLE tcpFile = INVALID_HANDLE_VALUE; + NTSTATUS status = STATUS_SUCCESS; + PCHAR interfaceName = 0; + char simple_name_buf[100]; + char *adapter_name; + + status = openTcpFile( &tcpFile ); + if( !NT_SUCCESS(status) ) { + DPRINT("failed %08x\n", status ); + return 0; + } + + status = getNthInterfaceEntity( tcpFile, index, &ent ); + + if( !NT_SUCCESS(status) ) { + DPRINT("failed %08x\n", status ); + return 0; + } + + status = tdiGetMibForIfEntity( tcpFile, + ent.tei_instance, + &entityInfo ); + if( NT_SUCCESS(status) ) { + adapter_name = entityInfo.offset.ent.if_descr; + } else { + sprintf( simple_name_buf, "eth%x", + (int)ent.tei_instance ); + adapter_name = simple_name_buf; + } + interfaceName = HeapAlloc( GetProcessHeap(), 0, + strlen(adapter_name) + 1 ); + strcpy( interfaceName, adapter_name ); + + closeTcpFile( tcpFile ); + + return interfaceName; +} + +void consumeInterfaceName(const char *name) { + HeapFree( GetProcessHeap(), 0, (char *)name ); +} + +DWORD getInterfaceIndexByName(const char *name, PDWORD index) +{ + DWORD ret = STATUS_SUCCESS; + int numInterfaces = getNumInterfaces(); + const char *iname = 0; + int i; + HANDLE tcpFile; + + ret = openTcpFile( &tcpFile ); + + if( !NT_SUCCESS(ret) ) { + DPRINT("Failure: %08x\n", ret); + return ret; + } + + for( i = 0; i < numInterfaces; i++ ) { + iname = getInterfaceNameByIndex( i ); + if( !strcmp(iname, name) ) { + *index = i; + } + HeapFree( GetProcessHeap(), 0, (char *)iname ); + } + + closeTcpFile( tcpFile ); + + return ret; +} + +InterfaceIndexTable *getInterfaceIndexTableInt( BOOL nonLoopbackOnly ) { + HANDLE tcpFile; + DWORD numInterfaces, curInterface = 0; + int i; + InterfaceIndexTable *ret; + TDIEntityID *entitySet; + DWORD numEntities; + NTSTATUS status; + + numInterfaces = getNumInterfaces(); + TRACE("getInterfaceIndexTable: numInterfaces: %d\n", numInterfaces); + ret = (InterfaceIndexTable *)calloc(1, + sizeof(InterfaceIndexTable) + (numInterfaces - 1) * sizeof(DWORD)); + if (ret) { + ret->numAllocated = numInterfaces; + } + + status = openTcpFile( &tcpFile ); + tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities ); + + for( i = 0; i < numEntities; i++ ) { + if( isInterface( &entitySet[i] ) && + (!nonLoopbackOnly || !isLoopback( tcpFile, &entitySet[i] )) ) { + ret->indexes[curInterface++] = entitySet[i].tei_instance; + } + } + + tdiFreeThingSet( entitySet ); + closeTcpFile( tcpFile ); + ret->numIndexes = curInterface; + + return ret; +} + +InterfaceIndexTable *getInterfaceIndexTable(void) { + return getInterfaceIndexTableInt( FALSE ); +} + +InterfaceIndexTable *getNonLoopbackInterfaceIndexTable(void) { + return getInterfaceIndexTableInt( TRUE ); +} + +DWORD getInterfaceIPAddrByName(const char *name) +{ + return INADDR_ANY; +} + +DWORD getInterfaceIPAddrByIndex(DWORD index) +{ + return INADDR_ANY; +} + +DWORD getInterfaceBCastAddrByName(const char *name) +{ + return INADDR_ANY; +} + +DWORD getInterfaceBCastAddrByIndex(DWORD index) +{ + return INADDR_ANY; +} + +DWORD getInterfaceMaskByName(const char *name) +{ + DWORD ret = INADDR_NONE; + return ret; +} + +DWORD getInterfaceMaskByIndex(DWORD index) +{ + DWORD ret = INADDR_NONE; + return ret; +} + +DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr, + PDWORD type) +{ + DWORD ret; + DWORD addrLen; + + if (!name || !len || !addr || !type) + return ERROR_INVALID_PARAMETER; + + if (addrLen > *len) { + ret = ERROR_INSUFFICIENT_BUFFER; + *len = addrLen; + } + else { + /* zero out remaining bytes for broken implementations */ + memset(addr + addrLen, 0, *len - addrLen); + *len = addrLen; + ret = NO_ERROR; + } + + ret = ERROR_NO_MORE_FILES; + return ret; +} + +DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr, + PDWORD type) +{ + const char *name = getInterfaceNameByIndex(index); + + if (name) + return getInterfacePhysicalByName(name, len, addr, type); + else + return ERROR_INVALID_DATA; +} + +DWORD getInterfaceMtuByName(const char *name, PDWORD mtu) +{ + *mtu = 0; + return ERROR_SUCCESS; +} + +DWORD getInterfaceMtuByIndex(DWORD index, PDWORD mtu) +{ + const char *name = getInterfaceNameByIndex(index); + + if (name) + return getInterfaceMtuByName(name, mtu); + else + return ERROR_INVALID_DATA; +} + +DWORD getInterfaceStatusByName(const char *name, PDWORD status) +{ + DWORD ret; + + if (!name) + return ERROR_INVALID_PARAMETER; + if (!status) + return ERROR_INVALID_PARAMETER; + + ret = ERROR_NO_MORE_FILES; + return ret; +} + +DWORD getInterfaceStatusByIndex(DWORD index, PDWORD status) +{ + const char *name = getInterfaceNameByIndex(index); + + if (name) + return getInterfaceStatusByName(name, status); + else + return ERROR_INVALID_DATA; +} + +DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry) +{ + BYTE addr[MAX_INTERFACE_PHYSADDR]; + DWORD ret, len = sizeof(addr), type; + + if (!name) + return ERROR_INVALID_PARAMETER; + if (!entry) + return ERROR_INVALID_PARAMETER; + + if (getInterfacePhysicalByName(name, &len, addr, &type) == NO_ERROR) { + WCHAR *assigner; + const char *walker; + + memset(entry, 0, sizeof(MIB_IFROW)); + for (assigner = entry->wszName, walker = name; *walker; + walker++, assigner++) + *assigner = *walker; + *assigner = 0; + getInterfaceIndexByName(name, &entry->dwIndex); + entry->dwPhysAddrLen = len; + memcpy(entry->bPhysAddr, addr, len); + memset(entry->bPhysAddr + len, 0, sizeof(entry->bPhysAddr) - len); + entry->dwType = type; + /* FIXME: how to calculate real speed? */ + getInterfaceMtuByName(name, &entry->dwMtu); + /* lie, there's no "administratively down" here */ + entry->dwAdminStatus = MIB_IF_ADMIN_STATUS_UP; + getInterfaceStatusByName(name, &entry->dwOperStatus); + /* punt on dwLastChange? */ + entry->dwDescrLen = min(strlen(name), MAX_INTERFACE_DESCRIPTION - 1); + memcpy(entry->bDescr, name, entry->dwDescrLen); + entry->bDescr[entry->dwDescrLen] = '\0'; + entry->dwDescrLen++; + ret = NO_ERROR; + } + else + ret = ERROR_INVALID_DATA; + return ret; +} + +DWORD getInterfaceEntryByIndex(DWORD index, PMIB_IFROW entry) +{ + HANDLE tcpFile; + NTSTATUS status = openTcpFile( &tcpFile ); + TDIEntityID entity; + + DPRINT("Called.\n"); + + if( !NT_SUCCESS(status) ) { + DPRINT("Failed: %08x\n", status); + return status; + } + + status = getNthInterfaceEntity( tcpFile, index, &entity ); + + if( !NT_SUCCESS(status) ) { + DPRINT("Failed: %08x\n", status); + closeTcpFile( tcpFile ); + return status; + } + + status = tdiGetMibForIfEntity( tcpFile, + entity.tei_instance, + (IFEntrySafelySized *) + &entry->wszName[MAX_INTERFACE_NAME_LEN] ); + + closeTcpFile( tcpFile ); + return status; +} + +char *toIPAddressString(unsigned int addr, char string[16]) +{ + if (string) { + struct in_addr iAddr; + + iAddr.s_addr = addr; + /* extra-anal, just to make auditors happy */ + strncpy(string, inet_ntoa(iAddr), 16); + string[16] = '\0'; + } + return string; +} diff --git a/reactos/lib/iphlpapi/iphlp_res.h b/reactos/lib/iphlpapi/iphlp_res.h new file mode 100644 index 00000000000..81d41b27de7 --- /dev/null +++ b/reactos/lib/iphlpapi/iphlp_res.h @@ -0,0 +1,12 @@ +#ifndef _IPHLP_RES_H +#define _IPHLP_RES_H + +typedef struct _IPHLP_RES_INFO { + DWORD riCount; + LPSOCKADDR riAddressList; +} IPHLP_RES_INFO, *PIPHLP_RES_INFO; + +PIPHLP_RES_INFO getResInfo(); +VOID disposeResInfo( PIPHLP_RES_INFO InfoPtr ); + +#endif/*_IPHLP_RES_H*/ diff --git a/reactos/lib/iphlpapi/iphlpapi.edf b/reactos/lib/iphlpapi/iphlpapi.edf index ee7dffebed0..7c42cd373e1 100644 --- a/reactos/lib/iphlpapi/iphlpapi.edf +++ b/reactos/lib/iphlpapi/iphlpapi.edf @@ -19,14 +19,14 @@ GetUdpTable=GetUdpTable@12 FlushIpNetTable=FlushIpNetTable@4 ;IpHlpDllEntry ;AllocateAndGetArpEntTableFromStack -AllocateAndGetIfTableFromStack@16 -AllocateAndGetIpAddrTableFromStack@16 -AllocateAndGetIpForwardTableFromStack@16 -AllocateAndGetIpNetTableFromStack@16 +AllocateAndGetIfTableFromStack=AllocateAndGetIfTableFromStack@16 +AllocateAndGetIpAddrTableFromStack=AllocateAndGetIpAddrTableFromStack@16 +AllocateAndGetIpForwardTableFromStack=AllocateAndGetIpForwardTableFromStack@16 +AllocateAndGetIpNetTableFromStack=AllocateAndGetIpNetTableFromStack@16 ;AllocateAndGetTcpExTableFromStack -AllocateAndGetTcpTableFromStack@16 +AllocateAndGetTcpTableFromStack=AllocateAndGetTcpTableFromStack@16 ;AllocateAndGetUdpExTableFromStack -AllocateAndGetUdpTableFromStack@16 +AllocateAndGetUdpTableFromStack=AllocateAndGetUdpTableFromStack@16 CreateIpNetEntry=CreateIpNetEntry@4 CreateProxyArpEntry=CreateProxyArpEntry@12 DeleteIPAddress=DeleteIPAddress@4 diff --git a/reactos/lib/iphlpapi/iphlpapi_main.c b/reactos/lib/iphlpapi/iphlpapi_main.c new file mode 100644 index 00000000000..8a93ef03087 --- /dev/null +++ b/reactos/lib/iphlpapi/iphlpapi_main.c @@ -0,0 +1,2102 @@ +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#endif +#ifdef HAVE_RESOLV_H +# include +#endif + +#ifdef __REACTOS__ +# include +# include +# include +# include +# include +# include +# include +# include "iphlpapiextra.h" +# include "wine/debug.h" +#else +# include "windef.h" +# include "winbase.h" +# include "winreg.h" +# include "debug.h" +#endif + +#include +#include "iphlpapi.h" +#include "ifenum.h" +#include "ipstats.h" +#include "iphlp_res.h" + +WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi); + +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 IpMask, DWORD IfIndex, PULONG NTEContext, PULONG NTEInstance) +{ + FIXME(":stub\n"); + /* marking Win2K+ functions not supported */ + return ERROR_NOT_SUPPORTED; +} + + +/****************************************************************** + * 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; + + TRACE("ppIfTable %p, bOrder %ld, heap 0x%08lx, flags 0x%08lx\n", ppIfTable, + (DWORD)bOrder, (DWORD)heap, flags); + if (!ppIfTable) + ret = ERROR_INVALID_PARAMETER; + else { + DWORD dwSize = 0; + + ret = GetIfTable(*ppIfTable, &dwSize, bOrder); + if (ret == ERROR_INSUFFICIENT_BUFFER) { + *ppIfTable = (PMIB_IFTABLE)HeapAlloc(heap, flags, dwSize); + ret = GetIfTable(*ppIfTable, &dwSize, bOrder); + } + } + TRACE("returning %ld\n", ret); + 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; + + TRACE("ppIpAddrTable %p, bOrder %ld, heap 0x%08lx, flags 0x%08lx\n", + ppIpAddrTable, (DWORD)bOrder, (DWORD)heap, flags); + if (!ppIpAddrTable) + ret = ERROR_INVALID_PARAMETER; + else { + DWORD dwSize = 0; + + ret = GetIpAddrTable(*ppIpAddrTable, &dwSize, bOrder); + if (ret == ERROR_INSUFFICIENT_BUFFER) { + *ppIpAddrTable = (PMIB_IPADDRTABLE)HeapAlloc(heap, flags, dwSize); + ret = GetIpAddrTable(*ppIpAddrTable, &dwSize, bOrder); + } + } + TRACE("returning %ld\n", ret); + 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; + + TRACE("ppIpForwardTable %p, bOrder %ld, heap 0x%08lx, flags 0x%08lx\n", + ppIpForwardTable, (DWORD)bOrder, (DWORD)heap, flags); + if (!ppIpForwardTable) + ret = ERROR_INVALID_PARAMETER; + else { + DWORD dwSize = 0; + + ret = GetIpForwardTable(*ppIpForwardTable, &dwSize, bOrder); + if (ret == ERROR_INSUFFICIENT_BUFFER) { + *ppIpForwardTable = (PMIB_IPFORWARDTABLE)HeapAlloc(heap, flags, dwSize); + ret = GetIpForwardTable(*ppIpForwardTable, &dwSize, bOrder); + } + } + TRACE("returning %ld\n", ret); + 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; + + TRACE("ppIpNetTable %p, bOrder %ld, heap 0x%08lx, flags 0x%08lx\n", + ppIpNetTable, (DWORD)bOrder, (DWORD)heap, flags); + if (!ppIpNetTable) + ret = ERROR_INVALID_PARAMETER; + else { + DWORD dwSize = 0; + + ret = GetIpNetTable(*ppIpNetTable, &dwSize, bOrder); + if (ret == ERROR_INSUFFICIENT_BUFFER) { + *ppIpNetTable = (PMIB_IPNETTABLE)HeapAlloc(heap, flags, dwSize); + ret = GetIpNetTable(*ppIpNetTable, &dwSize, bOrder); + } + } + TRACE("returning %ld\n", ret); + 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; + + TRACE("ppTcpTable %p, bOrder %ld, heap 0x%08lx, flags 0x%08lx\n", + ppTcpTable, (DWORD)bOrder, (DWORD)heap, flags); + if (!ppTcpTable) + ret = ERROR_INVALID_PARAMETER; + else { + DWORD dwSize = 0; + + ret = GetTcpTable(*ppTcpTable, &dwSize, bOrder); + if (ret == ERROR_INSUFFICIENT_BUFFER) { + *ppTcpTable = (PMIB_TCPTABLE)HeapAlloc(heap, flags, dwSize); + ret = GetTcpTable(*ppTcpTable, &dwSize, bOrder); + } + } + TRACE("returning %ld\n", ret); + 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; + + TRACE("ppUdpTable %p, bOrder %ld, heap 0x%08lx, flags 0x%08lx\n", + ppUdpTable, (DWORD)bOrder, (DWORD)heap, flags); + if (!ppUdpTable) + ret = ERROR_INVALID_PARAMETER; + else { + DWORD dwSize = 0; + + ret = GetUdpTable(*ppUdpTable, &dwSize, bOrder); + if (ret == ERROR_INSUFFICIENT_BUFFER) { + *ppUdpTable = (PMIB_UDPTABLE)HeapAlloc(heap, flags, dwSize); + ret = GetUdpTable(*ppUdpTable, &dwSize, bOrder); + } + } + TRACE("returning %ld\n", ret); + return ret; +} + + +/****************************************************************** + * CreateIpForwardEntry (IPHLPAPI.@) + * + * + * PARAMS + * + * pRoute [In/Out] + * + * RETURNS + * + * DWORD + * + */ +DWORD WINAPI CreateIpForwardEntry(PMIB_IPFORWARDROW pRoute) +{ + TRACE("pRoute %p\n", pRoute); + /* could use SIOCADDRT, not sure I want to */ + FIXME(":stub\n"); + return (DWORD) 0; +} + + +/****************************************************************** + * CreateIpNetEntry (IPHLPAPI.@) + * + * + * PARAMS + * + * pArpEntry [In/Out] + * + * RETURNS + * + * DWORD + * + */ +DWORD WINAPI CreateIpNetEntry(PMIB_IPNETROW pArpEntry) +{ + TRACE("pArpEntry %p\n", 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) +{ + TRACE("dwAddress 0x%08lx, dwMask 0x%08lx, dwIfIndex 0x%08lx\n", dwAddress, + dwMask, 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); + FIXME(":stub\n"); + /* marking Win2K+ functions not supported */ + return ERROR_NOT_SUPPORTED; +} + + +/****************************************************************** + * DeleteIpForwardEntry (IPHLPAPI.@) + * + * + * PARAMS + * + * pRoute [In/Out] + * + * RETURNS + * + * DWORD + * + */ +DWORD WINAPI DeleteIpForwardEntry(PMIB_IPFORWARDROW pRoute) +{ + TRACE("pRoute %p\n", pRoute); + /* could use SIOCDELRT, not sure I want to */ + FIXME(":stub\n"); + return (DWORD) 0; +} + + +/****************************************************************** + * DeleteIpNetEntry (IPHLPAPI.@) + * + * + * PARAMS + * + * pArpEntry [In/Out] + * + * RETURNS + * + * DWORD + * + */ +DWORD WINAPI DeleteIpNetEntry(PMIB_IPNETROW pArpEntry) +{ + TRACE("pArpEntry %p\n", 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) +{ + TRACE("dwAddress 0x%08lx, dwMask 0x%08lx, dwIfIndex 0x%08lx\n", dwAddress, + dwMask, 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) +{ + TRACE("pHandle %p, pOverlapped %p\n", pHandle, 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) +{ + TRACE("dwIfIndex 0x%08lx\n", 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) +{ + TRACE("AdapterName %p, IfIndex %p\n", AdapterName, 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; + + 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, + 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, + 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]); + + /* 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); + 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, matchedBits, matchedNdx = 0; + + for (ndx = 0, matchedBits = 0; ndx < table->dwNumEntries; ndx++) { + if ((dwDestAddr & table->table[ndx].dwForwardMask) == + (table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) { + DWORD numShifts, mask; + + for (numShifts = 0, mask = table->table[ndx].dwForwardMask; + mask && !(mask & 1); mask >>= 1, numShifts++) + ; + if (numShifts > matchedBits) { + matchedBits = numShifts; + 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; +} + + +/****************************************************************** + * 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 = getInterfaceStatsByIndex(pIfRow->dwIndex, 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(); + TRACE("GetIfTable: numInterfaces = %d\n", (int)numInterfaces); + ULONG 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 numInterfaces = getNumInterfaces(); + ULONG size = sizeof(IP_INTERFACE_INFO) + (numInterfaces - 1) * + sizeof(IP_ADAPTER_INDEX_MAP); + + if (!pIfTable || *dwOutBufLen < size) { + *dwOutBufLen = size; + ret = ERROR_INSUFFICIENT_BUFFER; + } + else { + InterfaceIndexTable *table = getInterfaceIndexTable(); + + if (table) { + size = sizeof(IP_INTERFACE_INFO) + (table->numIndexes - 1) * + 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; + } + free(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; + + TRACE("pIpNetTable %p, pdwSize %p, bOrder %ld\n", pIpNetTable, pdwSize, + (DWORD)bOrder); + if (!pdwSize) + ret = ERROR_INVALID_PARAMETER; + else { + DWORD numEntries = getNumArpEntries(); + ULONG size = sizeof(MIB_IPNETTABLE) + (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) + (table->dwNumEntries - 1) * + sizeof(MIB_IPNETROW); + if (*pdwSize < size) { + *pdwSize = size; + ret = ERROR_INSUFFICIENT_BUFFER; + } + else { + memcpy(pIpNetTable, table, size); + if (bOrder) + qsort(pIpNetTable->table, pIpNetTable->dwNumEntries, + sizeof(MIB_IPNETROW), IpNetTableSorter); + ret = NO_ERROR; + } + free(table); + } + else + ret = ERROR_OUTOFMEMORY; + } + } + TRACE("returning %ld\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; + 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; + + TRACE("resInfo->riCount = %d\n", resInfo->riCount); + + size = sizeof(FIXED_INFO) + (resInfo->riCount > 0 ? (resInfo->riCount - 1) * + sizeof(IP_ADDR_STRING) : 0); + if (!pFixedInfo || *pOutBufLen < size) { + *pOutBufLen = size; + disposeResInfo( resInfo ); + return ERROR_BUFFER_OVERFLOW; + } + + memset(pFixedInfo, 0, size); + size = sizeof(pFixedInfo->HostName); + GetComputerNameExA(ComputerNameDnsHostname, pFixedInfo->HostName, &size); + size = sizeof(pFixedInfo->DomainName); + GetComputerNameExA(ComputerNameDnsDomain, pFixedInfo->DomainName, &size); + + TRACE("GetComputerNameExA: %s\n", pFixedInfo->DomainName); + + if (resInfo->riCount > 0) { + PIP_ADDR_STRING ptr; + int i; + + for (i = 0, ptr = &pFixedInfo->DnsServerList; i < resInfo->riCount && ptr; + i++, ptr = ptr->Next) { + toIPAddressString + (((PSOCKADDR_IN)&resInfo->riAddressList[i])->sin_addr.s_addr, + ptr->IpAddress.String); + if (i == resInfo->riCount - 1) + ptr->Next = NULL; + else if (i == 0) + ptr->Next = (PIP_ADDR_STRING)((LPBYTE)pFixedInfo + sizeof(FIXED_INFO)); + else + ptr->Next = (PIP_ADDR_STRING)((PBYTE)ptr + sizeof(IP_ADDR_STRING)); + } + } + 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, 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; +} + + +/****************************************************************** + * 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) +{ + TRACE("IfIndex %ld, pPerAdapterInfo %p, pOutBufLen %p\n", IfIndex, + pPerAdapterInfo, pOutBufLen); + FIXME(":stub\n"); + /* marking Win2K+ functions not supported */ + return ERROR_NOT_SUPPORTED; +} + + +/****************************************************************** + * 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); +} + + +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; +} + + +/****************************************************************** + * GetTcpTable (IPHLPAPI.@) + * + * + * PARAMS + * + * pTcpTable [In/Out] + * pdwSize [In/Out] + * bOrder [In] + * + * RETURNS + * + * DWORD + * + */ +DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder) +{ + DWORD ret; + + TRACE("pTcpTable %p, pdwSize %p, bOrder %ld\n", pTcpTable, pdwSize, + (DWORD)bOrder); + if (!pdwSize) + ret = ERROR_INVALID_PARAMETER; + else { + DWORD numEntries = getNumTcpEntries(); + ULONG size = sizeof(MIB_TCPTABLE) + (numEntries - 1) * sizeof(MIB_TCPROW); + + if (!pTcpTable || *pdwSize < size) { + *pdwSize = size; + ret = ERROR_INSUFFICIENT_BUFFER; + } + else { + PMIB_TCPTABLE table = getTcpTable(); + + if (table) { + size = sizeof(MIB_TCPTABLE) + (table->dwNumEntries - 1) * + sizeof(MIB_TCPROW); + if (*pdwSize < size) { + *pdwSize = size; + ret = ERROR_INSUFFICIENT_BUFFER; + } + else { + memcpy(pTcpTable, table, size); + if (bOrder) + qsort(pTcpTable->table, pTcpTable->dwNumEntries, + sizeof(MIB_TCPROW), TcpTableSorter); + ret = NO_ERROR; + } + free(table); + } + else + ret = ERROR_OUTOFMEMORY; + } + } + TRACE("returning %ld\n", ret); + return ret; +} + + +/****************************************************************** + * 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); +} + + +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; +} + + +/****************************************************************** + * GetUdpTable (IPHLPAPI.@) + * + * + * PARAMS + * + * pUdpTable [In/Out] + * pdwSize [In/Out] + * bOrder [In] + * + * RETURNS + * + * DWORD + * + */ +DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder) +{ + DWORD ret; + + TRACE("pUdpTable %p, pdwSize %p, bOrder %ld\n", pUdpTable, pdwSize, + (DWORD)bOrder); + if (!pdwSize) + ret = ERROR_INVALID_PARAMETER; + else { + DWORD numEntries = getNumUdpEntries(); + ULONG size = sizeof(MIB_UDPTABLE) + (numEntries - 1) * sizeof(MIB_UDPROW); + + if (!pUdpTable || *pdwSize < size) { + *pdwSize = size; + ret = ERROR_INSUFFICIENT_BUFFER; + } + else { + PMIB_UDPTABLE table = getUdpTable(); + + if (table) { + size = sizeof(MIB_UDPTABLE) + (table->dwNumEntries - 1) * + sizeof(MIB_UDPROW); + if (*pdwSize < size) { + *pdwSize = size; + ret = ERROR_INSUFFICIENT_BUFFER; + } + else { + memcpy(pUdpTable, table, size); + if (bOrder) + qsort(pUdpTable->table, pUdpTable->dwNumEntries, + sizeof(MIB_UDPROW), UdpTableSorter); + ret = NO_ERROR; + } + free(table); + } + else + ret = ERROR_OUTOFMEMORY; + } + } + TRACE("returning %ld\n", ret); + return ret; +} + + +/****************************************************************** + * GetUniDirectionalAdapterInfo (IPHLPAPI.@) + * + * + * PARAMS + * + * pIPIfInfo [In/Out] + * dwOutBufLen [In/Out] + * + * RETURNS + * + * DWORD + * + */ +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.@) + * + * + * PARAMS + * + * AdapterInfo [In/Out] + * + * RETURNS + * + * DWORD + * + */ +DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo) +{ + TRACE("AdapterInfo %p\n", AdapterInfo); + /* not a stub, never going to support this (and I never mark an adapter as + DHCP enabled, see GetAdaptersInfo, so this should never get called) */ + return ERROR_NOT_SUPPORTED; +} + + +/****************************************************************** + * IpRenewAddress (IPHLPAPI.@) + * + * + * PARAMS + * + * AdapterInfo [In/Out] + * + * RETURNS + * + * DWORD + * + */ +DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo) +{ + TRACE("AdapterInfo %p\n", AdapterInfo); + /* not a stub, never going to support this (and I never mark an adapter as + DHCP enabled, see GetAdaptersInfo, so this should never get called) */ + return ERROR_NOT_SUPPORTED; +} + + +/****************************************************************** + * NotifyAddrChange (IPHLPAPI.@) + * + * + * PARAMS + * + * Handle [In/Out] + * overlapped [In/Out] + * + * RETURNS + * + * DWORD + * + */ +DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped) +{ + TRACE("Handle %p, overlapped %p\n", Handle, overlapped); + FIXME(":stub\n"); + /* marking Win2K+ functions not supported */ + return ERROR_NOT_SUPPORTED; +} + + +/****************************************************************** + * NotifyRouteChange (IPHLPAPI.@) + * + * + * PARAMS + * + * Handle [In/Out] + * overlapped [In/Out] + * + * RETURNS + * + * DWORD + * + */ +DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped) +{ + TRACE("Handle %p, overlapped %p\n", Handle, overlapped); + FIXME(":stub\n"); + /* marking Win2K+ functions not supported */ + return ERROR_NOT_SUPPORTED; +} + + +/****************************************************************** + * SendARP (IPHLPAPI.@) + * + * + * PARAMS + * + * DestIP [In] + * SrcIP [In] + * pMacAddr [In/Out] + * PhyAddrLen [In/Out] + * + * RETURNS + * + * DWORD + * + */ +DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen) +{ + TRACE("DestIP 0x%08lx, SrcIP 0x%08lx, pMacAddr %p, PhyAddrLen %p\n", DestIP, + SrcIP, pMacAddr, PhyAddrLen); + FIXME(":stub\n"); + /* marking Win2K+ functions not supported */ + return ERROR_NOT_SUPPORTED; +} + + +/****************************************************************** + * SetIfEntry (IPHLPAPI.@) + * + * + * PARAMS + * + * pIfRow [In/Out] + * + * RETURNS + * + * DWORD + * + */ +DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow) +{ + TRACE("pIfRow %p\n", pIfRow); + /* this is supposed to set an administratively interface 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). */ + FIXME(":stub\n"); + return ERROR_NOT_SUPPORTED; +} + + +/****************************************************************** + * SetIpForwardEntry (IPHLPAPI.@) + * + * + * PARAMS + * + * pRoute [In/Out] + * + * RETURNS + * + * DWORD + * + */ +DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute) +{ + TRACE("pRoute %p\n", pRoute); + /* this is to add a route entry, how's it distinguishable from + CreateIpForwardEntry? + could use SIOCADDRT, not sure I want to */ + FIXME(":stub\n"); + return (DWORD) 0; +} + + +/****************************************************************** + * SetIpNetEntry (IPHLPAPI.@) + * + * + * PARAMS + * + * pArpEntry [In/Out] + * + * RETURNS + * + * DWORD + * + */ +DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry) +{ + TRACE("pArpEntry %p\n", pArpEntry); + /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */ + FIXME(":stub\n"); + return (DWORD) 0; +} + + +/****************************************************************** + * SetIpStatistics (IPHLPAPI.@) + * + * + * PARAMS + * + * pIpStats [In/Out] + * + * RETURNS + * + * DWORD + * + */ +DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats) +{ + TRACE("pIpStats %p\n", pIpStats); + FIXME(":stub\n"); + return (DWORD) 0; +} + + +/****************************************************************** + * SetIpTTL (IPHLPAPI.@) + * + * + * PARAMS + * + * nTTL [In] + * + * RETURNS + * + * DWORD + * + */ +DWORD WINAPI SetIpTTL(UINT nTTL) +{ + TRACE("nTTL %d\n", nTTL); + /* could echo nTTL > /proc/net/sys/net/ipv4/ip_default_ttl, not sure I + want to. Could map EACCESS to ERROR_ACCESS_DENIED, I suppose */ + FIXME(":stub\n"); + return (DWORD) 0; +} + + +/****************************************************************** + * SetTcpEntry (IPHLPAPI.@) + * + * + * PARAMS + * + * pTcpRow [In/Out] + * + * RETURNS + * + * DWORD + * + */ +DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow) +{ + TRACE("pTcpRow %p\n", pTcpRow); + FIXME(":stub\n"); + return (DWORD) 0; +} + + +/****************************************************************** + * UnenableRouter (IPHLPAPI.@) + * + * + * PARAMS + * + * pOverlapped [In/Out] + * lpdwEnableCount [In/Out] + * + * RETURNS + * + * DWORD + * + */ +DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount) +{ + TRACE("pOverlapped %p, lpdwEnableCount %p\n", pOverlapped, lpdwEnableCount); + FIXME(":stub\n"); + /* could echo "0" > /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; +} + +/* + * @unimplemented + */ +DWORD STDCALL GetIpErrorString(IP_STATUS ErrorCode,PWCHAR Buffer,PDWORD Size) +{ + UNIMPLEMENTED + return 0L; +} + + +/* + * @unimplemented + */ +PIP_ADAPTER_ORDER_MAP STDCALL GetAdapterOrderMap(VOID) +{ + UNIMPLEMENTED + return 0L; +} + +/* + * @unimplemented + */ +DWORD STDCALL GetAdaptersAddresses(ULONG Family,DWORD Flags,PVOID Reserved,PIP_ADAPTER_ADDRESSES pAdapterAddresses,PULONG pOutBufLen) +{ + UNIMPLEMENTED + return 0L; +} + +/* + * @unimplemented + */ +BOOL STDCALL CancelIPChangeNotify(LPOVERLAPPED notifyOverlapped) +{ + UNIMPLEMENTED + return 0L; +} + +/* + * @unimplemented + */ +DWORD STDCALL GetBestInterfaceEx(struct sockaddr *pDestAddr,PDWORD pdwBestIfIndex) +{ + UNIMPLEMENTED + return 0L; +} + +/* + * @unimplemented + */ +DWORD STDCALL NhpAllocateAndGetInterfaceInfoFromStack(IP_INTERFACE_NAME_INFO **ppTable,PDWORD pdwCount,BOOL bOrder,HANDLE hHeap,DWORD dwFlags) +{ + UNIMPLEMENTED + return 0L; +} + +/* + * @unimplemented + */ +DWORD STDCALL GetIcmpStatisticsEx(PMIB_ICMP_EX pStats,DWORD dwFamily) +{ + UNIMPLEMENTED + return 0L; +} + diff --git a/reactos/lib/iphlpapi/iphlpapiextra.h b/reactos/lib/iphlpapi/iphlpapiextra.h new file mode 100644 index 00000000000..3aa0ae4d8c0 --- /dev/null +++ b/reactos/lib/iphlpapi/iphlpapiextra.h @@ -0,0 +1,11 @@ +#ifndef _IPHLPAPIEXTRA_H +#define _IPHLPAPIEXTRA_H + +#include +/* This is here until we switch to version 2.5 of the mingw headers */ +#if (__W32API_MAJOR_VERSION < 2 || __W32API_MINOR_VERSION < 5) +BOOL WINAPI +GetComputerNameExA(COMPUTER_NAME_FORMAT,LPSTR,LPDWORD); +#endif + +#endif/*_IPHLPAPIEXTRA_H*/ diff --git a/reactos/lib/iphlpapi/iphlpv6.c b/reactos/lib/iphlpapi/iphlpv6.c new file mode 100644 index 00000000000..6c6472b5488 --- /dev/null +++ b/reactos/lib/iphlpapi/iphlpv6.c @@ -0,0 +1,91 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#endif +#ifdef HAVE_RESOLV_H +# include +#endif + +#ifdef __REACTOS__ +# include +# include +# include +# include +# include +# include +# include +# include +# include "iphlpapiextra.h" +#else +# include "windef.h" +# include "winbase.h" +# include "winreg.h" +#endif + +#include "iphlpapi.h" +#include "ifenum.h" +#include "ipstats.h" +#include "iphlp_res.h" +#include "wine/debug.h" + +/* + * @unimplemented + */ +HANDLE STDCALL Icmp6CreateFile( + VOID + ) +{ + UNIMPLEMENTED + return 0L; +} + +/* + * @unimplemented + */ +DWORD +STDCALL +Icmp6SendEcho2( + HANDLE IcmpHandle, + HANDLE Event, + FARPROC ApcRoutine, + PVOID ApcContext, + struct sockaddr_in6 *SourceAddress, + struct sockaddr_in6 *DestinationAddress, + LPVOID RequestData, + WORD RequestSize, + PIP_OPTION_INFORMATION RequestOptions, + LPVOID ReplyBuffer, + DWORD ReplySize, + DWORD Timeout + ) +{ + UNIMPLEMENTED + return 0L; +} + +/* + * @unimplemented + */ +DWORD +STDCALL +Icmp6ParseReplies( + LPVOID ReplyBuffer, + DWORD ReplySize + ) +{ + UNIMPLEMENTED + return 0L; +} + diff --git a/reactos/lib/iphlpapi/ipprivate.h b/reactos/lib/iphlpapi/ipprivate.h index d71fd6268d8..bd4955caeea 100644 --- a/reactos/lib/iphlpapi/ipprivate.h +++ b/reactos/lib/iphlpapi/ipprivate.h @@ -1,15 +1,92 @@ #ifndef IPPRIVATE_H #define IPPRIVATE_H -typedef void (*EnumInterfacesFunc)( HANDLE RegHandle, PWCHAR InterfaceName, - PVOID Data ); -typedef void (*EnumNameServersFunc)( PWCHAR InterfaceName, PWCHAR Server, - PVOID Data ); - -typedef struct { - int NumServers; - int CurrentName; - PIP_ADDR_STRING AddrString; -} NAME_SERVER_LIST_PRIVATE, *PNAME_SERVER_LIST_PRIVATE; +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#endif +#ifdef HAVE_RESOLV_H +# include +#endif + +#define NTOS_MODE_USER +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "iphlpapiextra.h" +#include "ipregprivate.h" +#include "iphlpapi.h" +#include "ifenum.h" +#include "ipstats.h" +#include "iphlp_res.h" +#include "wine/debug.h" + +#undef TRACE +#define TRACE(fmt,args...) DbgPrint("(%s:%d - %s) " fmt, __FILE__, __LINE__, __FUNCTION__, ## args) + +#include "net/tdiinfo.h" +#include "tcpioctl.h" + +#ifndef ETH_ALEN +#define ETH_ALEN 6 +#endif + +#ifndef INADDR_NONE +#define INADDR_NONE (~0U) +#endif + +#ifndef IFENT_SOFTWARE_LOOPBACK +#define IFENT_SOFTWARE_LOOPBACK 24 /* This is an SNMP constant from rfc1213 */ +#endif/*IFENT_SOFTWARE_LOOPBACK*/ + +#define INDEX_IS_LOOPBACK 0x00800000 + +/* Type declarations */ + +#ifndef IFNAMSIZ +#define IFNAMSIZ 0x20 +#endif/*IFNAMSIZ*/ + +#define TCP_REQUEST_QUERY_INFORMATION_INIT { { { 0 } } } + +/* No caddr_t in reactos headers */ +typedef char *caddr_t; + +typedef union _IFEntrySafelySized { + PCHAR MaxSize[sizeof(DWORD) + + sizeof(IFEntry) + + MAX_ADAPTER_DESCRIPTION_LENGTH + 1]; + struct { + DWORD ProperlyOffsetTheStructure; + IFEntry ent; + } offset; +} IFEntrySafelySized; + +/** Prototypes **/ +NTSTATUS openTcpFile(PHANDLE tcpFile); +VOID closeTcpFile(HANDLE tcpFile); +NTSTATUS tdiGetEntityIDSet( HANDLE tcpFile, TDIEntityID **entitySet, + PDWORD numEntities ); +VOID tdiFreeThingSet( PVOID things ); #endif/*IPPRIVATE_H*/ diff --git a/reactos/lib/iphlpapi/ipregprivate.h b/reactos/lib/iphlpapi/ipregprivate.h index a7b1519d49f..a9e370c2eab 100644 --- a/reactos/lib/iphlpapi/ipregprivate.h +++ b/reactos/lib/iphlpapi/ipregprivate.h @@ -3,11 +3,11 @@ int GetLongestChildKeyName( HANDLE RegHandle ); LONG OpenChildKeyRead( HANDLE RegHandle, - PWCHAR ChildKeyName, + PCHAR ChildKeyName, PHKEY ReturnHandle ); -PWCHAR GetNthChildKeyName( HANDLE RegHandle, DWORD n ); -void ConsumeChildKeyName( PWCHAR Name ); -PWCHAR QueryRegistryValueString( HANDLE RegHandle, PWCHAR ValueName ); -void ConsumeRegValueString( PWCHAR NameServer ); +PCHAR GetNthChildKeyName( HANDLE RegHandle, DWORD n ); +void ConsumeChildKeyName( PCHAR Name ); +PCHAR QueryRegistryValueString( HANDLE RegHandle, PCHAR ValueName ); +void ConsumeRegValueString( PCHAR NameServer ); #endif/*IPREGPRIVATE_H*/ diff --git a/reactos/lib/iphlpapi/ipstats.h b/reactos/lib/iphlpapi/ipstats.h new file mode 100644 index 00000000000..92a61678835 --- /dev/null +++ b/reactos/lib/iphlpapi/ipstats.h @@ -0,0 +1,108 @@ +/* ipstats.h + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This module implements functions shared by DLLs that need to get network- + * related statistics. It's meant to hide some platform-specificisms, and + * share code that was previously duplicated. + */ +#ifndef WINE_IPSTATS_H_ +#define WINE_IPSTATS_H_ + +#include + +#include "windef.h" +#include "winbase.h" +#include "iprtrmib.h" + +/* Fills in entry's interface stats, using name to find them. + * Returns ERROR_INVALID_PARAMETER if name or entry is NULL, NO_ERROR otherwise. + */ +DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry); + +/* Ditto above by index. */ +DWORD getInterfaceStatsByIndex(DWORD index, PMIB_IFROW entry); + +/* Gets ICMP statistics into stats. Returns ERROR_INVALID_PARAMETER if stats is + * NULL, NO_ERROR otherwise. + */ +DWORD getICMPStats(MIB_ICMP *stats); + +/* Gets IP statistics into stats. Returns ERROR_INVALID_PARAMETER if stats is + * NULL, NO_ERROR otherwise. + */ +DWORD getIPStats(PMIB_IPSTATS stats, DWORD family); + +/* Gets TCP statistics into stats. Returns ERROR_INVALID_PARAMETER if stats is + * NULL, NO_ERROR otherwise. + */ +DWORD getTCPStats(MIB_TCPSTATS *stats, DWORD family); + +/* Gets UDP statistics into stats. Returns ERROR_INVALID_PARAMETER if stats is + * NULL, NO_ERROR otherwise. + */ +DWORD getUDPStats(MIB_UDPSTATS *stats, DWORD family); + +/* Route table functions */ + +DWORD getNumRoutes(void); + +/* Minimalist route entry, only has the fields I can actually fill in. How + * these map to the different windows route data structures is up to you. + */ +typedef struct _RouteEntry { + DWORD dest; + DWORD mask; + DWORD gateway; + DWORD ifIndex; + DWORD metric; +} RouteEntry; + +typedef struct _RouteTable { + DWORD numRoutes; + RouteEntry routes[1]; +} RouteTable; + +/* Allocates and returns to you the route table, or NULL if it can't allocate + * enough memory. free() the returned table. + */ +RouteTable *getRouteTable(void); + +/* Returns the number of entries in the arp table. */ +DWORD getNumArpEntries(void); + +/* Allocates and returns to you the arp table, or NULL if it can't allocate + * enough memory. free() the returned table. + */ +PMIB_IPNETTABLE getArpTable(void); + +/* Returns the number of entries in the UDP state table. */ +DWORD getNumUdpEntries(void); + +/* Allocates and returns to you the UDP state table, or NULL if it can't + * allocate enough memory. free() the returned table. + */ +PMIB_UDPTABLE getUdpTable(void); + +/* Returns the number of entries in the TCP state table. */ +DWORD getNumTcpEntries(void); + +/* Allocates and returns to you the TCP state table, or NULL if it can't + * allocate enough memory. free() the returned table. + */ +PMIB_TCPTABLE getTcpTable(void); + +#endif /* ndef WINE_IPSTATS_H_ */ diff --git a/reactos/lib/iphlpapi/ipstats_reactos.c b/reactos/lib/iphlpapi/ipstats_reactos.c new file mode 100644 index 00000000000..34a072375a1 --- /dev/null +++ b/reactos/lib/iphlpapi/ipstats_reactos.c @@ -0,0 +1,558 @@ +/* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This file implements statistics getting using the /proc filesystem exported + * by Linux, and maybe other OSes. + */ + +#include "ipprivate.h" +#include "ipstats.h" +#include "ifenum.h" + +#ifndef TCPS_ESTABLISHED +# define TCPS_ESTABLISHED TCP_ESTABLISHED +#endif +#ifndef TCPS_SYN_SENT +# define TCPS_SYN_SENT TCP_SYN_SENT +#endif +#ifndef TCPS_SYN_RECEIVED +# define TCPS_SYN_RECEIVED TCP_SYN_RECV +#endif +#ifndef TCPS_FIN_WAIT_1 +# define TCPS_FIN_WAIT_1 TCP_FIN_WAIT1 +#endif +#ifndef TCPS_FIN_WAIT_2 +# define TCPS_FIN_WAIT_2 TCP_FIN_WAIT2 +#endif +#ifndef TCPS_TIME_WAIT +# define TCPS_TIME_WAIT TCP_TIME_WAIT +#endif +#ifndef TCPS_CLOSED +# define TCPS_CLOSED TCP_CLOSE +#endif +#ifndef TCPS_CLOSE_WAIT +# define TCPS_CLOSE_WAIT TCP_CLOSE_WAIT +#endif +#ifndef TCPS_LAST_ACK +# define TCPS_LAST_ACK TCP_LAST_ACK +#endif +#ifndef TCPS_LISTEN +# define TCPS_LISTEN TCP_LISTEN +#endif +#ifndef TCPS_CLOSING +# define TCPS_CLOSING TCP_CLOSING +#endif + +BOOL isIpEntity( HANDLE tcpFile, TDIEntityID *ent ) { + DWORD entityType, returnedLen; + NTSTATUS status; + TCP_REQUEST_QUERY_INFORMATION_EX req; + + req.ID.toi_class = INFO_CLASS_GENERIC; + req.ID.toi_type = INFO_TYPE_PROVIDER; + req.ID.toi_id = ENTITY_TYPE_ID; + req.ID.toi_entity = *ent; + + status = + DeviceIoControl + ( tcpFile, + IOCTL_TCP_QUERY_INFORMATION_EX, + &req, + sizeof(req), + &entityType, + sizeof(entityType), + &returnedLen, + NULL ); + + DPRINT("Ent: %04x:d -> %04x\n", + ent->tei_entity, ent->tei_instance, entityType ); + + return NT_SUCCESS(status) && entityType == CL_NL_IP; +} + +NTSTATUS getNthIpEntity( HANDLE tcpFile, DWORD index, TDIEntityID *ent ) { + DWORD numEntities = 0; + DWORD numRoutes = 0; + TDIEntityID *entitySet = 0; + NTSTATUS status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities ); + int i; + + if( !NT_SUCCESS(status) ) + return status; + + for( i = 0; i < numEntities; i++ ) { + if( isIpEntity( tcpFile, &entitySet[i] ) ) { + DPRINT("Entity %d is an IP Entity\n", i); + if( numRoutes == index ) break; + else numRoutes++; + } + } + + DPRINT("Index %d is entity #%d - %04x:%08x\n", index, i, + entitySet[i].tei_entity, entitySet[i].tei_instance ); + + if( numRoutes == index && i < numEntities ) { + memcpy( ent, &entitySet[i], sizeof(*ent) ); + tdiFreeThingSet( entitySet ); + return STATUS_SUCCESS; + } else { + tdiFreeThingSet( entitySet ); + return STATUS_UNSUCCESSFUL; + } +} + +NTSTATUS tdiGetMibForIpEntity +( HANDLE tcpFile, TDIEntityID *ent, IPSNMPInfo *entry ) { + TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT; + NTSTATUS status = STATUS_SUCCESS; + DWORD returnSize; + + memset( entry, 0, sizeof( *entry ) ); + + DPRINT("TdiGetMibForIpEntity(tcpFile %x,entityId %x)\n", + (DWORD)tcpFile, ent->tei_instance); + + req.ID.toi_class = INFO_CLASS_PROTOCOL; + req.ID.toi_type = INFO_TYPE_PROVIDER; + req.ID.toi_id = IP_MIB_STATS_ID; + req.ID.toi_entity = *ent; + + status = DeviceIoControl( tcpFile, + IOCTL_TCP_QUERY_INFORMATION_EX, + &req, + sizeof(req), + entry, + sizeof(*entry), + &returnSize, + NULL ); + + DPRINT("TdiGetMibForIpEntity() => {\n" + " ipsi_forwarding ............ %d\n" + " ipsi_defaultttl ............ %d\n" + " ipsi_inreceives ............ %d\n" + " ipsi_indelivers ............ %d\n" + " ipsi_outrequests ........... %d\n" + " ipsi_routingdiscards ....... %d\n" + " ipsi_outdiscards ........... %d\n" + " ipsi_outnoroutes ........... %d\n" + " ipsi_numif ................. %d\n" + " ipsi_numaddr ............... %d\n" + " ipsi_numroutes ............. %d\n" + "} status %08x\n", + entry->ipsi_forwarding, + entry->ipsi_defaultttl, + entry->ipsi_inreceives, + entry->ipsi_indelivers, + entry->ipsi_outrequests, + entry->ipsi_routingdiscards, + entry->ipsi_outdiscards, + entry->ipsi_outnoroutes, + entry->ipsi_numif, + entry->ipsi_numaddr, + entry->ipsi_numroutes, + status); + + return status; +} + +NTSTATUS tdiGetRoutesForIpEntity +( HANDLE tcpFile, TDIEntityID *ent, int numRoutes, IPRouteEntry *routes ) { + TCP_REQUEST_QUERY_INFORMATION_EX req = TCP_REQUEST_QUERY_INFORMATION_INIT; + NTSTATUS status = STATUS_SUCCESS; + DWORD returnSize; + + DPRINT("TdiGetRoutesForIpEntity(tcpFile %x,entityId %x)\n", + (DWORD)tcpFile, ent->tei_instance); + + req.ID.toi_class = INFO_CLASS_PROTOCOL; + req.ID.toi_type = INFO_TYPE_PROVIDER; + req.ID.toi_id = IP_MIB_ROUTETABLE_ENTRY_ID; + req.ID.toi_entity = *ent; + + status = DeviceIoControl( tcpFile, + IOCTL_TCP_QUERY_INFORMATION_EX, + &req, + sizeof(req), + routes, + sizeof(*routes) * numRoutes, + &returnSize, + NULL ); + + return status; +} + +DWORD getInterfaceStatsByName(const char *name, PMIB_IFROW entry) +{ + if (!name) + return ERROR_INVALID_PARAMETER; + if (!entry) + return ERROR_INVALID_PARAMETER; + + return NO_ERROR; +} + +DWORD getInterfaceStatsByIndex(DWORD index, PMIB_IFROW entry) +{ + return ERROR_INVALID_PARAMETER; +} + +DWORD getICMPStats(MIB_ICMP *stats) +{ + FILE *fp; + + if (!stats) + return ERROR_INVALID_PARAMETER; + + memset(stats, 0, sizeof(MIB_ICMP)); + /* get most of these stats from /proc/net/snmp, no error if can't */ + fp = fopen("/proc/net/snmp", "r"); + if (fp) { + const char hdr[] = "Icmp:"; + char buf[512] = { 0 }, *ptr; + + do { + ptr = fgets(buf, sizeof(buf), fp); + } while (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1)); + if (ptr) { + /* last line was a header, get another */ + ptr = fgets(buf, sizeof(buf), fp); + if (ptr && strncasecmp(buf, hdr, sizeof(hdr) - 1) == 0) { + char *endPtr; + + ptr += sizeof(hdr); + if (ptr && *ptr) { + stats->stats.icmpInStats.dwMsgs = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpInStats.dwErrors = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpInStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpInStats.dwTimeExcds = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpInStats.dwParmProbs = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpInStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpInStats.dwRedirects = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpInStats.dwEchoReps = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpInStats.dwTimestamps = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpInStats.dwTimestampReps = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpInStats.dwAddrMasks = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpInStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpOutStats.dwMsgs = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpOutStats.dwErrors = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpOutStats.dwDestUnreachs = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpOutStats.dwTimeExcds = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpOutStats.dwParmProbs = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpOutStats.dwSrcQuenchs = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpOutStats.dwRedirects = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpOutStats.dwEchoReps = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpOutStats.dwTimestamps = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpOutStats.dwTimestampReps = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpOutStats.dwAddrMasks = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + if (ptr && *ptr) { + stats->stats.icmpOutStats.dwAddrMaskReps = strtoul(ptr, &endPtr, 10); + ptr = endPtr; + } + } + } + fclose(fp); + } + return NO_ERROR; +} + +DWORD getIPStats(PMIB_IPSTATS stats, DWORD family) +{ + if (!stats) + return ERROR_INVALID_PARAMETER; + return NO_ERROR; +} + +DWORD getTCPStats(MIB_TCPSTATS *stats, DWORD family) +{ + if (!stats) + return ERROR_INVALID_PARAMETER; + return NO_ERROR; +} + +DWORD getUDPStats(MIB_UDPSTATS *stats, DWORD family) +{ + if (!stats) + return ERROR_INVALID_PARAMETER; + return NO_ERROR; +} + +static DWORD getNumWithOneHeader(const char *filename) +{ + return 0; +} + +DWORD getNumRoutes(void) +{ + DWORD numEntities, numRoutes = 0; + TDIEntityID *entitySet; + HANDLE tcpFile; + int i; + NTSTATUS status; + + TRACE("called.\n"); + + status = openTcpFile( &tcpFile ); + + if( !NT_SUCCESS(status) ) { + TRACE("failure: %08x\n", (int)status ); + return 0; + } + + status = tdiGetEntityIDSet( tcpFile, &entitySet, &numEntities ); + + if( !NT_SUCCESS(status) ) { + TRACE("failure: %08x\n", (int)status ); + return 0; + } + + for( i = 0; i < numEntities; i++ ) { + if( isIpEntity( tcpFile, &entitySet[i] ) ) { + IPSNMPInfo isnmp; + memset( &isnmp, 0, sizeof( isnmp ) ); + status = tdiGetMibForIpEntity( tcpFile, &entitySet[i], &isnmp ); + if( !NT_SUCCESS(status) ) { + tdiFreeThingSet( entitySet ); + return status; + } + numRoutes += isnmp.ipsi_numroutes; + } + } + + TRACE("numRoutes: %d\n", (int)numRoutes); + + closeTcpFile( tcpFile ); + + return numRoutes; +} + +VOID HexDump( PCHAR Data, DWORD Len ) { + int i; + + for( i = 0; i < Len; i++ ) { + if( !(i & 0xf) ) { + if( i ) fprintf(stderr,"\n"); + fprintf(stderr,"%08x:", i); + } + fprintf( stderr, " %02x", Data[i] & 0xff ); + } + fprintf(stderr,"\n"); +} + +RouteTable *getRouteTable(void) +{ + RouteTable *out_route_table; + DWORD numRoutes = getNumRoutes(), routesAdded = 0; + IPSNMPInfo snmpInfo; + TDIEntityID ent; + HANDLE tcpFile; + NTSTATUS status = openTcpFile( &tcpFile ); + int i; + + if( !NT_SUCCESS(status) ) + return 0; + + out_route_table = HeapAlloc( GetProcessHeap(), 0, + sizeof(RouteTable) + + (sizeof(RouteEntry) * (numRoutes - 1)) ); + + out_route_table->numRoutes = numRoutes; + + for( i = 0; routesAdded < numRoutes; i++ ) { + int j; + IPRouteEntry *route_set; + + getNthIpEntity( tcpFile, i, &ent ); + tdiGetMibForIpEntity( tcpFile, &ent, &snmpInfo ); + route_set = HeapAlloc( GetProcessHeap(), 0, + sizeof( IPRouteEntry ) * + snmpInfo.ipsi_numroutes ); + + DPRINT( "%d routes in instance %d\n", snmpInfo.ipsi_numroutes, i ); + + if( !route_set ) { + closeTcpFile( tcpFile ); + HeapFree( GetProcessHeap(), 0, out_route_table ); + return 0; + } + + tdiGetRoutesForIpEntity( tcpFile, &ent, numRoutes, route_set ); + + DPRINT("Route set returned\n"); +#if 0 + HexDump( route_set, + sizeof( IPRouteEntry ) * + snmpInfo.ipsi_numroutes ); +#endif + + for( j = 0; j < snmpInfo.ipsi_numroutes; j++ ) { + int routeNum = j + routesAdded; + out_route_table->routes[routeNum].dest = + route_set[j].ire_dest; + out_route_table->routes[routeNum].mask = + route_set[j].ire_mask; + out_route_table->routes[routeNum].gateway = + route_set[j].ire_gw; + out_route_table->routes[routeNum].ifIndex = + route_set[j].ire_index; + out_route_table->routes[routeNum].metric = + route_set[j].ire_metric; + } + + routesAdded += snmpInfo.ipsi_numroutes; + } + + return out_route_table; +} + +DWORD getNumArpEntries(void) +{ + return getNumWithOneHeader("/proc/net/arp"); +} + +PMIB_IPNETTABLE getArpTable(void) +{ + return 0; +} + +DWORD getNumUdpEntries(void) +{ + return getNumWithOneHeader("/proc/net/udp"); +} + +PMIB_UDPTABLE getUdpTable(void) +{ + DWORD numEntries = getNumUdpEntries(); + PMIB_UDPTABLE ret; + + ret = (PMIB_UDPTABLE)calloc(1, sizeof(MIB_UDPTABLE) + + (numEntries - 1) * sizeof(MIB_UDPROW)); + if (ret) { + FILE *fp; + + /* get from /proc/net/udp, no error if can't */ + fp = fopen("/proc/net/udp", "r"); + if (fp) { + char buf[512] = { 0 }, *ptr; + + /* skip header line */ + ptr = fgets(buf, sizeof(buf), fp); + while (ptr && ret->dwNumEntries < numEntries) { + ptr = fgets(buf, sizeof(buf), fp); + if (ptr) { + char *endPtr; + + if (ptr && *ptr) { + strtoul(ptr, &endPtr, 16); /* skip */ + ptr = endPtr; + } + if (ptr && *ptr) { + ptr++; + ret->table[ret->dwNumEntries].dwLocalAddr = strtoul(ptr, &endPtr, + 16); + ptr = endPtr; + } + if (ptr && *ptr) { + ptr++; + ret->table[ret->dwNumEntries].dwLocalPort = strtoul(ptr, &endPtr, + 16); + ptr = endPtr; + } + ret->dwNumEntries++; + } + } + fclose(fp); + } + } + return ret; +} + +DWORD getNumTcpEntries(void) +{ + return getNumWithOneHeader("/proc/net/tcp"); +} + +PMIB_TCPTABLE getTcpTable(void) +{ + return 0; +} diff --git a/reactos/lib/iphlpapi/makefile b/reactos/lib/iphlpapi/makefile index fc8bb93cba7..8871cad628e 100644 --- a/reactos/lib/iphlpapi/makefile +++ b/reactos/lib/iphlpapi/makefile @@ -8,11 +8,13 @@ TARGET_NAME = iphlpapi TARGET_BASE = 0x777c0000 -TARGET_CFLAGS = -DUNICODE -D_UNICODE -D__USE_W32API -Wall -Werror +TARGET_CFLAGS += -DYDEBUG -DUNICODE -D_UNICODE -D__USE_W32API -D__REACTOS__ -D_WIN32_WINNT=0x0500 -Wall +#-Werror -TARGET_SDKLIBS = ntdll.a kernel32.a +TARGET_SDKLIBS = ntdll.a kernel32.a ws2_32.a -TARGET_OBJECTS = $(TARGET_NAME).o registry.o +TARGET_OBJECTS = iphlpapi_main.o icmp.o iphlpv6.o media.o registry.o \ + ifenum_reactos.o ipstats_reactos.o resinfo_reactos.o DEP_OBJECTS = $(TARGET_OBJECTS) diff --git a/reactos/lib/iphlpapi/media.c b/reactos/lib/iphlpapi/media.c new file mode 100644 index 00000000000..bd6a7c74966 --- /dev/null +++ b/reactos/lib/iphlpapi/media.c @@ -0,0 +1,59 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#endif +#ifdef HAVE_RESOLV_H +# include +#endif + +#ifdef __REACTOS__ +# include +# include +# include +# include +# include +# include +# include +# include "iphlpapiextra.h" +#else +# include "windef.h" +# include "winbase.h" +# include "winreg.h" +#endif + +#include "iphlpapi.h" +#include "ifenum.h" +#include "ipstats.h" +#include "iphlp_res.h" +#include "wine/debug.h" + +/* + * @unimplemented + */ +DWORD STDCALL DisableMediaSense(HANDLE *pHandle,OVERLAPPED *pOverLapped) +{ + UNIMPLEMENTED + return 0L; +} + +/* + * @unimplemented + */ +DWORD STDCALL RestoreMediaSense(OVERLAPPED* pOverlapped,LPDWORD lpdwEnableCount) +{ + UNIMPLEMENTED + return 0L; +} + diff --git a/reactos/lib/iphlpapi/merge-notes.txt b/reactos/lib/iphlpapi/merge-notes.txt new file mode 100644 index 00000000000..71f318919b1 --- /dev/null +++ b/reactos/lib/iphlpapi/merge-notes.txt @@ -0,0 +1,36 @@ +GetAdaptersInfo -- +Wine uses: Software\\Wine\\Wine\\Config\\Network + -- Wins support is todo so this part isn't so important. + -- Overall, workable +Wine uses ansi functions +GetNetworkParams -- + -- Make workable interface for _res + -- Wine based on real _res + -- Reactos based on my enumerator funcs + +ROUTE PRINT: + +iphlpapi_main.c:137 - ppIfTable 0104bd80, bOrder 1, heap 0xa0000000, flags 0x00000001 + - AllocateAndGetIfTableFromStack +iphlpapi_main.c:898 - pIfTable 0104bd00, pdwSize 0104bd00, bOrder 1 + - GetIfTable +(tcpip/main.c:168)(TiCreateFileObject) No EA information in IRP. + - We need a special case of no EA information to handle these ioctls in + tcpip.sys +iphlpapi_main.c:939 - returning 122 +iphlpapi_main.c:898 - pIfTable 0104bd00, pdwSize 0104bd00, bOrder 1 + - GetIfTable again +(tcpip/main.c:168)(TiCreateFileObject) No EA information in IRP. +(tcpip/main.c:168)(TiCreateFileObject) No EA information in IRP. +getInterfaceIndexTable: numInterfaces: 0 +iphlpapi_main.c:939 - returning 0 +iphlpapi_main.c:149 - returning 0 +iphlpapi_main.c:213 - ppIpForwardTable 0104bd78, bOrder 1, heap 0xa0000000, flags 0x00000001 + - AllocateAndGetIpForwardTableFromStack +iphlpapi_main.c:1151 - pIpForwardTable 00000000, pdwSize 0104bd00, bOrder 1 + - GetIpForwardTable +iphlpapi_main.c:1214 - returning 122 +iphlpapi_main.c:1151 - pIpForwardTable a0001d68, pdwSize 0104bd00, bOrder 1 + - GetIpForwardTable again +iphlpapi_main.c:1214 - returning 122 +iphlpapi_main.c:225 - returning 122 diff --git a/reactos/lib/iphlpapi/registry.c b/reactos/lib/iphlpapi/registry.c index 15eeb8c7425..99ae679931d 100644 --- a/reactos/lib/iphlpapi/registry.c +++ b/reactos/lib/iphlpapi/registry.c @@ -10,7 +10,7 @@ int GetLongestChildKeyName( HANDLE RegHandle ) { LONG Status; DWORD MaxAdapterName; - Status = RegQueryInfoKeyW(RegHandle, + Status = RegQueryInfoKeyA(RegHandle, NULL, NULL, NULL, @@ -29,9 +29,9 @@ int GetLongestChildKeyName( HANDLE RegHandle ) { } LONG OpenChildKeyRead( HANDLE RegHandle, - PWCHAR ChildKeyName, + PCHAR ChildKeyName, PHKEY ReturnHandle ) { - return RegOpenKeyExW( RegHandle, + return RegOpenKeyExA( RegHandle, ChildKeyName, 0, KEY_READ, @@ -42,10 +42,10 @@ LONG OpenChildKeyRead( HANDLE RegHandle, * Yields a malloced value that must be freed. */ -PWCHAR GetNthChildKeyName( HANDLE RegHandle, DWORD n ) { +PCHAR GetNthChildKeyName( HANDLE RegHandle, DWORD n ) { LONG Status; int MaxAdapterName = GetLongestChildKeyName( RegHandle ); - PWCHAR Value; + PCHAR Value; DWORD ValueLen; if (MaxAdapterName == -1) { @@ -54,8 +54,8 @@ PWCHAR GetNthChildKeyName( HANDLE RegHandle, DWORD n ) { } ValueLen = MaxAdapterName; - Value = (PWCHAR)malloc( MaxAdapterName * sizeof(WCHAR) ); - Status = RegEnumKeyExW( RegHandle, n, Value, &ValueLen, + Value = (PCHAR)HeapAlloc( GetProcessHeap(), 0, MaxAdapterName ); + Status = RegEnumKeyExA( RegHandle, n, Value, &ValueLen, NULL, NULL, NULL, NULL ); if (Status != ERROR_SUCCESS) return 0; @@ -65,27 +65,27 @@ PWCHAR GetNthChildKeyName( HANDLE RegHandle, DWORD n ) { } } -void ConsumeChildKeyName( PWCHAR Name ) { - if (Name) free( Name ); +void ConsumeChildKeyName( PCHAR Name ) { + if (Name) HeapFree( GetProcessHeap(), 0, Name ); } -PWCHAR QueryRegistryValueString( HANDLE RegHandle, PWCHAR ValueName ) { - PWCHAR Name; +PCHAR QueryRegistryValueString( HANDLE RegHandle, PCHAR ValueName ) { + PCHAR Name; DWORD ReturnedSize = 0; - if (RegQueryValueExW( RegHandle, ValueName, NULL, NULL, NULL, + if (RegQueryValueExA( RegHandle, ValueName, NULL, NULL, NULL, &ReturnedSize ) != 0) return 0; else { Name = malloc( (ReturnedSize + 1) * sizeof(WCHAR) ); - RegQueryValueExW( RegHandle, ValueName, NULL, NULL, (PVOID)Name, + RegQueryValueExA( RegHandle, ValueName, NULL, NULL, (PVOID)Name, &ReturnedSize ); Name[ReturnedSize] = 0; return Name; } } -void ConsumeRegValueString( PWCHAR Value ) { +void ConsumeRegValueString( PCHAR Value ) { if (Value) free(Value); } @@ -93,8 +93,8 @@ PWCHAR *QueryRegistryValueStringMulti( HANDLE RegHandle, PWCHAR ValueName ) { return 0; /* FIXME if needed */ } -void ConsumeRegValueStringMulti( PWCHAR *Value ) { - PWCHAR *Orig = Value; +void ConsumeRegValueStringMulti( PCHAR *Value ) { + PCHAR *Orig = Value; if (Value) { while (*Value) { free(*Value); diff --git a/reactos/lib/iphlpapi/resinfo_reactos.c b/reactos/lib/iphlpapi/resinfo_reactos.c new file mode 100644 index 00000000000..ec85a600b60 --- /dev/null +++ b/reactos/lib/iphlpapi/resinfo_reactos.c @@ -0,0 +1,52 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#ifdef HAVE_NETINET_IN_H +# include +#endif +#ifdef HAVE_ARPA_INET_H +# include +#endif +#ifdef HAVE_ARPA_NAMESER_H +# include +#endif +#ifdef HAVE_RESOLV_H +# include +#endif + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" + +#ifdef __REACTOS__ +# include /* ULONGLONG */ +# include /* Enables NSPAPI */ +# include /* SOCKET_ADDRESS */ +# include /* IP_ADAPTER_ADDRESSES */ +#endif + +#include "iphlpapi.h" +#include "ifenum.h" +#include "ipstats.h" +#include "iphlp_res.h" +#include "wine/debug.h" + +PIPHLP_RES_INFO getResInfo() { + PIPHLP_RES_INFO InfoPtr = + (PIPHLP_RES_INFO)HeapAlloc( GetProcessHeap(), 0, + sizeof(PIPHLP_RES_INFO) ); + if( InfoPtr ) { + InfoPtr->riCount = 0; + InfoPtr->riAddressList = (LPSOCKADDR)0; + } + + return InfoPtr; +} + +VOID disposeResInfo( PIPHLP_RES_INFO InfoPtr ) { + HeapFree( GetProcessHeap(), 0, InfoPtr ); +} -- 2.17.1