Big merge in wine code. This merged version is far more complete than
authorArt Yerkes <art.yerkes@gmail.com>
Sun, 15 Feb 2004 07:17:00 +0000 (07:17 +0000)
committerArt Yerkes <art.yerkes@gmail.com>
Sun, 15 Feb 2004 07:17:00 +0000 (07:17 +0000)
the previous one.   See notes and comments by me and the original author
of iphlpapi_main.c, Juan Lang.

svn path=/trunk/; revision=8194

17 files changed:
reactos/lib/iphlpapi/icmp.c [new file with mode: 0644]
reactos/lib/iphlpapi/ifenum.h [new file with mode: 0644]
reactos/lib/iphlpapi/ifenum_reactos.c [new file with mode: 0644]
reactos/lib/iphlpapi/iphlp_res.h [new file with mode: 0644]
reactos/lib/iphlpapi/iphlpapi.edf
reactos/lib/iphlpapi/iphlpapi_main.c [new file with mode: 0644]
reactos/lib/iphlpapi/iphlpapiextra.h [new file with mode: 0644]
reactos/lib/iphlpapi/iphlpv6.c [new file with mode: 0644]
reactos/lib/iphlpapi/ipprivate.h
reactos/lib/iphlpapi/ipregprivate.h
reactos/lib/iphlpapi/ipstats.h [new file with mode: 0644]
reactos/lib/iphlpapi/ipstats_reactos.c [new file with mode: 0644]
reactos/lib/iphlpapi/makefile
reactos/lib/iphlpapi/media.c [new file with mode: 0644]
reactos/lib/iphlpapi/merge-notes.txt [new file with mode: 0644]
reactos/lib/iphlpapi/registry.c
reactos/lib/iphlpapi/resinfo_reactos.c [new file with mode: 0644]

diff --git a/reactos/lib/iphlpapi/icmp.c b/reactos/lib/iphlpapi/icmp.c
new file mode 100644 (file)
index 0000000..29fa0f8
--- /dev/null
@@ -0,0 +1,117 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+# include <arpa/nameser.h>
+#endif
+#ifdef HAVE_RESOLV_H
+# include <resolv.h>
+#endif
+
+#ifdef __REACTOS__
+# include <windows.h>
+# include <windef.h>
+# include <winbase.h>
+# include <net/miniport.h>
+# include <winsock2.h>
+# include <nspapi.h>
+# include <iptypes.h>
+# 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 (file)
index 0000000..406fa0f
--- /dev/null
@@ -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 <stdarg.h>
+
+#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 (file)
index 0000000..9956b5e
--- /dev/null
@@ -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 (file)
index 0000000..81d41b2
--- /dev/null
@@ -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*/
index ee7dffe..7c42cd3 100644 (file)
@@ -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 (file)
index 0000000..8a93ef0
--- /dev/null
@@ -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 <stdarg.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+# include <arpa/nameser.h>
+#endif
+#ifdef HAVE_RESOLV_H
+# include <resolv.h>
+#endif
+
+#ifdef __REACTOS__
+# include <windows.h>
+# include <windef.h>
+# include <winbase.h>
+# include <net/miniport.h>
+# include <winsock2.h>
+# include <nspapi.h>
+# include <iptypes.h>
+# include "iphlpapiextra.h"
+# include "wine/debug.h"
+#else
+# include "windef.h"
+# include "winbase.h"
+# include "winreg.h"
+# include "debug.h"
+#endif
+
+#include <stdio.h>
+#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 (file)
index 0000000..3aa0ae4
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef _IPHLPAPIEXTRA_H
+#define _IPHLPAPIEXTRA_H
+
+#include <w32api.h>
+/* 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 (file)
index 0000000..6c6472b
--- /dev/null
@@ -0,0 +1,91 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+# include <arpa/nameser.h>
+#endif
+#ifdef HAVE_RESOLV_H
+# include <resolv.h>
+#endif
+
+#ifdef __REACTOS__
+# include <windows.h>
+# include <windef.h>
+# include <winbase.h>
+# include <net/miniport.h>
+# include <winsock2.h>
+# include <nspapi.h>
+# include <iptypes.h>
+# include <ws2tcpip.h>
+# 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;
+}
+
index d71fd62..bd4955c 100644 (file)
@@ -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 <stdarg.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+# include <arpa/nameser.h>
+#endif
+#ifdef HAVE_RESOLV_H
+# include <resolv.h>
+#endif
+
+#define NTOS_MODE_USER
+#include <ntos.h>
+#include <ddk/ntddk.h>
+#include <rosrtl/string.h>
+#include <ntdll/rtl.h>
+#include <windows.h>
+#include <windef.h>
+#include <winbase.h>
+#include <net/miniport.h>
+#include <winsock2.h>
+#include <nspapi.h>
+#include <iptypes.h>
+#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*/
index a7b1519..a9e370c 100644 (file)
@@ -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 (file)
index 0000000..92a6167
--- /dev/null
@@ -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 <stdarg.h>
+
+#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 (file)
index 0000000..34a0723
--- /dev/null
@@ -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;
+}
index fc8bb93..8871cad 100644 (file)
@@ -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 (file)
index 0000000..bd6a7c7
--- /dev/null
@@ -0,0 +1,59 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+# include <arpa/nameser.h>
+#endif
+#ifdef HAVE_RESOLV_H
+# include <resolv.h>
+#endif
+
+#ifdef __REACTOS__
+# include <windows.h>
+# include <windef.h>
+# include <winbase.h>
+# include <net/miniport.h>
+# include <winsock2.h>
+# include <nspapi.h>
+# include <iptypes.h>
+# 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 (file)
index 0000000..71f3189
--- /dev/null
@@ -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
index 15eeb8c..99ae679 100644 (file)
@@ -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 (file)
index 0000000..ec85a60
--- /dev/null
@@ -0,0 +1,52 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+# include <arpa/nameser.h>
+#endif
+#ifdef HAVE_RESOLV_H
+# include <resolv.h>
+#endif
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+
+#ifdef __REACTOS__
+# include <net/miniport.h> /* ULONGLONG */
+# include <winsock2.h>     /* Enables NSPAPI */
+# include <nspapi.h>       /* SOCKET_ADDRESS */
+# include <iptypes.h>      /* 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 );
+}