OSDN Git Service

* autoload.cc (WSAIoctl): Remove.
authorcorinna <corinna>
Thu, 21 Jun 2007 15:57:54 +0000 (15:57 +0000)
committercorinna <corinna>
Thu, 21 Jun 2007 15:57:54 +0000 (15:57 +0000)
* cygwin.din: Export freeifaddrs, getifaddrs.
* fhandler_socket.cc (fhandler_socket::ioctl): Drop SOCKET parameter
from get_ifconf.
* net.cc: Include ifaddrs.h.
(in_are_prefix_equal): Match addresses in network byte order.
(ip_addr_prefix): Convert address into host byte order before
testing with IN_LOOPBACK.
(struct ifall): Define.
(get_xp_ifs): Replace get_xp_ifconf.  Return struct ifall array.
(get_2k_ifs): Ditto, replace get_2k_ifconf.
(get_nt_ifs): Ditto, replace get_nt_ifconf.
(getifaddrs): New function.
(freeifaddrs): New function.
(get_ifconf): Call matching get_XX_ifs function and create
ifc content from here.  Drop lo fake since it's now in get_nt_ifs.
* posix.sgml: Add freeifaddrs and getifaddrs to list of implemented
BSD functions.
* wincap.h (wincapc::has_broken_if_oper_status): New element.
* wincap.cc: Implement above element throughout.
* include/ifaddrs.h: New file.
* include/cygwin/version.h: Bump API minor number.

winsup/cygwin/ChangeLog
winsup/cygwin/autoload.cc
winsup/cygwin/cygwin.din
winsup/cygwin/fhandler_socket.cc
winsup/cygwin/include/cygwin/version.h
winsup/cygwin/include/ifaddrs.h [new file with mode: 0644]
winsup/cygwin/net.cc
winsup/cygwin/posix.sgml
winsup/cygwin/wincap.cc
winsup/cygwin/wincap.h

index 1ca7ac7..b03732a 100644 (file)
@@ -1,3 +1,28 @@
+2007-06-21  Corinna Vinschen  <corinna@vinschen.de>
+
+       * autoload.cc (WSAIoctl): Remove.
+       * cygwin.din: Export freeifaddrs, getifaddrs.
+       * fhandler_socket.cc (fhandler_socket::ioctl): Drop SOCKET parameter
+       from get_ifconf.
+       * net.cc: Include ifaddrs.h.
+       (in_are_prefix_equal): Match addresses in network byte order.
+       (ip_addr_prefix): Convert address into host byte order before
+       testing with IN_LOOPBACK.
+       (struct ifall): Define.
+       (get_xp_ifs): Replace get_xp_ifconf.  Return struct ifall array.
+       (get_2k_ifs): Ditto, replace get_2k_ifconf.
+       (get_nt_ifs): Ditto, replace get_nt_ifconf.
+       (getifaddrs): New function.
+       (freeifaddrs): New function.
+       (get_ifconf): Call matching get_XX_ifs function and create
+       ifc content from here.  Drop lo fake since it's now in get_nt_ifs.
+       * posix.sgml: Add freeifaddrs and getifaddrs to list of implemented
+       BSD functions.
+       * wincap.h (wincapc::has_broken_if_oper_status): New element.
+       * wincap.cc: Implement above element throughout.
+       * include/ifaddrs.h: New file.
+       * include/cygwin/version.h: Bump API minor number.
+
 2007-06-20  Eric Blake  <ebb9@byu.net>
 
        * cygwin.din: Export exp10, exp10f, pow10, pow10f, strcasestr,
index 3d55cdd..82ecf46 100644 (file)
@@ -383,7 +383,6 @@ LoadDLLfunc (WSACloseEvent, 4, ws2_32)
 LoadDLLfunc (WSACreateEvent, 0, ws2_32)
 LoadDLLfunc (WSAEnumNetworkEvents, 12, ws2_32)
 LoadDLLfunc (WSAEventSelect, 12, ws2_32)
-LoadDLLfunc (WSAIoctl, 36, ws2_32)
 LoadDLLfunc (WSAGetLastError, 0, ws2_32)
 LoadDLLfunc (WSARecvFrom, 36, ws2_32)
 LoadDLLfunc (WSASendTo, 36, ws2_32)
index 9828b2e..7460532 100644 (file)
@@ -489,6 +489,7 @@ _fread = fread SIGFE
 free SIGFE
 _free = free SIGFE
 freeaddrinfo = cygwin_freeaddrinfo SIGFE
+freeifaddrs SIGFE
 freopen SIGFE
 _freopen = freopen SIGFE
 _freopen64 = freopen64 SIGFE
@@ -605,6 +606,7 @@ gethostbyname = cygwin_gethostbyname SIGFE
 gethostid SIGFE
 gethostname = cygwin_gethostname SIGFE
 _gethostname = cygwin_gethostname SIGFE
+getifaddrs SIGFE
 getitimer SIGFE
 getline = __getline SIGFE
 __getline SIGFE
index ff46fbe..03eadd3 100644 (file)
@@ -1455,7 +1455,7 @@ struct __old_ifreq {
 int
 fhandler_socket::ioctl (unsigned int cmd, void *p)
 {
-  extern int get_ifconf (SOCKET s, struct ifconf *ifc, int what); /* net.cc */
+  extern int get_ifconf (struct ifconf *ifc, int what); /* net.cc */
   int res;
   struct ifconf ifc, *ifcp;
   struct ifreq *ifrp;
@@ -1480,7 +1480,7 @@ fhandler_socket::ioctl (unsigned int cmd, void *p)
          ifc.ifc_len = ifcp->ifc_len;
          ifc.ifc_buf = ifcp->ifc_buf;
        }
-      res = get_ifconf (get_socket (), &ifc, cmd);
+      res = get_ifconf (&ifc, cmd);
       if (res)
        debug_printf ("error in get_ifconf");
       if (CYGWIN_VERSION_CHECK_FOR_OLD_IFREQ)
@@ -1544,7 +1544,7 @@ fhandler_socket::ioctl (unsigned int cmd, void *p)
              ifc.ifc_req[i].ifr_frndlyname = &iff[i];
          }
 
-       res = get_ifconf (get_socket (), &ifc, cmd);
+       res = get_ifconf (&ifc, cmd);
        if (res)
          {
            debug_printf ("error in get_ifconf");
index a3058af..51bcc60 100644 (file)
@@ -312,12 +312,13 @@ details. */
       170: Export insque, remque.
       171: Export exp10, exp10f, pow10, pow10f, strcasestr, funopen,
            fopencookie.
+      172: Export getifaddrs, freeifaddrs.
      */
 
      /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */
 
 #define CYGWIN_VERSION_API_MAJOR 0
-#define CYGWIN_VERSION_API_MINOR 171
+#define CYGWIN_VERSION_API_MINOR 172
 
      /* There is also a compatibity version number associated with the
        shared memory regions.  It is incremented when incompatible
diff --git a/winsup/cygwin/include/ifaddrs.h b/winsup/cygwin/include/ifaddrs.h
new file mode 100644 (file)
index 0000000..f6c28e7
--- /dev/null
@@ -0,0 +1,57 @@
+/*     $OpenBSD: ifaddrs.h,v 1.4 2004/01/22 21:48:02 espie Exp $       */
+
+/*
+ * Copyright (c) 1995, 1999
+ *     Berkeley Software Design, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
+ */
+
+#ifndef        _IFADDRS_H_
+#define        _IFADDRS_H_
+
+struct ifaddrs {
+       struct ifaddrs  *ifa_next;
+       char            *ifa_name;
+       unsigned int     ifa_flags;
+       struct sockaddr *ifa_addr;
+       struct sockaddr *ifa_netmask;
+       struct sockaddr *ifa_dstaddr;
+       void            *ifa_data;
+};
+
+/*
+ * This may have been defined in <net/if.h>.  Note that if <net/if.h> is
+ * to be included it must be included before this header file.
+ */
+/* CV 2007-06-20: Not a problem on Cygwin right now. */
+#ifndef        ifa_broadaddr
+#define        ifa_broadaddr   ifa_dstaddr     /* broadcast address interface */
+#endif
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+extern int getifaddrs(struct ifaddrs **);
+extern void freeifaddrs(struct ifaddrs *);
+__END_DECLS
+
+#endif
index 2f443ef..59e290c 100644 (file)
@@ -41,6 +41,7 @@ details. */
 #include "registry.h"
 #include "cygtls.h"
 #include "cygwin/in6.h"
+#include "ifaddrs.h"
 
 extern "C"
 {
@@ -1195,7 +1196,7 @@ static int in_are_prefix_equal (struct in_addr *p1, struct in_addr *p2, int len)
   if (0 > len || len > 32)
     return 0;
   uint32_t pfxmask = 0xffffffff << (32 - len);
-  return (p1->s_addr & pfxmask) == (p2->s_addr & pfxmask);
+  return (ntohl (p1->s_addr) & pfxmask) == (ntohl (p2->s_addr) & pfxmask);
 }
 
 extern "C" int
@@ -1207,8 +1208,8 @@ ip_addr_prefix (PIP_ADAPTER_UNICAST_ADDRESS pua, PIP_ADAPTER_PREFIX pap)
     {
     case AF_INET:
       /* Prior to Vista, the loopback prefix is not available. */
-      if (IN_LOOPBACK (((struct sockaddr_in *)
-                       pua->Address.lpSockaddr)->sin_addr.s_addr))
+      if (IN_LOOPBACK (ntohl (((struct sockaddr_in *)
+                             pua->Address.lpSockaddr)->sin_addr.s_addr)))
        return 8;
       for ( ; pap; pap = pap->Next)
        if (in_are_prefix_equal (
@@ -1302,166 +1303,192 @@ get_routedst (DWORD if_index)
   return INADDR_ANY;
 }
 
+struct ifall {
+  struct ifaddrs          ifa_ifa;
+  char                    ifa_name[IFNAMSIZ];
+  struct sockaddr_storage ifa_addr;
+  struct sockaddr_storage ifa_brddstaddr;
+  struct sockaddr_storage ifa_netmask;
+  struct sockaddr         ifa_hwaddr;
+  int                     ifa_metric;
+  int                     ifa_mtu;
+  int                     ifa_ifindex;
+  struct ifreq_frndlyname ifa_frndlyname;
+};
+
 /*
- * IFCONF XP SP1 and above.
- * Use IP Helpper function GetAdaptersAddresses.
+ * Get network interfaces XP SP1 and above.
+ * Use IP Helper function GetAdaptersAddresses.
  */
-
-static void
-get_xp_ifconf (SOCKET s, struct ifconf *ifc, int what)
+static struct ifall *
+get_xp_ifs (ULONG family)
 {
   PIP_ADAPTER_ADDRESSES pa0 = NULL, pap;
   PIP_ADAPTER_UNICAST_ADDRESS pua;
-  LPINTERFACE_INFO iie;
   int cnt = 0;
-  DWORD size = 0;
+  struct ifall *ifret = NULL, *ifp;
+  struct sockaddr_in *if_sin;
+  struct sockaddr_in6 *if_sin6;
 
-  if (!get_adapters_addresses (&pa0, AF_INET))
+  if (!get_adapters_addresses (&pa0, family))
     goto done;
 
   for (pap = pa0; pap; pap = pap->Next)
     for (pua = pap->FirstUnicastAddress; pua; pua = pua->Next)
       ++cnt;
-  /* If the size matches exactly the number of interfaces, WSAIoctl fails
-     with WSAError set to WSAEFAULT, for no apparent reason.  So we allocate
-     space for one more INTERFACE_INFO structure here. */
-  iie = (LPINTERFACE_INFO) alloca ((cnt + 1) * sizeof (INTERFACE_INFO));
-  if (WSAIoctl (s, SIO_GET_INTERFACE_LIST, NULL, 0, iie,
-               (cnt + 1) * sizeof (INTERFACE_INFO), &size, NULL, NULL))
-    {
-      set_winsock_errno ();
-      cnt = 0;
-      goto done;
-    }
 
-  struct ifreq *ifr = ifc->ifc_req;
+  if (!(ifret = (struct ifall *) calloc (cnt, sizeof (struct ifall))))
+    goto done;
+  ifp = ifret;
+
   for (pap = pa0; pap; pap = pap->Next)
     {
       int idx = 0;
       for (pua = pap->FirstUnicastAddress; pua; pua = pua->Next)
        {
-         int iinf_idx;
-         for (iinf_idx = 0; iinf_idx < cnt; ++iinf_idx)
-           if (iie[iinf_idx].iiAddress.AddressIn.sin_addr.s_addr
-               ==  ((sockaddr_in *) pua->Address.lpSockaddr)->sin_addr.s_addr)
-             break;
-         if (iinf_idx >= cnt)
-           continue;
+         struct sockaddr *sa = (struct sockaddr *) pua->Address.lpSockaddr;
+#         define sin   ((struct sockaddr_in *) sa)
+#         define sin6  ((struct sockaddr_in6 *) sa)
+         size_t sa_size = (sa->sa_family == AF_INET6
+                           ? sizeof *sin6 : sizeof *sin);
+         /* Next in chain */
+         ifp->ifa_ifa.ifa_next = (struct ifaddrs *) &ifp[1].ifa_ifa;
+         /* Interface name */
          if (!idx)
-           strcpy (ifr->ifr_name, pap->AdapterName);
+           strcpy (ifp->ifa_name, pap->AdapterName);
          else
-           __small_sprintf (ifr->ifr_name, "%s:%u", pap->AdapterName, idx);
+           __small_sprintf (ifp->ifa_name, "%s:%u", pap->AdapterName, idx);
+         ifp->ifa_ifa.ifa_name = ifp->ifa_name;
          ++idx;
-         switch (what)
+         /* Flags */
+         ifp->ifa_ifa.ifa_flags = IFF_UP;
+         if (pap->IfType == IF_TYPE_SOFTWARE_LOOPBACK)
+           ifp->ifa_ifa.ifa_flags |= IFF_LOOPBACK;
+         else if (pap->IfType == IF_TYPE_PPP)
+           ifp->ifa_ifa.ifa_flags |= IFF_POINTOPOINT;
+         else if (sa->sa_family == AF_INET)
+           ifp->ifa_ifa.ifa_flags |= IFF_BROADCAST;
+         if (!(pap->Flags & IP_ADAPTER_NO_MULTICAST))
+           ifp->ifa_ifa.ifa_flags |= IFF_MULTICAST;
+         if (pap->OperStatus == IfOperStatusUp
+             || pap->OperStatus == IfOperStatusUnknown)
+           ifp->ifa_ifa.ifa_flags |= IFF_RUNNING;
+         if (pap->OperStatus != IfOperStatusLowerLayerDown)
+           ifp->ifa_ifa.ifa_flags |= IFF_LOWER_UP;
+         if (pap->OperStatus == IfOperStatusDormant)
+           ifp->ifa_ifa.ifa_flags |= IFF_DORMANT;
+         if (sa->sa_family == AF_INET)
            {
-           case SIOCGIFFLAGS:
-             {
-               ifr->ifr_flags = convert_ifr_flags (iie[iinf_idx].iiFlags);
-               if (pap->OperStatus == IfOperStatusUp
-                   || pap->OperStatus == IfOperStatusUnknown)
-                 ifr->ifr_flags |= IFF_RUNNING;
-               if (pap->OperStatus != IfOperStatusLowerLayerDown)
-                 ifr->ifr_flags |= IFF_LOWER_UP;
-               if (pap->OperStatus == IfOperStatusDormant)
-                 ifr->ifr_flags |= IFF_DORMANT;
-               ULONG hwaddr[2], hwlen = 6;
-               if (SendARP (iie[iinf_idx].iiAddress.AddressIn.sin_addr.s_addr,
-                            0, hwaddr, &hwlen))
-                 ifr->ifr_flags |= IFF_NOARP;
-             }
-             break;
-           case SIOCGIFCONF:
-           case SIOCGIFADDR:
-             memcpy (&ifr->ifr_addr,
-                     &iie[iinf_idx].iiAddress.AddressIn,
-                     sizeof (struct sockaddr_in));
+             ULONG hwaddr[2], hwlen = 6;
+             if (SendARP (sin->sin_addr.s_addr, 0, hwaddr, &hwlen))
+               ifp->ifa_ifa.ifa_flags |= IFF_NOARP;
+           }
+         /* Address */
+         memcpy (&ifp->ifa_addr, sa, sa_size);
+         ifp->ifa_ifa.ifa_addr = (struct sockaddr *) &ifp->ifa_addr;
+         /* Netmask */
+         int prefix = ip_addr_prefix (pua, pap->FirstPrefix);
+         switch (sa->sa_family)
+           {
+           case AF_INET:
+             if_sin = (struct sockaddr_in *) &ifp->ifa_netmask;
+             if_sin->sin_addr.s_addr = htonl (UINT32_MAX << (32 - prefix));
+             if_sin->sin_family = AF_INET;
              break;
-           case SIOCGIFBRDADDR:
-             memcpy (&ifr->ifr_broadaddr,
-                     &iie[iinf_idx].iiBroadcastAddress.AddressIn,
-                     sizeof (struct sockaddr_in));
+           case AF_INET6:
+             if_sin6 = (struct sockaddr_in6 *) &ifp->ifa_netmask;
+             for (cnt = 0; cnt < 4 && prefix; ++cnt, prefix -= 32)
+               if_sin6->sin6_addr.s6_addr32[cnt] = UINT32_MAX;
+               if (prefix < 32)
+                 if_sin6->sin6_addr.s6_addr32[cnt] <<= 32 - prefix;
              break;
-           case SIOCGIFDSTADDR:
-             if (pap->IfType == IF_TYPE_PPP)
-               {
-                 struct sockaddr_in *sa = (struct sockaddr_in *)
-                                          &ifr->ifr_dstaddr;
-                 sa->sin_addr.s_addr = get_routedst (pap->IfIndex);
-                 sa->sin_family = AF_INET;
-                 sa->sin_port = 0;
+           }
+         ifp->ifa_ifa.ifa_netmask = (struct sockaddr *) &ifp->ifa_netmask;
+         if (pap->IfType == IF_TYPE_PPP)
+           {
+             /* Destination address */
+             if (sa->sa_family == AF_INET)
+               {
+                 if_sin = (struct sockaddr_in *) &ifp->ifa_brddstaddr;
+                 if_sin->sin_addr.s_addr = get_routedst (pap->IfIndex);
+                 if_sin->sin_family = AF_INET;
                }
              else
-               memcpy (&ifr->ifr_addr,
-                       &iie[iinf_idx].iiAddress.AddressIn,
-                       sizeof (struct sockaddr_in));
-             break;
-           case SIOCGIFNETMASK:
-             memcpy (&ifr->ifr_netmask,
-                     &iie[iinf_idx].iiNetmask.AddressIn,
-                     sizeof (struct sockaddr_in));
-             break;
-           case SIOCGIFHWADDR:
-             for (UINT i = 0; i < IFHWADDRLEN; ++i)
-               if (i >= pap->PhysicalAddressLength)
-                 ifr->ifr_hwaddr.sa_data[i] = '\0';
-               else
-                 ifr->ifr_hwaddr.sa_data[i] = pap->PhysicalAddress[i];
-             ifr->ifr_hwaddr.sa_family = AF_INET;
-             break;
-           case SIOCGIFMETRIC:
-             if (wincap.has_gaa_on_link_prefix ())
-               ifr->ifr_metric = ((PIP_ADAPTER_ADDRESSES_LH) pap)->Ipv4Metric;
-             else
-               ifr->ifr_metric = 1;
-             break;
-           case SIOCGIFMTU:
-             ifr->ifr_mtu = pap->Mtu;
-             break;
-           case SIOCGIFINDEX:
-             ifr->ifr_ifindex = pap->IfIndex;
-             break;
-           case SIOCGIFFRNDLYNAM:
-             {
-               struct ifreq_frndlyname *iff = (struct ifreq_frndlyname *)
-                                              ifr->ifr_frndlyname;
-               iff->ifrf_len = sys_wcstombs (iff->ifrf_friendlyname,
-                                             IFRF_FRIENDLYNAMESIZ,
-                                             pap->FriendlyName);
-             }
-             break;
+               /* FIXME: No official way to get the dstaddr for ipv6? */
+               memcpy (&ifp->ifa_addr, sa, sa_size);
+             ifp->ifa_ifa.ifa_dstaddr = (struct sockaddr *)
+                                        &ifp->ifa_brddstaddr;
            }
-         if ((caddr_t) ++ifr >
-             ifc->ifc_buf + ifc->ifc_len - sizeof (struct ifreq))
-           goto done;
+         else
+           {
+             /* Broadcast address  */
+             if (sa->sa_family == AF_INET)
+               {
+                 if_sin = (struct sockaddr_in *) &ifp->ifa_brddstaddr;
+                 uint32_t mask = 
+                 ((struct sockaddr_in *) &ifp->ifa_netmask)->sin_addr.s_addr;
+                 if_sin->sin_addr.s_addr = sin->sin_addr.s_addr & mask | ~mask;
+                 if_sin->sin_family = AF_INET;
+                 ifp->ifa_ifa.ifa_broadaddr = (struct sockaddr *)
+                                              &ifp->ifa_brddstaddr;
+               }
+             else /* No IPv6 broadcast */
+               ifp->ifa_ifa.ifa_broadaddr = NULL;
+           }
+         /* Hardware address */
+         for (UINT i = 0; i < IFHWADDRLEN; ++i)
+           if (i >= pap->PhysicalAddressLength)
+             ifp->ifa_hwaddr.sa_data[i] = '\0';
+           else
+             ifp->ifa_hwaddr.sa_data[i] = pap->PhysicalAddress[i];
+         /* Metric */
+         if (wincap.has_gaa_on_link_prefix ())
+           ifp->ifa_metric = (sa->sa_family == AF_INET
+                             ? ((PIP_ADAPTER_ADDRESSES_LH) pap)->Ipv4Metric
+                             : ((PIP_ADAPTER_ADDRESSES_LH) pap)->Ipv6Metric);
+         else
+           ifp->ifa_metric = 1;
+         /* MTU */
+         ifp->ifa_mtu = pap->Mtu;
+         /* Interface index */
+         ifp->ifa_ifindex = pap->IfIndex;
+         /* Friendly name */
+         struct ifreq_frndlyname *iff = (struct ifreq_frndlyname *)
+                                        &ifp->ifa_frndlyname;
+         iff->ifrf_len = sys_wcstombs (iff->ifrf_friendlyname,
+                                       IFRF_FRIENDLYNAMESIZ,
+                                       pap->FriendlyName);
+         ++ifp;
+#         undef sin
+#         undef sin6
        }
     }
+  /* Since every entry is set to the next entry, the last entry points to an
+     invalid next entry now.  Fix it retroactively. */
+  if (ifp > ifret)
+    ifp[-1].ifa_ifa.ifa_next = NULL;
 
 done:
   if (pa0)
     free (pa0);
-  /* Set the correct length */
-  ifc->ifc_len = cnt * sizeof (struct ifreq);
+  return ifret;
 }
 
 /*
- * IFCONF NTSP4, W2K:
+ * Get network interfaces NTSP4, W2K, XP w/o service packs.
  * Use IP Helper Library
  */
-static void
-get_2k_ifconf (struct ifconf *ifc, int what)
+static struct ifall *
+get_2k_ifs ()
 {
-  int cnt = 0;
   int ethId = 0, pppId = 0, slpId = 0, tokId = 0;
 
-  /* Union maps buffer to correct struct */
-  struct ifreq *ifr = ifc->ifc_req;
-
-  DWORD ip_cnt, lip, lnp;
+  DWORD ip_cnt;
   DWORD siz_ip_table = 0;
   PMIB_IPADDRTABLE ipt;
   PMIB_IFROW ifrow;
-  struct sockaddr_in *sa = NULL;
-  struct sockaddr *so = NULL;
+  struct ifall *ifret = NULL, *ifp = NULL;
+  struct sockaddr_in *if_sin;
 
   typedef struct ifcount_t
   {
@@ -1478,6 +1505,10 @@ get_2k_ifconf (struct ifconf *ifc, int what)
       && (ipt = (PMIB_IPADDRTABLE) alloca (siz_ip_table))
       && !GetIpAddrTable (ipt, &siz_ip_table, TRUE))
     {
+      if (!(ifret = (struct ifall *) calloc (ipt->dwNumEntries, sizeof (struct ifall))))
+       goto done;
+      ifp = ifret;
+
       iflist =
        (ifcount_t *) alloca (sizeof (ifcount_t) * (ipt->dwNumEntries + 1));
       memset (iflist, 0, sizeof (ifcount_t) * (ipt->dwNumEntries + 1));
@@ -1501,7 +1532,7 @@ get_2k_ifconf (struct ifconf *ifc, int what)
              ifEntry->count++;
            }
        }
-      // reset the last element. This is just the stopper for the loop.
+      /* reset the last element. This is just the stopper for the loop. */
       iflist[ipt->dwNumEntries].count = 0;
 
       /* Iterate over all configured IP-addresses */
@@ -1522,30 +1553,32 @@ get_2k_ifconf (struct ifconf *ifc, int what)
              ifEntry++;
            }
 
-         /* Setup the interface name */
-         if (ifrow->dwType == MIB_IF_TYPE_LOOPBACK)
-           strcpy (ifr->ifr_name, "lo");
+         /* Next in chain */
+         ifp->ifa_ifa.ifa_next = (struct ifaddrs *) &ifp[1].ifa_ifa;
+         /* Interface name */
+         if (ifrow->dwType == IF_TYPE_SOFTWARE_LOOPBACK)
+           strcpy (ifp->ifa_name, "lo");
          else
            {
              const char *name = "";
              switch (ifrow->dwType)
                {
-                 case MIB_IF_TYPE_TOKENRING:
+                 case IF_TYPE_ISO88025_TOKENRING:
                    name = "tok";
                    if (ifEntry->enumerated == 0)
                      ifEntry->classId = tokId++;
                    break;
-                 case MIB_IF_TYPE_ETHERNET:
+                 case IF_TYPE_ETHERNET_CSMACD:
                    name = "eth";
                    if (ifEntry->enumerated == 0)
                      ifEntry->classId = ethId++;
                    break;
-                 case MIB_IF_TYPE_PPP:
+                 case IF_TYPE_PPP:
                    name = "ppp";
                    if (ifEntry->enumerated == 0)
                      ifEntry->classId = pppId++;
                    break;
-                 case MIB_IF_TYPE_SLIP:
+                 case IF_TYPE_SLIP:
                    name = "slp";
                    if (ifEntry->enumerated == 0)
                      ifEntry->classId = slpId++;
@@ -1553,99 +1586,96 @@ get_2k_ifconf (struct ifconf *ifc, int what)
                  default:
                    continue;
                }
-             if (ifEntry->enumerated == 0)
-               __small_sprintf (ifr->ifr_name, "%s%u", name, ifEntry->classId);
-             else
-               __small_sprintf (ifr->ifr_name, "%s%u:%u", name,
-                                ifEntry->classId, ifEntry->enumerated);
+             __small_sprintf (ifp->ifa_name,
+                              ifEntry->enumerated ? "%s%u:%u" : "%s%u",
+                              name, ifEntry->classId, ifEntry->enumerated);
              ifEntry->enumerated++;
            }
-
-             /* setup sockaddr struct */
-         switch (what)
+         ifp->ifa_ifa.ifa_name = ifp->ifa_name;
+         /* Flags */
+         if (ifrow->dwType == IF_TYPE_SOFTWARE_LOOPBACK)
+           ifp->ifa_ifa.ifa_flags |= IFF_LOOPBACK;
+         else if (ifrow->dwType == IF_TYPE_PPP
+                  || ifrow->dwType == IF_TYPE_SLIP)
+           ifp->ifa_ifa.ifa_flags |= IFF_POINTOPOINT | IFF_NOARP;
+         else
+           ifp->ifa_ifa.ifa_flags |= IFF_BROADCAST;
+         if (ifrow->dwAdminStatus == IF_ADMIN_STATUS_UP)
            {
-             case SIOCGIFFLAGS:
-               if (ifrow->dwType == MIB_IF_TYPE_LOOPBACK)
-                 ifr->ifr_flags = IFF_LOOPBACK;
-               else
-                 ifr->ifr_flags = IFF_BROADCAST | IFF_MULTICAST;
-               if (ifrow->dwAdminStatus == MIB_IF_ADMIN_STATUS_UP)
-                 {
-                   ifr->ifr_flags |= IFF_UP;
-                   if (ifrow->dwOperStatus >= MIB_IF_OPER_STATUS_CONNECTED)
-                     ifr->ifr_flags |= IFF_RUNNING;
-                 }
-               break;
-             case SIOCGIFCONF:
-             case SIOCGIFADDR:
-               sa = (struct sockaddr_in *) &ifr->ifr_addr;
-               sa->sin_addr.s_addr = ipt->table[ip_cnt].dwAddr;
-               sa->sin_family = AF_INET;
-               sa->sin_port = 0;
-               break;
-             case SIOCGIFBRDADDR:
-               sa = (struct sockaddr_in *) &ifr->ifr_broadaddr;
+             ifp->ifa_ifa.ifa_flags |= IFF_UP | IFF_LOWER_UP;
+             /* Bug in NT4's IP Helper lib.  The dwOperStatus has just
+                two values, 0 or 1, non operational, operational. */
+             if (ifrow->dwOperStatus >= (wincap.has_broken_if_oper_status ()
+                                         ? 1 : IF_OPER_STATUS_CONNECTED))
+               ifp->ifa_ifa.ifa_flags |= IFF_RUNNING;
+           }
+         /* Address */
+         if_sin = (struct sockaddr_in *) &ifp->ifa_addr;
+         if_sin->sin_addr.s_addr = ipt->table[ip_cnt].dwAddr;
+         if_sin->sin_family = AF_INET;
+         ifp->ifa_ifa.ifa_addr = (struct sockaddr *) &ifp->ifa_addr;
+         /* Netmask */
+         if_sin = (struct sockaddr_in *) &ifp->ifa_netmask;
+         if_sin->sin_addr.s_addr = ipt->table[ip_cnt].dwMask;
+         if_sin->sin_family = AF_INET;
+         ifp->ifa_ifa.ifa_netmask = (struct sockaddr *) &ifp->ifa_netmask;
+         if_sin = (struct sockaddr_in *) &ifp->ifa_brddstaddr;
+         if (ifrow->dwType == IF_TYPE_PPP
+             || ifrow->dwType == IF_TYPE_SLIP)
+           {
+             /* Destination address */
+             if_sin->sin_addr.s_addr =
+               get_routedst (ipt->table[ip_cnt].dwIndex);
+             ifp->ifa_ifa.ifa_dstaddr = (struct sockaddr *)
+                                        &ifp->ifa_brddstaddr;
+           }
+         else
+           {
+             /* Broadcast address */
 #if 0
-               /* Unfortunately, the field returns only crap. */
-               sa->sin_addr.s_addr = ipt->table[ip_cnt].dwBCastAddr;
+             /* Unfortunately, the field returns only crap. */
+             if_sin->sin_addr.s_addr = ipt->table[ip_cnt].dwBCastAddr;
 #else
-               lip = ipt->table[ip_cnt].dwAddr;
-               lnp = ipt->table[ip_cnt].dwMask;
-               sa->sin_addr.s_addr = lip & lnp | ~lnp;
-               sa->sin_family = AF_INET;
-               sa->sin_port = 0;
+             uint32_t mask = ipt->table[ip_cnt].dwMask;
+             if_sin->sin_addr.s_addr = ipt->table[ip_cnt].dwAddr
+                                       & mask | ~mask;
 #endif
-               break;
-             case SIOCGIFDSTADDR:
-               sa = (struct sockaddr_in *) &ifr->ifr_dstaddr;
-               if (ifrow->dwType == MIB_IF_TYPE_PPP
-                   || ifrow->dwType == MIB_IF_TYPE_SLIP)
-                 sa->sin_addr.s_addr =
-                       get_routedst (ipt->table[ip_cnt].dwIndex);
-               else
-                 sa->sin_addr.s_addr = ipt->table[ip_cnt].dwAddr;
-               sa->sin_family = AF_INET;
-               sa->sin_port = 0;
-               break;
-             case SIOCGIFNETMASK:
-               sa = (struct sockaddr_in *) &ifr->ifr_netmask;
-               sa->sin_addr.s_addr = ipt->table[ip_cnt].dwMask;
-               sa->sin_family = AF_INET;
-               sa->sin_port = 0;
-               break;
-             case SIOCGIFHWADDR:
-               so = &ifr->ifr_hwaddr;
-               for (UINT i = 0; i < IFHWADDRLEN; ++i)
-                 if (i >= ifrow->dwPhysAddrLen)
-                   so->sa_data[i] = '\0';
-                 else
-                   so->sa_data[i] = ifrow->bPhysAddr[i];
-               so->sa_family = AF_INET;
-               break;
-             case SIOCGIFMETRIC:
-               ifr->ifr_metric = 1;
-               break;
-             case SIOCGIFMTU:
-               ifr->ifr_mtu = ifrow->dwMtu;
-               break;
-             case SIOCGIFINDEX:
-               ifr->ifr_ifindex = ifrow->dwIndex;
-               break;
+             ifp->ifa_ifa.ifa_broadaddr = (struct sockaddr *)
+                                          &ifp->ifa_brddstaddr;
            }
-         ++cnt;
-         if ((caddr_t) ++ifr >
-             ifc->ifc_buf + ifc->ifc_len - sizeof (struct ifreq))
-           goto done;
+         if_sin->sin_family = AF_INET;
+         /* Hardware address */
+         for (UINT i = 0; i < IFHWADDRLEN; ++i)
+           if (i >= ifrow->dwPhysAddrLen)
+             ifp->ifa_hwaddr.sa_data[i] = '\0';
+           else
+             ifp->ifa_hwaddr.sa_data[i] = ifrow->bPhysAddr[i];
+         /* Metric */
+         ifp->ifa_metric = 1;
+         /* MTU */
+         ifp->ifa_mtu = ifrow->dwMtu;
+         /* Interface index */
+         ifp->ifa_ifindex = ifrow->dwIndex;
+         /* Friendly name */
+         struct ifreq_frndlyname *iff = (struct ifreq_frndlyname *)
+                                        &ifp->ifa_frndlyname;
+         iff->ifrf_len = sys_wcstombs (iff->ifrf_friendlyname,
+                                       IFRF_FRIENDLYNAMESIZ,
+                                       ifrow->wszName);
+         ++ifp;
        }
     }
+  /* Since every entry is set to the next entry, the last entry points to an
+     invalid next entry now.  Fix it retroactively. */
+  if (ifp > ifret)
+    ifp[-1].ifa_ifa.ifa_next = NULL;
 
 done:
-  /* Set the correct length */
-  ifc->ifc_len = cnt * sizeof (struct ifreq);
+  return ifret;
 }
 
 /*
- * IFCONF Windows NT < SP4:
+ * Get network interfaces Windows NT < SP4:
  * Look at the Bind value in
  * HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Linkage\
  * This is a REG_MULTI_SZ with strings of the form:
@@ -1655,286 +1685,353 @@ done:
  *                                                     Parameters\Tcpip
  * at the IPAddress, Subnetmask and DefaultGateway values for the
  * required values.
+ * Also fake "lo" since there's no representation in the registry.
  */
-static void
-get_nt_ifconf (struct ifconf *ifc, int what)
+static struct ifall *
+get_nt_ifs ()
 {
   HKEY key;
+  LONG ret;
+  struct ifall *ifret = NULL, *ifp;
   unsigned long lip, lnp;
-  struct sockaddr_in *sa = NULL;
-  struct sockaddr *so = NULL;
+  struct sockaddr_in *sin = NULL;
   DWORD size;
-  int cnt = 1;
-  char *binding = (char *) 0;
-
-  /* Union maps buffer to correct struct */
-  struct ifreq *ifr = ifc->ifc_req;
-
-  if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
-                   "SYSTEM\\"
-                   "CurrentControlSet\\"
-                   "Services\\"
-                   "Tcpip\\" "Linkage",
-                   0, KEY_READ, &key) == ERROR_SUCCESS)
-    {
-      if (RegQueryValueEx (key, "Bind",
-                          NULL, NULL,
-                          NULL, &size) == ERROR_SUCCESS)
+  int cnt = 0, idx;
+  char *binding = NULL;
+
+  if ((ret = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
+                          "SYSTEM\\"
+                          "CurrentControlSet\\"
+                          "Services\\"
+                          "Tcpip\\" "Linkage",
+                          0, KEY_READ, &key)) == ERROR_SUCCESS)
+    {
+      if ((ret = RegQueryValueEx (key, "Bind", NULL, NULL,
+                                 NULL, &size)) == ERROR_SUCCESS)
        {
          binding = (char *) alloca (size);
-         if (RegQueryValueEx (key, "Bind",
-                              NULL, NULL,
-                              (unsigned char *) binding,
-                              &size) != ERROR_SUCCESS)
-           {
-             binding = NULL;
-           }
+         if ((ret = RegQueryValueEx (key, "Bind", NULL, NULL,
+                                     (unsigned char *) binding,
+                                     &size)) != ERROR_SUCCESS)
+           binding = NULL;
        }
       RegCloseKey (key);
     }
 
-  if (binding)
+  if (!binding)
     {
-      char *bp, eth[2] = "/";
-      char cardkey[256], ipaddress[256], netmask[256];
+      __seterrno_from_win_error (ret);
+      return NULL;
+    }
 
-      for (bp = binding; *bp; bp += strlen (bp) + 1)
-       {
-         bp += strlen ("\\Device\\");
-         strcpy (cardkey, "SYSTEM\\CurrentControlSet\\Services\\");
-         strcat (cardkey, bp);
-         strcat (cardkey, "\\Parameters\\Tcpip");
+  char *bp, eth[2] = "/";
+  char cardkey[256], ipaddress[256], netmask[256];
 
-         if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, cardkey,
-                           0, KEY_READ, &key) != ERROR_SUCCESS)
-           continue;
+  for (bp = binding; *bp; bp += strlen (bp) + 1)
+    {
+      bp += strlen ("\\Device\\");
+      strcpy (cardkey, "SYSTEM\\CurrentControlSet\\Services\\");
+      strcat (cardkey, bp);
+      strcat (cardkey, "\\Parameters\\Tcpip");
 
-         if (RegQueryValueEx (key, "IPAddress",
-                              NULL, NULL,
-                              (unsigned char *) ipaddress,
-                              (size = 256, &size)) == ERROR_SUCCESS
-             && RegQueryValueEx (key, "SubnetMask",
-                                 NULL, NULL,
-                                 (unsigned char *) netmask,
-                                 (size = 256, &size)) == ERROR_SUCCESS)
-           {
-             char *ip, *np;
-             char dhcpaddress[256], dhcpnetmask[256];
+      if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, cardkey,
+                       0, KEY_READ, &key) != ERROR_SUCCESS)
+       continue;
 
-             for (ip = ipaddress, np = netmask;
-                  *ip && *np;
-                  ip += strlen (ip) + 1, np += strlen (np) + 1)
-               {
-                 if ((caddr_t) ++ifr > ifc->ifc_buf
-                     + ifc->ifc_len - sizeof (struct ifreq))
-                   break;
+      if (RegQueryValueEx (key, "IPAddress",
+                          NULL, NULL,
+                          (unsigned char *) ipaddress,
+                          (size = 256, &size)) == ERROR_SUCCESS
+         && RegQueryValueEx (key, "SubnetMask",
+                             NULL, NULL,
+                             (unsigned char *) netmask,
+                             (size = 256, &size)) == ERROR_SUCCESS)
+        ++cnt;
+      RegCloseKey (key);
+    }
+  ++cnt; /* loopback */
+  if (!(ifret = (struct ifall *) malloc (cnt * sizeof (struct ifall))))
+    return NULL;
+  /* Set up lo interface first */
+  idx = 0;
+  ifp = ifret + idx;
+  memset (ifp, 0, sizeof *ifp);
+  /* Next in chain */
+  ifp->ifa_ifa.ifa_next = (struct ifaddrs *) &ifp[1].ifa_ifa;
+  /* Interface name */
+  strcpy (ifp->ifa_name, "lo");
+  ifp->ifa_ifa.ifa_name = ifp->ifa_name;
+  /* Flags */
+  ifp->ifa_ifa.ifa_flags = IFF_UP | IFF_LOWER_UP | IFF_RUNNING | IFF_LOOPBACK;
+  /* Address */
+  sin = (struct sockaddr_in *) &ifp->ifa_addr;
+  sin->sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+  sin->sin_family = AF_INET;
+  ifp->ifa_ifa.ifa_addr = (struct sockaddr *) &ifp->ifa_addr;
+  /* Netmask */
+  sin = (struct sockaddr_in *) &ifp->ifa_netmask;
+  sin->sin_addr.s_addr = htonl (IN_CLASSA_NET);
+  sin->sin_family = AF_INET;
+  ifp->ifa_ifa.ifa_netmask = (struct sockaddr *) &ifp->ifa_netmask;
+  /* Broadcast address  */
+  sin = (struct sockaddr_in *) &ifp->ifa_brddstaddr;
+  sin->sin_addr.s_addr = htonl (INADDR_LOOPBACK | IN_CLASSA_HOST);
+  sin->sin_family = AF_INET;
+  ifp->ifa_ifa.ifa_broadaddr = (struct sockaddr *) &ifp->ifa_brddstaddr;
+  /* Hardware address */
+  ; // Nothing to do... */
+  /* Metric */
+  ifp->ifa_metric = 1;
+  /* MTU */
+  ifp->ifa_mtu = 1520; /* Default value for MS TCP Loopback interface. */
+  /* Interface index */
+  ifp->ifa_ifindex = -1;
+  /* Friendly name */
+  struct ifreq_frndlyname *iff = (struct ifreq_frndlyname *)
+                                 &ifp->ifa_frndlyname;
+  strcpy (iff->ifrf_friendlyname, "Default loopback");
+  iff->ifrf_len = 16;
+
+  for (bp = binding; *bp; bp += strlen (bp) + 1)
+    {
+      bp += strlen ("\\Device\\");
+      strcpy (cardkey, "SYSTEM\\CurrentControlSet\\Services\\");
+      strcat (cardkey, bp);
+      strcat (cardkey, "\\Parameters\\Tcpip");
+
+      if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, cardkey,
+                       0, KEY_READ, &key) != ERROR_SUCCESS)
+       continue;
+
+      if (RegQueryValueEx (key, "IPAddress",
+                          NULL, NULL,
+                          (unsigned char *) ipaddress,
+                          (size = 256, &size)) == ERROR_SUCCESS
+         && RegQueryValueEx (key, "SubnetMask",
+                             NULL, NULL,
+                             (unsigned char *) netmask,
+                             (size = 256, &size)) == ERROR_SUCCESS)
+       {
+         char *ip, *np;
+         char dhcpaddress[256], dhcpnetmask[256];
+         bool ppp = false;
 
-                 if (!strncmp (bp, "NdisWan", 7))
-                   {
-                     strcpy (ifr->ifr_name, "ppp");
-                     strcat (ifr->ifr_name, bp + 7);
-                   }
-                 else
-                   {
-                     ++*eth;
-                     strcpy (ifr->ifr_name, "eth");
-                     strcat (ifr->ifr_name, eth);
-                   }
-                 memset (&ifr->ifr_addr, '\0', sizeof ifr->ifr_addr);
-                 if (cygwin_inet_addr (ip) == 0L
-                     && RegQueryValueEx (key, "DhcpIPAddress",
-                                         NULL, NULL,
-                                         (unsigned char *) dhcpaddress,
-                                         (size = 256, &size))
-                     == ERROR_SUCCESS
-                     && RegQueryValueEx (key, "DhcpSubnetMask",
-                                         NULL, NULL,
-                                         (unsigned char *) dhcpnetmask,
-                                         (size = 256, &size))
-                     == ERROR_SUCCESS)
-                   {
-                     switch (what)
-                       {
-                         case SIOCGIFFLAGS:
-                           ifr->ifr_flags = IFF_UP | IFF_RUNNING
-                                            | IFF_BROADCAST;
-                           break;
-                         case SIOCGIFCONF:
-                         case SIOCGIFADDR:
-                         case SIOCGIFDSTADDR:
-                           sa = (struct sockaddr_in *) &ifr->ifr_addr;
-                           sa->sin_addr.s_addr =
-                             cygwin_inet_addr (dhcpaddress);
-                           sa->sin_family = AF_INET;
-                           sa->sin_port = 0;
-                           break;
-                         case SIOCGIFBRDADDR:
-                           lip = cygwin_inet_addr (dhcpaddress);
-                           lnp = cygwin_inet_addr (dhcpnetmask);
-                           sa = (struct sockaddr_in *) &ifr->ifr_broadaddr;
-                           sa->sin_addr.s_addr = lip & lnp | ~lnp;
-                           sa->sin_family = AF_INET;
-                           sa->sin_port = 0;
-                           break;
-                         case SIOCGIFNETMASK:
-                           sa = (struct sockaddr_in *) &ifr->ifr_netmask;
-                           sa->sin_addr.s_addr =
-                             cygwin_inet_addr (dhcpnetmask);
-                           sa->sin_family = AF_INET;
-                           sa->sin_port = 0;
-                           break;
-                         case SIOCGIFHWADDR:
-                           so = &ifr->ifr_hwaddr;
-                           memset (so->sa_data, 0, IFHWADDRLEN);
-                           so->sa_family = AF_INET;
-                           break;
-                         case SIOCGIFMETRIC:
-                           ifr->ifr_metric = 1;
-                           break;
-                         case SIOCGIFMTU:
-                           ifr->ifr_mtu = 1500;
-                           break;
-                         case SIOCGIFINDEX:
-                           ifr->ifr_ifindex = -1;
-                           break;
-                       }
-                   }
-                 else
-                   {
-                     switch (what)
-                       {
-                         case SIOCGIFFLAGS:
-                           ifr->ifr_flags = IFF_UP | IFF_RUNNING
-                                            | IFF_BROADCAST;
-                           break;
-                         case SIOCGIFCONF:
-                         case SIOCGIFADDR:
-                         case SIOCGIFDSTADDR:
-                           sa = (struct sockaddr_in *) &ifr->ifr_addr;
-                           sa->sin_addr.s_addr = cygwin_inet_addr (ip);
-                           sa->sin_family = AF_INET;
-                           sa->sin_port = 0;
-                           break;
-                         case SIOCGIFBRDADDR:
-                           lip = cygwin_inet_addr (ip);
-                           lnp = cygwin_inet_addr (np);
-                           sa = (struct sockaddr_in *) &ifr->ifr_broadaddr;
-                           sa->sin_addr.s_addr = lip & lnp | ~lnp;
-                           sa->sin_family = AF_INET;
-                           sa->sin_port = 0;
-                           break;
-                         case SIOCGIFNETMASK:
-                           sa = (struct sockaddr_in *) &ifr->ifr_netmask;
-                           sa->sin_addr.s_addr = cygwin_inet_addr (np);
-                           sa->sin_family = AF_INET;
-                           sa->sin_port = 0;
-                           break;
-                         case SIOCGIFHWADDR:
-                           so = &ifr->ifr_hwaddr;
-                           memset (so->sa_data, 0, IFHWADDRLEN);
-                           so->sa_family = AF_INET;
-                           break;
-                         case SIOCGIFMETRIC:
-                           ifr->ifr_metric = 1;
-                           break;
-                         case SIOCGIFMTU:
-                           ifr->ifr_mtu = 1500;
-                           break;
-                         case SIOCGIFINDEX:
-                           ifr->ifr_ifindex = -1;
-                           break;
-                       }
-                   }
-                 ++cnt;
+         for (ip = ipaddress, np = netmask;
+              *ip && *np;
+              ip += strlen (ip) + 1, np += strlen (np) + 1)
+           {
+             bool dhcp = false;
+             if (cygwin_inet_addr (ip) == 0L
+                 && RegQueryValueEx (key, "DhcpIPAddress",
+                                     NULL, NULL,
+                                     (unsigned char *) dhcpaddress,
+                                     (size = 256, &size))
+                 == ERROR_SUCCESS
+                 && RegQueryValueEx (key, "DhcpSubnetMask",
+                                     NULL, NULL,
+                                     (unsigned char *) dhcpnetmask,
+                                     (size = 256, &size))
+                 == ERROR_SUCCESS)
+               dhcp = true;
+             if (++idx == cnt
+                 && !(ifp = (struct ifall *)
+                            realloc (ifret, ++cnt * sizeof (struct ifall))))
+                 {
+                   free (ifret);
+                   return NULL;
+                 }
+             ifp = ifret + idx;
+             memset (ifp, 0, sizeof *ifp);
+             /* Next in chain */
+             ifp->ifa_ifa.ifa_next = (struct ifaddrs *) &ifp[1].ifa_ifa;
+             /* Interface name */
+             if (!strncmp (bp, "NdisWan", 7))
+               {
+                 strcpy (ifp->ifa_name, "ppp");
+                 strcat (ifp->ifa_name, bp + 7);
+                 ppp = true;
+               }
+             else
+               {
+                 ++*eth;
+                 strcpy (ifp->ifa_name, "eth");
+                 strcat (ifp->ifa_name, eth);
+               }
+             ifp->ifa_ifa.ifa_name = ifp->ifa_name;
+             /* Flags */
+             ifp->ifa_ifa.ifa_flags = IFF_UP | IFF_LOWER_UP | IFF_RUNNING;
+             if (ppp)
+               ifp->ifa_ifa.ifa_flags |= IFF_POINTOPOINT | IFF_NOARP;
+             else
+               ifp->ifa_ifa.ifa_flags |= IFF_BROADCAST;
+             /* Address */
+             sin = (struct sockaddr_in *) &ifp->ifa_addr;
+             sin->sin_addr.s_addr = cygwin_inet_addr (dhcp ? dhcpaddress : ip);
+             sin->sin_family = AF_INET;
+             ifp->ifa_ifa.ifa_addr = (struct sockaddr *) &ifp->ifa_addr;
+             /* Netmask */
+             sin = (struct sockaddr_in *) &ifp->ifa_netmask;
+             sin->sin_addr.s_addr = cygwin_inet_addr (dhcp ? dhcpnetmask : np);
+             sin->sin_family = AF_INET;
+             ifp->ifa_ifa.ifa_netmask = (struct sockaddr *) &ifp->ifa_netmask;
+             if (ppp)
+               {
+                 /* Destination address */
+                 sin = (struct sockaddr_in *) &ifp->ifa_brddstaddr;
+                 sin->sin_addr.s_addr =
+                   cygwin_inet_addr (dhcp ? dhcpaddress : ip);
+                 sin->sin_family = AF_INET;
+                 ifp->ifa_ifa.ifa_dstaddr = (struct sockaddr *)
+                                            &ifp->ifa_brddstaddr;
+               }
+             else
+               {
+                 /* Broadcast address */
+                 lip = cygwin_inet_addr (dhcp ? dhcpaddress : ip);
+                 lnp = cygwin_inet_addr (dhcp ? dhcpnetmask : np);
+                 sin = (struct sockaddr_in *) &ifp->ifa_brddstaddr;
+                 sin->sin_addr.s_addr = lip & lnp | ~lnp;
+                 sin->sin_family = AF_INET;
+                 ifp->ifa_ifa.ifa_broadaddr = (struct sockaddr *)
+                                              &ifp->ifa_brddstaddr;
                }
+             /* Hardware address */
+             ; // Nothing to do... */
+             /* Metric */
+             ifp->ifa_metric = 1;
+             /* MTU */
+             ifp->ifa_mtu = 1500;
+             /* Interface index */
+             ifp->ifa_ifindex = -1;
+             /* Friendly name */
+             struct ifreq_frndlyname *iff = (struct ifreq_frndlyname *)
+                                            &ifp->ifa_frndlyname;
+             strcpy (iff->ifrf_friendlyname, bp);
+             iff->ifrf_len = strlen (iff->ifrf_friendlyname);
            }
-         RegCloseKey (key);
        }
+      RegCloseKey (key);
     }
+  /* Since every entry is set to the next entry, the last entry points to an
+     invalid next entry now.  Fix it retroactively. */
+  if (ifp > ifret)
+    ifp->ifa_ifa.ifa_next = NULL;
+  return ifret;
+}
 
-  /* Set the correct length */
-  ifc->ifc_len = cnt * sizeof (struct ifreq);
+extern "C" int
+getifaddrs (struct ifaddrs **ifap)
+{
+  if (!ifap)
+    {
+      set_errno (EINVAL);
+      return -1;
+    }
+  struct ifall *ifp;
+  if (wincap.has_gaa_prefixes () && !CYGWIN_VERSION_CHECK_FOR_OLD_IFREQ)
+    ifp = get_xp_ifs (AF_UNSPEC);
+  else if (wincap.has_ip_helper_lib ())
+    ifp = get_2k_ifs ();
+  else
+    ifp = get_nt_ifs ();
+  *ifap = &ifp->ifa_ifa;
+  return ifp ? 0 : -1;
 }
 
-int
-get_ifconf (SOCKET s, struct ifconf *ifc, int what)
+extern "C" void
+freeifaddrs (struct ifaddrs *ifp)
 {
-  unsigned long lip, lnp;
-  struct sockaddr_in *sa;
+  if (ifp)
+    free (ifp);
+}
 
+int
+get_ifconf (struct ifconf *ifc, int what)
+{
   sig_dispatch_pending ();
   myfault efault;
   if (efault.faulted (EFAULT))
     return -1;
 
-  /* Union maps buffer to correct struct */
-  struct ifreq *ifr = ifc->ifc_req;
-
-  /* Ensure we have space for two struct ifreqs, fail if not. */
-  if (ifc->ifc_len < (int) (2 * sizeof (struct ifreq)))
+  /* Ensure we have space for at least one struct ifreqs, fail if not. */
+  if (ifc->ifc_len < (int) sizeof (struct ifreq))
     {
-      set_errno (EFAULT);
+      set_errno (EINVAL);
       return -1;
     }
 
-  if (!wincap.has_ip_helper_lib ())
+  struct ifall *ifret, *ifp;
+  if (wincap.has_gaa_prefixes () && !CYGWIN_VERSION_CHECK_FOR_OLD_IFREQ)
+    ifret = get_xp_ifs (AF_INET);
+  else if (wincap.has_ip_helper_lib ())
+    ifret = get_2k_ifs ();
+  else
+    ifret = get_nt_ifs ();
+  if (!ifret)
+    return -1;
+
+  struct sockaddr_in *sin;
+  struct ifreq *ifr = ifc->ifc_req;
+  int cnt = 0;
+  for (ifp = ifret; ifp; ifp = (struct ifall *) ifp->ifa_ifa.ifa_next)
     {
-      /* Set up interface lo0 first */
-      strcpy (ifr->ifr_name, "lo");
-      memset (&ifr->ifr_addr, '\0', sizeof (ifr->ifr_addr));
+      ++cnt;
+      strcpy (ifr->ifr_name, ifp->ifa_name);
       switch (what)
-       {
-         case SIOCGIFFLAGS:
-           ifr->ifr_flags = IFF_UP | IFF_RUNNING | IFF_LOOPBACK;
-           break;
-         case SIOCGIFCONF:
-         case SIOCGIFADDR:
-         case SIOCGIFDSTADDR:
-           sa = (struct sockaddr_in *) &ifr->ifr_addr;
-           sa->sin_addr.s_addr = htonl (INADDR_LOOPBACK);
-           sa->sin_family = AF_INET;
-           sa->sin_port = 0;
-           break;
-         case SIOCGIFBRDADDR:
-           lip = htonl (INADDR_LOOPBACK);
-           lnp = cygwin_inet_addr ("255.0.0.0");
-           sa = (struct sockaddr_in *) &ifr->ifr_broadaddr;
-           sa->sin_addr.s_addr = lip & lnp | ~lnp;
-           sa->sin_family = AF_INET;
-           sa->sin_port = 0;
-           break;
-         case SIOCGIFNETMASK:
-           sa = (struct sockaddr_in *) &ifr->ifr_netmask;
-           sa->sin_addr.s_addr = cygwin_inet_addr ("255.0.0.0");
-           sa->sin_family = AF_INET;
-           sa->sin_port = 0;
-           break;
-         case SIOCGIFHWADDR:
-           ifr->ifr_hwaddr.sa_family = AF_INET;
-           memset (ifr->ifr_hwaddr.sa_data, 0, IFHWADDRLEN);
-           break;
-         case SIOCGIFMETRIC:
-           ifr->ifr_metric = 1;
-           break;
-         case SIOCGIFMTU:
-           /* Default value for MS TCP Loopback interface. */
-           ifr->ifr_mtu = 1520;
-           break;
-         case SIOCGIFINDEX:
-           ifr->ifr_ifindex = -1;
-           break;
-         default:
-           set_errno (EINVAL);
-           return -1;
+        {
+       case SIOCGIFFLAGS:
+         ifr->ifr_flags = ifp->ifa_ifa.ifa_flags;
+         break;
+       case SIOCGIFCONF:
+       case SIOCGIFADDR:
+         sin = (struct sockaddr_in *) &ifr->ifr_addr;
+         memcpy (sin, &ifp->ifa_addr, sizeof *sin);
+         break;
+       case SIOCGIFNETMASK:
+         sin = (struct sockaddr_in *) &ifr->ifr_netmask;
+         memcpy (sin, &ifp->ifa_netmask, sizeof *sin);
+         break;
+       case SIOCGIFDSTADDR:
+         sin = (struct sockaddr_in *) &ifr->ifr_dstaddr;
+         if (ifp->ifa_ifa.ifa_flags & IFF_POINTOPOINT)
+           memcpy (sin, &ifp->ifa_brddstaddr, sizeof *sin);
+         else /* Return addr as on Linux. */
+           memcpy (sin, &ifp->ifa_addr, sizeof *sin);
+         break;
+       case SIOCGIFBRDADDR:
+         sin = (struct sockaddr_in *) &ifr->ifr_broadaddr;
+         if (!(ifp->ifa_ifa.ifa_flags & IFF_POINTOPOINT))
+           memcpy (sin, &ifp->ifa_brddstaddr, sizeof *sin);
+         else
+           {
+             sin->sin_addr.s_addr = INADDR_ANY;
+             sin->sin_family = AF_INET;
+             sin->sin_port = 0;
+           }
+         break;
+       case SIOCGIFHWADDR:
+         memcpy (&ifr->ifr_hwaddr, &ifp->ifa_hwaddr, sizeof ifr->ifr_hwaddr);
+         break;
+       case SIOCGIFMETRIC:
+         ifr->ifr_metric = ifp->ifa_metric;
+         break;
+       case SIOCGIFMTU:
+         ifr->ifr_mtu = ifp->ifa_mtu;
+         break;
+       case SIOCGIFINDEX:
+         ifr->ifr_ifindex = ifp->ifa_ifindex;
+         break;
+       case SIOCGIFFRNDLYNAM:
+         memcpy (ifr->ifr_frndlyname, &ifp->ifa_frndlyname,
+                 sizeof (struct ifreq_frndlyname));
        }
+      if ((caddr_t) ++ifr >
+         ifc->ifc_buf + ifc->ifc_len - sizeof (struct ifreq))
+       break;
     }
-
-  if (wincap.has_gaa_prefixes () && !CYGWIN_VERSION_CHECK_FOR_OLD_IFREQ)
-    get_xp_ifconf (s, ifc, what);
-  else if (wincap.has_ip_helper_lib ())
-    get_2k_ifconf (ifc, what);
-  else
-    get_nt_ifconf (ifc, what);
+  /* Set the correct length */
+  ifc->ifc_len = cnt * sizeof (struct ifreq);
+  free (ifret);
   return 0;
 }
 
index 4d2838b..f90c315 100644 (file)
@@ -836,6 +836,7 @@ also ISO/IEC 9945:2003 and IEEE Std 1003.1-2001 (POSIX.1-2001).</para>
     fiprintf
     flock
     forkpty
+    freeifaddrs
     fstatfs
     fts_children
     fts_close
@@ -851,6 +852,7 @@ also ISO/IEC 9945:2003 and IEEE Std 1003.1-2001 (POSIX.1-2001).</para>
     gammaf
     gammaf_r
     getdtablesize
+    getifaddrs
     getpagesize
     getpeereid
     getprogname
index a92f782..7923d5a 100644 (file)
@@ -18,6 +18,7 @@ static NO_COPY wincaps wincap_unknown = {
   is_server:false,
   has_security_descriptor_control:false,
   has_ip_helper_lib:false,
+  has_broken_if_oper_status:false,
   has_physical_mem_access:true,
   has_process_io_counters:false,
   has_terminal_services:false,
@@ -45,6 +46,7 @@ static NO_COPY wincaps wincap_nt4 = {
   is_server:false,
   has_security_descriptor_control:false,
   has_ip_helper_lib:false,
+  has_broken_if_oper_status:false,
   has_physical_mem_access:true,
   has_process_io_counters:false,
   has_terminal_services:false,
@@ -72,6 +74,7 @@ static NO_COPY wincaps wincap_nt4sp4 = {
   is_server:false,
   has_security_descriptor_control:false,
   has_ip_helper_lib:true,
+  has_broken_if_oper_status:true,
   has_physical_mem_access:true,
   has_process_io_counters:false,
   has_terminal_services:false,
@@ -99,6 +102,7 @@ static NO_COPY wincaps wincap_2000 = {
   is_server:false,
   has_security_descriptor_control:true,
   has_ip_helper_lib:true,
+  has_broken_if_oper_status:false,
   has_physical_mem_access:true,
   has_process_io_counters:true,
   has_terminal_services:true,
@@ -126,6 +130,7 @@ static NO_COPY wincaps wincap_xp = {
   is_server:false,
   has_security_descriptor_control:true,
   has_ip_helper_lib:true,
+  has_broken_if_oper_status:false,
   has_physical_mem_access:true,
   has_process_io_counters:true,
   has_terminal_services:true,
@@ -153,6 +158,7 @@ static NO_COPY wincaps wincap_2003 = {
   is_server:true,
   has_security_descriptor_control:true,
   has_ip_helper_lib:true,
+  has_broken_if_oper_status:false,
   has_physical_mem_access:false,
   has_process_io_counters:true,
   has_terminal_services:true,
@@ -180,6 +186,7 @@ static NO_COPY wincaps wincap_vista = {
   is_server:false,
   has_security_descriptor_control:true,
   has_ip_helper_lib:true,
+  has_broken_if_oper_status:false,
   has_physical_mem_access:false,
   has_process_io_counters:true,
   has_terminal_services:true,
index 5d0ce75..2215bf9 100644 (file)
@@ -18,6 +18,7 @@ struct wincaps
   unsigned is_server                                    : 1;
   unsigned has_security_descriptor_control              : 1;
   unsigned has_ip_helper_lib                            : 1;
+  unsigned has_broken_if_oper_status                    : 1;
   unsigned has_physical_mem_access                      : 1;
   unsigned has_process_io_counters                      : 1;
   unsigned has_terminal_services                       : 1;
@@ -61,6 +62,7 @@ public:
   bool  IMPLEMENT (is_server)
   bool  IMPLEMENT (has_security_descriptor_control)
   bool  IMPLEMENT (has_ip_helper_lib)
+  bool  IMPLEMENT (has_broken_if_oper_status)
   bool  IMPLEMENT (has_physical_mem_access)
   bool  IMPLEMENT (has_process_io_counters)
   bool  IMPLEMENT (has_terminal_services)