From 377538cbcf8c1f0aab9b40ed2ff3df414904272f Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jan=20Dj=C3=A4rv?= Date: Sat, 13 Aug 2011 12:48:03 +0200 Subject: [PATCH] Fix network-interface-list|info on newer BSD derived OS:es. * 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 | 6 ++++ configure.in | 13 ++++++- src/ChangeLog | 11 ++++++ src/process.c | 94 ++++++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 111 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index 30f22850d40..55deca05751 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2011-08-13 Jan Djärv + + * 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 * configure.in (HAVE_PTHREAD): Add check for -lpthread (Bug#9216). diff --git a/configure.in b/configure.in index c0e5b3acbb5..cfb9dc8bab2 100644 --- a/configure.in +++ b/configure.in @@ -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 #endif]) +AC_CHECK_HEADERS(ifaddrs.h, , , [AC_INCLUDES_DEFAULT +#if HAVE_SYS_SOCKET_H +#include +#endif]) +AC_CHECK_HEADERS(net/if_dl.h, , , [AC_INCLUDES_DEFAULT +#if HAVE_SYS_SOCKET_H +#include +#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 ]) 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 diff --git a/src/ChangeLog b/src/ChangeLog index 5c65159a841..899ee14686d 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,14 @@ +2011-08-13 Jan Djärv + + * 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 * xdisp.c (iterate_out_of_display_property): xassert that diff --git a/src/process.c b/src/process.c index 236c27e5c3a..b3c295cecde 100644 --- a/src/process.c +++ b/src/process.c @@ -58,6 +58,17 @@ along with GNU Emacs. If not, see . */ #include #endif /* HAVE_NET_IF_H */ +#if defined(HAVE_IFADDRS_H) +/* Must be after net/if.h */ +#include + +/* We only use structs from this header when we use getifaddrs. */ +#if defined(HAVE_NET_IF_DL_H) +#include +#endif + +#endif + #ifdef NEED_BSDTTY #include #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; -- 2.39.2