Fix network-interface-list|info on newer BSD derived OS:es.
authorJan Djärv <jan.h.d@swipnet.se>
Sat, 13 Aug 2011 10:48:03 +0000 (12:48 +0200)
committerJan Djärv <jan.h.d@swipnet.se>
Sat, 13 Aug 2011 10:48:03 +0000 (12:48 +0200)
* configure.in: Add header check: sys/socket.h,
ifaddrs.h, net/if_dl.h.  Check for getifaddrs and freeifaddrs.
Check for sa_len in struct ifreq.ifr_addr (Bug#8477).

* src/process.c: Include ifaddrs.h and net/if_dl.h if available (Bug#8477).
(Fnetwork_interface_list): Allocate in increments of bytes instead
of sizeof (struct ifreq).  Iterate over ifconf.ifc_req by counting
bytes (Bug#8477).  Count bytes correctly when ifr_addr is a struct
sockaddr.
(struct ifflag_def): notrailers is smart on OSX.
(Fnetwork_interface_info): Handle case when ifr_flags is negative.
Get hardware address with getifaddrs if available.

ChangeLog
configure.in
src/ChangeLog
src/process.c

index 30f2285..55deca0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2011-08-13  Jan Djärv  <jan.h.d@swipnet.se>
+
+       * configure.in: Add header check: sys/socket.h (Bug#8477),
+       ifaddrs.h, net/if_dl.h.  Check for getifaddrs and freeifaddrs.
+       Check for sa_len in struct ifreq.ifr_addr (Bug#8477).
+
 2011-08-04  Jan Djärv  <jan.h.d@swipnet.se>
 
        * configure.in (HAVE_PTHREAD): Add check for -lpthread (Bug#9216).
index c0e5b3a..cfb9dc8 100644 (file)
@@ -1299,10 +1299,20 @@ if test $emacs_cv_struct_exception != yes; then
   AC_DEFINE(NO_MATHERR, 1, [Define to 1 if you don't have struct exception in math.h.])
 fi
 
+AC_CHECK_HEADERS(sys/socket.h)
 AC_CHECK_HEADERS(net/if.h, , , [AC_INCLUDES_DEFAULT
 #if HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
 #endif])
+AC_CHECK_HEADERS(ifaddrs.h, , , [AC_INCLUDES_DEFAULT
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif])
+AC_CHECK_HEADERS(net/if_dl.h, , , [AC_INCLUDES_DEFAULT
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif])
+AC_CHECK_FUNCS(getifaddrs freeifaddrs)
 
 dnl checks for structure members
 AC_STRUCT_TM
@@ -1313,7 +1323,8 @@ AC_CHECK_MEMBER(struct tm.tm_gmtoff,
                [#include <time.h>])
 AC_CHECK_MEMBERS([struct ifreq.ifr_flags, struct ifreq.ifr_hwaddr,
                  struct ifreq.ifr_netmask, struct ifreq.ifr_broadaddr,
-                 struct ifreq.ifr_addr], , ,
+                 struct ifreq.ifr_addr,
+                 struct ifreq.ifr_addr.sa_len], , ,
                 [AC_INCLUDES_DEFAULT
 #if HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
index 5c65159..899ee14 100644 (file)
@@ -1,3 +1,14 @@
+2011-08-13  Jan Djärv  <jan.h.d@swipnet.se>
+
+       * process.c: Include ifaddrs.h and net/if_dl.h if available (Bug#8477).
+       (Fnetwork_interface_list): Allocate in increments of bytes instead
+       of sizeof (struct ifreq).  Iterate over ifconf.ifc_req by counting
+       bytes (Bug#8477).  Count bytes correctly when ifr_addr is a struct
+       sockaddr.
+       (struct ifflag_def): notrailers is smart on OSX.
+       (Fnetwork_interface_info): Handle case when ifr_flags is negative.
+       Get hardware address with getifaddrs if available.
+
 2011-08-12  Eli Zaretskii  <eliz@gnu.org>
 
        * xdisp.c (iterate_out_of_display_property): xassert that
index 236c27e..b3c295c 100644 (file)
@@ -58,6 +58,17 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <net/if.h>
 #endif /* HAVE_NET_IF_H */
 
+#if defined(HAVE_IFADDRS_H)
+/* Must be after net/if.h */
+#include <ifaddrs.h>
+
+/* We only use structs from this header when we use getifaddrs.  */
+#if defined(HAVE_NET_IF_DL_H)
+#include <net/if_dl.h>
+#endif
+
+#endif
+
 #ifdef NEED_BSDTTY
 #include <bsdtty.h>
 #endif
@@ -3557,9 +3568,9 @@ format; see the description of ADDRESS in `make-network-process'.  */)
   (void)
 {
   struct ifconf ifconf;
-  struct ifreq *ifreqs = NULL;
-  int ifaces = 0;
-  int buf_size, s;
+  struct ifreq *ifreq;
+  void *buf = NULL;
+  int buf_size = 512, s, i;
   Lisp_Object res;
 
   s = socket (AF_INET, SOCK_STREAM, 0);
@@ -3567,20 +3578,19 @@ format; see the description of ADDRESS in `make-network-process'.  */)
     return Qnil;
 
  again:
-  ifaces += 25;
-  buf_size = ifaces * sizeof (ifreqs[0]);
-  ifreqs = (struct ifreq *)xrealloc(ifreqs, buf_size);
-  if (!ifreqs)
+  buf_size *= 2;
+  buf = xrealloc(buf, buf_size);
+  if (!buf)
     {
       close (s);
       return Qnil;
     }
 
-  ifconf.ifc_len = buf_size;
-  ifconf.ifc_req = ifreqs;
+  ifconf.ifc_buf = buf;
   if (ioctl (s, SIOCGIFCONF, &ifconf))
     {
       close (s);
+      xfree (buf);
       return Qnil;
     }
 
@@ -3588,15 +3598,29 @@ format; see the description of ADDRESS in `make-network-process'.  */)
     goto again;
 
   close (s);
-  ifaces = ifconf.ifc_len / sizeof (ifreqs[0]);
 
   res = Qnil;
-  while (--ifaces >= 0)
+  for (ifreq = ifconf.ifc_req;
+       (char *) ifreq < (char *) (ifconf.ifc_req) + ifconf.ifc_len;
+       )
     {
-      struct ifreq *ifq = &ifreqs[ifaces];
+      struct ifreq *ifq = ifreq;
+#ifdef HAVE_STRUCT_IFREQ_IFR_ADDR_SA_LEN
+#define SIZEOF_IFREQ(sif)                                               \
+      ((sif)->ifr_addr.sa_len < sizeof(struct sockaddr) ?               \
+       sizeof((*sif)) : sizeof ((sif)->ifr_name) + sif->ifr_addr.sa_len)
+
+      int len = SIZEOF_IFREQ (ifq);
+#else
+      int len = sizeof (*ifreq);
+#endif
       char namebuf[sizeof (ifq->ifr_name) + 1];
+      i += len;
+      ifreq = (struct ifreq*) ((char*) ifreq + len);
+
       if (ifq->ifr_addr.sa_family != AF_INET)
        continue;
+
       memcpy (namebuf, ifq->ifr_name, sizeof (ifq->ifr_name));
       namebuf[sizeof (ifq->ifr_name)] = 0;
       res = Fcons (Fcons (build_string (namebuf),
@@ -3605,6 +3629,7 @@ format; see the description of ADDRESS in `make-network-process'.  */)
                   res);
     }
 
+  xfree (buf);
   return res;
 }
 #endif /* SIOCGIFCONF */
@@ -3642,8 +3667,13 @@ static const struct ifflag_def ifflag_table[] = {
   { IFF_PROMISC,       "promisc" },
 #endif
 #ifdef IFF_NOTRAILERS
+#ifdef NS_IMPL_COCOA
+  /* Really means smart, notrailers is obsolete */
+  { IFF_NOTRAILERS,    "smart" },
+#else
   { IFF_NOTRAILERS,    "notrailers" },
 #endif
+#endif
 #ifdef IFF_ALLMULTI
   { IFF_ALLMULTI,      "allmulti" },
 #endif
@@ -3696,6 +3726,9 @@ FLAGS is the current flags of the interface.  */)
   Lisp_Object elt;
   int s;
   int any = 0;
+#if defined(HAVE_GETIFADDRS)
+  struct ifaddrs *ifap;
+#endif
 
   CHECK_STRING (ifname);
 
@@ -3714,6 +3747,12 @@ FLAGS is the current flags of the interface.  */)
       const struct ifflag_def *fp;
       int fnum;
 
+      /* If flags is smaller than int (i.e. short) it may have the high bit set
+         due to IFF_MULTICAST.  In that case, sign extending it into
+         an int is wrong.  */
+      if (flags < 0 && sizeof (rq.ifr_flags) < sizeof (flags))
+        flags = (unsigned short) rq.ifr_flags;
+
       any = 1;
       for (fp = ifflag_table; flags != 0 && fp->flag_sym; fp++)
        {
@@ -3747,7 +3786,38 @@ FLAGS is the current flags of the interface.  */)
        p->contents[n] = make_number (((unsigned char *)&rq.ifr_hwaddr.sa_data[0])[n]);
       elt = Fcons (make_number (rq.ifr_hwaddr.sa_family), hwaddr);
     }
+#elif defined(HAVE_GETIFADDRS) && defined(LLADDR)
+  if (getifaddrs (&ifap) != -1)
+    {
+      Lisp_Object hwaddr = Fmake_vector (make_number (6), Qnil);
+      register struct Lisp_Vector *p = XVECTOR (hwaddr);
+      struct ifaddrs *it;
+
+      for (it = ifap; it != NULL; it = it->ifa_next)
+        {
+          struct sockaddr_dl *sdl = (struct sockaddr_dl*) it->ifa_addr;
+          unsigned char linkaddr[6];
+          int n;
+
+          if (it->ifa_addr->sa_family != AF_LINK
+              || strcmp (it->ifa_name, SSDATA (ifname)) != 0
+              || sdl->sdl_alen != 6)
+            continue;
+
+          memcpy (linkaddr, LLADDR(sdl), sdl->sdl_alen);
+          for (n = 0; n < 6; n++)
+            p->contents[n] = make_number (linkaddr[n]);
+
+          elt = Fcons (make_number (it->ifa_addr->sa_family), hwaddr);
+          break;
+        }
+    }
+#ifdef HAVE_FREEIFADDRS
+  freeifaddrs (ifap);
 #endif
+
+#endif /* HAVE_GETIFADDRS && LLADDR */
+
   res = Fcons (elt, res);
 
   elt = Qnil;