From: Robert Pluim Date: Fri, 15 Nov 2019 10:11:30 +0000 (+0100) Subject: Extend network-interface-list to return IPv6 and network info X-Git-Tag: emacs-27.0.90~527 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=650a514e996287106f9a9525b6f27068ec2a0cbf;p=emacs.git Extend network-interface-list to return IPv6 and network info Bug#38218 * src/process.c (Fnetwork_interface_list): Extend argument list to allow requesting full network info and/or IPv4/IPv6 info. (network_interface_list) [HAVE_GETIFADDRS]: Use getifaddrs to retrieve interface IP addresses. * src/process.h: Update prototype of network_interface_list. * src/w32.c (g_b_init_get_adapters_addresses): New init flag. (globals_of_w32): Initialize it. (GetAdaptersAddresses_Proc): New function typedef. (get_adapters_addresses): New wrapper function. (init_winsock): Load htonl and ntohl. (sys_htonl, sys_ntohl): New wrapper functions. (network_interface_list): Implement in terms of get_adapters_addresses. * nt/inc/sys/socket.h: Add sys_htonl and sys_ntohl prototypes. * etc/NEWS: Announce IPv4/IPv6 changes in network-interface-list. * doc/lispref/processes.texi (Misc Network): Document updated arglist and return values for network-interface-list. --- diff --git a/doc/lispref/processes.texi b/doc/lispref/processes.texi index fc5832253f9..e33ae287ff9 100644 --- a/doc/lispref/processes.texi +++ b/doc/lispref/processes.texi @@ -2971,12 +2971,67 @@ non-@code{nil} if that particular network option is supported by on network connections. Note that they are supported only on some systems. -@defun network-interface-list -This function returns a list describing the network interfaces -of the machine you are using. The value is an alist whose -elements have the form @code{(@var{name} . @var{address})}. -@var{address} has the same form as the @var{local-address} -and @var{remote-address} arguments to @code{make-network-process}. +@defun network-interface-list &optional full family +This function returns a list describing the network interfaces of the +machine you are using. The value is an alist whose elements have the +form @code{(@var{ifname} . @var{address})}. @var{ifname} is a string +naming the interface, @var{address} has the same form as the +@var{local-address} and @var{remote-address} arguments to +@code{make-network-process}, i.e. a vector of integers. By default +both IPv4 and IPv6 addresses are returned if possible. + +Optional argument @var{full} non-@code{nil} means to instead return a +list of one or more elements of the form @w{@code{(@var{ifname} +@var{addr} @var{bcast} @var{netmask})}}. @var{ifname} is a non-unique +string naming the interface. @var{addr}, @var{bcast}, and +@var{netmask} are vectors of integers detailing the IP address, +broadcast address, and network mask. + +Optional argument @var{family} specified as symbol @code{ipv4} or +@code{ipv6} restricts the returned information to IPv4 and IPv6 +addresses respectively, independently of the value of @var{full}. +Speficying @code{ipv6} when IPv6 support is not available will result +in an error being signaled. + +Some examples: + +@example +(network-interface-list) @result{} +(("vmnet8" . + [172 16 76 1 0]) + ("vmnet1" . + [172 16 206 1 0]) + ("lo0" . + [65152 0 0 0 0 0 0 1 0]) + ("lo0" . + [0 0 0 0 0 0 0 1 0]) + ("lo0" . + [127 0 0 1 0])) +@end example + +@example +(network-interface-list t) @result{} +(("vmnet8" + [172 16 76 1 0] + [172 16 76 255 0] + [255 255 255 0 0]) + ("vmnet1" + [172 16 206 1 0] + [172 16 206 255 0] + [255 255 255 0 0]) + ("lo0" + [65152 0 0 0 0 0 0 1 0] + [65152 0 0 0 65535 65535 65535 65535 0] + [65535 65535 65535 65535 0 0 0 0 0]) + ("lo0" + [0 0 0 0 0 0 0 1 0] + [0 0 0 0 0 0 0 1 0] + [65535 65535 65535 65535 65535 65535 65535 65535 0]) + ("lo0" + [127 0 0 1 0] + [127 255 255 255 0] + [255 0 0 0 0])) +@end example @end defun @defun network-interface-info ifname @@ -2996,6 +3051,8 @@ The layer 2 address (Ethernet MAC address, for instance). @item flags The current flags of the interface. @end table + +Note that this function returns only IPv4 information. @end defun @defun format-network-address address &optional omit-port diff --git a/etc/NEWS b/etc/NEWS index 7e86ccc71e3..a97cf20ea7c 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -240,6 +240,11 @@ in addition to the decimal/hex/octal representation. Default nil. ** New function 'network-lookup-address-info'. This does IPv4 and/or IPv6 address lookups on hostnames. ++++ +** 'network-interface-list' can now return IPv4 and IPv6 addresses. +IPv4 and IPv6 addresses are now returned by default if available, +optionally including netmask/broadcast address information. + --- ** Control of the threshold for using the 'distant-foreground' color. The threshold for color distance below which the 'distant-foreground' diff --git a/lisp/net/nsm.el b/lisp/net/nsm.el index 205b7974883..5dc5244e6d5 100644 --- a/lisp/net/nsm.el +++ b/lisp/net/nsm.el @@ -228,21 +228,22 @@ host address is a localhost address, or in the same subnet as one of the local interfaces, this function returns nil. Non-nil otherwise." (let ((addresses (network-lookup-address-info host)) - (network-interface-list (network-interface-list)) + (network-interface-list (network-interface-list t)) (off-net t)) (when (or (and (functionp nsm-trust-local-network) (funcall nsm-trust-local-network)) nsm-trust-local-network) (mapc - (lambda (address) + (lambda (ip) (mapc - (lambda (iface) - (let ((info (network-interface-info (car iface)))) + (lambda (info) + (let ((local-ip (nth 1 info)) + (mask (nth 2 info))) (when - (nsm-network-same-subnet (substring (car info) 0 -1) - (substring (car (cddr info)) 0 -1) - (substring address 0 -1)) + (nsm-network-same-subnet (substring local-ip 0 -1) + (substring mask 0 -1) + (substring ip 0 -1)) (setq off-net nil)))) network-interface-list)) addresses)) diff --git a/nt/inc/sys/socket.h b/nt/inc/sys/socket.h index 6d26ff907e6..0f3943b453a 100644 --- a/nt/inc/sys/socket.h +++ b/nt/inc/sys/socket.h @@ -92,6 +92,8 @@ typedef unsigned short uint16_t; #define connect sys_connect #define htons sys_htons #define ntohs sys_ntohs +#define htonl sys_htonl +#define ntohl sys_ntohl #define inet_addr sys_inet_addr #define gethostname sys_gethostname #define gethostbyname sys_gethostbyname @@ -112,6 +114,8 @@ int sys_bind (int s, const struct sockaddr *addr, int namelen); int sys_connect (int s, const struct sockaddr *addr, int namelen); u_short sys_htons (u_short hostshort); u_short sys_ntohs (u_short netshort); +u_long sys_htonl (u_long hostlong); +u_long sys_ntohl (u_long netlong); unsigned long sys_inet_addr (const char * cp); int sys_gethostname (char * name, int namelen); struct hostent * sys_gethostbyname (const char * name); diff --git a/src/process.c b/src/process.c index 9158cfd347c..0f82682ae5f 100644 --- a/src/process.c +++ b/src/process.c @@ -4255,73 +4255,86 @@ usage: (make-network-process &rest ARGS) */) } -#ifdef HAVE_NET_IF_H -#ifdef SIOCGIFCONF +#ifdef HAVE_GETIFADDRS static Lisp_Object -network_interface_list (void) +network_interface_list (bool full, unsigned short match) { - struct ifconf ifconf; - struct ifreq *ifreq; - void *buf = NULL; - ptrdiff_t buf_size = 512; - int s; - Lisp_Object res; - ptrdiff_t count; + Lisp_Object res = Qnil; + struct ifaddrs *ifap; - s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0); - if (s < 0) + if (getifaddrs (&ifap) == -1) return Qnil; - count = SPECPDL_INDEX (); - record_unwind_protect_int (close_file_unwind, s); - do + for (struct ifaddrs *it = ifap; it != NULL; it = it->ifa_next) { - buf = xpalloc (buf, &buf_size, 1, INT_MAX, 1); - ifconf.ifc_buf = buf; - ifconf.ifc_len = buf_size; - if (ioctl (s, SIOCGIFCONF, &ifconf)) - { - emacs_close (s); - xfree (buf); - return Qnil; - } - } - while (ifconf.ifc_len == buf_size); - - res = unbind_to (count, Qnil); - ifreq = ifconf.ifc_req; - while ((char *) ifreq < (char *) ifconf.ifc_req + ifconf.ifc_len) - { - 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; + int addr_len; + uint32_t *maskp; + uint32_t *addrp; + Lisp_Object elt = Qnil; - int len = SIZEOF_IFREQ (ifq); -#else - int len = sizeof (*ifreq); + /* BSD can allegedly return interfaces with a NULL address. */ + if (it->ifa_addr == NULL) + continue; + if (match && it->ifa_addr->sa_family != match) + continue; + if (it->ifa_addr->sa_family == AF_INET) + { + DECLARE_POINTER_ALIAS (sin1, struct sockaddr_in, it->ifa_netmask); + maskp = (uint32_t *)&sin1->sin_addr; + DECLARE_POINTER_ALIAS (sin2, struct sockaddr_in, it->ifa_addr); + addrp = (uint32_t *)&sin2->sin_addr; + len = sizeof (struct sockaddr_in); + addr_len = 1; + } +#ifdef AF_INET6 + else if (it->ifa_addr->sa_family == AF_INET6) + { + DECLARE_POINTER_ALIAS (sin6_1, struct sockaddr_in6, it->ifa_netmask); + maskp = (uint32_t *) &sin6_1->sin6_addr; + DECLARE_POINTER_ALIAS (sin6_2, struct sockaddr_in6, it->ifa_addr); + addrp = (uint32_t *) &sin6_2->sin6_addr; + len = sizeof (struct sockaddr_in6); + addr_len = 4; + } #endif - char namebuf[sizeof (ifq->ifr_name) + 1]; - ifreq = (struct ifreq *) ((char *) ifreq + len); + else + continue; - if (ifq->ifr_addr.sa_family != AF_INET) - continue; + Lisp_Object addr = conv_sockaddr_to_lisp (it->ifa_addr, len); - memcpy (namebuf, ifq->ifr_name, sizeof (ifq->ifr_name)); - namebuf[sizeof (ifq->ifr_name)] = 0; - res = Fcons (Fcons (build_string (namebuf), - conv_sockaddr_to_lisp (&ifq->ifr_addr, - sizeof (struct sockaddr))), - res); + if (full) + { + elt = Fcons (conv_sockaddr_to_lisp (it->ifa_netmask, len), elt); + /* There is an it->ifa_broadaddr field, but its contents are + unreliable, so always calculate the broadcast address from + the address and the netmask. */ + int i; + uint32_t mask; + for (i = 0; i < addr_len; i++) + { + mask = maskp[i]; + maskp[i] = (addrp[i] & mask) | ~mask; + } + elt = Fcons (conv_sockaddr_to_lisp (it->ifa_netmask, len), elt); + elt = Fcons (addr, elt); + } + else + { + elt = addr; + } + res = Fcons (Fcons (build_string (it->ifa_name), elt), res); } +#ifdef HAVE_FREEIFADDRS + freeifaddrs (ifap); +#endif - xfree (buf); return res; } -#endif /* SIOCGIFCONF */ +#endif /* HAVE_GETIFADDRS */ +#ifdef HAVE_NET_IF_H #if defined (SIOCGIFADDR) || defined (SIOCGIFHWADDR) || defined (SIOCGIFFLAGS) struct ifflag_def { @@ -4550,17 +4563,46 @@ network_interface_info (Lisp_Object ifname) #endif /* defined (HAVE_NET_IF_H) */ DEFUN ("network-interface-list", Fnetwork_interface_list, - Snetwork_interface_list, 0, 0, 0, + Snetwork_interface_list, 0, 2, 0, doc: /* Return an alist of all network interfaces and their network address. -Each element is a cons, the car of which is a string containing the -interface name, and the cdr is the network address in internal -format; see the description of ADDRESS in `make-network-process'. +Each element is cons of the form (IFNAME . IP) where IFNAME is a +string containing the interface name, and IP is the network address in +internal format; see the description of ADDRESS in +`make-network-process'. The interface name is not guaranteed to be +unique. + +Optional parameter FULL non-nil means return all IP address info for +each interface. Each element is then a list of the form + (IFNAME IP BCAST MASK) +where IFNAME is the interface name, IP the IP address, +BCAST the broadcast address, and MASK the network mask. + +Optional parameter FAMILY controls the type of addresses to return. +The default of nil means both IPv4 and IPv6, symbol `ipv4' means IPv4 +only, symbol `ipv6' means IPv6 only. + +See also `network-interface-info', which is limited to IPv4 only. If the information is not available, return nil. */) - (void) + (Lisp_Object full, Lisp_Object family) { -#if (defined HAVE_NET_IF_H && defined SIOCGIFCONF) || defined WINDOWSNT - return network_interface_list (); +#if defined HAVE_GETIFADDRS || defined WINDOWSNT + unsigned short match; + bool full_info = false; + + if (! NILP (full)) + full_info = true; + if (NILP (family)) + match = 0; + else if (EQ (family, Qipv4)) + match = AF_INET; +#ifdef AF_INET6 + else if (EQ (family, Qipv6)) + match = AF_INET6; +#endif + else + error ("Unsupported address family"); + return network_interface_list (full_info, match); #else return Qnil; #endif diff --git a/src/process.h b/src/process.h index 5e957c4298e..bf15317eb4f 100644 --- a/src/process.h +++ b/src/process.h @@ -291,7 +291,7 @@ extern void catch_child_signal (void); extern void restore_nofile_limit (void); #ifdef WINDOWSNT -extern Lisp_Object network_interface_list (void); +extern Lisp_Object network_interface_list (bool full, unsigned short match); extern Lisp_Object network_interface_info (Lisp_Object); #endif diff --git a/src/w32.c b/src/w32.c index 26ea15d8910..76c226892a4 100644 --- a/src/w32.c +++ b/src/w32.c @@ -227,6 +227,8 @@ typedef struct _REPARSE_DATA_BUFFER { #undef connect #undef htons #undef ntohs +#undef htonl +#undef ntohl #undef inet_addr #undef gethostname #undef gethostbyname @@ -326,6 +328,7 @@ static BOOL g_b_init_set_file_security_a; static BOOL g_b_init_set_named_security_info_w; static BOOL g_b_init_set_named_security_info_a; static BOOL g_b_init_get_adapters_info; +static BOOL g_b_init_get_adapters_addresses; static BOOL g_b_init_reg_open_key_ex_w; static BOOL g_b_init_reg_query_value_ex_w; static BOOL g_b_init_expand_environment_strings_w; @@ -503,6 +506,12 @@ typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR); typedef DWORD (WINAPI *GetAdaptersInfo_Proc) ( PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen); +typedef DWORD (WINAPI *GetAdaptersAddresses_Proc) ( + ULONG, + ULONG, + PVOID, + PIP_ADAPTER_ADDRESSES, + PULONG); int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int); int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL); @@ -1368,6 +1377,31 @@ get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen) return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen); } +static DWORD WINAPI +get_adapters_addresses (ULONG family, PIP_ADAPTER_ADDRESSES pAdapterAddresses, PULONG pOutBufLen) +{ + static GetAdaptersAddresses_Proc s_pfn_Get_Adapters_Addresses = NULL; + HMODULE hm_iphlpapi = NULL; + + if (is_windows_9x () == TRUE) + return ERROR_NOT_SUPPORTED; + + if (g_b_init_get_adapters_addresses == 0) + { + g_b_init_get_adapters_addresses = 1; + hm_iphlpapi = LoadLibrary ("Iphlpapi.dll"); + if (hm_iphlpapi) + s_pfn_Get_Adapters_Addresses = (GetAdaptersAddresses_Proc) + get_proc_addr (hm_iphlpapi, "GetAdaptersAddresses"); + } + if (s_pfn_Get_Adapters_Addresses == NULL) + return ERROR_NOT_SUPPORTED; + ULONG flags = GAA_FLAG_SKIP_ANYCAST + | GAA_FLAG_SKIP_MULTICAST + | GAA_FLAG_SKIP_DNS_SERVER; + return s_pfn_Get_Adapters_Addresses (family, flags, NULL, pAdapterAddresses, pOutBufLen); +} + static LONG WINAPI reg_open_key_ex_w (HKEY hkey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult) @@ -7414,6 +7448,8 @@ int (PASCAL *pfn_WSACleanup) (void); u_short (PASCAL *pfn_htons) (u_short hostshort); u_short (PASCAL *pfn_ntohs) (u_short netshort); +u_long (PASCAL *pfn_htonl) (u_long hostlong); +u_long (PASCAL *pfn_ntohl) (u_long netlong); unsigned long (PASCAL *pfn_inet_addr) (const char * cp); int (PASCAL *pfn_gethostname) (char * name, int namelen); struct hostent * (PASCAL *pfn_gethostbyname) (const char * name); @@ -7504,6 +7540,8 @@ init_winsock (int load_now) LOAD_PROC (shutdown); LOAD_PROC (htons); LOAD_PROC (ntohs); + LOAD_PROC (htonl); + LOAD_PROC (ntohl); LOAD_PROC (inet_addr); LOAD_PROC (gethostname); LOAD_PROC (gethostbyname); @@ -7884,6 +7922,19 @@ sys_ntohs (u_short netshort) return (winsock_lib != NULL) ? pfn_ntohs (netshort) : netshort; } +u_long +sys_htonl (u_long hostlong) +{ + return (winsock_lib != NULL) ? + pfn_htonl (hostlong) : hostlong; +} + +u_long +sys_ntohl (u_long netlong) +{ + return (winsock_lib != NULL) ? + pfn_ntohl (netlong) : netlong; +} unsigned long sys_inet_addr (const char * cp) @@ -9382,9 +9433,197 @@ network_interface_get_info (Lisp_Object ifname) } Lisp_Object -network_interface_list (void) +network_interface_list (bool full, unsigned short match) { - return network_interface_get_info (Qnil); + ULONG ainfo_len = sizeof (IP_ADAPTER_ADDRESSES); + ULONG family = match; + IP_ADAPTER_ADDRESSES *adapter, *ainfo = xmalloc (ainfo_len); + DWORD retval = get_adapters_addresses (family, ainfo, &ainfo_len); + Lisp_Object res = Qnil; + + if (retval == ERROR_BUFFER_OVERFLOW) + { + ainfo = xrealloc (ainfo, ainfo_len); + retval = get_adapters_addresses (family, ainfo, &ainfo_len); + } + + if (retval != ERROR_SUCCESS) + { + xfree (ainfo); + return res; + } + + /* For the below, we need some winsock functions, so make sure + the winsock DLL is loaded. If we cannot successfully load + it, they will have no use of the information we provide, + anyway, so punt. */ + if (!winsock_lib && !init_winsock (1)) + return res; + + int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0; + int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0; + int tnl_count = 0; + int if_num; + char namebuf[MAX_ADAPTER_NAME_LENGTH + 4]; + static const char *ifmt[] = { + "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d", + "lo%d", "ifx%d", "tunnel%d" + }; + enum { + NONE = -1, + ETHERNET = 0, + TOKENRING = 1, + FDDI = 2, + PPP = 3, + SLIP = 4, + WLAN = 5, + LOOPBACK = 6, + OTHER_IF = 7, + TUNNEL = 8 + } ifmt_idx; + + for (adapter = ainfo; adapter; adapter = adapter->Next) + { + + /* Present Unix-compatible interface names, instead of the + Windows names, which are really GUIDs not readable by + humans. */ + + switch (adapter->IfType) + { + case IF_TYPE_ETHERNET_CSMACD: + ifmt_idx = ETHERNET; + if_num = eth_count++; + break; + case IF_TYPE_ISO88025_TOKENRING: + ifmt_idx = TOKENRING; + if_num = tr_count++; + break; + case IF_TYPE_FDDI: + ifmt_idx = FDDI; + if_num = fddi_count++; + break; + case IF_TYPE_PPP: + ifmt_idx = PPP; + if_num = ppp_count++; + break; + case IF_TYPE_SLIP: + ifmt_idx = SLIP; + if_num = sl_count++; + break; + case IF_TYPE_IEEE80211: + ifmt_idx = WLAN; + if_num = wlan_count++; + break; + case IF_TYPE_SOFTWARE_LOOPBACK: + ifmt_idx = LOOPBACK; + if_num = lo_count++; + break; + case IF_TYPE_TUNNEL: + ifmt_idx = TUNNEL; + if_num = tnl_count++; + break; + default: + ifmt_idx = OTHER_IF; + if_num = ifx_count++; + break; + } + sprintf (namebuf, ifmt[ifmt_idx], if_num); + + IP_ADAPTER_UNICAST_ADDRESS *address; + for (address = adapter->FirstUnicastAddress; address; address = address->Next) + { + int len; + int addr_len; + uint32_t *maskp; + uint32_t *addrp; + Lisp_Object elt = Qnil; + struct sockaddr *ifa_addr = address->Address.lpSockaddr; + + if (ifa_addr == NULL) + continue; + if (match && ifa_addr->sa_family != match) + continue; + + struct sockaddr_in ipv4; +#ifdef AF_INET6 + struct sockaddr_in6 ipv6; +#endif + struct sockaddr *sin; + + if (ifa_addr->sa_family == AF_INET) + { + ipv4.sin_family = AF_INET; + ipv4.sin_port = 0; + DECLARE_POINTER_ALIAS (sin_in, struct sockaddr_in, ifa_addr); + addrp = (uint32_t *)&sin_in->sin_addr; + maskp = (uint32_t *)&ipv4.sin_addr; + sin = (struct sockaddr *)&ipv4; + len = sizeof (struct sockaddr_in); + addr_len = 1; + } +#ifdef AF_INET6 + else if (ifa_addr->sa_family == AF_INET6) + { + ipv6.sin6_family = AF_INET6; + ipv6.sin6_port = 0; + DECLARE_POINTER_ALIAS (sin_in6, struct sockaddr_in6, ifa_addr); + addrp = (uint32_t *)&sin_in6->sin6_addr; + maskp = (uint32_t *)&ipv6.sin6_addr; + sin = (struct sockaddr *)&ipv6; + len = sizeof (struct sockaddr_in6); + addr_len = 4; + } +#endif + else + continue; + + Lisp_Object addr = conv_sockaddr_to_lisp (ifa_addr, len); + + if (full) + { + /* GetAdaptersAddress returns information in network + byte order, so convert from host to network order + when generating the netmask. */ + int i; + ULONG numbits = address->OnLinkPrefixLength; + for (i = 0; i < addr_len; i++) + { + if (numbits >= 32) + { + maskp[i] = -1U; + numbits -= 32; + } + else if (numbits) + { + maskp[i] = sys_htonl (-1U << (32 - numbits)); + numbits = 0; + } + else + { + maskp[i] = 0; + } + } + elt = Fcons (conv_sockaddr_to_lisp (sin, len), elt); + uint32_t mask; + for (i = 0; i < addr_len; i++) + { + mask = maskp[i]; + maskp[i] = (addrp[i] & mask) | ~mask; + + } + elt = Fcons (conv_sockaddr_to_lisp (sin, len), elt); + elt = Fcons (addr, elt); + } + else + { + elt = addr; + } + res = Fcons (Fcons (build_string (namebuf), elt), res); + } + } + xfree (ainfo); + return res; } Lisp_Object @@ -10099,6 +10338,7 @@ globals_of_w32 (void) g_b_init_set_named_security_info_w = 0; g_b_init_set_named_security_info_a = 0; g_b_init_get_adapters_info = 0; + g_b_init_get_adapters_addresses = 0; g_b_init_reg_open_key_ex_w = 0; g_b_init_reg_query_value_ex_w = 0; g_b_init_expand_environment_strings_w = 0;