diff options
| author | Robert Pluim | 2019-11-15 11:11:30 +0100 |
|---|---|---|
| committer | Robert Pluim | 2019-11-26 08:46:13 +0100 |
| commit | 650a514e996287106f9a9525b6f27068ec2a0cbf (patch) | |
| tree | 188170aae76f32d894d8df1baa7f435fbfe99d88 /src | |
| parent | 5c3d0cf7910afa6b3fbdba24ac5c5817f268eb0e (diff) | |
| download | emacs-650a514e996287106f9a9525b6f27068ec2a0cbf.tar.gz emacs-650a514e996287106f9a9525b6f27068ec2a0cbf.zip | |
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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/process.c | 158 | ||||
| -rw-r--r-- | src/process.h | 2 | ||||
| -rw-r--r-- | src/w32.c | 244 |
3 files changed, 343 insertions, 61 deletions
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) */) | |||
| 4255 | } | 4255 | } |
| 4256 | 4256 | ||
| 4257 | 4257 | ||
| 4258 | #ifdef HAVE_NET_IF_H | ||
| 4259 | 4258 | ||
| 4260 | #ifdef SIOCGIFCONF | 4259 | #ifdef HAVE_GETIFADDRS |
| 4261 | static Lisp_Object | 4260 | static Lisp_Object |
| 4262 | network_interface_list (void) | 4261 | network_interface_list (bool full, unsigned short match) |
| 4263 | { | 4262 | { |
| 4264 | struct ifconf ifconf; | 4263 | Lisp_Object res = Qnil; |
| 4265 | struct ifreq *ifreq; | 4264 | struct ifaddrs *ifap; |
| 4266 | void *buf = NULL; | ||
| 4267 | ptrdiff_t buf_size = 512; | ||
| 4268 | int s; | ||
| 4269 | Lisp_Object res; | ||
| 4270 | ptrdiff_t count; | ||
| 4271 | 4265 | ||
| 4272 | s = socket (AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0); | 4266 | if (getifaddrs (&ifap) == -1) |
| 4273 | if (s < 0) | ||
| 4274 | return Qnil; | 4267 | return Qnil; |
| 4275 | count = SPECPDL_INDEX (); | ||
| 4276 | record_unwind_protect_int (close_file_unwind, s); | ||
| 4277 | 4268 | ||
| 4278 | do | 4269 | for (struct ifaddrs *it = ifap; it != NULL; it = it->ifa_next) |
| 4279 | { | 4270 | { |
| 4280 | buf = xpalloc (buf, &buf_size, 1, INT_MAX, 1); | 4271 | int len; |
| 4281 | ifconf.ifc_buf = buf; | 4272 | int addr_len; |
| 4282 | ifconf.ifc_len = buf_size; | 4273 | uint32_t *maskp; |
| 4283 | if (ioctl (s, SIOCGIFCONF, &ifconf)) | 4274 | uint32_t *addrp; |
| 4284 | { | 4275 | Lisp_Object elt = Qnil; |
| 4285 | emacs_close (s); | ||
| 4286 | xfree (buf); | ||
| 4287 | return Qnil; | ||
| 4288 | } | ||
| 4289 | } | ||
| 4290 | while (ifconf.ifc_len == buf_size); | ||
| 4291 | |||
| 4292 | res = unbind_to (count, Qnil); | ||
| 4293 | ifreq = ifconf.ifc_req; | ||
| 4294 | while ((char *) ifreq < (char *) ifconf.ifc_req + ifconf.ifc_len) | ||
| 4295 | { | ||
| 4296 | struct ifreq *ifq = ifreq; | ||
| 4297 | #ifdef HAVE_STRUCT_IFREQ_IFR_ADDR_SA_LEN | ||
| 4298 | #define SIZEOF_IFREQ(sif) \ | ||
| 4299 | ((sif)->ifr_addr.sa_len < sizeof (struct sockaddr) \ | ||
| 4300 | ? sizeof (*(sif)) : sizeof ((sif)->ifr_name) + (sif)->ifr_addr.sa_len) | ||
| 4301 | 4276 | ||
| 4302 | int len = SIZEOF_IFREQ (ifq); | 4277 | /* BSD can allegedly return interfaces with a NULL address. */ |
| 4303 | #else | 4278 | if (it->ifa_addr == NULL) |
| 4304 | int len = sizeof (*ifreq); | 4279 | continue; |
| 4280 | if (match && it->ifa_addr->sa_family != match) | ||
| 4281 | continue; | ||
| 4282 | if (it->ifa_addr->sa_family == AF_INET) | ||
| 4283 | { | ||
| 4284 | DECLARE_POINTER_ALIAS (sin1, struct sockaddr_in, it->ifa_netmask); | ||
| 4285 | maskp = (uint32_t *)&sin1->sin_addr; | ||
| 4286 | DECLARE_POINTER_ALIAS (sin2, struct sockaddr_in, it->ifa_addr); | ||
| 4287 | addrp = (uint32_t *)&sin2->sin_addr; | ||
| 4288 | len = sizeof (struct sockaddr_in); | ||
| 4289 | addr_len = 1; | ||
| 4290 | } | ||
| 4291 | #ifdef AF_INET6 | ||
| 4292 | else if (it->ifa_addr->sa_family == AF_INET6) | ||
| 4293 | { | ||
| 4294 | DECLARE_POINTER_ALIAS (sin6_1, struct sockaddr_in6, it->ifa_netmask); | ||
| 4295 | maskp = (uint32_t *) &sin6_1->sin6_addr; | ||
| 4296 | DECLARE_POINTER_ALIAS (sin6_2, struct sockaddr_in6, it->ifa_addr); | ||
| 4297 | addrp = (uint32_t *) &sin6_2->sin6_addr; | ||
| 4298 | len = sizeof (struct sockaddr_in6); | ||
| 4299 | addr_len = 4; | ||
| 4300 | } | ||
| 4305 | #endif | 4301 | #endif |
| 4306 | char namebuf[sizeof (ifq->ifr_name) + 1]; | 4302 | else |
| 4307 | ifreq = (struct ifreq *) ((char *) ifreq + len); | 4303 | continue; |
| 4308 | 4304 | ||
| 4309 | if (ifq->ifr_addr.sa_family != AF_INET) | 4305 | Lisp_Object addr = conv_sockaddr_to_lisp (it->ifa_addr, len); |
| 4310 | continue; | ||
| 4311 | 4306 | ||
| 4312 | memcpy (namebuf, ifq->ifr_name, sizeof (ifq->ifr_name)); | 4307 | if (full) |
| 4313 | namebuf[sizeof (ifq->ifr_name)] = 0; | 4308 | { |
| 4314 | res = Fcons (Fcons (build_string (namebuf), | 4309 | elt = Fcons (conv_sockaddr_to_lisp (it->ifa_netmask, len), elt); |
| 4315 | conv_sockaddr_to_lisp (&ifq->ifr_addr, | 4310 | /* There is an it->ifa_broadaddr field, but its contents are |
| 4316 | sizeof (struct sockaddr))), | 4311 | unreliable, so always calculate the broadcast address from |
| 4317 | res); | 4312 | the address and the netmask. */ |
| 4313 | int i; | ||
| 4314 | uint32_t mask; | ||
| 4315 | for (i = 0; i < addr_len; i++) | ||
| 4316 | { | ||
| 4317 | mask = maskp[i]; | ||
| 4318 | maskp[i] = (addrp[i] & mask) | ~mask; | ||
| 4319 | } | ||
| 4320 | elt = Fcons (conv_sockaddr_to_lisp (it->ifa_netmask, len), elt); | ||
| 4321 | elt = Fcons (addr, elt); | ||
| 4322 | } | ||
| 4323 | else | ||
| 4324 | { | ||
| 4325 | elt = addr; | ||
| 4326 | } | ||
| 4327 | res = Fcons (Fcons (build_string (it->ifa_name), elt), res); | ||
| 4318 | } | 4328 | } |
| 4329 | #ifdef HAVE_FREEIFADDRS | ||
| 4330 | freeifaddrs (ifap); | ||
| 4331 | #endif | ||
| 4319 | 4332 | ||
| 4320 | xfree (buf); | ||
| 4321 | return res; | 4333 | return res; |
| 4322 | } | 4334 | } |
| 4323 | #endif /* SIOCGIFCONF */ | 4335 | #endif /* HAVE_GETIFADDRS */ |
| 4324 | 4336 | ||
| 4337 | #ifdef HAVE_NET_IF_H | ||
| 4325 | #if defined (SIOCGIFADDR) || defined (SIOCGIFHWADDR) || defined (SIOCGIFFLAGS) | 4338 | #if defined (SIOCGIFADDR) || defined (SIOCGIFHWADDR) || defined (SIOCGIFFLAGS) |
| 4326 | 4339 | ||
| 4327 | struct ifflag_def { | 4340 | struct ifflag_def { |
| @@ -4550,17 +4563,46 @@ network_interface_info (Lisp_Object ifname) | |||
| 4550 | #endif /* defined (HAVE_NET_IF_H) */ | 4563 | #endif /* defined (HAVE_NET_IF_H) */ |
| 4551 | 4564 | ||
| 4552 | DEFUN ("network-interface-list", Fnetwork_interface_list, | 4565 | DEFUN ("network-interface-list", Fnetwork_interface_list, |
| 4553 | Snetwork_interface_list, 0, 0, 0, | 4566 | Snetwork_interface_list, 0, 2, 0, |
| 4554 | doc: /* Return an alist of all network interfaces and their network address. | 4567 | doc: /* Return an alist of all network interfaces and their network address. |
| 4555 | Each element is a cons, the car of which is a string containing the | 4568 | Each element is cons of the form (IFNAME . IP) where IFNAME is a |
| 4556 | interface name, and the cdr is the network address in internal | 4569 | string containing the interface name, and IP is the network address in |
| 4557 | format; see the description of ADDRESS in `make-network-process'. | 4570 | internal format; see the description of ADDRESS in |
| 4571 | `make-network-process'. The interface name is not guaranteed to be | ||
| 4572 | unique. | ||
| 4573 | |||
| 4574 | Optional parameter FULL non-nil means return all IP address info for | ||
| 4575 | each interface. Each element is then a list of the form | ||
| 4576 | (IFNAME IP BCAST MASK) | ||
| 4577 | where IFNAME is the interface name, IP the IP address, | ||
| 4578 | BCAST the broadcast address, and MASK the network mask. | ||
| 4579 | |||
| 4580 | Optional parameter FAMILY controls the type of addresses to return. | ||
| 4581 | The default of nil means both IPv4 and IPv6, symbol `ipv4' means IPv4 | ||
| 4582 | only, symbol `ipv6' means IPv6 only. | ||
| 4583 | |||
| 4584 | See also `network-interface-info', which is limited to IPv4 only. | ||
| 4558 | 4585 | ||
| 4559 | If the information is not available, return nil. */) | 4586 | If the information is not available, return nil. */) |
| 4560 | (void) | 4587 | (Lisp_Object full, Lisp_Object family) |
| 4561 | { | 4588 | { |
| 4562 | #if (defined HAVE_NET_IF_H && defined SIOCGIFCONF) || defined WINDOWSNT | 4589 | #if defined HAVE_GETIFADDRS || defined WINDOWSNT |
| 4563 | return network_interface_list (); | 4590 | unsigned short match; |
| 4591 | bool full_info = false; | ||
| 4592 | |||
| 4593 | if (! NILP (full)) | ||
| 4594 | full_info = true; | ||
| 4595 | if (NILP (family)) | ||
| 4596 | match = 0; | ||
| 4597 | else if (EQ (family, Qipv4)) | ||
| 4598 | match = AF_INET; | ||
| 4599 | #ifdef AF_INET6 | ||
| 4600 | else if (EQ (family, Qipv6)) | ||
| 4601 | match = AF_INET6; | ||
| 4602 | #endif | ||
| 4603 | else | ||
| 4604 | error ("Unsupported address family"); | ||
| 4605 | return network_interface_list (full_info, match); | ||
| 4564 | #else | 4606 | #else |
| 4565 | return Qnil; | 4607 | return Qnil; |
| 4566 | #endif | 4608 | #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); | |||
| 291 | extern void restore_nofile_limit (void); | 291 | extern void restore_nofile_limit (void); |
| 292 | 292 | ||
| 293 | #ifdef WINDOWSNT | 293 | #ifdef WINDOWSNT |
| 294 | extern Lisp_Object network_interface_list (void); | 294 | extern Lisp_Object network_interface_list (bool full, unsigned short match); |
| 295 | extern Lisp_Object network_interface_info (Lisp_Object); | 295 | extern Lisp_Object network_interface_info (Lisp_Object); |
| 296 | #endif | 296 | #endif |
| 297 | 297 | ||
| @@ -227,6 +227,8 @@ typedef struct _REPARSE_DATA_BUFFER { | |||
| 227 | #undef connect | 227 | #undef connect |
| 228 | #undef htons | 228 | #undef htons |
| 229 | #undef ntohs | 229 | #undef ntohs |
| 230 | #undef htonl | ||
| 231 | #undef ntohl | ||
| 230 | #undef inet_addr | 232 | #undef inet_addr |
| 231 | #undef gethostname | 233 | #undef gethostname |
| 232 | #undef gethostbyname | 234 | #undef gethostbyname |
| @@ -326,6 +328,7 @@ static BOOL g_b_init_set_file_security_a; | |||
| 326 | static BOOL g_b_init_set_named_security_info_w; | 328 | static BOOL g_b_init_set_named_security_info_w; |
| 327 | static BOOL g_b_init_set_named_security_info_a; | 329 | static BOOL g_b_init_set_named_security_info_a; |
| 328 | static BOOL g_b_init_get_adapters_info; | 330 | static BOOL g_b_init_get_adapters_info; |
| 331 | static BOOL g_b_init_get_adapters_addresses; | ||
| 329 | static BOOL g_b_init_reg_open_key_ex_w; | 332 | static BOOL g_b_init_reg_open_key_ex_w; |
| 330 | static BOOL g_b_init_reg_query_value_ex_w; | 333 | static BOOL g_b_init_reg_query_value_ex_w; |
| 331 | static BOOL g_b_init_expand_environment_strings_w; | 334 | static BOOL g_b_init_expand_environment_strings_w; |
| @@ -503,6 +506,12 @@ typedef BOOL (WINAPI *IsValidSecurityDescriptor_Proc) (PSECURITY_DESCRIPTOR); | |||
| 503 | typedef DWORD (WINAPI *GetAdaptersInfo_Proc) ( | 506 | typedef DWORD (WINAPI *GetAdaptersInfo_Proc) ( |
| 504 | PIP_ADAPTER_INFO pAdapterInfo, | 507 | PIP_ADAPTER_INFO pAdapterInfo, |
| 505 | PULONG pOutBufLen); | 508 | PULONG pOutBufLen); |
| 509 | typedef DWORD (WINAPI *GetAdaptersAddresses_Proc) ( | ||
| 510 | ULONG, | ||
| 511 | ULONG, | ||
| 512 | PVOID, | ||
| 513 | PIP_ADAPTER_ADDRESSES, | ||
| 514 | PULONG); | ||
| 506 | 515 | ||
| 507 | int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int); | 516 | int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int); |
| 508 | int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL); | 517 | int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL); |
| @@ -1368,6 +1377,31 @@ get_adapters_info (PIP_ADAPTER_INFO pAdapterInfo, PULONG pOutBufLen) | |||
| 1368 | return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen); | 1377 | return s_pfn_Get_Adapters_Info (pAdapterInfo, pOutBufLen); |
| 1369 | } | 1378 | } |
| 1370 | 1379 | ||
| 1380 | static DWORD WINAPI | ||
| 1381 | get_adapters_addresses (ULONG family, PIP_ADAPTER_ADDRESSES pAdapterAddresses, PULONG pOutBufLen) | ||
| 1382 | { | ||
| 1383 | static GetAdaptersAddresses_Proc s_pfn_Get_Adapters_Addresses = NULL; | ||
| 1384 | HMODULE hm_iphlpapi = NULL; | ||
| 1385 | |||
| 1386 | if (is_windows_9x () == TRUE) | ||
| 1387 | return ERROR_NOT_SUPPORTED; | ||
| 1388 | |||
| 1389 | if (g_b_init_get_adapters_addresses == 0) | ||
| 1390 | { | ||
| 1391 | g_b_init_get_adapters_addresses = 1; | ||
| 1392 | hm_iphlpapi = LoadLibrary ("Iphlpapi.dll"); | ||
| 1393 | if (hm_iphlpapi) | ||
| 1394 | s_pfn_Get_Adapters_Addresses = (GetAdaptersAddresses_Proc) | ||
| 1395 | get_proc_addr (hm_iphlpapi, "GetAdaptersAddresses"); | ||
| 1396 | } | ||
| 1397 | if (s_pfn_Get_Adapters_Addresses == NULL) | ||
| 1398 | return ERROR_NOT_SUPPORTED; | ||
| 1399 | ULONG flags = GAA_FLAG_SKIP_ANYCAST | ||
| 1400 | | GAA_FLAG_SKIP_MULTICAST | ||
| 1401 | | GAA_FLAG_SKIP_DNS_SERVER; | ||
| 1402 | return s_pfn_Get_Adapters_Addresses (family, flags, NULL, pAdapterAddresses, pOutBufLen); | ||
| 1403 | } | ||
| 1404 | |||
| 1371 | static LONG WINAPI | 1405 | static LONG WINAPI |
| 1372 | reg_open_key_ex_w (HKEY hkey, LPCWSTR lpSubKey, DWORD ulOptions, | 1406 | reg_open_key_ex_w (HKEY hkey, LPCWSTR lpSubKey, DWORD ulOptions, |
| 1373 | REGSAM samDesired, PHKEY phkResult) | 1407 | REGSAM samDesired, PHKEY phkResult) |
| @@ -7414,6 +7448,8 @@ int (PASCAL *pfn_WSACleanup) (void); | |||
| 7414 | 7448 | ||
| 7415 | u_short (PASCAL *pfn_htons) (u_short hostshort); | 7449 | u_short (PASCAL *pfn_htons) (u_short hostshort); |
| 7416 | u_short (PASCAL *pfn_ntohs) (u_short netshort); | 7450 | u_short (PASCAL *pfn_ntohs) (u_short netshort); |
| 7451 | u_long (PASCAL *pfn_htonl) (u_long hostlong); | ||
| 7452 | u_long (PASCAL *pfn_ntohl) (u_long netlong); | ||
| 7417 | unsigned long (PASCAL *pfn_inet_addr) (const char * cp); | 7453 | unsigned long (PASCAL *pfn_inet_addr) (const char * cp); |
| 7418 | int (PASCAL *pfn_gethostname) (char * name, int namelen); | 7454 | int (PASCAL *pfn_gethostname) (char * name, int namelen); |
| 7419 | struct hostent * (PASCAL *pfn_gethostbyname) (const char * name); | 7455 | struct hostent * (PASCAL *pfn_gethostbyname) (const char * name); |
| @@ -7504,6 +7540,8 @@ init_winsock (int load_now) | |||
| 7504 | LOAD_PROC (shutdown); | 7540 | LOAD_PROC (shutdown); |
| 7505 | LOAD_PROC (htons); | 7541 | LOAD_PROC (htons); |
| 7506 | LOAD_PROC (ntohs); | 7542 | LOAD_PROC (ntohs); |
| 7543 | LOAD_PROC (htonl); | ||
| 7544 | LOAD_PROC (ntohl); | ||
| 7507 | LOAD_PROC (inet_addr); | 7545 | LOAD_PROC (inet_addr); |
| 7508 | LOAD_PROC (gethostname); | 7546 | LOAD_PROC (gethostname); |
| 7509 | LOAD_PROC (gethostbyname); | 7547 | LOAD_PROC (gethostbyname); |
| @@ -7884,6 +7922,19 @@ sys_ntohs (u_short netshort) | |||
| 7884 | return (winsock_lib != NULL) ? | 7922 | return (winsock_lib != NULL) ? |
| 7885 | pfn_ntohs (netshort) : netshort; | 7923 | pfn_ntohs (netshort) : netshort; |
| 7886 | } | 7924 | } |
| 7925 | u_long | ||
| 7926 | sys_htonl (u_long hostlong) | ||
| 7927 | { | ||
| 7928 | return (winsock_lib != NULL) ? | ||
| 7929 | pfn_htonl (hostlong) : hostlong; | ||
| 7930 | } | ||
| 7931 | |||
| 7932 | u_long | ||
| 7933 | sys_ntohl (u_long netlong) | ||
| 7934 | { | ||
| 7935 | return (winsock_lib != NULL) ? | ||
| 7936 | pfn_ntohl (netlong) : netlong; | ||
| 7937 | } | ||
| 7887 | 7938 | ||
| 7888 | unsigned long | 7939 | unsigned long |
| 7889 | sys_inet_addr (const char * cp) | 7940 | sys_inet_addr (const char * cp) |
| @@ -9382,9 +9433,197 @@ network_interface_get_info (Lisp_Object ifname) | |||
| 9382 | } | 9433 | } |
| 9383 | 9434 | ||
| 9384 | Lisp_Object | 9435 | Lisp_Object |
| 9385 | network_interface_list (void) | 9436 | network_interface_list (bool full, unsigned short match) |
| 9386 | { | 9437 | { |
| 9387 | return network_interface_get_info (Qnil); | 9438 | ULONG ainfo_len = sizeof (IP_ADAPTER_ADDRESSES); |
| 9439 | ULONG family = match; | ||
| 9440 | IP_ADAPTER_ADDRESSES *adapter, *ainfo = xmalloc (ainfo_len); | ||
| 9441 | DWORD retval = get_adapters_addresses (family, ainfo, &ainfo_len); | ||
| 9442 | Lisp_Object res = Qnil; | ||
| 9443 | |||
| 9444 | if (retval == ERROR_BUFFER_OVERFLOW) | ||
| 9445 | { | ||
| 9446 | ainfo = xrealloc (ainfo, ainfo_len); | ||
| 9447 | retval = get_adapters_addresses (family, ainfo, &ainfo_len); | ||
| 9448 | } | ||
| 9449 | |||
| 9450 | if (retval != ERROR_SUCCESS) | ||
| 9451 | { | ||
| 9452 | xfree (ainfo); | ||
| 9453 | return res; | ||
| 9454 | } | ||
| 9455 | |||
| 9456 | /* For the below, we need some winsock functions, so make sure | ||
| 9457 | the winsock DLL is loaded. If we cannot successfully load | ||
| 9458 | it, they will have no use of the information we provide, | ||
| 9459 | anyway, so punt. */ | ||
| 9460 | if (!winsock_lib && !init_winsock (1)) | ||
| 9461 | return res; | ||
| 9462 | |||
| 9463 | int eth_count = 0, tr_count = 0, fddi_count = 0, ppp_count = 0; | ||
| 9464 | int sl_count = 0, wlan_count = 0, lo_count = 0, ifx_count = 0; | ||
| 9465 | int tnl_count = 0; | ||
| 9466 | int if_num; | ||
| 9467 | char namebuf[MAX_ADAPTER_NAME_LENGTH + 4]; | ||
| 9468 | static const char *ifmt[] = { | ||
| 9469 | "eth%d", "tr%d", "fddi%d", "ppp%d", "sl%d", "wlan%d", | ||
| 9470 | "lo%d", "ifx%d", "tunnel%d" | ||
| 9471 | }; | ||
| 9472 | enum { | ||
| 9473 | NONE = -1, | ||
| 9474 | ETHERNET = 0, | ||
| 9475 | TOKENRING = 1, | ||
| 9476 | FDDI = 2, | ||
| 9477 | PPP = 3, | ||
| 9478 | SLIP = 4, | ||
| 9479 | WLAN = 5, | ||
| 9480 | LOOPBACK = 6, | ||
| 9481 | OTHER_IF = 7, | ||
| 9482 | TUNNEL = 8 | ||
| 9483 | } ifmt_idx; | ||
| 9484 | |||
| 9485 | for (adapter = ainfo; adapter; adapter = adapter->Next) | ||
| 9486 | { | ||
| 9487 | |||
| 9488 | /* Present Unix-compatible interface names, instead of the | ||
| 9489 | Windows names, which are really GUIDs not readable by | ||
| 9490 | humans. */ | ||
| 9491 | |||
| 9492 | switch (adapter->IfType) | ||
| 9493 | { | ||
| 9494 | case IF_TYPE_ETHERNET_CSMACD: | ||
| 9495 | ifmt_idx = ETHERNET; | ||
| 9496 | if_num = eth_count++; | ||
| 9497 | break; | ||
| 9498 | case IF_TYPE_ISO88025_TOKENRING: | ||
| 9499 | ifmt_idx = TOKENRING; | ||
| 9500 | if_num = tr_count++; | ||
| 9501 | break; | ||
| 9502 | case IF_TYPE_FDDI: | ||
| 9503 | ifmt_idx = FDDI; | ||
| 9504 | if_num = fddi_count++; | ||
| 9505 | break; | ||
| 9506 | case IF_TYPE_PPP: | ||
| 9507 | ifmt_idx = PPP; | ||
| 9508 | if_num = ppp_count++; | ||
| 9509 | break; | ||
| 9510 | case IF_TYPE_SLIP: | ||
| 9511 | ifmt_idx = SLIP; | ||
| 9512 | if_num = sl_count++; | ||
| 9513 | break; | ||
| 9514 | case IF_TYPE_IEEE80211: | ||
| 9515 | ifmt_idx = WLAN; | ||
| 9516 | if_num = wlan_count++; | ||
| 9517 | break; | ||
| 9518 | case IF_TYPE_SOFTWARE_LOOPBACK: | ||
| 9519 | ifmt_idx = LOOPBACK; | ||
| 9520 | if_num = lo_count++; | ||
| 9521 | break; | ||
| 9522 | case IF_TYPE_TUNNEL: | ||
| 9523 | ifmt_idx = TUNNEL; | ||
| 9524 | if_num = tnl_count++; | ||
| 9525 | break; | ||
| 9526 | default: | ||
| 9527 | ifmt_idx = OTHER_IF; | ||
| 9528 | if_num = ifx_count++; | ||
| 9529 | break; | ||
| 9530 | } | ||
| 9531 | sprintf (namebuf, ifmt[ifmt_idx], if_num); | ||
| 9532 | |||
| 9533 | IP_ADAPTER_UNICAST_ADDRESS *address; | ||
| 9534 | for (address = adapter->FirstUnicastAddress; address; address = address->Next) | ||
| 9535 | { | ||
| 9536 | int len; | ||
| 9537 | int addr_len; | ||
| 9538 | uint32_t *maskp; | ||
| 9539 | uint32_t *addrp; | ||
| 9540 | Lisp_Object elt = Qnil; | ||
| 9541 | struct sockaddr *ifa_addr = address->Address.lpSockaddr; | ||
| 9542 | |||
| 9543 | if (ifa_addr == NULL) | ||
| 9544 | continue; | ||
| 9545 | if (match && ifa_addr->sa_family != match) | ||
| 9546 | continue; | ||
| 9547 | |||
| 9548 | struct sockaddr_in ipv4; | ||
| 9549 | #ifdef AF_INET6 | ||
| 9550 | struct sockaddr_in6 ipv6; | ||
| 9551 | #endif | ||
| 9552 | struct sockaddr *sin; | ||
| 9553 | |||
| 9554 | if (ifa_addr->sa_family == AF_INET) | ||
| 9555 | { | ||
| 9556 | ipv4.sin_family = AF_INET; | ||
| 9557 | ipv4.sin_port = 0; | ||
| 9558 | DECLARE_POINTER_ALIAS (sin_in, struct sockaddr_in, ifa_addr); | ||
| 9559 | addrp = (uint32_t *)&sin_in->sin_addr; | ||
| 9560 | maskp = (uint32_t *)&ipv4.sin_addr; | ||
| 9561 | sin = (struct sockaddr *)&ipv4; | ||
| 9562 | len = sizeof (struct sockaddr_in); | ||
| 9563 | addr_len = 1; | ||
| 9564 | } | ||
| 9565 | #ifdef AF_INET6 | ||
| 9566 | else if (ifa_addr->sa_family == AF_INET6) | ||
| 9567 | { | ||
| 9568 | ipv6.sin6_family = AF_INET6; | ||
| 9569 | ipv6.sin6_port = 0; | ||
| 9570 | DECLARE_POINTER_ALIAS (sin_in6, struct sockaddr_in6, ifa_addr); | ||
| 9571 | addrp = (uint32_t *)&sin_in6->sin6_addr; | ||
| 9572 | maskp = (uint32_t *)&ipv6.sin6_addr; | ||
| 9573 | sin = (struct sockaddr *)&ipv6; | ||
| 9574 | len = sizeof (struct sockaddr_in6); | ||
| 9575 | addr_len = 4; | ||
| 9576 | } | ||
| 9577 | #endif | ||
| 9578 | else | ||
| 9579 | continue; | ||
| 9580 | |||
| 9581 | Lisp_Object addr = conv_sockaddr_to_lisp (ifa_addr, len); | ||
| 9582 | |||
| 9583 | if (full) | ||
| 9584 | { | ||
| 9585 | /* GetAdaptersAddress returns information in network | ||
| 9586 | byte order, so convert from host to network order | ||
| 9587 | when generating the netmask. */ | ||
| 9588 | int i; | ||
| 9589 | ULONG numbits = address->OnLinkPrefixLength; | ||
| 9590 | for (i = 0; i < addr_len; i++) | ||
| 9591 | { | ||
| 9592 | if (numbits >= 32) | ||
| 9593 | { | ||
| 9594 | maskp[i] = -1U; | ||
| 9595 | numbits -= 32; | ||
| 9596 | } | ||
| 9597 | else if (numbits) | ||
| 9598 | { | ||
| 9599 | maskp[i] = sys_htonl (-1U << (32 - numbits)); | ||
| 9600 | numbits = 0; | ||
| 9601 | } | ||
| 9602 | else | ||
| 9603 | { | ||
| 9604 | maskp[i] = 0; | ||
| 9605 | } | ||
| 9606 | } | ||
| 9607 | elt = Fcons (conv_sockaddr_to_lisp (sin, len), elt); | ||
| 9608 | uint32_t mask; | ||
| 9609 | for (i = 0; i < addr_len; i++) | ||
| 9610 | { | ||
| 9611 | mask = maskp[i]; | ||
| 9612 | maskp[i] = (addrp[i] & mask) | ~mask; | ||
| 9613 | |||
| 9614 | } | ||
| 9615 | elt = Fcons (conv_sockaddr_to_lisp (sin, len), elt); | ||
| 9616 | elt = Fcons (addr, elt); | ||
| 9617 | } | ||
| 9618 | else | ||
| 9619 | { | ||
| 9620 | elt = addr; | ||
| 9621 | } | ||
| 9622 | res = Fcons (Fcons (build_string (namebuf), elt), res); | ||
| 9623 | } | ||
| 9624 | } | ||
| 9625 | xfree (ainfo); | ||
| 9626 | return res; | ||
| 9388 | } | 9627 | } |
| 9389 | 9628 | ||
| 9390 | Lisp_Object | 9629 | Lisp_Object |
| @@ -10099,6 +10338,7 @@ globals_of_w32 (void) | |||
| 10099 | g_b_init_set_named_security_info_w = 0; | 10338 | g_b_init_set_named_security_info_w = 0; |
| 10100 | g_b_init_set_named_security_info_a = 0; | 10339 | g_b_init_set_named_security_info_a = 0; |
| 10101 | g_b_init_get_adapters_info = 0; | 10340 | g_b_init_get_adapters_info = 0; |
| 10341 | g_b_init_get_adapters_addresses = 0; | ||
| 10102 | g_b_init_reg_open_key_ex_w = 0; | 10342 | g_b_init_reg_open_key_ex_w = 0; |
| 10103 | g_b_init_reg_query_value_ex_w = 0; | 10343 | g_b_init_reg_query_value_ex_w = 0; |
| 10104 | g_b_init_expand_environment_strings_w = 0; | 10344 | g_b_init_expand_environment_strings_w = 0; |