user32: Moved the class extra bytes check to catch uninitialised data sooner.
[wine] / dlls / iphlpapi / iphlpapi_main.c
index d8e7762..d01fe28 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * iphlpapi dll implementation
  *
- * Copyright (C) 2003 Juan Lang
+ * Copyright (C) 2003,2006 Juan Lang
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -15,7 +15,7 @@
  *
  * 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
 #include "config.h"
@@ -26,6 +26,9 @@
 #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
 #include "windef.h"
 #include "winbase.h"
 #include "winreg.h"
+#define USE_WS_PREFIX
+#include "winsock2.h"
 #include "iphlpapi.h"
 #include "ifenum.h"
 #include "ipstats.h"
+
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
 
+#ifndef INADDR_NONE
+#define INADDR_NONE ~0UL
+#endif
+
+static int resolver_initialised;
+
+/* call res_init() just once because of a bug in Mac OS X 10.4 */
+static void initialise_resolver(void)
+{
+    if (!resolver_initialised)
+    {
+        res_init();
+        resolver_initialised = 1;
+    }
+}
+
 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;
@@ -61,24 +81,25 @@ BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
 /******************************************************************
  *    AddIPAddress (IPHLPAPI.@)
  *
+ * Add an IP address to an adapter.
  *
  * PARAMS
- *
- *  Address [In]
- *  IpMask [In]
- *  IfIndex [In]
- *  NTEContext [In/Out]
- *  NTEInstance [In/Out]
+ *  Address     [In]  IP address to add to the adapter
+ *  IpMask      [In]  subnet mask for the IP address
+ *  IfIndex     [In]  adapter index to add the address
+ *  NTEContext  [Out] Net Table Entry (NTE) context for the IP address
+ *  NTEInstance [Out] NTE instance for the IP address
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * FIXME
+ *  Stub. Currently returns ERROR_NOT_SUPPORTED.
  */
 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;
 }
 
@@ -86,24 +107,27 @@ DWORD WINAPI AddIPAddress(IPAddr Address, IPMask IpMask, DWORD IfIndex, PULONG N
 /******************************************************************
  *    AllocateAndGetIfTableFromStack (IPHLPAPI.@)
  *
+ * Get table of local interfaces.
+ * Like GetIfTable(), but allocate the returned table from heap.
  *
  * PARAMS
+ *  ppIfTable [Out] pointer into which the MIB_IFTABLE is
+ *                  allocated and returned.
+ *  bOrder    [In]  whether to sort the table
+ *  heap      [In]  heap from which the table is allocated
+ *  flags     [In]  flags to HeapAlloc
  *
- *  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
- *
+ * 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 %d, heap %p, flags 0x%08x\n", ppIfTable,
+        bOrder, heap, flags);
   if (!ppIfTable)
     ret = ERROR_INVALID_PARAMETER;
   else {
@@ -111,10 +135,23 @@ DWORD WINAPI AllocateAndGetIfTableFromStack(PMIB_IFTABLE *ppIfTable,
 
     ret = GetIfTable(*ppIfTable, &dwSize, bOrder);
     if (ret == ERROR_INSUFFICIENT_BUFFER) {
-      *ppIfTable = (PMIB_IFTABLE)HeapAlloc(heap, flags, dwSize);
+      *ppIfTable = HeapAlloc(heap, flags, dwSize);
       ret = GetIfTable(*ppIfTable, &dwSize, bOrder);
     }
   }
+  TRACE("returning %d\n", ret);
+  return ret;
+}
+
+
+static int IpAddrTableSorter(const void *a, const void *b)
+{
+  int ret;
+
+  if (a && b)
+    ret = ((const MIB_IPADDRROW*)a)->dwAddr - ((const MIB_IPADDRROW*)b)->dwAddr;
+  else
+    ret = 0;
   return ret;
 }
 
@@ -122,35 +159,56 @@ DWORD WINAPI AllocateAndGetIfTableFromStack(PMIB_IFTABLE *ppIfTable,
 /******************************************************************
  *    AllocateAndGetIpAddrTableFromStack (IPHLPAPI.@)
  *
+ * Get interface-to-IP address mapping table. 
+ * Like GetIpAddrTable(), but allocate the returned table from heap.
  *
  * 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
+ *  ppIpAddrTable [Out] pointer into which the MIB_IPADDRTABLE is
+ *                      allocated and returned.
+ *  bOrder        [In]  whether to sort the table
+ *  heap          [In]  heap from which the table is allocated
+ *  flags         [In]  flags to HeapAlloc
  *
  * RETURNS
- *
- *  DWORD
- *
+ *  ERROR_INVALID_PARAMETER if ppIpAddrTable is NULL, other error codes on
+ *  failure, NO_ERROR on success.
  */
 DWORD WINAPI AllocateAndGetIpAddrTableFromStack(PMIB_IPADDRTABLE *ppIpAddrTable,
  BOOL bOrder, HANDLE heap, DWORD flags)
 {
   DWORD ret;
 
-  if (!ppIpAddrTable)
-    ret = ERROR_INVALID_PARAMETER;
-  else {
-    DWORD dwSize = 0;
+  TRACE("ppIpAddrTable %p, bOrder %d, heap %p, flags 0x%08x\n",
+   ppIpAddrTable, bOrder, heap, flags);
+  ret = getIPAddrTable(ppIpAddrTable, heap, flags);
+  if (!ret && bOrder)
+    qsort((*ppIpAddrTable)->table, (*ppIpAddrTable)->dwNumEntries,
+     sizeof(MIB_IPADDRROW), IpAddrTableSorter);
+  TRACE("returning %d\n", ret);
+  return ret;
+}
 
-    ret = GetIpAddrTable(*ppIpAddrTable, &dwSize, bOrder);
-    if (ret == ERROR_INSUFFICIENT_BUFFER) {
-      *ppIpAddrTable = (PMIB_IPADDRTABLE)HeapAlloc(heap, flags, dwSize);
-      ret = GetIpAddrTable(*ppIpAddrTable, &dwSize, bOrder);
+
+static int IpForwardTableSorter(const void *a, const void *b)
+{
+  int ret;
+
+  if (a && b) {
+   const MIB_IPFORWARDROW* rowA = (const MIB_IPFORWARDROW*)a;
+   const MIB_IPFORWARDROW* rowB = (const MIB_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;
 }
 
@@ -158,33 +216,44 @@ DWORD WINAPI AllocateAndGetIpAddrTableFromStack(PMIB_IPADDRTABLE *ppIpAddrTable,
 /******************************************************************
  *    AllocateAndGetIpForwardTableFromStack (IPHLPAPI.@)
  *
+ * Get the route table.
+ * Like GetIpForwardTable(), but allocate the returned table from heap.
  *
- *  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
+ * PARAMS
+ *  ppIpForwardTable [Out] pointer into which the MIB_IPFORWARDTABLE is
+ *                         allocated and returned.
+ *  bOrder           [In]  whether to sort the table
+ *  heap             [In]  heap from which the table is allocated
+ *  flags            [In]  flags to HeapAlloc
  *
+ * RETURNS
+ *  ERROR_INVALID_PARAMETER if ppIfTable is NULL, other error codes
+ *  on failure, NO_ERROR on success.
  */
 DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *
  ppIpForwardTable, BOOL bOrder, HANDLE heap, DWORD flags)
 {
   DWORD ret;
 
-  if (!ppIpForwardTable)
-    ret = ERROR_INVALID_PARAMETER;
-  else {
-    DWORD dwSize = 0;
+  TRACE("ppIpForwardTable %p, bOrder %d, heap %p, flags 0x%08x\n",
+   ppIpForwardTable, bOrder, heap, flags);
+  ret = getRouteTable(ppIpForwardTable, heap, flags);
+  if (!ret && bOrder)
+    qsort((*ppIpForwardTable)->table, (*ppIpForwardTable)->dwNumEntries,
+     sizeof(MIB_IPFORWARDROW), IpForwardTableSorter);
+  TRACE("returning %d\n", ret);
+  return ret;
+}
 
-    ret = GetIpForwardTable(*ppIpForwardTable, &dwSize, bOrder);
-    if (ret == ERROR_INSUFFICIENT_BUFFER) {
-      *ppIpForwardTable = (PMIB_IPFORWARDTABLE)HeapAlloc(heap, flags, dwSize);
-      ret = GetIpForwardTable(*ppIpForwardTable, &dwSize, bOrder);
-    }
-  }
+
+static int IpNetTableSorter(const void *a, const void *b)
+{
+  int ret;
+
+  if (a && b)
+    ret = ((const MIB_IPNETROW*)a)->dwAddr - ((const MIB_IPNETROW*)b)->dwAddr;
+  else
+    ret = 0;
   return ret;
 }
 
@@ -192,35 +261,58 @@ DWORD WINAPI AllocateAndGetIpForwardTableFromStack(PMIB_IPFORWARDTABLE *
 /******************************************************************
  *    AllocateAndGetIpNetTableFromStack (IPHLPAPI.@)
  *
+ * Get the IP-to-physical address mapping table.
+ * Like GetIpNetTable(), but allocate the returned table from heap.
  *
  * 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
+ *  ppIpNetTable [Out] pointer into which the MIB_IPNETTABLE is
+ *                     allocated and returned.
+ *  bOrder       [In]  whether to sort the table
+ *  heap         [In]  heap from which the table is allocated
+ *  flags        [In]  flags to HeapAlloc
  *
  * RETURNS
- *
- *  DWORD
- *
+ *  ERROR_INVALID_PARAMETER if ppIpNetTable is NULL, other error codes
+ *  on failure, NO_ERROR on success.
  */
 DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable,
  BOOL bOrder, HANDLE heap, DWORD flags)
 {
   DWORD ret;
 
-  if (!ppIpNetTable)
-    ret = ERROR_INVALID_PARAMETER;
-  else {
-    DWORD dwSize = 0;
+  TRACE("ppIpNetTable %p, bOrder %d, heap %p, flags 0x%08x\n",
+   ppIpNetTable, bOrder, heap, flags);
+  ret = getArpTable(ppIpNetTable, heap, flags);
+  if (!ret && bOrder)
+    qsort((*ppIpNetTable)->table, (*ppIpNetTable)->dwNumEntries,
+     sizeof(MIB_IPADDRROW), IpNetTableSorter);
+  TRACE("returning %d\n", ret);
+  return ret;
+}
 
-    ret = GetIpNetTable(*ppIpNetTable, &dwSize, bOrder);
-    if (ret == ERROR_INSUFFICIENT_BUFFER) {
-      *ppIpNetTable = (PMIB_IPNETTABLE)HeapAlloc(heap, flags, dwSize);
-      ret = GetIpNetTable(*ppIpNetTable, &dwSize, bOrder);
+
+static int TcpTableSorter(const void *a, const void *b)
+{
+  int ret;
+
+  if (a && b) {
+    const MIB_TCPROW* rowA = a;
+    const MIB_TCPROW* rowB = b;
+
+    ret = ntohl (rowA->dwLocalAddr) - ntohl (rowB->dwLocalAddr);
+    if (ret == 0) {
+       ret = ntohs ((unsigned short)rowA->dwLocalPort) -
+          ntohs ((unsigned short)rowB->dwLocalPort);
+      if (ret == 0) {
+         ret = ntohl (rowA->dwRemoteAddr) - ntohl (rowB->dwRemoteAddr);
+        if (ret == 0)
+           ret = ntohs ((unsigned short)rowA->dwRemotePort) -
+              ntohs ((unsigned short)rowB->dwRemotePort);
+      }
     }
   }
+  else
+    ret = 0;
   return ret;
 }
 
@@ -228,35 +320,52 @@ DWORD WINAPI AllocateAndGetIpNetTableFromStack(PMIB_IPNETTABLE *ppIpNetTable,
 /******************************************************************
  *    AllocateAndGetTcpTableFromStack (IPHLPAPI.@)
  *
+ * Get the TCP connection table.
+ * Like GetTcpTable(), but allocate the returned table from heap.
  *
  * 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
+ *  ppTcpTable [Out] pointer into which the MIB_TCPTABLE is
+ *                   allocated and returned.
+ *  bOrder     [In]  whether to sort the table
+ *  heap       [In]  heap from which the table is allocated
+ *  flags      [In]  flags to HeapAlloc
  *
  * RETURNS
- *
- *  DWORD
- *
+ *  ERROR_INVALID_PARAMETER if ppTcpTable is NULL, whatever GetTcpTable()
+ *  returns otherwise.
  */
 DWORD WINAPI AllocateAndGetTcpTableFromStack(PMIB_TCPTABLE *ppTcpTable,
  BOOL bOrder, HANDLE heap, DWORD flags)
 {
   DWORD ret;
 
-  if (!ppTcpTable)
-    ret = ERROR_INVALID_PARAMETER;
-  else {
-    DWORD dwSize = 0;
+  TRACE("ppTcpTable %p, bOrder %d, heap %p, flags 0x%08x\n",
+   ppTcpTable, bOrder, heap, flags);
 
-    ret = GetTcpTable(*ppTcpTable, &dwSize, bOrder);
-    if (ret == ERROR_INSUFFICIENT_BUFFER) {
-      *ppTcpTable = (PMIB_TCPTABLE)HeapAlloc(heap, flags, dwSize);
-      ret = GetTcpTable(*ppTcpTable, &dwSize, bOrder);
-    }
+  *ppTcpTable = NULL;
+  ret = getTcpTable(ppTcpTable, 0, heap, flags);
+  if (!ret && bOrder)
+    qsort((*ppTcpTable)->table, (*ppTcpTable)->dwNumEntries,
+     sizeof(MIB_TCPROW), TcpTableSorter);
+  TRACE("returning %d\n", ret);
+  return ret;
+}
+
+
+static int UdpTableSorter(const void *a, const void *b)
+{
+  int ret;
+
+  if (a && b) {
+    const MIB_UDPROW* rowA = (const MIB_UDPROW*)a;
+    const MIB_UDPROW* rowB = (const MIB_UDPROW*)b;
+
+    ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
+    if (ret == 0)
+      ret = rowA->dwLocalPort - rowB->dwLocalPort;
   }
+  else
+    ret = 0;
   return ret;
 }
 
@@ -264,35 +373,32 @@ DWORD WINAPI AllocateAndGetTcpTableFromStack(PMIB_TCPTABLE *ppTcpTable,
 /******************************************************************
  *    AllocateAndGetUdpTableFromStack (IPHLPAPI.@)
  *
+ * Get the UDP listener table.
+ * Like GetUdpTable(), but allocate the returned table from heap.
  *
  * 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
+ *  ppUdpTable [Out] pointer into which the MIB_UDPTABLE is
+ *                   allocated and returned.
+ *  bOrder     [In]  whether to sort the table
+ *  heap       [In]  heap from which the table is allocated
+ *  flags      [In]  flags to HeapAlloc
  *
  * RETURNS
- *
- *  DWORD
- *
+ *  ERROR_INVALID_PARAMETER if ppUdpTable is NULL, whatever GetUdpTable()
+ *  returns otherwise.
  */
 DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable,
  BOOL bOrder, HANDLE heap, DWORD flags)
 {
   DWORD ret;
 
-  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("ppUdpTable %p, bOrder %d, heap %p, flags 0x%08x\n",
+   ppUdpTable, bOrder, heap, flags);
+  ret = getUdpTable(ppUdpTable, heap, flags);
+  if (!ret && bOrder)
+    qsort((*ppUdpTable)->table, (*ppUdpTable)->dwNumEntries,
+     sizeof(MIB_UDPROW), UdpTableSorter);
+  TRACE("returning %d\n", ret);
   return ret;
 }
 
@@ -300,20 +406,22 @@ DWORD WINAPI AllocateAndGetUdpTableFromStack(PMIB_UDPTABLE *ppUdpTable,
 /******************************************************************
  *    CreateIpForwardEntry (IPHLPAPI.@)
  *
+ * Create a route in the local computer's IP table.
  *
  * PARAMS
- *
- *  pRoute [In/Out]
+ *  pRoute [In] new route information
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * FIXME
+ *  Stub, always returns NO_ERROR.
  */
 DWORD WINAPI CreateIpForwardEntry(PMIB_IPFORWARDROW pRoute)
 {
+  FIXME("(pRoute %p): stub\n", pRoute);
   /* could use SIOCADDRT, not sure I want to */
-  FIXME(":stub\n");
   return (DWORD) 0;
 }
 
@@ -321,20 +429,22 @@ DWORD WINAPI CreateIpForwardEntry(PMIB_IPFORWARDROW pRoute)
 /******************************************************************
  *    CreateIpNetEntry (IPHLPAPI.@)
  *
+ * Create entry in the ARP table.
  *
  * PARAMS
- *
- *  pArpEntry [In/Out]
+ *  pArpEntry [In] new ARP entry
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * FIXME
+ *  Stub, always returns NO_ERROR.
  */
 DWORD WINAPI CreateIpNetEntry(PMIB_IPNETROW pArpEntry)
 {
+  FIXME("(pArpEntry %p)\n", pArpEntry);
   /* could use SIOCSARP on systems that support it, not sure I want to */
-  FIXME(":stub\n");
   return (DWORD) 0;
 }
 
@@ -342,22 +452,24 @@ DWORD WINAPI CreateIpNetEntry(PMIB_IPNETROW pArpEntry)
 /******************************************************************
  *    CreateProxyArpEntry (IPHLPAPI.@)
  *
+ * Create a Proxy ARP (PARP) entry for an IP address.
  *
  * PARAMS
- *
- *  dwAddress [In]
- *  dwMask [In]
- *  dwIfIndex [In]
+ *  dwAddress [In] IP address for which this computer acts as a proxy. 
+ *  dwMask    [In] subnet mask for dwAddress
+ *  dwIfIndex [In] interface index
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * FIXME
+ *  Stub, returns ERROR_NOT_SUPPORTED.
  */
 DWORD WINAPI CreateProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
 {
-  FIXME(":stub\n");
-  /* marking Win2K+ functions not supported */
+  FIXME("(dwAddress 0x%08x, dwMask 0x%08x, dwIfIndex 0x%08x): stub\n",
+   dwAddress, dwMask, dwIfIndex);
   return ERROR_NOT_SUPPORTED;
 }
 
@@ -365,20 +477,21 @@ DWORD WINAPI CreateProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
 /******************************************************************
  *    DeleteIPAddress (IPHLPAPI.@)
  *
+ * Delete an IP address added with AddIPAddress().
  *
  * PARAMS
- *
- *  NTEContext [In]
+ *  NTEContext [In] NTE context from AddIPAddress();
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * FIXME
+ *  Stub, returns ERROR_NOT_SUPPORTED.
  */
 DWORD WINAPI DeleteIPAddress(ULONG NTEContext)
 {
-  FIXME(":stub\n");
-  /* marking Win2K+ functions not supported */
+  FIXME("(NTEContext %d): stub\n", NTEContext);
   return ERROR_NOT_SUPPORTED;
 }
 
@@ -386,20 +499,22 @@ DWORD WINAPI DeleteIPAddress(ULONG NTEContext)
 /******************************************************************
  *    DeleteIpForwardEntry (IPHLPAPI.@)
  *
+ * Delete a route.
  *
  * PARAMS
- *
- *  pRoute [In/Out]
+ *  pRoute [In] route to delete
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * FIXME
+ *  Stub, returns NO_ERROR.
  */
 DWORD WINAPI DeleteIpForwardEntry(PMIB_IPFORWARDROW pRoute)
 {
+  FIXME("(pRoute %p): stub\n", pRoute);
   /* could use SIOCDELRT, not sure I want to */
-  FIXME(":stub\n");
   return (DWORD) 0;
 }
 
@@ -407,20 +522,22 @@ DWORD WINAPI DeleteIpForwardEntry(PMIB_IPFORWARDROW pRoute)
 /******************************************************************
  *    DeleteIpNetEntry (IPHLPAPI.@)
  *
+ * Delete an ARP entry.
  *
  * PARAMS
- *
- *  pArpEntry [In/Out]
+ *  pArpEntry [In] ARP entry to delete
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * FIXME
+ *  Stub, returns NO_ERROR.
  */
 DWORD WINAPI DeleteIpNetEntry(PMIB_IPNETROW pArpEntry)
 {
+  FIXME("(pArpEntry %p): stub\n", pArpEntry);
   /* could use SIOCDARP on systems that support it, not sure I want to */
-  FIXME(":stub\n");
   return (DWORD) 0;
 }
 
@@ -428,22 +545,24 @@ DWORD WINAPI DeleteIpNetEntry(PMIB_IPNETROW pArpEntry)
 /******************************************************************
  *    DeleteProxyArpEntry (IPHLPAPI.@)
  *
+ * Delete a Proxy ARP entry.
  *
  * PARAMS
- *
- *  dwAddress [In]
- *  dwMask [In]
- *  dwIfIndex [In]
+ *  dwAddress [In] IP address for which this computer acts as a proxy. 
+ *  dwMask    [In] subnet mask for dwAddress
+ *  dwIfIndex [In] interface index
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * FIXME
+ *  Stub, returns ERROR_NOT_SUPPORTED.
  */
 DWORD WINAPI DeleteProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
 {
-  FIXME(":stub\n");
-  /* marking Win2K+ functions not supported */
+  FIXME("(dwAddress 0x%08x, dwMask 0x%08x, dwIfIndex 0x%08x): stub\n",
+   dwAddress, dwMask, dwIfIndex);
   return ERROR_NOT_SUPPORTED;
 }
 
@@ -451,23 +570,25 @@ DWORD WINAPI DeleteProxyArpEntry(DWORD dwAddress, DWORD dwMask, DWORD dwIfIndex)
 /******************************************************************
  *    EnableRouter (IPHLPAPI.@)
  *
+ * Turn on ip forwarding.
  *
  * PARAMS
- *
- *  pHandle [In/Out]
- *  pOverlapped [In/Out]
+ *  pHandle     [In/Out]
+ *  pOverlapped [In/Out] hEvent member should contain a valid handle.
  *
  * RETURNS
+ *  Success: ERROR_IO_PENDING
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * FIXME
+ *  Stub, returns ERROR_NOT_SUPPORTED.
  */
 DWORD WINAPI EnableRouter(HANDLE * pHandle, OVERLAPPED * pOverlapped)
 {
-  FIXME(":stub\n");
+  FIXME("(pHandle %p, pOverlapped %p): stub\n", pHandle, pOverlapped);
   /* 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;
 }
 
@@ -475,21 +596,22 @@ DWORD WINAPI EnableRouter(HANDLE * pHandle, OVERLAPPED * pOverlapped)
 /******************************************************************
  *    FlushIpNetTable (IPHLPAPI.@)
  *
+ * Delete all ARP entries of an interface
  *
  * PARAMS
- *
- *  dwIfIndex [In]
+ *  dwIfIndex [In] interface index
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * FIXME
+ *  Stub, returns ERROR_NOT_SUPPORTED.
  */
 DWORD WINAPI FlushIpNetTable(DWORD dwIfIndex)
 {
-  FIXME(":stub\n");
-  /* this flushes the arp cache of the given index
-     marking Win2K+ functions not supported */
+  FIXME("(dwIfIndex 0x%08x): stub\n", dwIfIndex);
+  /* this flushes the arp cache of the given index */
   return ERROR_NOT_SUPPORTED;
 }
 
@@ -497,94 +619,164 @@ DWORD WINAPI FlushIpNetTable(DWORD dwIfIndex)
 /******************************************************************
  *    GetAdapterIndex (IPHLPAPI.@)
  *
+ * Get interface index from its name.
  *
  * PARAMS
- *
- *  AdapterName [In/Out]
- *  IfIndex [In/Out]
+ *  AdapterName [In]  unicode string with the adapter name
+ *  IfIndex     [Out] returns found interface index
  *
  * RETURNS
- *
- *  DWORD
- *
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  */
 DWORD WINAPI GetAdapterIndex(LPWSTR AdapterName, PULONG IfIndex)
 {
-  FIXME(":stub\n");
-  /* marking Win2K+ functions not supported */
-  return ERROR_NOT_SUPPORTED;
+  char adapterName[MAX_ADAPTER_NAME];
+  int i;
+  DWORD ret;
+
+  TRACE("(AdapterName %p, IfIndex %p)\n", AdapterName, IfIndex);
+  /* The adapter name is guaranteed not to have any unicode characters, so
+   * this translation is never lossy */
+  for (i = 0; i < sizeof(adapterName) - 1 && AdapterName[i]; i++)
+    adapterName[i] = (char)AdapterName[i];
+  adapterName[i] = '\0';
+  ret = getInterfaceIndexByName(adapterName, IfIndex);
+  TRACE("returning %d\n", ret);
+  return ret;
 }
 
 
 /******************************************************************
  *    GetAdaptersInfo (IPHLPAPI.@)
  *
+ * Get information about adapters.
  *
  * PARAMS
- *
- *  pAdapterInfo [In/Out]
- *  pOutBufLen [In/Out]
+ *  pAdapterInfo [Out] buffer for adapter infos
+ *  pOutBufLen   [In]  length of output buffer
  *
  * RETURNS
- *
- *  DWORD
- *
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  */
 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
-         - we don't know about DHCP or WINS (and these must be single anyway) */
-      ULONG size = sizeof(IP_ADAPTER_INFO) * numNonLoopbackInterfaces;
-
+      DWORD numIPAddresses = getNumIPAddresses();
+      ULONG size;
+
+      /* This may slightly overestimate the amount of space needed, because
+       * the IP addresses include the loopback address, but it's easier
+       * to make sure there's more than enough space than to make sure there's
+       * precisely enough space.
+       */
+      size = sizeof(IP_ADAPTER_INFO) * numNonLoopbackInterfaces;
+      size += numIPAddresses  * sizeof(IP_ADDR_STRING); 
       if (!pAdapterInfo || *pOutBufLen < size) {
         *pOutBufLen = size;
         ret = ERROR_BUFFER_OVERFLOW;
       }
       else {
-        InterfaceIndexTable *table = getNonLoopbackInterfaceIndexTable();
-
+        InterfaceIndexTable *table = NULL;
+        PMIB_IPADDRTABLE ipAddrTable = NULL;
+        PMIB_IPFORWARDTABLE routeTable = NULL;
+
+        ret = getIPAddrTable(&ipAddrTable, GetProcessHeap(), 0);
+        if (!ret)
+          ret = getRouteTable(&routeTable, GetProcessHeap(), 0);
+        if (!ret)
+          table = getNonLoopbackInterfaceIndexTable();
         if (table) {
           size = sizeof(IP_ADAPTER_INFO) * table->numIndexes;
+          size += ipAddrTable->dwNumEntries * sizeof(IP_ADDR_STRING); 
           if (*pOutBufLen < size) {
             *pOutBufLen = size;
             ret = ERROR_INSUFFICIENT_BUFFER;
           }
           else {
             DWORD ndx;
+            HKEY hKey;
+            BOOL winsEnabled = FALSE;
+            IP_ADDRESS_STRING primaryWINS, secondaryWINS;
+            PIP_ADDR_STRING nextIPAddr = (PIP_ADDR_STRING)((LPBYTE)pAdapterInfo
+             + numNonLoopbackInterfaces * sizeof(IP_ADAPTER_INFO));
 
             memset(pAdapterInfo, 0, size);
+            /* @@ Wine registry key: HKCU\Software\Wine\Network */
+            if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Network",
+             &hKey) == ERROR_SUCCESS) {
+              DWORD size = sizeof(primaryWINS.String);
+              unsigned long addr;
+
+              RegQueryValueExA(hKey, "WinsServer", NULL, NULL,
+               (LPBYTE)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,
+               (LPBYTE)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;
+              DWORD i;
+              PIP_ADDR_STRING currentIPAddr = &ptr->IpAddressList;
+              BOOL firstIPAddr = TRUE;
 
               /* on Win98 this is left empty, but whatever */
-              strncpy(ptr->AdapterName,
-               getInterfaceNameByIndex(table->indexes[ndx]),
-               sizeof(ptr->AdapterName));
-              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;
+              getInterfaceNameByIndex(table->indexes[ndx], ptr->AdapterName);
+              ptr->AddressLength = sizeof(ptr->Address);
+              getInterfacePhysicalByIndex(table->indexes[ndx],
+               &ptr->AddressLength, ptr->Address, &ptr->Type);
               ptr->Index = table->indexes[ndx];
-              toIPAddressString(getInterfaceIPAddrByIndex(table->indexes[ndx]),
-               ptr->IpAddressList.IpAddress.String);
-              toIPAddressString(getInterfaceMaskByIndex(table->indexes[ndx]),
-               ptr->IpAddressList.IpMask.String);
+              for (i = 0; i < ipAddrTable->dwNumEntries; i++) {
+                if (ipAddrTable->table[i].dwIndex == ptr->Index) {
+                  if (firstIPAddr) {
+                    toIPAddressString(ipAddrTable->table[i].dwAddr,
+                     ptr->IpAddressList.IpAddress.String);
+                    toIPAddressString(ipAddrTable->table[i].dwMask,
+                     ptr->IpAddressList.IpMask.String);
+                    firstIPAddr = FALSE;
+                  }
+                  else {
+                    currentIPAddr->Next = nextIPAddr;
+                    currentIPAddr = nextIPAddr;
+                    toIPAddressString(ipAddrTable->table[i].dwAddr,
+                     currentIPAddr->IpAddress.String);
+                    toIPAddressString(ipAddrTable->table[i].dwMask,
+                     currentIPAddr->IpMask.String);
+                    nextIPAddr++;
+                  }
+                }
+              }
+              /* Find first router through this interface, which we'll assume
+               * is the default gateway for this adapter */
+              for (i = 0; i < routeTable->dwNumEntries; i++)
+                if (routeTable->table[i].dwForwardIfIndex == ptr->Index
+                 && routeTable->table[i].dwForwardType ==
+                 MIB_IPROUTE_TYPE_INDIRECT)
+                  toIPAddressString(routeTable->table[i].dwForwardNextHop,
+                   ptr->GatewayList.IpAddress.String);
+              if (winsEnabled) {
+                ptr->HaveWins = TRUE;
+                memcpy(ptr->PrimaryWinsServer.IpAddress.String,
+                 primaryWINS.String, sizeof(primaryWINS.String));
+                memcpy(ptr->SecondaryWinsServer.IpAddress.String,
+                 secondaryWINS.String, sizeof(secondaryWINS.String));
+              }
               if (ndx < table->numIndexes - 1)
                 ptr->Next = &pAdapterInfo[ndx + 1];
               else
@@ -592,15 +784,18 @@ DWORD WINAPI GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
             }
             ret = NO_ERROR;
           }
-          free(table);
+          HeapFree(GetProcessHeap(), 0, table);
         }
         else
           ret = ERROR_OUTOFMEMORY;
+        HeapFree(GetProcessHeap(), 0, routeTable);
+        HeapFree(GetProcessHeap(), 0, ipAddrTable);
       }
     }
     else
       ret = ERROR_NO_DATA;
   }
+  TRACE("returning %d\n", ret);
   return ret;
 }
 
@@ -608,30 +803,58 @@ DWORD WINAPI GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
 /******************************************************************
  *    GetBestInterface (IPHLPAPI.@)
  *
+ * Get the interface, with the best route for the given IP address.
  *
  * PARAMS
- *
- *  dwDestAddr [In]
- *  pdwBestIfIndex [In/Out]
+ *  dwDestAddr     [In]  IP address to search the interface for
+ *  pdwBestIfIndex [Out] found best interface
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
+ */
+DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
+{
+    struct WS_sockaddr_in sa_in;
+    memset(&sa_in, 0, sizeof(sa_in));
+    sa_in.sin_family = AF_INET;
+    sa_in.sin_addr.S_un.S_addr = dwDestAddr;
+    return GetBestInterfaceEx((struct WS_sockaddr *)&sa_in, pdwBestIfIndex);
+}
+
+/******************************************************************
+ *    GetBestInterfaceEx (IPHLPAPI.@)
  *
- *  DWORD
+ * Get the interface, with the best route for the given IP address.
+ *
+ * PARAMS
+ *  dwDestAddr     [In]  IP address to search the interface for
+ *  pdwBestIfIndex [Out] found best interface
  *
+ * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  */
-DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
+DWORD WINAPI GetBestInterfaceEx(struct WS_sockaddr *pDestAddr, PDWORD pdwBestIfIndex)
 {
   DWORD ret;
 
-  if (!pdwBestIfIndex)
+  TRACE("pDestAddr %p, pdwBestIfIndex %p\n", pDestAddr, pdwBestIfIndex);
+  if (!pDestAddr || !pdwBestIfIndex)
     ret = ERROR_INVALID_PARAMETER;
   else {
     MIB_IPFORWARDROW ipRow;
 
-    ret = GetBestRoute(dwDestAddr, 0, &ipRow);
-    if (ret == ERROR_SUCCESS)
-      *pdwBestIfIndex = ipRow.dwForwardIfIndex;
+    if (pDestAddr->sa_family == AF_INET) {
+      ret = GetBestRoute(((struct WS_sockaddr_in *)pDestAddr)->sin_addr.S_un.S_addr, 0, &ipRow);
+      if (ret == ERROR_SUCCESS)
+        *pdwBestIfIndex = ipRow.dwForwardIfIndex;
+    } else {
+      FIXME("address family %d not supported\n", pDestAddr->sa_family);
+      ret = ERROR_NOT_SUPPORTED;
+    }
   }
+  TRACE("returning %d\n", ret);
   return ret;
 }
 
@@ -639,32 +862,34 @@ DWORD WINAPI GetBestInterface(IPAddr dwDestAddr, PDWORD pdwBestIfIndex)
 /******************************************************************
  *    GetBestRoute (IPHLPAPI.@)
  *
+ * Get the best route for the given IP address.
  *
  * PARAMS
- *
- *  dwDestAddr [In]
- *  dwSourceAddr [In]
- *  OUT [In]
+ *  dwDestAddr   [In]  IP address to search the best route for
+ *  dwSourceAddr [In]  optional source IP address
+ *  pBestRoute   [Out] found best route
  *
  * RETURNS
- *
- *  DWORD
- *
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  */
 DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDROW pBestRoute)
 {
   PMIB_IPFORWARDTABLE table;
   DWORD ret;
 
+  TRACE("dwDestAddr 0x%08x, dwSourceAddr 0x%08x, pBestRoute %p\n", dwDestAddr,
+   dwSourceAddr, pBestRoute);
   if (!pBestRoute)
     return ERROR_INVALID_PARAMETER;
 
-  AllocateAndGetIpForwardTableFromStack(&table, FALSE, GetProcessHeap(), 0);
-  if (table) {
-    DWORD ndx, matchedBits, matchedNdx = 0;
+  ret = AllocateAndGetIpForwardTableFromStack(&table, FALSE, GetProcessHeap(), 0);
+  if (!ret) {
+    DWORD ndx, matchedBits, matchedNdx = table->dwNumEntries;
 
     for (ndx = 0, matchedBits = 0; ndx < table->dwNumEntries; ndx++) {
-      if ((dwDestAddr & table->table[ndx].dwForwardMask) ==
+      if (table->table[ndx].dwForwardType != MIB_IPROUTE_TYPE_INVALID &&
+       (dwDestAddr & table->table[ndx].dwForwardMask) ==
        (table->table[ndx].dwForwardDest & table->table[ndx].dwForwardMask)) {
         DWORD numShifts, mask;
 
@@ -675,14 +900,24 @@ DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDRO
           matchedBits = numShifts;
           matchedNdx = ndx;
         }
+        else if (!matchedBits && table->table[ndx].dwForwardType ==
+         MIB_IPROUTE_TYPE_INDIRECT) {
+          /* default to a default gateway */
+          matchedNdx = ndx;
+        }
       }
     }
-    memcpy(pBestRoute, &table->table[matchedNdx], sizeof(MIB_IPFORWARDROW));
+    if (matchedNdx < table->dwNumEntries) {
+      memcpy(pBestRoute, &table->table[matchedNdx], sizeof(MIB_IPFORWARDROW));
+      ret = ERROR_SUCCESS;
+    }
+    else {
+      /* No route matches, which can happen if there's no default route. */
+      ret = ERROR_HOST_UNREACHABLE;
+    }
     HeapFree(GetProcessHeap(), 0, table);
-    ret = ERROR_SUCCESS;
   }
-  else
-    ret = ERROR_OUTOFMEMORY;
+  TRACE("returning %d\n", ret);
   return ret;
 }
 
@@ -690,21 +925,22 @@ DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDRO
 /******************************************************************
  *    GetFriendlyIfIndex (IPHLPAPI.@)
  *
+ * Get a "friendly" version of IfIndex, which is one that doesn't
+ * have the top byte set.  Doesn't validate whether IfIndex is a valid
+ * adapter index.
  *
  * PARAMS
- *
- *  IfIndex [In]
+ *  IfIndex [In] interface index to get the friendly one for
  *
  * RETURNS
- *
- *  DWORD
- *
+ *  A friendly version of IfIndex.
  */
 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 %d\n", IfIndex);
   return IfIndex;
 }
 
@@ -712,44 +948,50 @@ DWORD WINAPI GetFriendlyIfIndex(DWORD IfIndex)
 /******************************************************************
  *    GetIcmpStatistics (IPHLPAPI.@)
  *
+ * Get the ICMP statistics for the local computer.
  *
  * PARAMS
- *
- *  pStats [In/Out]
+ *  pStats [Out] buffer for ICMP statistics
  *
  * RETURNS
- *
- *  DWORD
- *
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  */
 DWORD WINAPI GetIcmpStatistics(PMIB_ICMP pStats)
 {
-  return getICMPStats(pStats);
+  DWORD ret;
+
+  TRACE("pStats %p\n", pStats);
+  ret = getICMPStats(pStats);
+  TRACE("returning %d\n", ret);
+  return ret;
 }
 
 
 /******************************************************************
  *    GetIfEntry (IPHLPAPI.@)
  *
+ * Get information about an interface.
  *
  * PARAMS
- *
- *  pIfRow [In/Out]
+ *  pIfRow [In/Out] In:  dwIndex of MIB_IFROW selects the interface.
+ *                  Out: interface information
  *
  * RETURNS
- *
- *  DWORD
- *
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  */
 DWORD WINAPI GetIfEntry(PMIB_IFROW pIfRow)
 {
   DWORD ret;
-  const char *name;
+  char nameBuf[MAX_ADAPTER_NAME];
+  char *name;
 
+  TRACE("pIfRow %p\n", pIfRow);
   if (!pIfRow)
     return ERROR_INVALID_PARAMETER;
 
-  name = getInterfaceNameByIndex(pIfRow->dwIndex);
+  name = getInterfaceNameByIndex(pIfRow->dwIndex, nameBuf);
   if (name) {
     ret = getInterfaceEntryByName(name, pIfRow);
     if (ret == NO_ERROR)
@@ -757,6 +999,7 @@ DWORD WINAPI GetIfEntry(PMIB_IFROW pIfRow)
   }
   else
     ret = ERROR_INVALID_DATA;
+  TRACE("returning %d\n", ret);
   return ret;
 }
 
@@ -766,7 +1009,7 @@ static int IfTableSorter(const void *a, const void *b)
   int ret;
 
   if (a && b)
-    ret = ((PMIB_IFROW)a)->dwIndex - ((PMIB_IFROW)b)->dwIndex;
+    ret = ((const MIB_IFROW*)a)->dwIndex - ((const MIB_IFROW*)b)->dwIndex;
   else
     ret = 0;
   return ret;
@@ -776,28 +1019,37 @@ static int IfTableSorter(const void *a, const void *b)
 /******************************************************************
  *    GetIfTable (IPHLPAPI.@)
  *
+ * Get a table of local interfaces.
  *
  * PARAMS
- *
- *  pIfTable [In/Out]
- *  pdwSize [In/Out]
- *  bOrder [In]
+ *  pIfTable [Out]    buffer for local interfaces table
+ *  pdwSize  [In/Out] length of output buffer
+ *  bOrder   [In]     whether to sort the table
  *
  * RETURNS
- *
- *  DWORD
- *
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
+ *
+ * NOTES
+ *  If pdwSize is less than required, the function will return
+ *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
+ *  size.
+ *  If bOrder is true, the returned table will be sorted by interface index.
  */
 DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
 {
   DWORD ret;
 
+  TRACE("pIfTable %p, pdwSize %p, bOrder %d\n", pdwSize, pdwSize,
+   (DWORD)bOrder);
   if (!pdwSize)
     ret = ERROR_INVALID_PARAMETER;
   else {
     DWORD numInterfaces = getNumInterfaces();
-    ULONG size = sizeof(MIB_IFTABLE) + (numInterfaces - 1) * sizeof(MIB_IFROW);
+    ULONG size = sizeof(MIB_IFTABLE);
 
+    if (numInterfaces > 1)
+      size += (numInterfaces - 1) * sizeof(MIB_IFROW);
     if (!pIfTable || *pdwSize < size) {
       *pdwSize = size;
       ret = ERROR_INSUFFICIENT_BUFFER;
@@ -806,8 +1058,9 @@ DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
       InterfaceIndexTable *table = getInterfaceIndexTable();
 
       if (table) {
-        size = sizeof(MIB_IFTABLE) + (table->numIndexes - 1) *
-         sizeof(MIB_IFROW);
+        size = sizeof(MIB_IFTABLE);
+        if (table->numIndexes > 1)
+          size += (table->numIndexes - 1) * sizeof(MIB_IFROW);
         if (*pdwSize < size) {
           *pdwSize = size;
           ret = ERROR_INSUFFICIENT_BUFFER;
@@ -815,6 +1068,7 @@ DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
         else {
           DWORD ndx;
 
+          *pdwSize = size;
           pIfTable->dwNumEntries = 0;
           for (ndx = 0; ndx < table->numIndexes; ndx++) {
             pIfTable->table[ndx].dwIndex = table->indexes[ndx];
@@ -826,12 +1080,13 @@ DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
              IfTableSorter);
           ret = NO_ERROR;
         }
-        free(table);
+        HeapFree(GetProcessHeap(), 0, table);
       }
       else
         ret = ERROR_OUTOFMEMORY;
     }
   }
+  TRACE("returning %d\n", ret);
   return ret;
 }
 
@@ -839,28 +1094,32 @@ DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
 /******************************************************************
  *    GetInterfaceInfo (IPHLPAPI.@)
  *
+ * Get a list of network interface adapters.
  *
  * PARAMS
- *
- *  pIfTable [In/Out]
- *  dwOutBufLen [In/Out]
+ *  pIfTable    [Out] buffer for interface adapters
+ *  dwOutBufLen [Out] if buffer is too small, returns required size
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * BUGS
+ *  MSDN states this should return non-loopback interfaces only.
  */
 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);
+    ULONG size = sizeof(IP_INTERFACE_INFO);
 
+    if (numInterfaces > 1)
+      size += (numInterfaces - 1) * sizeof(IP_ADAPTER_INDEX_MAP);
     if (!pIfTable || *dwOutBufLen < size) {
       *dwOutBufLen = size;
       ret = ERROR_INSUFFICIENT_BUFFER;
@@ -869,22 +1128,25 @@ DWORD WINAPI GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen)
       InterfaceIndexTable *table = getInterfaceIndexTable();
 
       if (table) {
-        size = sizeof(IP_INTERFACE_INFO) + (table->numIndexes - 1) *
-         sizeof(IP_ADAPTER_INDEX_MAP);
+        size = sizeof(IP_INTERFACE_INFO);
+        if (table->numIndexes > 1)
+          size += (table->numIndexes - 1) * sizeof(IP_ADAPTER_INDEX_MAP);
         if (*dwOutBufLen < size) {
           *dwOutBufLen = size;
           ret = ERROR_INSUFFICIENT_BUFFER;
         }
         else {
           DWORD ndx;
+          char nameBuf[MAX_ADAPTER_NAME];
 
+          *dwOutBufLen = size;
           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]);
+            name = getInterfaceNameByIndex(table->indexes[ndx], nameBuf);
             for (walker = name, assigner = pIfTable->Adapter[ndx].Name;
              walker && *walker &&
              assigner - pIfTable->Adapter[ndx].Name < MAX_ADAPTER_NAME - 1;
@@ -895,24 +1157,13 @@ DWORD WINAPI GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen)
           }
           ret = NO_ERROR;
         }
-        free(table);
+        HeapFree(GetProcessHeap(), 0, table);
       }
       else
         ret = ERROR_OUTOFMEMORY;
     }
   }
-  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;
+  TRACE("returning %d\n", ret);
   return ret;
 }
 
@@ -920,95 +1171,58 @@ static int IpAddrTableSorter(const void *a, const void *b)
 /******************************************************************
  *    GetIpAddrTable (IPHLPAPI.@)
  *
+ * Get interface-to-IP address mapping table. 
  *
  * PARAMS
- *
- *  pIpAddrTable [In/Out]
- *  pdwSize [In/Out]
- *  bOrder [In]
+ *  pIpAddrTable [Out]    buffer for mapping table
+ *  pdwSize      [In/Out] length of output buffer
+ *  bOrder       [In]     whether to sort the table
  *
  * RETURNS
- *
- *  DWORD
- *
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
+ *
+ * NOTES
+ *  If pdwSize is less than required, the function will return
+ *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
+ *  size.
+ *  If bOrder is true, the returned table will be sorted by the next hop and
+ *  an assortment of arbitrary parameters.
  */
 DWORD WINAPI GetIpAddrTable(PMIB_IPADDRTABLE pIpAddrTable, PULONG pdwSize, BOOL bOrder)
 {
   DWORD ret;
 
+  TRACE("pIpAddrTable %p, pdwSize %p, bOrder %d\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);
+    PMIB_IPADDRTABLE table;
 
-    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;
-
-          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]);
-            pIpAddrTable->table[ndx].dwBCastAddr =
-             getInterfaceBCastAddrByIndex(table->indexes[ndx]);
-            /* 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);
+    ret = getIPAddrTable(&table, GetProcessHeap(), 0);
+    if (ret == NO_ERROR)
+    {
+      ULONG size = sizeof(MIB_IPADDRTABLE);
+
+      if (table->dwNumEntries > 1)
+        size += (table->dwNumEntries - 1) * sizeof(MIB_IPADDRROW);
+      if (!pIpAddrTable || *pdwSize < size) {
+        *pdwSize = size;
+        ret = ERROR_INSUFFICIENT_BUFFER;
       }
-      else
-        ret = ERROR_OUTOFMEMORY;
-    }
-  }
-  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 {
+        *pdwSize = size;
+        memcpy(pIpAddrTable, table, size);
+        if (bOrder)
+          qsort(pIpAddrTable->table, pIpAddrTable->dwNumEntries,
+           sizeof(MIB_IPADDRROW), IpAddrTableSorter);
+        ret = NO_ERROR;
       }
+      HeapFree(GetProcessHeap(), 0, table);
     }
   }
-  else
-    ret = 0;
+  TRACE("returning %d\n", ret);
   return ret;
 }
 
@@ -1016,96 +1230,67 @@ static int IpForwardTableSorter(const void *a, const void *b)
 /******************************************************************
  *    GetIpForwardTable (IPHLPAPI.@)
  *
+ * Get the route table.
  *
  * PARAMS
- *
- *  pIpForwardTable [In/Out]
- *  pdwSize [In/Out]
- *  bOrder [In]
+ *  pIpForwardTable [Out]    buffer for route table
+ *  pdwSize         [In/Out] length of output buffer
+ *  bOrder          [In]     whether to sort the table
  *
  * RETURNS
- *
- *  DWORD
- *
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
+ *
+ * NOTES
+ *  If pdwSize is less than required, the function will return
+ *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
+ *  size.
+ *  If bOrder is true, the returned table will be sorted by the next hop and
+ *  an assortment of arbitrary parameters.
  */
 DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSize, BOOL bOrder)
 {
   DWORD ret;
 
+  TRACE("pIpForwardTable %p, pdwSize %p, bOrder %d\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);
+    ULONG sizeNeeded = sizeof(MIB_IPFORWARDTABLE);
 
+    if (numRoutes > 1)
+      sizeNeeded += (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);
+      PMIB_IPFORWARDTABLE table;
+
+      ret = getRouteTable(&table, GetProcessHeap(), 0);
+      if (!ret) {
+        sizeNeeded = sizeof(MIB_IPFORWARDTABLE);
+        if (table->dwNumEntries > 1)
+          sizeNeeded += (table->dwNumEntries - 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;
-          }
+          *pdwSize = sizeNeeded;
+          memcpy(pIpForwardTable, table, sizeNeeded);
           if (bOrder)
             qsort(pIpForwardTable->table, pIpForwardTable->dwNumEntries,
              sizeof(MIB_IPFORWARDROW), IpForwardTableSorter);
           ret = NO_ERROR;
         }
-        free(table);
+        HeapFree(GetProcessHeap(), 0, table);
       }
-      else
-        ret = ERROR_OUTOFMEMORY;
     }
   }
-  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;
+  TRACE("returning %d\n", ret);
   return ret;
 }
 
@@ -1113,56 +1298,66 @@ static int IpNetTableSorter(const void *a, const void *b)
 /******************************************************************
  *    GetIpNetTable (IPHLPAPI.@)
  *
+ * Get the IP-to-physical address mapping table.
  *
  * PARAMS
- *
- *  pIpNetTable [In/Out]
- *  pdwSize [In/Out]
- *  bOrder [In]
+ *  pIpNetTable [Out]    buffer for mapping table
+ *  pdwSize     [In/Out] length of output buffer
+ *  bOrder      [In]     whether to sort the table
  *
  * RETURNS
- *
- *  DWORD
- *
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
+ *
+ * NOTES
+ *  If pdwSize is less than required, the function will return
+ *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the required byte
+ *  size.
+ *  If bOrder is true, the returned table will be sorted by IP address.
  */
 DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder)
 {
   DWORD ret;
 
+  TRACE("pIpNetTable %p, pdwSize %p, bOrder %d\n", pIpNetTable, pdwSize,
+   (DWORD)bOrder);
   if (!pdwSize)
     ret = ERROR_INVALID_PARAMETER;
   else {
     DWORD numEntries = getNumArpEntries();
-    ULONG size = sizeof(MIB_IPNETTABLE) + (numEntries - 1) *
-     sizeof(MIB_IPNETROW);
+    ULONG size = sizeof(MIB_IPNETTABLE);
 
+    if (numEntries > 1)
+      size += (numEntries - 1) * sizeof(MIB_IPNETROW);
     if (!pIpNetTable || *pdwSize < size) {
       *pdwSize = size;
       ret = ERROR_INSUFFICIENT_BUFFER;
     }
     else {
-      PMIB_IPNETTABLE table = getArpTable();
+      PMIB_IPNETTABLE table;
 
-      if (table) {
-        size = sizeof(MIB_IPNETTABLE) + (table->dwNumEntries - 1) *
-         sizeof(MIB_IPNETROW);
+      ret = getArpTable(&table, GetProcessHeap(), 0);
+      if (!ret) {
+        size = sizeof(MIB_IPNETTABLE);
+        if (table->dwNumEntries > 1)
+          size += (table->dwNumEntries - 1) * sizeof(MIB_IPNETROW);
         if (*pdwSize < size) {
           *pdwSize = size;
           ret = ERROR_INSUFFICIENT_BUFFER;
         }
         else {
+          *pdwSize = size;
           memcpy(pIpNetTable, table, size);
           if (bOrder)
             qsort(pIpNetTable->table, pIpNetTable->dwNumEntries,
              sizeof(MIB_IPNETROW), IpNetTableSorter);
           ret = NO_ERROR;
         }
-        free(table);
+        HeapFree(GetProcessHeap(), 0, table);
       }
-      else
-        ret = ERROR_OUTOFMEMORY;
     }
   }
+  TRACE("returning %d\n", ret);
   return ret;
 }
 
@@ -1170,45 +1365,55 @@ DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOr
 /******************************************************************
  *    GetIpStatistics (IPHLPAPI.@)
  *
+ * Get the IP statistics for the local computer.
  *
  * PARAMS
- *
- *  pStats [In/Out]
+ *  pStats [Out] buffer for IP statistics
  *
  * RETURNS
- *
- *  DWORD
- *
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  */
 DWORD WINAPI GetIpStatistics(PMIB_IPSTATS pStats)
 {
-  return getIPStats(pStats);
+  DWORD ret;
+
+  TRACE("pStats %p\n", pStats);
+  ret = getIPStats(pStats);
+  TRACE("returning %d\n", ret);
+  return ret;
 }
 
 
 /******************************************************************
  *    GetNetworkParams (IPHLPAPI.@)
  *
+ * Get the network parameters for the local computer.
  *
  * PARAMS
- *
- *  pFixedInfo [In/Out]
- *  pOutBufLen [In/Out]
+ *  pFixedInfo [Out]    buffer for network parameters
+ *  pOutBufLen [In/Out] length of output buffer
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * NOTES
+ *  If pOutBufLen is less than required, the function will return
+ *  ERROR_INSUFFICIENT_BUFFER, and pOutBufLen will be set to the required byte
+ *  size.
  */
 DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
 {
-  DWORD size;
+  DWORD ret, size;
+  LONG regReturn;
   HKEY hKey;
 
+  TRACE("pFixedInfo %p, pOutBufLen %p\n", pFixedInfo, pOutBufLen);
   if (!pOutBufLen)
     return ERROR_INVALID_PARAMETER;
 
-  res_init();
+  initialise_resolver();
   size = sizeof(FIXED_INFO) + (_res.nscount > 0 ? (_res.nscount  - 1) *
    sizeof(IP_ADDR_STRING) : 0);
   if (!pFixedInfo || *pOutBufLen < size) {
@@ -1238,45 +1443,51 @@ DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
     }
   }
   pFixedInfo->NodeType = HYBRID_NODETYPE;
-  if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,
-   "\\SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &hKey)
-   == ERROR_SUCCESS)
+  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);
+    RegQueryValueExA(hKey, "ScopeID", NULL, NULL, (LPBYTE)pFixedInfo->ScopeId, &size);
     RegCloseKey(hKey);
   }
 
   /* 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 */
-  return NO_ERROR;
+  ret = NO_ERROR;
+  TRACE("returning %d\n", ret);
+  return ret;
 }
 
 
 /******************************************************************
  *    GetNumberOfInterfaces (IPHLPAPI.@)
  *
+ * Get the number of interfaces.
  *
  * PARAMS
- *
- *  pdwNumIf [In/Out]
+ *  pdwNumIf [Out] number of interfaces
  *
  * RETURNS
- *
- *  DWORD
- *
+ *  NO_ERROR on success, ERROR_INVALID_PARAMETER if pdwNumIf is NULL.
  */
 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 %d\n", ret);
   return ret;
 }
 
@@ -1284,87 +1495,94 @@ DWORD WINAPI GetNumberOfInterfaces(PDWORD pdwNumIf)
 /******************************************************************
  *    GetPerAdapterInfo (IPHLPAPI.@)
  *
+ * Get information about an adapter corresponding to an interface.
  *
  * PARAMS
- *
- *  IfIndex [In]
- *  pPerAdapterInfo [In/Out]
- *  pOutBufLen [In/Out]
+ *  IfIndex         [In]     interface info
+ *  pPerAdapterInfo [Out]    buffer for per adapter info
+ *  pOutBufLen      [In/Out] length of output buffer
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * FIXME
+ *  Stub, returns empty IP_PER_ADAPTER_INFO in every case.
  */
 DWORD WINAPI GetPerAdapterInfo(ULONG IfIndex, PIP_PER_ADAPTER_INFO pPerAdapterInfo, PULONG pOutBufLen)
 {
-  FIXME(":stub\n");
-  /* marking Win2K+ functions not supported */
-  return ERROR_NOT_SUPPORTED;
+  ULONG bytesNeeded = sizeof(IP_PER_ADAPTER_INFO);
+  DWORD ret;
+
+  TRACE("(IfIndex %d, pPerAdapterInfo %p, pOutBufLen %p)\n", IfIndex,
+   pPerAdapterInfo, pOutBufLen);
+  if (!pOutBufLen)
+    ret = ERROR_INVALID_PARAMETER;
+  else if (!pPerAdapterInfo)
+  {
+    *pOutBufLen = bytesNeeded;
+    ret = NO_ERROR;
+  }
+  else if (*pOutBufLen < bytesNeeded)
+  {
+    *pOutBufLen = bytesNeeded;
+    ret = ERROR_BUFFER_OVERFLOW;
+  }
+  else
+  {
+    memset(pPerAdapterInfo, 0, bytesNeeded);
+    ret = NO_ERROR;
+  }
+  return ret;
 }
 
 
 /******************************************************************
  *    GetRTTAndHopCount (IPHLPAPI.@)
  *
+ * Get round-trip time (RTT) and hop count.
  *
  * PARAMS
  *
- *  DestIpAddress [In]
- *  HopCount [In/Out]
- *  MaxHops [In]
- *  RTT [In/Out]
+ *  DestIpAddress [In]  destination address to get the info for
+ *  HopCount      [Out] retrieved hop count
+ *  MaxHops       [In]  maximum hops to search for the destination
+ *  RTT           [Out] RTT in milliseconds
  *
  * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE
  *
- *  BOOL
- *
+ * FIXME
+ *  Stub, returns FALSE.
  */
 BOOL WINAPI GetRTTAndHopCount(IPAddr DestIpAddress, PULONG HopCount, ULONG MaxHops, PULONG RTT)
 {
-  FIXME(":stub\n");
-  return (BOOL) 0;
+  FIXME("(DestIpAddress 0x%08lx, HopCount %p, MaxHops %d, RTT %p): stub\n",
+   DestIpAddress, HopCount, MaxHops, RTT);
+  return FALSE;
 }
 
 
 /******************************************************************
  *    GetTcpStatistics (IPHLPAPI.@)
  *
+ * Get the TCP statistics for the local computer.
  *
  * PARAMS
- *
- *  pStats [In/Out]
+ *  pStats [Out] buffer for TCP statistics
  *
  * RETURNS
- *
- *  DWORD
- *
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  */
 DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS pStats)
 {
-  return getTCPStats(pStats);
-}
-
-
-static int TcpTableSorter(const void *a, const void *b)
-{
-  int ret;
-
-  if (a && b) {
-    PMIB_TCPROW rowA = (PMIB_TCPROW)a, rowB = (PMIB_TCPROW)b;
+  DWORD ret;
 
-    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;
+  TRACE("pStats %p\n", pStats);
+  ret = getTCPStats(pStats);
+  TRACE("returning %d\n", ret);
   return ret;
 }
 
@@ -1372,55 +1590,59 @@ static int TcpTableSorter(const void *a, const void *b)
 /******************************************************************
  *    GetTcpTable (IPHLPAPI.@)
  *
+ * Get the table of active TCP connections.
  *
  * PARAMS
- *
- *  pTcpTable [In/Out]
- *  pdwSize [In/Out]
- *  bOrder [In]
+ *  pTcpTable [Out]    buffer for TCP connections table
+ *  pdwSize   [In/Out] length of output buffer
+ *  bOrder    [In]     whether to order the table
  *
  * RETURNS
- *
- *  DWORD
- *
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
+ *
+ * NOTES
+ *  If pdwSize is less than required, the function will return 
+ *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to 
+ *  the required byte size.
+ *  If bOrder is true, the returned table will be sorted, first by
+ *  local address and port number, then by remote address and port
+ *  number.
  */
 DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
 {
   DWORD ret;
 
+  TRACE("pTcpTable %p, pdwSize %p, bOrder %d\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);
+    DWORD size = sizeof(MIB_TCPTABLE);
 
+    if (numEntries > 1)
+      size += (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);
+      ret = getTcpTable(&pTcpTable, numEntries, 0, 0);
+      if (!ret) {
+        size = sizeof(MIB_TCPTABLE);
+        if (pTcpTable->dwNumEntries > 1)
+          size += (pTcpTable->dwNumEntries - 1) * sizeof(MIB_TCPROW);
+        *pdwSize = size;
+
+        if (bOrder)
+           qsort(pTcpTable->table, pTcpTable->dwNumEntries,
+                 sizeof(MIB_TCPROW), TcpTableSorter);
+        ret = NO_ERROR;
       }
-      else
-        ret = ERROR_OUTOFMEMORY;
     }
   }
+  TRACE("returning %d\n", ret);
   return ret;
 }
 
@@ -1428,35 +1650,22 @@ DWORD WINAPI GetTcpTable(PMIB_TCPTABLE pTcpTable, PDWORD pdwSize, BOOL bOrder)
 /******************************************************************
  *    GetUdpStatistics (IPHLPAPI.@)
  *
+ * Get the UDP statistics for the local computer.
  *
  * PARAMS
- *
- *  pStats [In/Out]
+ *  pStats [Out] buffer for UDP statistics
  *
  * RETURNS
- *
- *  DWORD
- *
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  */
 DWORD WINAPI GetUdpStatistics(PMIB_UDPSTATS pStats)
 {
-  return getUDPStats(pStats);
-}
-
-
-static int UdpTableSorter(const void *a, const void *b)
-{
-  int ret;
-
-  if (a && b) {
-    PMIB_UDPROW rowA = (PMIB_UDPROW)a, rowB = (PMIB_UDPROW)b;
+  DWORD ret;
 
-    ret = rowA->dwLocalAddr - rowB->dwLocalAddr;
-    if (ret == 0)
-      ret = rowA->dwLocalPort - rowB->dwLocalPort;
-  }
-  else
-    ret = 0;
+  TRACE("pStats %p\n", pStats);
+  ret = getUDPStats(pStats);
+  TRACE("returning %d\n", ret);
   return ret;
 }
 
@@ -1464,55 +1673,69 @@ static int UdpTableSorter(const void *a, const void *b)
 /******************************************************************
  *    GetUdpTable (IPHLPAPI.@)
  *
+ * Get a table of active UDP connections.
  *
  * PARAMS
- *
- *  pUdpTable [In/Out]
- *  pdwSize [In/Out]
- *  bOrder [In]
+ *  pUdpTable [Out]    buffer for UDP connections table
+ *  pdwSize   [In/Out] length of output buffer
+ *  bOrder    [In]     whether to order the table
  *
  * RETURNS
- *
- *  DWORD
- *
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
+ *
+ * NOTES
+ *  If pdwSize is less than required, the function will return 
+ *  ERROR_INSUFFICIENT_BUFFER, and *pdwSize will be set to the
+ *  required byte size.
+ *  If bOrder is true, the returned table will be sorted, first by
+ *  local address, then by local port number.
  */
 DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
 {
   DWORD ret;
 
+  TRACE("pUdpTable %p, pdwSize %p, bOrder %d\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);
+    DWORD size = sizeof(MIB_UDPTABLE);
 
+    if (numEntries > 1)
+      size += (numEntries - 1) * sizeof(MIB_UDPROW);
     if (!pUdpTable || *pdwSize < size) {
       *pdwSize = size;
       ret = ERROR_INSUFFICIENT_BUFFER;
     }
     else {
-      PMIB_UDPTABLE table = getUdpTable();
+      PMIB_UDPTABLE table;
 
-      if (table) {
-        size = sizeof(MIB_UDPTABLE) + (table->dwNumEntries - 1) *
-         sizeof(MIB_UDPROW);
+      ret = getUdpTable(&table, GetProcessHeap(), 0);
+      if (!ret) {
+        size = sizeof(MIB_UDPTABLE);
+        if (table->dwNumEntries > 1)
+          size += (table->dwNumEntries - 1) * sizeof(MIB_UDPROW);
         if (*pdwSize < size) {
           *pdwSize = size;
           ret = ERROR_INSUFFICIENT_BUFFER;
         }
         else {
+          *pdwSize = size;
           memcpy(pUdpTable, table, size);
           if (bOrder)
             qsort(pUdpTable->table, pUdpTable->dwNumEntries,
              sizeof(MIB_UDPROW), UdpTableSorter);
           ret = NO_ERROR;
         }
-        free(table);
+        HeapFree(GetProcessHeap(), 0, table);
       }
       else
         ret = ERROR_OUTOFMEMORY;
     }
   }
+  TRACE("returning %d\n", ret);
   return ret;
 }
 
@@ -1520,19 +1743,24 @@ DWORD WINAPI GetUdpTable(PMIB_UDPTABLE pUdpTable, PDWORD pdwSize, BOOL bOrder)
 /******************************************************************
  *    GetUniDirectionalAdapterInfo (IPHLPAPI.@)
  *
+ * This is a Win98-only function to get information on "unidirectional"
+ * adapters.  Since this is pretty nonsensical in other contexts, it
+ * never returns anything.
  *
  * PARAMS
- *
- *  pIPIfInfo [In/Out]
- *  dwOutBufLen [In/Out]
+ *  pIPIfInfo   [Out] buffer for adapter infos
+ *  dwOutBufLen [Out] length of the output buffer
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * FIXME
+ *  Stub, returns ERROR_NOT_SUPPORTED.
  */
 DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIPIfInfo, PULONG dwOutBufLen)
 {
+  TRACE("pIPIfInfo %p, dwOutBufLen %p\n", pIPIfInfo, dwOutBufLen);
   /* a unidirectional adapter?? not bloody likely! */
   return ERROR_NOT_SUPPORTED;
 }
@@ -1541,18 +1769,25 @@ DWORD WINAPI GetUniDirectionalAdapterInfo(PIP_UNIDIRECTIONAL_ADAPTER_ADDRESS pIP
 /******************************************************************
  *    IpReleaseAddress (IPHLPAPI.@)
  *
+ * Release an IP obtained through DHCP,
  *
  * PARAMS
- *
- *  AdapterInfo [In/Out]
+ *  AdapterInfo [In] adapter to release IP address
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
+ * NOTES
+ *  Since GetAdaptersInfo never returns adapters that have DHCP enabled,
+ *  this function does nothing.
  *
+ * FIXME
+ *  Stub, returns ERROR_NOT_SUPPORTED.
  */
 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;
@@ -1562,18 +1797,25 @@ DWORD WINAPI IpReleaseAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
 /******************************************************************
  *    IpRenewAddress (IPHLPAPI.@)
  *
+ * Renew an IP obtained through DHCP.
  *
  * PARAMS
- *
- *  AdapterInfo [In/Out]
+ *  AdapterInfo [In] adapter to renew IP address
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
+ * NOTES
+ *  Since GetAdaptersInfo never returns adapters that have DHCP enabled,
+ *  this function does nothing.
  *
+ * FIXME
+ *  Stub, returns ERROR_NOT_SUPPORTED.
  */
 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;
@@ -1583,21 +1825,22 @@ DWORD WINAPI IpRenewAddress(PIP_ADAPTER_INDEX_MAP AdapterInfo)
 /******************************************************************
  *    NotifyAddrChange (IPHLPAPI.@)
  *
+ * Notify caller whenever the ip-interface map is changed.
  *
  * PARAMS
- *
- *  Handle [In/Out]
- *  overlapped [In/Out]
+ *  Handle     [Out] handle usable in asynchronous notification
+ *  overlapped [In]  overlapped structure that notifies the caller
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * FIXME
+ *  Stub, returns ERROR_NOT_SUPPORTED.
  */
 DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
 {
-  FIXME(":stub\n");
-  /* marking Win2K+ functions not supported */
+  FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
   return ERROR_NOT_SUPPORTED;
 }
 
@@ -1605,21 +1848,22 @@ DWORD WINAPI NotifyAddrChange(PHANDLE Handle, LPOVERLAPPED overlapped)
 /******************************************************************
  *    NotifyRouteChange (IPHLPAPI.@)
  *
+ * Notify caller whenever the ip routing table is changed.
  *
  * PARAMS
- *
- *  Handle [In/Out]
- *  overlapped [In/Out]
+ *  Handle     [Out] handle usable in asynchronous notification
+ *  overlapped [In]  overlapped structure that notifies the caller
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * FIXME
+ *  Stub, returns ERROR_NOT_SUPPORTED.
  */
 DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
 {
-  FIXME(":stub\n");
-  /* marking Win2K+ functions not supported */
+  FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
   return ERROR_NOT_SUPPORTED;
 }
 
@@ -1627,23 +1871,25 @@ DWORD WINAPI NotifyRouteChange(PHANDLE Handle, LPOVERLAPPED overlapped)
 /******************************************************************
  *    SendARP (IPHLPAPI.@)
  *
+ * Send an ARP request.
  *
  * PARAMS
- *
- *  DestIP [In]
- *  SrcIP [In]
- *  pMacAddr [In/Out]
- *  PhyAddrLen [In/Out]
+ *  DestIP     [In]     attempt to obtain this IP
+ *  SrcIP      [In]     optional sender IP address
+ *  pMacAddr   [Out]    buffer for the mac address
+ *  PhyAddrLen [In/Out] length of the output buffer
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * FIXME
+ *  Stub, returns ERROR_NOT_SUPPORTED.
  */
 DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAddrLen)
 {
-  FIXME(":stub\n");
-  /* marking Win2K+ functions not supported */
+  FIXME("(DestIP 0x%08lx, SrcIP 0x%08lx, pMacAddr %p, PhyAddrLen %p): stub\n",
+   DestIP, SrcIP, pMacAddr, PhyAddrLen);
   return ERROR_NOT_SUPPORTED;
 }
 
@@ -1651,23 +1897,25 @@ DWORD WINAPI SendARP(IPAddr DestIP, IPAddr SrcIP, PULONG pMacAddr, PULONG PhyAdd
 /******************************************************************
  *    SetIfEntry (IPHLPAPI.@)
  *
+ * Set the administrative status of an interface.
  *
  * PARAMS
- *
- *  pIfRow [In/Out]
+ *  pIfRow [In] dwAdminStatus member specifies the new status.
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * FIXME
+ *  Stub, returns ERROR_NOT_SUPPORTED.
  */
 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
 {
-  /* this is supposed to set an administratively interface up or down.
+  FIXME("(pIfRow %p): stub\n", pIfRow);
+  /* this is supposed to set an interface administratively up or down.
      Could do SIOCSIFFLAGS and set/clear IFF_UP, but, not sure I want to, and
      this sort of down is indistinguishable from other sorts of down (e.g. no
      link). */
-  FIXME(":stub\n");
   return ERROR_NOT_SUPPORTED;
 }
 
@@ -1675,22 +1923,24 @@ DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
 /******************************************************************
  *    SetIpForwardEntry (IPHLPAPI.@)
  *
+ * Modify an existing route.
  *
  * PARAMS
- *
- *  pRoute [In/Out]
+ *  pRoute [In] route with the new information
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * FIXME
+ *  Stub, returns NO_ERROR.
  */
 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
 {
+  FIXME("(pRoute %p): stub\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;
 }
 
@@ -1698,20 +1948,22 @@ DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
 /******************************************************************
  *    SetIpNetEntry (IPHLPAPI.@)
  *
+ * Modify an existing ARP entry.
  *
  * PARAMS
- *
- *  pArpEntry [In/Out]
+ *  pArpEntry [In] ARP entry with the new information
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * FIXME
+ *  Stub, returns NO_ERROR.
  */
 DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
 {
+  FIXME("(pArpEntry %p): stub\n", pArpEntry);
   /* same as CreateIpNetEntry here, could use SIOCSARP, not sure I want to */
-  FIXME(":stub\n");
   return (DWORD) 0;
 }
 
@@ -1719,19 +1971,21 @@ DWORD WINAPI SetIpNetEntry(PMIB_IPNETROW pArpEntry)
 /******************************************************************
  *    SetIpStatistics (IPHLPAPI.@)
  *
+ * Toggle IP forwarding and det the default TTL value.
  *
  * PARAMS
- *
- *  pIpStats [In/Out]
+ *  pIpStats [In] IP statistics with the new information
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * FIXME
+ *  Stub, returns NO_ERROR.
  */
 DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
 {
-  FIXME(":stub\n");
+  FIXME("(pIpStats %p): stub\n", pIpStats);
   return (DWORD) 0;
 }
 
@@ -1739,21 +1993,23 @@ DWORD WINAPI SetIpStatistics(PMIB_IPSTATS pIpStats)
 /******************************************************************
  *    SetIpTTL (IPHLPAPI.@)
  *
+ * Set the default TTL value.
  *
  * PARAMS
- *
- *  nTTL [In]
+ *  nTTL [In] new TTL value
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * FIXME
+ *  Stub, returns NO_ERROR.
  */
 DWORD WINAPI SetIpTTL(UINT nTTL)
 {
+  FIXME("(nTTL %d): stub\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;
 }
 
@@ -1761,19 +2017,21 @@ DWORD WINAPI SetIpTTL(UINT nTTL)
 /******************************************************************
  *    SetTcpEntry (IPHLPAPI.@)
  *
+ * Set the state of a TCP connection.
  *
  * PARAMS
- *
- *  pTcpRow [In/Out]
+ *  pTcpRow [In] specifies connection with new state
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * FIXME
+ *  Stub, returns NO_ERROR.
  */
 DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
 {
-  FIXME(":stub\n");
+  FIXME("(pTcpRow %p): stub\n", pTcpRow);
   return (DWORD) 0;
 }
 
@@ -1781,22 +2039,26 @@ DWORD WINAPI SetTcpEntry(PMIB_TCPROW pTcpRow)
 /******************************************************************
  *    UnenableRouter (IPHLPAPI.@)
  *
+ * Decrement the IP-forwarding reference count. Turn off IP-forwarding
+ * if it reaches zero.
  *
  * PARAMS
- *
- *  pOverlapped [In/Out]
- *  lpdwEnableCount [In/Out]
+ *  pOverlapped     [In/Out] should be the same as in EnableRouter()
+ *  lpdwEnableCount [Out]    optional, receives reference count
  *
  * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
- *  DWORD
- *
+ * FIXME
+ *  Stub, returns ERROR_NOT_SUPPORTED.
  */
 DWORD WINAPI UnenableRouter(OVERLAPPED * pOverlapped, LPDWORD lpdwEnableCount)
 {
-  FIXME(":stub\n");
+  FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
+   lpdwEnableCount);
   /* 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;
 }