iphlpapi: Remove one IP address per interface restriction.
- remove restriction of one IP address per interface
- remove dead code, and make static functions that can be
- update comments and copyright notice
diff --git a/dlls/iphlpapi/ifenum.c b/dlls/iphlpapi/ifenum.c
index 0283d36..31b0532 100644
--- a/dlls/iphlpapi/ifenum.c
+++ b/dlls/iphlpapi/ifenum.c
@@ -1,4 +1,4 @@
-/* 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
@@ -455,38 +455,7 @@
   return ret;
 }
 
-DWORD getInterfaceIPAddrByName(const char *name)
-{
-  DWORD ret = INADDR_ANY;
-
-  if (name) {
-    int fd = socket(PF_INET, SOCK_DGRAM, 0);
-
-    if (fd != -1) {
-      struct ifreq ifr;
-
-      lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
-      if (ioctl(fd, SIOCGIFADDR, &ifr) == 0)
-        memcpy(&ret, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
-      close(fd);
-    }
-  }
-  return ret;
-}
-
-DWORD getInterfaceIPAddrByIndex(DWORD index)
-{
-  DWORD ret;
-  const char *name = getInterfaceNameByIndex(index);
-
-  if (name)
-    ret = getInterfaceIPAddrByName(name);
-  else
-    ret = INADDR_ANY;
-  return ret;
-}
-
-DWORD getInterfaceBCastAddrByName(const char *name)
+static DWORD getInterfaceBCastAddrByName(const char *name)
 {
   DWORD ret = INADDR_ANY;
 
@@ -505,19 +474,7 @@
   return ret;
 }
 
-DWORD getInterfaceBCastAddrByIndex(DWORD index)
-{
-  DWORD ret;
-  const char *name = getInterfaceNameByIndex(index);
-
-  if (name)
-    ret = getInterfaceBCastAddrByName(name);
-  else
-    ret = INADDR_ANY;
-  return ret;
-}
-
-DWORD getInterfaceMaskByName(const char *name)
+static DWORD getInterfaceMaskByName(const char *name)
 {
   DWORD ret = INADDR_NONE;
 
@@ -536,18 +493,6 @@
   return ret;
 }
 
-DWORD getInterfaceMaskByIndex(DWORD index)
-{
-  DWORD ret;
-  const char *name = getInterfaceNameByIndex(index);
-
-  if (name)
-    ret = getInterfaceMaskByName(name);
-  else
-    ret = INADDR_NONE;
-  return ret;
-}
-
 #if defined (SIOCGIFHWADDR)
 DWORD getInterfacePhysicalByName(const char *name, PDWORD len, PBYTE addr,
  PDWORD type)
@@ -657,12 +602,16 @@
     else {
       struct arpreq arp;
       struct sockaddr_in *saddr;
+      struct ifreq ifr;
 
+      /* get IP addr */
+      lstrcpynA(ifr.ifr_name, name, IFNAMSIZ);
+      ioctl(fd, SIOCGIFADDR, &ifr);
       memset(&arp, 0, sizeof(struct arpreq));
       arp.arp_pa.sa_family = AF_INET;
       saddr = (struct sockaddr_in *)&arp; /* proto addr is first member */
       saddr->sin_family = AF_INET;
-      saddr->sin_addr.s_addr = getInterfaceIPAddrByName(name);
+      memcpy(&saddr->sin_addr.s_addr, ifr.ifr_addr.sa_data + 2, sizeof(DWORD));
       if ((ioctl(fd, SIOCGARP, &arp)))
         ret = ERROR_INVALID_DATA;
       else {
@@ -793,7 +742,7 @@
     return ERROR_INVALID_DATA;
 }
 
-DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
+static DWORD getInterfaceMtuByName(const char *name, PDWORD mtu)
 {
   DWORD ret;
   int fd;
@@ -825,17 +774,7 @@
   return ret;
 }
 
-DWORD getInterfaceMtuByIndex(DWORD index, PDWORD mtu)
-{
-  const char *name = getInterfaceNameByIndex(index);
-
-  if (name)
-    return getInterfaceMtuByName(name, mtu);
-  else
-    return ERROR_INVALID_DATA;
-}
-
-DWORD getInterfaceStatusByName(const char *name, PDWORD status)
+static DWORD getInterfaceStatusByName(const char *name, PDWORD status)
 {
   DWORD ret;
   int fd;
@@ -866,16 +805,6 @@
   return ret;
 }
 
-DWORD getInterfaceStatusByIndex(DWORD index, PDWORD status)
-{
-  const char *name = getInterfaceNameByIndex(index);
-
-  if (name)
-    return getInterfaceStatusByName(name, status);
-  else
-    return ERROR_INVALID_DATA;
-}
-
 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry)
 {
   BYTE addr[MAX_INTERFACE_PHYSADDR];
@@ -927,6 +856,74 @@
     return ERROR_INVALID_DATA;
 }
 
+/* Enumerates the IP addresses in the system using SIOCGIFCONF, returning
+ * the count to you in *pcAddresses.  It also returns to you the struct ifconf
+ * used by the call to ioctl, so that you may process the addresses further.
+ * Free ifc->ifc_buf using HeapFree.
+ * Returns NO_ERROR on success, something else on failure.
+ */
+static DWORD enumIPAddresses(PDWORD pcAddresses, struct ifconf *ifc)
+{
+  DWORD ret;
+  int fd;
+
+  fd = socket(PF_INET, SOCK_DGRAM, 0);
+  if (fd != -1) {
+    int ioctlRet = 0;
+    DWORD guessedNumAddresses = 0, numAddresses = 0;
+    caddr_t ifPtr;
+
+    ret = NO_ERROR;
+    ifc->ifc_len = 0;
+    ifc->ifc_buf = NULL;
+    /* there is no way to know the interface count beforehand,
+       so we need to loop again and again upping our max each time
+       until returned < max */
+    do {
+      HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
+      if (guessedNumAddresses == 0)
+        guessedNumAddresses = INITIAL_INTERFACES_ASSUMED;
+      else
+        guessedNumAddresses *= 2;
+      ifc->ifc_len = sizeof(struct ifreq) * guessedNumAddresses;
+      ifc->ifc_buf = HeapAlloc(GetProcessHeap(), 0, ifc->ifc_len);
+      ioctlRet = ioctl(fd, SIOCGIFCONF, ifc);
+    } while (ioctlRet == 0 &&
+     ifc->ifc_len == (sizeof(struct ifreq) * guessedNumAddresses));
+
+    if (ioctlRet == 0) {
+      ifPtr = ifc->ifc_buf;
+      while (ifPtr && ifPtr < ifc->ifc_buf + ifc->ifc_len) {
+        numAddresses++;
+        ifPtr += ifreq_len((struct ifreq *)ifPtr);
+      }
+    }
+    else
+      ret = ERROR_INVALID_PARAMETER; /* FIXME: map from errno to Win32 */
+    if (!ret)
+      *pcAddresses = numAddresses;
+    else
+    {
+      HeapFree(GetProcessHeap(), 0, ifc->ifc_buf);
+      ifc->ifc_buf = NULL;
+    }
+    close(fd);
+  }
+  else
+    ret = ERROR_NO_SYSTEM_RESOURCES;
+  return ret;
+}
+
+DWORD getNumIPAddresses(void)
+{
+  DWORD numAddresses = 0;
+  struct ifconf ifc;
+
+  if (!enumIPAddresses(&numAddresses, &ifc))
+    HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
+  return numAddresses;
+}
+
 DWORD getIPAddrTable(PMIB_IPADDRTABLE *ppIpAddrTable, HANDLE heap, DWORD flags)
 {
   DWORD ret;
@@ -935,84 +932,50 @@
     ret = ERROR_INVALID_PARAMETER;
   else
   {
-    int fd;
+    DWORD numAddresses = 0;
+    struct ifconf ifc;
 
-    fd = socket(PF_INET, SOCK_DGRAM, 0);
-    if (fd != -1) {
-      int ioctlRet;
-      DWORD guessedNumAddresses, numAddresses;
-      struct ifconf ifc;
-      caddr_t ifPtr;
+    ret = enumIPAddresses(&numAddresses, &ifc);
+    if (!ret)
+    {
+      *ppIpAddrTable = HeapAlloc(heap, flags, sizeof(MIB_IPADDRTABLE) +
+       (numAddresses - 1) * sizeof(MIB_IPADDRROW));
+      if (*ppIpAddrTable) {
+        DWORD i = 0, bcast;
+        caddr_t ifPtr;
 
-      guessedNumAddresses = 0;
-      ioctlRet = 0;
-      memset(&ifc, 0, sizeof(ifc));
-      /* there is no way to know the interface count beforehand,
-         so we need to loop again and again upping our max each time
-         until returned < max */
-      do {
-        if (guessedNumAddresses == 0)
-          guessedNumAddresses = INITIAL_INTERFACES_ASSUMED;
-        else
-          guessedNumAddresses *= 2;
-        HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
-        ifc.ifc_len = sizeof(struct ifreq) * guessedNumAddresses;
-        ifc.ifc_buf = HeapAlloc(GetProcessHeap(), 0, ifc.ifc_len);
-        ioctlRet = ioctl(fd, SIOCGIFCONF, &ifc);
-      } while (ioctlRet == 0 &&
-       ifc.ifc_len == (sizeof(struct ifreq) * guessedNumAddresses));
-
-      if (ioctlRet == 0) {
-        numAddresses = 0;
+        ret = NO_ERROR;
+        (*ppIpAddrTable)->dwNumEntries = numAddresses;
         ifPtr = ifc.ifc_buf;
-        while (ifPtr && ifPtr < ifc.ifc_buf + ifc.ifc_len) {
-          numAddresses++;
-          ifPtr += ifreq_len((struct ifreq *)ifPtr);
+        while (!ret && ifPtr && ifPtr < ifc.ifc_buf + ifc.ifc_len) {
+          struct ifreq *ifr = (struct ifreq *)ifPtr;
+
+          ret = getInterfaceIndexByName(ifr->ifr_name,
+           &(*ppIpAddrTable)->table[i].dwIndex);
+          memcpy(&(*ppIpAddrTable)->table[i].dwAddr, ifr->ifr_addr.sa_data + 2,
+           sizeof(DWORD));
+          (*ppIpAddrTable)->table[i].dwMask =
+           getInterfaceMaskByName(ifr->ifr_name);
+          /* the dwBCastAddr member isn't the broadcast address, it indicates
+           * whether the interface uses the 1's broadcast address (1) or the
+           * 0's broadcast address (0).
+           */
+          bcast = getInterfaceBCastAddrByName(ifr->ifr_name);
+          (*ppIpAddrTable)->table[i].dwBCastAddr =
+           (bcast & (*ppIpAddrTable)->table[i].dwMask) ? 1 : 0;
+          /* FIXME: hardcoded reasm size, not sure where to get it */
+          (*ppIpAddrTable)->table[i].dwReasmSize = 65535;
+
+          (*ppIpAddrTable)->table[i].unused1 = 0;
+          (*ppIpAddrTable)->table[i].wType = 0;
+          ifPtr += ifreq_len(ifr);
+          i++;
         }
-        *ppIpAddrTable = HeapAlloc(heap, flags, sizeof(MIB_IPADDRTABLE) +
-         (numAddresses - 1) * sizeof(MIB_IPADDRROW));
-        if (*ppIpAddrTable) {
-          DWORD i = 0, bcast;
-
-          ret = NO_ERROR;
-          (*ppIpAddrTable)->dwNumEntries = numAddresses;
-          ifPtr = ifc.ifc_buf;
-          while (!ret && ifPtr && ifPtr < ifc.ifc_buf + ifc.ifc_len) {
-            struct ifreq *ifr = (struct ifreq *)ifPtr;
-
-            ret = getInterfaceIndexByName(ifr->ifr_name,
-             &(*ppIpAddrTable)->table[i].dwIndex);
-            (*ppIpAddrTable)->table[i].dwAddr =
-             getInterfaceIPAddrByIndex((*ppIpAddrTable)->table[i].dwIndex);
-            (*ppIpAddrTable)->table[i].dwMask =
-             getInterfaceMaskByIndex((*ppIpAddrTable)->table[i].dwIndex);
-            /* the dwBCastAddr member isn't the broadcast address, it indicates
-             * whether the interface uses the 1's broadcast address (1) or the
-             * 0's broadcast address (0).
-             */
-            bcast = getInterfaceBCastAddrByIndex(
-             (*ppIpAddrTable)->table[i].dwIndex);
-            (*ppIpAddrTable)->table[i].dwBCastAddr =
-             (bcast & (*ppIpAddrTable)->table[i].dwMask) ? 1 : 0;
-            /* FIXME: hardcoded reasm size, not sure where to get it */
-            (*ppIpAddrTable)->table[i].dwReasmSize = 65535;
-
-            (*ppIpAddrTable)->table[i].unused1 = 0;
-            (*ppIpAddrTable)->table[i].wType = 0;
-            ifPtr += ifreq_len(ifr);
-            i++;
-          }
-        }
-        else
-          ret = ERROR_OUTOFMEMORY;
       }
       else
-        ret = ERROR_INVALID_PARAMETER;
+        ret = ERROR_OUTOFMEMORY;
       HeapFree(GetProcessHeap(), 0, ifc.ifc_buf);
-      close(fd);
     }
-    else
-      ret = ERROR_NO_SYSTEM_RESOURCES;
   }
   return ret;
 }
diff --git a/dlls/iphlpapi/ifenum.h b/dlls/iphlpapi/ifenum.h
index 3dd9135..75a2ad4 100644
--- a/dlls/iphlpapi/ifenum.h
+++ b/dlls/iphlpapi/ifenum.h
@@ -1,5 +1,5 @@
 /* ifenum.h
- * 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
@@ -81,16 +81,6 @@
  */
 DWORD getInterfaceIndexByName(const char *name, PDWORD index);
 
-/* This bunch returns IP addresses, and INADDR_ANY or INADDR_NONE if not found,
- * appropriately depending on the f/n.
- */
-DWORD getInterfaceIPAddrByName(const char *name);
-DWORD getInterfaceIPAddrByIndex(DWORD index);
-DWORD getInterfaceMaskByName(const char *name);
-DWORD getInterfaceMaskByIndex(DWORD index);
-DWORD getInterfaceBCastAddrByName(const char *name);
-DWORD getInterfaceBCastAddrByIndex(DWORD index);
-
 /* Gets a few physical charactersistics of a device:  MAC addr len, MAC addr,
  * and type as one of the MIB_IF_TYPEs.
  * len's in-out: on in, needs to say how many bytes are available in addr,
@@ -109,14 +99,6 @@
 DWORD getInterfacePhysicalByIndex(DWORD index, PDWORD len, PBYTE addr,
  PDWORD type);
 
-/* Get the operational status as a (MIB_)IF_OPER_STATUS type.
- */
-DWORD getInterfaceStatusByName(const char *name, PDWORD status);
-DWORD getInterfaceStatusByIndex(DWORD index, PDWORD status);
-
-DWORD getInterfaceMtuByName(const char *name, PDWORD mtu);
-DWORD getInterfaceMtuByIndex(DWORD index, PDWORD mtu);
-
 /* Fills in the MIB_IFROW by name/index.  Doesn't fill in interface statistics,
  * see ipstats.h for that.
  * Returns ERROR_INVALID_PARAMETER if name or entry is NULL, ERROR_INVALID_DATA
@@ -125,6 +107,8 @@
 DWORD getInterfaceEntryByName(const char *name, PMIB_IFROW entry);
 DWORD getInterfaceEntryByIndex(DWORD index, PMIB_IFROW entry);
 
+DWORD getNumIPAddresses(void);
+
 /* Gets the configured IP addresses for the system, and sets *ppIpAddrTable to
  * a table of them allocated from heap, or NULL if out of memory.  Returns
  * NO_ERROR on success, something else on failure.  Note there may be more than
diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c
index df90fd6..9e43db0 100644
--- a/dlls/iphlpapi/iphlpapi_main.c
+++ b/dlls/iphlpapi/iphlpapi_main.c
@@ -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
@@ -618,6 +618,7 @@
 DWORD WINAPI GetAdapterIndex(LPWSTR AdapterName, PULONG IfIndex)
 {
   FIXME("(AdapterName %p, IfIndex %p): stub\n", AdapterName, IfIndex);
+  /* FIXME: implement using getInterfaceIndexByName */
   return ERROR_NOT_SUPPORTED;
 }
 
@@ -646,22 +647,34 @@
     DWORD numNonLoopbackInterfaces = getNumNonLoopbackInterfaces();
 
     if (numNonLoopbackInterfaces > 0) {
-      /* this calculation assumes only one address in the IP_ADDR_STRING lists.
-         that's okay, because:
-         - we don't get multiple addresses per adapter anyway
-         - we don't know about per-adapter gateways
-         - DHCP and WINS servers can have max one entry per list */
-      ULONG size = sizeof(IP_ADAPTER_INFO) * numNonLoopbackInterfaces;
+      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;
+      if (numIPAddresses > numNonLoopbackInterfaces)
+        size += (numIPAddresses - numNonLoopbackInterfaces) *
+         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;
 
+        ret = getIPAddrTable(&ipAddrTable, GetProcessHeap(), 0);
+        if (!ret)
+          table = getNonLoopbackInterfaceIndexTable();
         if (table) {
           size = sizeof(IP_ADAPTER_INFO) * table->numIndexes;
+          if (ipAddrTable->dwNumEntries > numNonLoopbackInterfaces)
+            size += (ipAddrTable->dwNumEntries - numNonLoopbackInterfaces) *
+             sizeof(IP_ADDR_STRING); 
           if (*pOutBufLen < size) {
             *pOutBufLen = size;
             ret = ERROR_INSUFFICIENT_BUFFER;
@@ -671,10 +684,13 @@
             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) {
+            if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Network",
+             &hKey) == ERROR_SUCCESS) {
               DWORD size = sizeof(primaryWINS.String);
               unsigned long addr;
 
@@ -693,7 +709,9 @@
             }
             for (ndx = 0; ndx < table->numIndexes; ndx++) {
               PIP_ADAPTER_INFO ptr = &pAdapterInfo[ndx];
-              DWORD addrLen = sizeof(ptr->Address), type;
+              DWORD addrLen = sizeof(ptr->Address), type, i;
+              PIP_ADDR_STRING currentIPAddr = &ptr->IpAddressList;
+              BOOL firstIPAddr = TRUE;
 
               /* on Win98 this is left empty, but whatever */
               lstrcpynA(ptr->AdapterName,
@@ -707,10 +725,26 @@
               ptr->AddressLength = addrLen;
               ptr->Type = type;
               ptr->Index = table->indexes[ndx];
-              toIPAddressString(getInterfaceIPAddrByIndex(table->indexes[ndx]),
-               ptr->IpAddressList.IpAddress.String);
-              toIPAddressString(getInterfaceMaskByIndex(table->indexes[ndx]),
-               ptr->IpAddressList.IpMask.String);
+              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].dwBCastAddr,
+                     ptr->IpAddressList.IpMask.String);
+                    firstIPAddr = FALSE;
+                  }
+                  else {
+                    currentIPAddr->Next = nextIPAddr;
+                    currentIPAddr = nextIPAddr;
+                    toIPAddressString(ipAddrTable->table[i].dwAddr,
+                     currentIPAddr->IpAddress.String);
+                    toIPAddressString(ipAddrTable->table[i].dwBCastAddr,
+                     currentIPAddr->IpMask.String);
+                    nextIPAddr++;
+                  }
+                }
+              }
               if (winsEnabled) {
                 ptr->HaveWins = TRUE;
                 memcpy(ptr->PrimaryWinsServer.IpAddress.String,
@@ -729,6 +763,8 @@
         }
         else
           ret = ERROR_OUTOFMEMORY;
+        if (ipAddrTable)
+          HeapFree(GetProcessHeap(), 0, ipAddrTable);
       }
     }
     else
@@ -1038,6 +1074,7 @@
         else {
           DWORD ndx;
 
+          *dwOutBufLen = size;
           pIfTable->NumAdapters = 0;
           for (ndx = 0; ndx < table->numIndexes; ndx++) {
             const char *walker, *name;
@@ -1791,7 +1828,7 @@
 DWORD WINAPI SetIfEntry(PMIB_IFROW pIfRow)
 {
   FIXME("(pIfRow %p): stub\n", pIfRow);
-  /* this is supposed to set an administratively interface up or down.
+  /* 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). */
diff --git a/dlls/iphlpapi/ipstats.c b/dlls/iphlpapi/ipstats.c
index 8a6d8d6..f49a7cd 100644
--- a/dlls/iphlpapi/ipstats.c
+++ b/dlls/iphlpapi/ipstats.c
@@ -1,4 +1,4 @@
-/* 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
diff --git a/dlls/iphlpapi/ipstats.h b/dlls/iphlpapi/ipstats.h
index 7055d2b..15ce8bb 100644
--- a/dlls/iphlpapi/ipstats.h
+++ b/dlls/iphlpapi/ipstats.h
@@ -1,5 +1,5 @@
 /* ipstats.h
- * 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