Sync with trunk (r48545)
[reactos.git] / dll / win32 / iphlpapi / iphlpapi_main.c
index 09555bc..717fd2d 100644 (file)
@@ -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 Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 #include "config.h"
 #include "resinfo.h"
 #include "route.h"
 #include "wine/debug.h"
+#include "dhcpcsdk.h"
+#include "dhcpcapi.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(iphlpapi);
 
+typedef struct _NAME_SERVER_LIST_CONTEXT {
+    ULONG uSizeAvailable;
+    ULONG uSizeRequired;
+    PIP_PER_ADAPTER_INFO pData;
+    UINT NumServers;
+    IP_ADDR_STRING *pLastAddr;
+} NAME_SERVER_LIST_CONTEXT, *PNAME_SERVER_LIST_CONTEXT;
+
 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
 {
   switch (fdwReason) {
@@ -88,6 +98,20 @@ DWORD WINAPI AddIPAddress(IPAddr Address, IPMask Netmask, DWORD IfIndex, PULONG
     return RtlNtStatusToDosError(addIPAddress(Address, Netmask, IfIndex, NteContext, NteInstance));
 }
 
+DWORD getInterfaceGatewayByIndex(DWORD index)
+{
+   DWORD ndx, retVal = 0, numRoutes = getNumRoutes();
+   RouteTable *table = getRouteTable();
+   if (!table) return 0;
+
+    for (ndx = 0; ndx < numRoutes; ndx++)
+    {
+        if ((table->routes[ndx].ifIndex == (index)) && (table->routes[ndx].dest == 0))
+            retVal = table->routes[ndx].gateway;
+    }
+    HeapFree(GetProcessHeap(), 0, table);
+    return retVal;
+}
 
 /******************************************************************
  *    AllocateAndGetIfTableFromStack (IPHLPAPI.@)
@@ -622,9 +646,12 @@ DWORD WINAPI GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
               DWORD addrLen = sizeof(ptr->Address), type;
               const char *ifname =
                   getInterfaceNameByIndex(table->indexes[ndx]);
+              if (!ifname) {
+                  ret = ERROR_OUTOFMEMORY;
+                  break;
+              }
 
               /* on Win98 this is left empty, but whatever */
-
               strncpy(ptr->AdapterName,ifname,sizeof(ptr->AdapterName));
               consumeInterfaceName(ifname);
               ptr->AdapterName[MAX_ADAPTER_NAME_LENGTH] = '\0';
@@ -640,6 +667,8 @@ DWORD WINAPI GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen)
                ptr->IpAddressList.IpAddress.String);
               toIPAddressString(getInterfaceMaskByIndex(table->indexes[ndx]),
                ptr->IpAddressList.IpMask.String);
+              toIPAddressString(getInterfaceGatewayByIndex(table->indexes[ndx]),
+               ptr->GatewayList.IpAddress.String);
               getDhcpInfoForAdapter(table->indexes[ndx], &dhcpEnabled,
                                     &dhcpServer, &ptr->LeaseObtained,
                                     &ptr->LeaseExpires);
@@ -760,6 +789,32 @@ DWORD WINAPI GetBestRoute(DWORD dwDestAddr, DWORD dwSourceAddr, PMIB_IPFORWARDRO
   return ret;
 }
 
+/******************************************************************
+ *    GetExtendedTcpTable (IPHLPAPI.@)
+ *
+ * Get the table of TCP endpoints available to the application.
+ *
+ * PARAMS
+ *  pTcpTable [Out]    table struct with the filtered TCP endpoints available to application
+ *  pdwSize   [In/Out] estimated size of the structure returned in pTcpTable, in bytes
+ *  bOrder    [In]     whether to order the table
+ *  ulAf       [in]    version of IP used by the TCP endpoints
+ *  TableClass [in]    type of the TCP table structure from TCP_TABLE_CLASS
+ *  Reserved [in]      reserved - this value must be zero
+ *
+ * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: either ERROR_INSUFFICIENT_BUFFER or ERROR_INVALID_PARAMETER
+ *
+ * NOTES
+ */
+DWORD WINAPI GetExtendedTcpTable(PVOID pTcpTable, PDWORD pdwSize, BOOL bOrder, ULONG ulAf, TCP_TABLE_CLASS TableClass, ULONG Reserved)
+{
+       DWORD ret = NO_ERROR;
+       UNIMPLEMENTED;
+       return ret;     
+}
+
 
 /******************************************************************
  *    GetFriendlyIfIndex (IPHLPAPI.@)
@@ -881,8 +936,9 @@ DWORD WINAPI GetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
     ret = ERROR_INVALID_PARAMETER;
   else {
     DWORD numInterfaces = getNumInterfaces();
+    ULONG size;
     TRACE("GetIfTable: numInterfaces = %d\n", (int)numInterfaces);
-    ULONG size = sizeof(MIB_IFTABLE) + (numInterfaces - 1) * sizeof(MIB_IFROW);
+    size = sizeof(MIB_IFTABLE) + (numInterfaces - 1) * sizeof(MIB_IFROW);
 
     if (!pIfTable || *pdwSize < size) {
       *pdwSize = size;
@@ -946,8 +1002,9 @@ DWORD WINAPI GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen)
     ret = ERROR_INVALID_PARAMETER;
   else {
     DWORD numNonLoopbackInterfaces = getNumNonLoopbackInterfaces();
+    ULONG size;
     TRACE("numNonLoopbackInterfaces == 0x%x\n", numNonLoopbackInterfaces);
-    ULONG size = sizeof(IP_INTERFACE_INFO) + (numNonLoopbackInterfaces) *
+    size = sizeof(IP_INTERFACE_INFO) + (numNonLoopbackInterfaces) *
      sizeof(IP_ADAPTER_INDEX_MAP);
 
     if (!pIfTable || *dwOutBufLen < size) {
@@ -956,9 +1013,9 @@ DWORD WINAPI GetInterfaceInfo(PIP_INTERFACE_INFO pIfTable, PULONG dwOutBufLen)
     }
     else {
       InterfaceIndexTable *table = getNonLoopbackInterfaceIndexTable();
-      TRACE("table->numIndexes == 0x%x\n", table->numIndexes);
 
       if (table) {
+        TRACE("table->numIndexes == 0x%x\n", table->numIndexes);
         size = sizeof(IP_INTERFACE_INFO) + (table->numIndexes) *
          sizeof(IP_ADAPTER_INDEX_MAP);
         if (*dwOutBufLen < size) {
@@ -1160,7 +1217,7 @@ DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSi
           pIpForwardTable->dwNumEntries = table->numRoutes;
           for (ndx = 0; ndx < numRoutes; ndx++) {
             pIpForwardTable->table[ndx].dwForwardIfIndex =
-             table->routes[ndx].ifIndex;
+             table->routes[ndx].ifIndex + 1;
             pIpForwardTable->table[ndx].dwForwardDest =
              table->routes[ndx].dest;
             pIpForwardTable->table[ndx].dwForwardMask =
@@ -1190,7 +1247,7 @@ DWORD WINAPI GetIpForwardTable(PMIB_IPFORWARDTABLE pIpForwardTable, PULONG pdwSi
              sizeof(MIB_IPFORWARDROW), IpForwardTableSorter);
           ret = NO_ERROR;
         }
-        free(table);
+        HeapFree(GetProcessHeap(), 0, table);
       }
       else
         ret = ERROR_OUTOFMEMORY;
@@ -1230,45 +1287,45 @@ static int IpNetTableSorter(const void *a, const void *b)
  */
 DWORD WINAPI GetIpNetTable(PMIB_IPNETTABLE pIpNetTable, PULONG pdwSize, BOOL bOrder)
 {
-  DWORD ret;
+  DWORD ret = NO_ERROR;
 
-  TRACE("pIpNetTable %p, pdwSize %p, bOrder %ld\n", pIpNetTable, pdwSize,
+  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();
-
       if (table) {
-        size = sizeof(MIB_IPNETTABLE) + (table->dwNumEntries - 1) *
-         sizeof(MIB_IPNETROW);
+        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 %ld\n", ret);
+  TRACE("returning %d\n", ret);
   return ret;
 }
 
@@ -1344,7 +1401,7 @@ DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
   if (!resInfo)
     return ERROR_OUTOFMEMORY;
 
-  size = sizeof(FIXED_INFO) + (resInfo->riCount > 0 ? (resInfo->riCount  - 1) *
+  size = sizeof(FIXED_INFO) + (resInfo->riCount > 1 ? (resInfo->riCount-1) *
    sizeof(IP_ADDR_STRING) : 0);
   if (!pFixedInfo || *pOutBufLen < size) {
     *pOutBufLen = size;
@@ -1360,25 +1417,40 @@ DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen)
 
   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) {
-        struct sockaddr_in *addr_v4 =
-            (struct sockaddr_in *)&resInfo->riAddressList[i];
-        toIPAddressString
-            (addr_v4->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));
+  if (resInfo->riCount > 0) 
+  {
+    CopyMemory(&pFixedInfo->DnsServerList, resInfo->DnsList, sizeof(IP_ADDR_STRING));
+    if (resInfo->riCount > 1)
+    {
+      IP_ADDR_STRING *pSrc = resInfo->DnsList->Next;
+      IP_ADDR_STRING *pTarget = (struct _IP_ADDR_STRING*)((char*)pFixedInfo + sizeof(FIXED_INFO));
+
+      pFixedInfo->DnsServerList.Next = pTarget;
+
+      do
+      {
+        CopyMemory(pTarget, pSrc, sizeof(IP_ADDR_STRING));
+        resInfo->riCount--;
+        if (resInfo->riCount > 1)
+        {
+          pTarget->Next = (IP_ADDR_STRING*)((char*)pTarget + sizeof(IP_ADDR_STRING));
+          pTarget = pTarget->Next;
+          pSrc = pSrc->Next;
+        }
+        else
+        {
+          pTarget->Next = NULL;
+          break;
+        }
+      }
+      while(TRUE);
+    }
+    else
+    {
+      pFixedInfo->DnsServerList.Next = NULL;
     }
   }
+
   pFixedInfo->NodeType = HYBRID_NODETYPE;
   regReturn = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
    "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP", 0, KEY_READ, &hKey);
@@ -1433,6 +1505,33 @@ DWORD WINAPI GetNumberOfInterfaces(PDWORD pdwNumIf)
 }
 
 
+/******************************************************************
+ *    GetOwnerModuleFromTcpEntry (IPHLPAPI.@)
+ *
+ * Get data about the module that issued the context bind for a specific IPv4 TCP endpoint in a MIB table row
+ *
+ * PARAMS
+ *  pTcpEntry [in]    pointer to a MIB_TCPROW_OWNER_MODULE structure
+ *  Class [in]         TCPIP_OWNER_MODULE_INFO_CLASS enumeration value
+ *  Buffer [out]       pointer a buffer containing a TCPIP_OWNER_MODULE_BASIC_INFO structure with the owner module data. 
+ *  pdwSize [in, out]  estimated size of the structure returned in Buffer, in bytes
+ *
+ * RETURNS
+ *  Success: NO_ERROR
+ *  Failure: ERROR_INSUFFICIENT_BUFFER, ERROR_INVALID_PARAMETER, ERROR_NOT_ENOUGH_MEMORY
+ *            ERROR_NOT_FOUND or ERROR_PARTIAL_COPY
+ *
+ * NOTES
+ * The type of data returned in Buffer is indicated by the value of the Class parameter.
+ */
+DWORD WINAPI GetOwnerModuleFromTcpEntry( PMIB_TCPROW_OWNER_MODULE pTcpEntry, TCPIP_OWNER_MODULE_INFO_CLASS Class, PVOID Buffer, PDWORD pdwSize)
+{
+       DWORD ret = NO_ERROR;
+       UNIMPLEMENTED;
+       return ret;     
+}
+
+
 /******************************************************************
  *    GetPerAdapterInfo (IPHLPAPI.@)
  *
@@ -1448,13 +1547,88 @@ DWORD WINAPI GetNumberOfInterfaces(PDWORD pdwNumIf)
  *  DWORD
  *
  */
+static void CreateNameServerListEnumNamesFunc( PWCHAR Interface, PWCHAR Server, PVOID Data)
+{
+  IP_ADDR_STRING *pNext;
+  PNAME_SERVER_LIST_CONTEXT Context = (PNAME_SERVER_LIST_CONTEXT)Data;
+
+  if (!Context->NumServers)
+  {
+    if (Context->uSizeAvailable >= Context->uSizeRequired)
+    {
+      WideCharToMultiByte(CP_ACP, 0, Server, -1, Context->pData->DnsServerList.IpAddress.String, 16, NULL, NULL);
+      Context->pData->DnsServerList.IpAddress.String[15] = '\0';
+      Context->pLastAddr = &Context->pData->DnsServerList;
+    }
+  }
+  else
+  {
+     Context->uSizeRequired += sizeof(IP_ADDR_STRING);
+     if (Context->uSizeAvailable >= Context->uSizeRequired)
+     {
+         pNext = (IP_ADDR_STRING*)(((char*)Context->pLastAddr) + sizeof(IP_ADDR_STRING));
+         WideCharToMultiByte(CP_ACP, 0, Server, -1, pNext->IpAddress.String, 16, NULL, NULL);
+         pNext->IpAddress.String[15] = '\0';
+         Context->pLastAddr->Next = pNext;
+         Context->pLastAddr = pNext;
+         pNext->Next = NULL;
+     }
+  }
+  Context->NumServers++;
+}
+
 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;
+  HKEY hkey;
+  DWORD dwSize = 0;
+  const char *ifName;
+  NAME_SERVER_LIST_CONTEXT Context;
+  WCHAR keyname[200] = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\";
+
+  if (!pOutBufLen)
+    return ERROR_INVALID_PARAMETER;
+
+  if (!pPerAdapterInfo || *pOutBufLen < sizeof(IP_PER_ADAPTER_INFO))
+  {
+    *pOutBufLen = sizeof(IP_PER_ADAPTER_INFO);
+    return ERROR_BUFFER_OVERFLOW;
+  }
+
+  ifName = getInterfaceNameByIndex(IfIndex);
+  if (!ifName)
+    return ERROR_INVALID_PARAMETER;
+
+  MultiByteToWideChar(CP_ACP, 0, ifName, -1, &keyname[62], sizeof(keyname)/sizeof(WCHAR) - 63);
+  HeapFree(GetProcessHeap(), 0, (LPVOID)ifName);
+
+  if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &hkey) != ERROR_SUCCESS)
+  {
+    return ERROR_NOT_SUPPORTED;
+  }
+  Context.NumServers = 0;
+  Context.uSizeAvailable = *pOutBufLen;
+  Context.uSizeRequired = sizeof(IP_PER_ADAPTER_INFO);
+  Context.pData = pPerAdapterInfo;
+
+  if (*pOutBufLen >= sizeof(IP_PER_ADAPTER_INFO))
+    ZeroMemory(pPerAdapterInfo, sizeof(IP_PER_ADAPTER_INFO));
+
+  EnumNameServers(hkey, &keyname[62], &Context, CreateNameServerListEnumNamesFunc);
+
+  if (Context.uSizeRequired > Context.uSizeAvailable)
+  {
+    *pOutBufLen = Context.uSizeRequired;
+    RegCloseKey(hkey);
+    return ERROR_BUFFER_OVERFLOW;
+  }
+
+  if(RegQueryValueExW(hkey, L"DHCPNameServer", NULL, NULL, NULL, &dwSize) == ERROR_SUCCESS)
+  {
+    pPerAdapterInfo->AutoconfigActive = TRUE;
+  }
+
+  RegCloseKey(hkey);
+  return NOERROR;
 }
 
 
@@ -1552,58 +1726,60 @@ 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;
+  DWORD ret = NO_ERROR;
 
-  TRACE("pTcpTable %p, pdwSize %p, bOrder %ld\n", pTcpTable, pdwSize,
+  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);
-      }
-      else
-        ret = ERROR_OUTOFMEMORY;
-    }
+      PMIB_TCPTABLE pTcpTable = getTcpTable();
+         if (pTcpTable)
+      {
+        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;
+         }
+       }
   }
-  TRACE("returning %ld\n", ret);
+  TRACE("returning %d\n", ret);
   return ret;
 }
 
@@ -1730,16 +1906,20 @@ 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)
 {
@@ -1752,66 +1932,91 @@ 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
- *
- *  DWORD
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
  */
 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;
+  DWORD Status, Version = 0;
+
+  if (!AdapterInfo || !AdapterInfo->Name)
+      return ERROR_INVALID_PARAMETER;
+
+  /* Maybe we should do this in DllMain */
+  if (DhcpCApiInitialize(&Version) != ERROR_SUCCESS)
+      return ERROR_PROC_NOT_FOUND;
+
+  if (DhcpReleaseIpAddressLease(AdapterInfo->Index))
+      Status = ERROR_SUCCESS;
+  else
+      Status = ERROR_PROC_NOT_FOUND;
+
+  DhcpCApiCleanup();
+
+  return Status;
 }
 
 
 /******************************************************************
  *    IpRenewAddress (IPHLPAPI.@)
  *
+ * Renew an IP obtained through DHCP.
  *
  * PARAMS
- *
- *  AdapterInfo [In/Out]
+ *  AdapterInfo [In] adapter to renew IP address
  *
  * RETURNS
- *
- *  DWORD
- *
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  */
 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;
+  DWORD Status, Version = 0;
+
+  if (!AdapterInfo || !AdapterInfo->Name)
+      return ERROR_INVALID_PARAMETER;
+
+  /* Maybe we should do this in DllMain */
+  if (DhcpCApiInitialize(&Version) != ERROR_SUCCESS)
+      return ERROR_PROC_NOT_FOUND;
+
+  if (DhcpRenewIpAddressLease(AdapterInfo->Index))
+      Status = ERROR_SUCCESS;
+  else
+      Status = ERROR_PROC_NOT_FOUND;
+
+  DhcpCApiCleanup();
+
+  return Status;
 }
 
 
 /******************************************************************
  *    NotifyAddrChange (IPHLPAPI.@)
  *
+ * Notify caller whenever the ip-interface map is changed.
  *
  * PARAMS
- *
- *  Handle [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)
 {
-  TRACE("Handle %p, overlapped %p\n", Handle, overlapped);
-  FIXME(":stub\n");
-  /* marking Win2K+ functions not supported */
+  FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
   return ERROR_NOT_SUPPORTED;
 }
 
@@ -1819,22 +2024,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)
 {
-  TRACE("Handle %p, overlapped %p\n", Handle, overlapped);
-  FIXME(":stub\n");
-  /* marking Win2K+ functions not supported */
+  FIXME("(Handle %p, overlapped %p): stub\n", Handle, overlapped);
   return ERROR_NOT_SUPPORTED;
 }
 
@@ -1842,25 +2047,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)
 {
-  TRACE("DestIP 0x%08lx, SrcIP 0x%08lx, pMacAddr %p, PhyAddrLen %p\n", DestIP,
-   SrcIP, pMacAddr, PhyAddrLen);
-  FIXME(":stub\n");
-  /* marking Win2K+ functions not supported */
+  FIXME("(DestIP 0x%08x, SrcIP 0x%08x, pMacAddr %p, PhyAddrLen %p): stub\n",
+   DestIP, SrcIP, pMacAddr, PhyAddrLen);
   return ERROR_NOT_SUPPORTED;
 }
 
@@ -1868,24 +2073,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)
 {
-  TRACE("pIfRow %p\n", 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;
 }
 
@@ -1893,14 +2099,14 @@ DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
 /******************************************************************
  *    SetIpForwardEntry (IPHLPAPI.@)
  *
+ * Modify an existing route.
  *
  * PARAMS
- *
- *  pRoute [In/Out]
+ *  pRoute [In] route with the new information
  *
  * RETURNS
- *
- *  DWORD
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  *
  */
 DWORD WINAPI SetIpForwardEntry(PMIB_IPFORWARDROW pRoute)
@@ -1912,111 +2118,152 @@ 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
- *
- *  DWORD
- *
+ *  Success: NO_ERROR
+ *  Failure: error code from winerror.h
  */
 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;
+  HANDLE tcpFile;
+  NTSTATUS status;
+  TCP_REQUEST_SET_INFORMATION_EX_ARP_ENTRY req =
+      TCP_REQUEST_SET_INFORMATION_INIT;
+  TDIEntityID id;
+  DWORD returnSize;
+  PMIB_IPNETROW arpBuff;
+
+  if (!pArpEntry)
+      return ERROR_INVALID_PARAMETER;
+
+  if (!NT_SUCCESS(openTcpFile( &tcpFile )))
+      return ERROR_NOT_SUPPORTED;
+
+  if (!NT_SUCCESS(getNthIpEntity( tcpFile, pArpEntry->dwIndex, &id )))
+  {
+      closeTcpFile(tcpFile);
+      return ERROR_INVALID_PARAMETER;
+  }
+
+  req.Req.ID.toi_class = INFO_CLASS_PROTOCOL;
+  req.Req.ID.toi_type = INFO_TYPE_PROVIDER;
+  req.Req.ID.toi_id = IP_MIB_ARPTABLE_ENTRY_ID;
+  req.Req.ID.toi_entity.tei_instance = id.tei_instance;
+  req.Req.ID.toi_entity.tei_entity = AT_ENTITY;
+  req.Req.BufferSize = sizeof(MIB_IPNETROW);
+  arpBuff = (PMIB_IPNETROW)&req.Req.Buffer[0];
+
+  RtlCopyMemory(arpBuff, pArpEntry, sizeof(MIB_IPNETROW));
+
+  status = DeviceIoControl( tcpFile,
+                            IOCTL_TCP_SET_INFORMATION_EX,
+                            &req,
+                            sizeof(req),
+                            NULL,
+                            0,
+                            &returnSize,
+                            NULL );
+
+  closeTcpFile(tcpFile);
+
+  if (status)
+     return NO_ERROR;
+  else
+     return ERROR_INVALID_PARAMETER;
 }
 
 
 /******************************************************************
  *    SetIpStatistics (IPHLPAPI.@)
  *
+ * Toggle IP forwarding and det the default TTL value.
  *
  * PARAMS
- *
- *  pIpStats [In/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)
 {
-  TRACE("pIpStats %p\n", pIpStats);
-  FIXME(":stub\n");
-  return (DWORD) 0;
+  FIXME("(pIpStats %p): stub\n", pIpStats);
+  return 0;
 }
 
 
 /******************************************************************
  *    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)
 {
-  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;
+  FIXME("(nTTL %d): stub\n", nTTL);
+  return 0;
 }
 
 
 /******************************************************************
  *    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)
 {
-  TRACE("pTcpRow %p\n", pTcpRow);
-  FIXME(":stub\n");
-  return (DWORD) 0;
+  FIXME("(pTcpRow %p): stub\n", pTcpRow);
+  return 0;
 }
 
 
 /******************************************************************
  *    UnenableRouter (IPHLPAPI.@)
  *
+ * Decrement the IP-forwarding reference count. Turn off IP-forwarding
+ * if it reaches zero.
  *
  * PARAMS
- *
- *  pOverlapped [In/Out]
- *  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)
 {
-  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 */
+  FIXME("(pOverlapped %p, lpdwEnableCount %p): stub\n", pOverlapped,
+   lpdwEnableCount);
   return ERROR_NOT_SUPPORTED;
 }
 
@@ -2040,12 +2287,206 @@ PIP_ADAPTER_ORDER_MAP WINAPI GetAdapterOrderMap(VOID)
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
-DWORD WINAPI GetAdaptersAddresses(ULONG Family,DWORD Flags,PVOID Reserved,PIP_ADAPTER_ADDRESSES pAdapterAddresses,PULONG pOutBufLen)
+DWORD WINAPI GetAdaptersAddresses(ULONG Family,ULONG Flags,PVOID Reserved,PIP_ADAPTER_ADDRESSES pAdapterAddresses,PULONG pOutBufLen)
 {
+#if 0
+    InterfaceIndexTable *indexTable;
+    IFInfo ifInfo;
+    int i;
+    ULONG ret, requiredSize = 0;
+    PIP_ADAPTER_ADDRESSES currentAddress;
+    PUCHAR currentLocation;
+    HANDLE tcpFile;
+
+    if (!pOutBufLen) return ERROR_INVALID_PARAMETER;
+    if (Reserved) return ERROR_INVALID_PARAMETER;
+
+    indexTable = getNonLoopbackInterfaceIndexTable(); //I think we want non-loopback here
+    if (!indexTable)
+        return ERROR_NOT_ENOUGH_MEMORY;
+
+    ret = openTcpFile(&tcpFile);
+    if (!NT_SUCCESS(ret))
+        return ERROR_NO_DATA;
+
+    for (i = indexTable->numIndexes; i >= 0; i--)
+    {
+        if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
+                                           NULL,
+                                           indexTable->indexes[i],
+                                           &ifInfo)))
+        {
+            /* The whole struct */
+            requiredSize += sizeof(IP_ADAPTER_ADDRESSES);
+
+            /* Friendly name */
+            if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
+                requiredSize += strlen((char *)ifInfo.if_info.ent.if_descr) + 1; //FIXME
+
+            /* Adapter name */
+            requiredSize += strlen((char *)ifInfo.if_info.ent.if_descr) + 1;
+
+            /* Unicast address */
+            if (!(Flags & GAA_FLAG_SKIP_UNICAST))
+                requiredSize += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
+
+            /* FIXME: Implement multicast, anycast, and dns server stuff */
+
+            /* FIXME: Implement dns suffix and description */
+            requiredSize += 2 * sizeof(WCHAR);
+
+            /* We're only going to implement what's required for XP SP0 */
+        }
+    }
+
+    if (*pOutBufLen < requiredSize)
+    {
+        *pOutBufLen = requiredSize;
+        closeTcpFile(tcpFile);
+        free(indexTable);
+        return ERROR_BUFFER_OVERFLOW;
+    }
+
+    RtlZeroMemory(pAdapterAddresses, requiredSize);
+
+    /* Let's set up the pointers */
+    currentAddress = pAdapterAddresses;
+    for (i = indexTable->numIndexes; i >= 0; i--)
+    {
+        if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
+                                           NULL,
+                                           indexTable->indexes[i],
+                                           &ifInfo)))
+        {
+            currentLocation = (PUCHAR)currentAddress + (ULONG_PTR)sizeof(IP_ADAPTER_ADDRESSES);
+
+            /* FIXME: Friendly name */
+            if (!(Flags & GAA_FLAG_SKIP_FRIENDLY_NAME))
+            {
+                currentAddress->FriendlyName = (PVOID)currentLocation;
+                currentLocation += sizeof(WCHAR);
+            }
+
+            /* Adapter name */
+            currentAddress->AdapterName = (PVOID)currentLocation;
+            currentLocation += strlen((char *)ifInfo.if_info.ent.if_descr) + 1;
+
+            /* Unicast address */
+            if (!(Flags & GAA_FLAG_SKIP_UNICAST))
+            {
+                currentAddress->FirstUnicastAddress = (PVOID)currentLocation;
+                currentLocation += sizeof(IP_ADAPTER_UNICAST_ADDRESS);
+                currentAddress->FirstUnicastAddress->Address.lpSockaddr = (PVOID)currentLocation;
+                currentLocation += sizeof(struct sockaddr);
+            }
+
+            /* FIXME: Implement multicast, anycast, and dns server stuff */
+
+            /* FIXME: Implement dns suffix and description */
+            currentAddress->DnsSuffix = (PVOID)currentLocation;
+            currentLocation += sizeof(WCHAR);
+
+            currentAddress->Description = (PVOID)currentLocation;
+            currentLocation += sizeof(WCHAR);
+
+            currentAddress->Next = (PVOID)currentLocation;
+
+            /* We're only going to implement what's required for XP SP0 */
+
+            currentAddress = currentAddress->Next;
+        }
+    }
+
+    /* Terminate the last address correctly */
+    if (currentAddress)
+        currentAddress->Next = NULL;
+
+    /* Now again, for real this time */
+
+    currentAddress = pAdapterAddresses;
+    for (i = indexTable->numIndexes; i >= 0; i--)
+    {
+        if (NT_SUCCESS(getIPAddrEntryForIf(tcpFile,
+                                           NULL,
+                                           indexTable->indexes[i],
+                                           &ifInfo)))
+        {
+            /* Make sure we're not looping more than we hoped for */
+            ASSERT(currentAddress);
+
+            /* Alignment information */
+            currentAddress->Length = sizeof(IP_ADAPTER_ADDRESSES);
+            currentAddress->IfIndex = indexTable->indexes[i];
+
+            /* Adapter name */
+            strcpy(currentAddress->AdapterName, (char *)ifInfo.if_info.ent.if_descr);
+
+            if (!(Flags & GAA_FLAG_SKIP_UNICAST))
+            {
+                currentAddress->FirstUnicastAddress->Length = sizeof(IP_ADAPTER_UNICAST_ADDRESS);
+                currentAddress->FirstUnicastAddress->Flags = 0; //FIXME
+                currentAddress->FirstUnicastAddress->Next = NULL; //FIXME: Support more than one address per adapter
+                currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_family = AF_INET;
+                memcpy(currentAddress->FirstUnicastAddress->Address.lpSockaddr->sa_data,
+                       &ifInfo.ip_addr.iae_addr,
+                       sizeof(ifInfo.ip_addr.iae_addr));
+                currentAddress->FirstUnicastAddress->Address.iSockaddrLength = sizeof(ifInfo.ip_addr.iae_addr) + sizeof(USHORT);
+                currentAddress->FirstUnicastAddress->PrefixOrigin = IpPrefixOriginOther; //FIXME
+                currentAddress->FirstUnicastAddress->SuffixOrigin = IpPrefixOriginOther; //FIXME
+                currentAddress->FirstUnicastAddress->DadState = IpDadStatePreferred; //FIXME
+                currentAddress->FirstUnicastAddress->ValidLifetime = 0xFFFFFFFF; //FIXME
+                currentAddress->FirstUnicastAddress->PreferredLifetime = 0xFFFFFFFF; //FIXME
+                currentAddress->FirstUnicastAddress->LeaseLifetime = 0xFFFFFFFF; //FIXME
+            }
+
+            /* FIXME: Implement multicast, anycast, and dns server stuff */
+            currentAddress->FirstAnycastAddress = NULL;
+            currentAddress->FirstMulticastAddress = NULL;
+            currentAddress->FirstDnsServerAddress = NULL;
+
+            /* FIXME: Implement dns suffix, description, and friendly name */
+            currentAddress->DnsSuffix[0] = UNICODE_NULL;
+            currentAddress->Description[0] = UNICODE_NULL;
+            currentAddress->FriendlyName[0] = UNICODE_NULL;
+
+            /* Physical Address */
+            memcpy(currentAddress->PhysicalAddress, ifInfo.if_info.ent.if_physaddr, ifInfo.if_info.ent.if_physaddrlen);
+            currentAddress->PhysicalAddressLength = ifInfo.if_info.ent.if_physaddrlen;
+
+            /* Flags */
+            currentAddress->Flags = 0; //FIXME
+
+            /* MTU */
+            currentAddress->Mtu = ifInfo.if_info.ent.if_mtu;
+
+            /* Interface type */
+            currentAddress->IfType = ifInfo.if_info.ent.if_type;
+
+            /* Operational status */
+            currentAddress->OperStatus = ifInfo.if_info.ent.if_operstatus;
+
+            /* We're only going to implement what's required for XP SP0 */
+
+            /* Move to the next address */
+            currentAddress = currentAddress->Next;
+        }
+    }
+
+    closeTcpFile(tcpFile);
+    free(indexTable);
+
+    return NO_ERROR;
+#else
+    if (!pOutBufLen) return ERROR_INVALID_PARAMETER;
+    if (!pAdapterAddresses || *pOutBufLen == 0)
+      return ERROR_BUFFER_OVERFLOW;
+    if (Reserved) return ERROR_INVALID_PARAMETER;
+
     FIXME(":stub\n");
-    return 0L;
+    return ERROR_NO_DATA;
+#endif
 }
 
 /*
@@ -2084,4 +2525,49 @@ DWORD WINAPI GetIcmpStatisticsEx(PMIB_ICMP_EX pStats,DWORD dwFamily)
     return 0L;
 }
 
+/******************************************************************
+ *    GetIfTable2 (IPHLPAPI.@)
+ *
+ * PARAMS
+ *  pIfTable [In/Out]
+ */
+NETIOAPI_API WINAPI GetIfTable2(PMIB_IF_TABLE2 *pIfTable)
+{
+    UNIMPLEMENTED;
+    return ERROR_NOT_SUPPORTED;
+}
 
+/******************************************************************
+ *    GetIfEntry2 (IPHLPAPI.@)
+ *
+ * PARAMS
+ *  pIfRow [In/Out]
+ */
+NETIOAPI_API WINAPI GetIfEntry2(IN OUT PMIB_IF_ROW2 pIfRow)
+{
+  TRACE("pIfRow %p\n", pIfRow);
+  if (!pIfRow)
+    return ERROR_INVALID_PARAMETER;
+    
+  UNIMPLEMENTED;
+  return ERROR_NOT_SUPPORTED;
+}
+
+DWORD WINAPI
+SetIpForwardEntryToStack(PMIB_IPFORWARDROW pRoute)
+{
+    FIXME("SetIpForwardEntryToStack() stub\n");
+    return 0L;
+}
+
+DWORD WINAPI
+NhGetInterfaceNameFromDeviceGuid(DWORD dwUnknown1,
+                                 DWORD dwUnknown2,
+                                 DWORD dwUnknown3,
+                                 DWORD dwUnknown4,
+                                 DWORD dwUnknown5)
+{
+    FIXME("NhGetInterfaceNameFromDeviceGuid() stub\n");
+    return 0L;
+}