15e9cd1aeSAssar Westerlund /* 2*ae771770SStanislav Sedov * Copyright (c) 2000 - 2002, 2005 Kungliga Tekniska Högskolan 35e9cd1aeSAssar Westerlund * (Royal Institute of Technology, Stockholm, Sweden). 45e9cd1aeSAssar Westerlund * All rights reserved. 55e9cd1aeSAssar Westerlund * 65e9cd1aeSAssar Westerlund * Redistribution and use in source and binary forms, with or without 75e9cd1aeSAssar Westerlund * modification, are permitted provided that the following conditions 85e9cd1aeSAssar Westerlund * are met: 95e9cd1aeSAssar Westerlund * 105e9cd1aeSAssar Westerlund * 1. Redistributions of source code must retain the above copyright 115e9cd1aeSAssar Westerlund * notice, this list of conditions and the following disclaimer. 125e9cd1aeSAssar Westerlund * 135e9cd1aeSAssar Westerlund * 2. Redistributions in binary form must reproduce the above copyright 145e9cd1aeSAssar Westerlund * notice, this list of conditions and the following disclaimer in the 155e9cd1aeSAssar Westerlund * documentation and/or other materials provided with the distribution. 165e9cd1aeSAssar Westerlund * 175e9cd1aeSAssar Westerlund * 3. Neither the name of the Institute nor the names of its contributors 185e9cd1aeSAssar Westerlund * may be used to endorse or promote products derived from this software 195e9cd1aeSAssar Westerlund * without specific prior written permission. 205e9cd1aeSAssar Westerlund * 215e9cd1aeSAssar Westerlund * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 225e9cd1aeSAssar Westerlund * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 235e9cd1aeSAssar Westerlund * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 245e9cd1aeSAssar Westerlund * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 255e9cd1aeSAssar Westerlund * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 265e9cd1aeSAssar Westerlund * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 275e9cd1aeSAssar Westerlund * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 285e9cd1aeSAssar Westerlund * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 295e9cd1aeSAssar Westerlund * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 305e9cd1aeSAssar Westerlund * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 315e9cd1aeSAssar Westerlund * SUCH DAMAGE. 325e9cd1aeSAssar Westerlund */ 335e9cd1aeSAssar Westerlund 345e9cd1aeSAssar Westerlund #include <config.h> 355e9cd1aeSAssar Westerlund #include "roken.h" 365e9cd1aeSAssar Westerlund 375e9cd1aeSAssar Westerlund #ifdef __osf__ 385e9cd1aeSAssar Westerlund /* hate */ 395e9cd1aeSAssar Westerlund struct rtentry; 405e9cd1aeSAssar Westerlund struct mbuf; 415e9cd1aeSAssar Westerlund #endif 425e9cd1aeSAssar Westerlund #ifdef HAVE_NET_IF_H 435e9cd1aeSAssar Westerlund #include <net/if.h> 445e9cd1aeSAssar Westerlund #endif 455e9cd1aeSAssar Westerlund 465e9cd1aeSAssar Westerlund #ifdef HAVE_SYS_SOCKIO_H 475e9cd1aeSAssar Westerlund #include <sys/sockio.h> 485e9cd1aeSAssar Westerlund #endif /* HAVE_SYS_SOCKIO_H */ 495e9cd1aeSAssar Westerlund 505e9cd1aeSAssar Westerlund #ifdef HAVE_NETINET_IN6_VAR_H 515e9cd1aeSAssar Westerlund #include <netinet/in6_var.h> 525e9cd1aeSAssar Westerlund #endif /* HAVE_NETINET_IN6_VAR_H */ 535e9cd1aeSAssar Westerlund 545e9cd1aeSAssar Westerlund #include <ifaddrs.h> 555e9cd1aeSAssar Westerlund 56c19800e8SDoug Rabson #ifdef __hpux 57c19800e8SDoug Rabson #define lifconf if_laddrconf 58c19800e8SDoug Rabson #define lifc_len iflc_len 59c19800e8SDoug Rabson #define lifc_buf iflc_buf 60c19800e8SDoug Rabson #define lifc_req iflc_req 61c19800e8SDoug Rabson 62c19800e8SDoug Rabson #define lifreq if_laddrreq 63c19800e8SDoug Rabson #define lifr_addr iflr_addr 64c19800e8SDoug Rabson #define lifr_name iflr_name 65c19800e8SDoug Rabson #define lifr_dstaddr iflr_dstaddr 66c19800e8SDoug Rabson #define lifr_broadaddr iflr_broadaddr 67c19800e8SDoug Rabson #define lifr_flags iflr_flags 68c19800e8SDoug Rabson #define lifr_index iflr_index 69c19800e8SDoug Rabson #endif 70c19800e8SDoug Rabson 710cadf2f4SJacques Vidrine #ifdef AF_NETLINK 720cadf2f4SJacques Vidrine 730cadf2f4SJacques Vidrine /* 740cadf2f4SJacques Vidrine * The linux - AF_NETLINK version of getifaddrs - from Usagi. 750cadf2f4SJacques Vidrine * Linux does not return v6 addresses from SIOCGIFCONF. 760cadf2f4SJacques Vidrine */ 770cadf2f4SJacques Vidrine 780cadf2f4SJacques Vidrine /* $USAGI: ifaddrs.c,v 1.18 2002/03/06 01:50:46 yoshfuji Exp $ */ 790cadf2f4SJacques Vidrine 800cadf2f4SJacques Vidrine /************************************************************************** 810cadf2f4SJacques Vidrine * ifaddrs.c 820cadf2f4SJacques Vidrine * Copyright (C)2000 Hideaki YOSHIFUJI, All Rights Reserved. 830cadf2f4SJacques Vidrine * 840cadf2f4SJacques Vidrine * Redistribution and use in source and binary forms, with or without 850cadf2f4SJacques Vidrine * modification, are permitted provided that the following conditions 860cadf2f4SJacques Vidrine * are met: 870cadf2f4SJacques Vidrine * 1. Redistributions of source code must retain the above copyright 880cadf2f4SJacques Vidrine * notice, this list of conditions and the following disclaimer. 890cadf2f4SJacques Vidrine * 2. Redistributions in binary form must reproduce the above copyright 900cadf2f4SJacques Vidrine * notice, this list of conditions and the following disclaimer in the 910cadf2f4SJacques Vidrine * documentation and/or other materials provided with the distribution. 920cadf2f4SJacques Vidrine * 3. Neither the name of the author nor the names of its contributors 930cadf2f4SJacques Vidrine * may be used to endorse or promote products derived from this software 940cadf2f4SJacques Vidrine * without specific prior written permission. 950cadf2f4SJacques Vidrine * 960cadf2f4SJacques Vidrine * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 970cadf2f4SJacques Vidrine * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 980cadf2f4SJacques Vidrine * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 990cadf2f4SJacques Vidrine * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1000cadf2f4SJacques Vidrine * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1010cadf2f4SJacques Vidrine * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1020cadf2f4SJacques Vidrine * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 1030cadf2f4SJacques Vidrine * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 1040cadf2f4SJacques Vidrine * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 1050cadf2f4SJacques Vidrine * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 1060cadf2f4SJacques Vidrine * SUCH DAMAGE. 1070cadf2f4SJacques Vidrine */ 1080cadf2f4SJacques Vidrine 1090cadf2f4SJacques Vidrine #include "config.h" 1100cadf2f4SJacques Vidrine 1110cadf2f4SJacques Vidrine #include <string.h> 1120cadf2f4SJacques Vidrine #include <time.h> 1130cadf2f4SJacques Vidrine #include <malloc.h> 1140cadf2f4SJacques Vidrine #include <errno.h> 1150cadf2f4SJacques Vidrine #include <unistd.h> 1160cadf2f4SJacques Vidrine 1170cadf2f4SJacques Vidrine #include <sys/socket.h> 1180cadf2f4SJacques Vidrine #include <asm/types.h> 1190cadf2f4SJacques Vidrine #include <linux/netlink.h> 1200cadf2f4SJacques Vidrine #include <linux/rtnetlink.h> 1210cadf2f4SJacques Vidrine #include <sys/types.h> 1220cadf2f4SJacques Vidrine #include <sys/socket.h> 123c19800e8SDoug Rabson #include <sys/poll.h> 1240cadf2f4SJacques Vidrine #include <netpacket/packet.h> 1250cadf2f4SJacques Vidrine #include <net/ethernet.h> /* the L2 protocols */ 1260cadf2f4SJacques Vidrine #include <sys/uio.h> 1270cadf2f4SJacques Vidrine #include <net/if.h> 1280cadf2f4SJacques Vidrine #include <net/if_arp.h> 1290cadf2f4SJacques Vidrine #include <ifaddrs.h> 1300cadf2f4SJacques Vidrine #include <netinet/in.h> 1310cadf2f4SJacques Vidrine 1320cadf2f4SJacques Vidrine #define __set_errno(e) (errno = (e)) 1330cadf2f4SJacques Vidrine #define __close(fd) (close(fd)) 1340cadf2f4SJacques Vidrine #undef ifa_broadaddr 1350cadf2f4SJacques Vidrine #define ifa_broadaddr ifa_dstaddr 1360cadf2f4SJacques Vidrine #define IFA_NETMASK 1370cadf2f4SJacques Vidrine 1380cadf2f4SJacques Vidrine /* ====================================================================== */ 1390cadf2f4SJacques Vidrine struct nlmsg_list{ 1400cadf2f4SJacques Vidrine struct nlmsg_list *nlm_next; 1410cadf2f4SJacques Vidrine struct nlmsghdr *nlh; 1420cadf2f4SJacques Vidrine int size; 1430cadf2f4SJacques Vidrine time_t seq; 1440cadf2f4SJacques Vidrine }; 1450cadf2f4SJacques Vidrine 1460cadf2f4SJacques Vidrine struct rtmaddr_ifamap { 1470cadf2f4SJacques Vidrine void *address; 1480cadf2f4SJacques Vidrine void *local; 1490cadf2f4SJacques Vidrine #ifdef IFA_NETMASK 1500cadf2f4SJacques Vidrine void *netmask; 1510cadf2f4SJacques Vidrine #endif 1520cadf2f4SJacques Vidrine void *broadcast; 1530cadf2f4SJacques Vidrine #ifdef HAVE_IFADDRS_IFA_ANYCAST 1540cadf2f4SJacques Vidrine void *anycast; 1550cadf2f4SJacques Vidrine #endif 1560cadf2f4SJacques Vidrine int address_len; 1570cadf2f4SJacques Vidrine int local_len; 1580cadf2f4SJacques Vidrine #ifdef IFA_NETMASK 1590cadf2f4SJacques Vidrine int netmask_len; 1600cadf2f4SJacques Vidrine #endif 1610cadf2f4SJacques Vidrine int broadcast_len; 1620cadf2f4SJacques Vidrine #ifdef HAVE_IFADDRS_IFA_ANYCAST 1630cadf2f4SJacques Vidrine int anycast_len; 1640cadf2f4SJacques Vidrine #endif 1650cadf2f4SJacques Vidrine }; 1660cadf2f4SJacques Vidrine 1670cadf2f4SJacques Vidrine /* ====================================================================== */ 1680cadf2f4SJacques Vidrine static size_t 1690cadf2f4SJacques Vidrine ifa_sa_len(sa_family_t family, int len) 1700cadf2f4SJacques Vidrine { 1710cadf2f4SJacques Vidrine size_t size; 1720cadf2f4SJacques Vidrine switch(family){ 1730cadf2f4SJacques Vidrine case AF_INET: 1740cadf2f4SJacques Vidrine size = sizeof(struct sockaddr_in); 1750cadf2f4SJacques Vidrine break; 1760cadf2f4SJacques Vidrine case AF_INET6: 1770cadf2f4SJacques Vidrine size = sizeof(struct sockaddr_in6); 1780cadf2f4SJacques Vidrine break; 1790cadf2f4SJacques Vidrine case AF_PACKET: 1800cadf2f4SJacques Vidrine size = (size_t)(((struct sockaddr_ll *)NULL)->sll_addr) + len; 1810cadf2f4SJacques Vidrine if (size < sizeof(struct sockaddr_ll)) 1820cadf2f4SJacques Vidrine size = sizeof(struct sockaddr_ll); 1830cadf2f4SJacques Vidrine break; 1840cadf2f4SJacques Vidrine default: 1850cadf2f4SJacques Vidrine size = (size_t)(((struct sockaddr *)NULL)->sa_data) + len; 1860cadf2f4SJacques Vidrine if (size < sizeof(struct sockaddr)) 1870cadf2f4SJacques Vidrine size = sizeof(struct sockaddr); 188c19800e8SDoug Rabson break; 1890cadf2f4SJacques Vidrine } 1900cadf2f4SJacques Vidrine return size; 1910cadf2f4SJacques Vidrine } 1920cadf2f4SJacques Vidrine 1930cadf2f4SJacques Vidrine static void 1940cadf2f4SJacques Vidrine ifa_make_sockaddr(sa_family_t family, 1950cadf2f4SJacques Vidrine struct sockaddr *sa, 1960cadf2f4SJacques Vidrine void *p, size_t len, 1970cadf2f4SJacques Vidrine uint32_t scope, uint32_t scopeid) 1980cadf2f4SJacques Vidrine { 1990cadf2f4SJacques Vidrine if (sa == NULL) return; 2000cadf2f4SJacques Vidrine switch(family){ 2010cadf2f4SJacques Vidrine case AF_INET: 2020cadf2f4SJacques Vidrine memcpy(&((struct sockaddr_in*)sa)->sin_addr, (char *)p, len); 2030cadf2f4SJacques Vidrine break; 2040cadf2f4SJacques Vidrine case AF_INET6: 2050cadf2f4SJacques Vidrine memcpy(&((struct sockaddr_in6*)sa)->sin6_addr, (char *)p, len); 2060cadf2f4SJacques Vidrine if (IN6_IS_ADDR_LINKLOCAL(p) || 2070cadf2f4SJacques Vidrine IN6_IS_ADDR_MC_LINKLOCAL(p)){ 2080cadf2f4SJacques Vidrine ((struct sockaddr_in6*)sa)->sin6_scope_id = scopeid; 2090cadf2f4SJacques Vidrine } 2100cadf2f4SJacques Vidrine break; 2110cadf2f4SJacques Vidrine case AF_PACKET: 2120cadf2f4SJacques Vidrine memcpy(((struct sockaddr_ll*)sa)->sll_addr, (char *)p, len); 2130cadf2f4SJacques Vidrine ((struct sockaddr_ll*)sa)->sll_halen = len; 2140cadf2f4SJacques Vidrine break; 2150cadf2f4SJacques Vidrine default: 2160cadf2f4SJacques Vidrine memcpy(sa->sa_data, p, len); /*XXX*/ 2170cadf2f4SJacques Vidrine break; 2180cadf2f4SJacques Vidrine } 2190cadf2f4SJacques Vidrine sa->sa_family = family; 2200cadf2f4SJacques Vidrine #ifdef HAVE_SOCKADDR_SA_LEN 2210cadf2f4SJacques Vidrine sa->sa_len = ifa_sa_len(family, len); 2220cadf2f4SJacques Vidrine #endif 2230cadf2f4SJacques Vidrine } 2240cadf2f4SJacques Vidrine 2250cadf2f4SJacques Vidrine #ifndef IFA_NETMASK 2260cadf2f4SJacques Vidrine static struct sockaddr * 2270cadf2f4SJacques Vidrine ifa_make_sockaddr_mask(sa_family_t family, 2280cadf2f4SJacques Vidrine struct sockaddr *sa, 2290cadf2f4SJacques Vidrine uint32_t prefixlen) 2300cadf2f4SJacques Vidrine { 2310cadf2f4SJacques Vidrine int i; 2320cadf2f4SJacques Vidrine char *p = NULL, c; 2330cadf2f4SJacques Vidrine uint32_t max_prefixlen = 0; 2340cadf2f4SJacques Vidrine 2350cadf2f4SJacques Vidrine if (sa == NULL) return NULL; 2360cadf2f4SJacques Vidrine switch(family){ 2370cadf2f4SJacques Vidrine case AF_INET: 2380cadf2f4SJacques Vidrine memset(&((struct sockaddr_in*)sa)->sin_addr, 0, sizeof(((struct sockaddr_in*)sa)->sin_addr)); 2390cadf2f4SJacques Vidrine p = (char *)&((struct sockaddr_in*)sa)->sin_addr; 2400cadf2f4SJacques Vidrine max_prefixlen = 32; 2410cadf2f4SJacques Vidrine break; 2420cadf2f4SJacques Vidrine case AF_INET6: 2430cadf2f4SJacques Vidrine memset(&((struct sockaddr_in6*)sa)->sin6_addr, 0, sizeof(((struct sockaddr_in6*)sa)->sin6_addr)); 2440cadf2f4SJacques Vidrine p = (char *)&((struct sockaddr_in6*)sa)->sin6_addr; 2450cadf2f4SJacques Vidrine #if 0 /* XXX: fill scope-id? */ 2460cadf2f4SJacques Vidrine if (IN6_IS_ADDR_LINKLOCAL(p) || 2470cadf2f4SJacques Vidrine IN6_IS_ADDR_MC_LINKLOCAL(p)){ 2480cadf2f4SJacques Vidrine ((struct sockaddr_in6*)sa)->sin6_scope_id = scopeid; 2490cadf2f4SJacques Vidrine } 2500cadf2f4SJacques Vidrine #endif 2510cadf2f4SJacques Vidrine max_prefixlen = 128; 2520cadf2f4SJacques Vidrine break; 2530cadf2f4SJacques Vidrine default: 2540cadf2f4SJacques Vidrine return NULL; 2550cadf2f4SJacques Vidrine } 2560cadf2f4SJacques Vidrine sa->sa_family = family; 2570cadf2f4SJacques Vidrine #ifdef HAVE_SOCKADDR_SA_LEN 2580cadf2f4SJacques Vidrine sa->sa_len = ifa_sa_len(family, len); 2590cadf2f4SJacques Vidrine #endif 2600cadf2f4SJacques Vidrine if (p){ 2610cadf2f4SJacques Vidrine if (prefixlen > max_prefixlen) 2620cadf2f4SJacques Vidrine prefixlen = max_prefixlen; 2630cadf2f4SJacques Vidrine for (i=0; i<(prefixlen / 8); i++) 2640cadf2f4SJacques Vidrine *p++ = 0xff; 2650cadf2f4SJacques Vidrine c = 0xff; 2660cadf2f4SJacques Vidrine c <<= (8 - (prefixlen % 8)); 2670cadf2f4SJacques Vidrine *p = c; 2680cadf2f4SJacques Vidrine } 2690cadf2f4SJacques Vidrine return sa; 2700cadf2f4SJacques Vidrine } 2710cadf2f4SJacques Vidrine #endif 2720cadf2f4SJacques Vidrine 2730cadf2f4SJacques Vidrine /* ====================================================================== */ 2740cadf2f4SJacques Vidrine static int 2750cadf2f4SJacques Vidrine nl_sendreq(int sd, int request, int flags, int *seq) 2760cadf2f4SJacques Vidrine { 2770cadf2f4SJacques Vidrine char reqbuf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 2780cadf2f4SJacques Vidrine NLMSG_ALIGN(sizeof(struct rtgenmsg))]; 2790cadf2f4SJacques Vidrine struct sockaddr_nl nladdr; 2800cadf2f4SJacques Vidrine struct nlmsghdr *req_hdr; 2810cadf2f4SJacques Vidrine struct rtgenmsg *req_msg; 2820cadf2f4SJacques Vidrine time_t t = time(NULL); 2830cadf2f4SJacques Vidrine 2840cadf2f4SJacques Vidrine if (seq) *seq = t; 2850cadf2f4SJacques Vidrine memset(&reqbuf, 0, sizeof(reqbuf)); 2860cadf2f4SJacques Vidrine req_hdr = (struct nlmsghdr *)reqbuf; 2870cadf2f4SJacques Vidrine req_msg = (struct rtgenmsg *)NLMSG_DATA(req_hdr); 2880cadf2f4SJacques Vidrine req_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*req_msg)); 2890cadf2f4SJacques Vidrine req_hdr->nlmsg_type = request; 2900cadf2f4SJacques Vidrine req_hdr->nlmsg_flags = flags | NLM_F_REQUEST; 2910cadf2f4SJacques Vidrine req_hdr->nlmsg_pid = 0; 2920cadf2f4SJacques Vidrine req_hdr->nlmsg_seq = t; 2930cadf2f4SJacques Vidrine req_msg->rtgen_family = AF_UNSPEC; 2940cadf2f4SJacques Vidrine memset(&nladdr, 0, sizeof(nladdr)); 2950cadf2f4SJacques Vidrine nladdr.nl_family = AF_NETLINK; 2960cadf2f4SJacques Vidrine return (sendto(sd, (void *)req_hdr, req_hdr->nlmsg_len, 0, 2970cadf2f4SJacques Vidrine (struct sockaddr *)&nladdr, sizeof(nladdr))); 2980cadf2f4SJacques Vidrine } 2990cadf2f4SJacques Vidrine 3000cadf2f4SJacques Vidrine static int 3010cadf2f4SJacques Vidrine nl_recvmsg(int sd, int request, int seq, 3020cadf2f4SJacques Vidrine void *buf, size_t buflen, 3030cadf2f4SJacques Vidrine int *flags) 3040cadf2f4SJacques Vidrine { 3050cadf2f4SJacques Vidrine struct msghdr msg; 3060cadf2f4SJacques Vidrine struct iovec iov = { buf, buflen }; 3070cadf2f4SJacques Vidrine struct sockaddr_nl nladdr; 3080cadf2f4SJacques Vidrine int read_len; 3090cadf2f4SJacques Vidrine 3100cadf2f4SJacques Vidrine for (;;){ 3110cadf2f4SJacques Vidrine msg.msg_name = (void *)&nladdr; 3120cadf2f4SJacques Vidrine msg.msg_namelen = sizeof(nladdr); 3130cadf2f4SJacques Vidrine msg.msg_iov = &iov; 3140cadf2f4SJacques Vidrine msg.msg_iovlen = 1; 3150cadf2f4SJacques Vidrine msg.msg_control = NULL; 3160cadf2f4SJacques Vidrine msg.msg_controllen = 0; 3170cadf2f4SJacques Vidrine msg.msg_flags = 0; 3180cadf2f4SJacques Vidrine read_len = recvmsg(sd, &msg, 0); 3190cadf2f4SJacques Vidrine if ((read_len < 0 && errno == EINTR) || (msg.msg_flags & MSG_TRUNC)) 3200cadf2f4SJacques Vidrine continue; 3210cadf2f4SJacques Vidrine if (flags) *flags = msg.msg_flags; 3220cadf2f4SJacques Vidrine break; 3230cadf2f4SJacques Vidrine } 3240cadf2f4SJacques Vidrine return read_len; 3250cadf2f4SJacques Vidrine } 3260cadf2f4SJacques Vidrine 3270cadf2f4SJacques Vidrine static int 3280cadf2f4SJacques Vidrine nl_getmsg(int sd, int request, int seq, 3290cadf2f4SJacques Vidrine struct nlmsghdr **nlhp, 3300cadf2f4SJacques Vidrine int *done) 3310cadf2f4SJacques Vidrine { 3320cadf2f4SJacques Vidrine struct nlmsghdr *nh; 3330cadf2f4SJacques Vidrine size_t bufsize = 65536, lastbufsize = 0; 3340cadf2f4SJacques Vidrine void *buff = NULL; 3350cadf2f4SJacques Vidrine int result = 0, read_size; 3360cadf2f4SJacques Vidrine int msg_flags; 3370cadf2f4SJacques Vidrine pid_t pid = getpid(); 3380cadf2f4SJacques Vidrine for (;;){ 3390cadf2f4SJacques Vidrine void *newbuff = realloc(buff, bufsize); 3400cadf2f4SJacques Vidrine if (newbuff == NULL || bufsize < lastbufsize) { 3410cadf2f4SJacques Vidrine result = -1; 3420cadf2f4SJacques Vidrine break; 3430cadf2f4SJacques Vidrine } 3440cadf2f4SJacques Vidrine buff = newbuff; 3450cadf2f4SJacques Vidrine result = read_size = nl_recvmsg(sd, request, seq, buff, bufsize, &msg_flags); 3460cadf2f4SJacques Vidrine if (read_size < 0 || (msg_flags & MSG_TRUNC)){ 3470cadf2f4SJacques Vidrine lastbufsize = bufsize; 3480cadf2f4SJacques Vidrine bufsize *= 2; 3490cadf2f4SJacques Vidrine continue; 3500cadf2f4SJacques Vidrine } 3510cadf2f4SJacques Vidrine if (read_size == 0) break; 3520cadf2f4SJacques Vidrine nh = (struct nlmsghdr *)buff; 3530cadf2f4SJacques Vidrine for (nh = (struct nlmsghdr *)buff; 3540cadf2f4SJacques Vidrine NLMSG_OK(nh, read_size); 3550cadf2f4SJacques Vidrine nh = (struct nlmsghdr *)NLMSG_NEXT(nh, read_size)){ 3560cadf2f4SJacques Vidrine if (nh->nlmsg_pid != pid || 3570cadf2f4SJacques Vidrine nh->nlmsg_seq != seq) 3580cadf2f4SJacques Vidrine continue; 3590cadf2f4SJacques Vidrine if (nh->nlmsg_type == NLMSG_DONE){ 3600cadf2f4SJacques Vidrine (*done)++; 3610cadf2f4SJacques Vidrine break; /* ok */ 3620cadf2f4SJacques Vidrine } 3630cadf2f4SJacques Vidrine if (nh->nlmsg_type == NLMSG_ERROR){ 3640cadf2f4SJacques Vidrine struct nlmsgerr *nlerr = (struct nlmsgerr *)NLMSG_DATA(nh); 3650cadf2f4SJacques Vidrine result = -1; 3660cadf2f4SJacques Vidrine if (nh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) 3670cadf2f4SJacques Vidrine __set_errno(EIO); 3680cadf2f4SJacques Vidrine else 3690cadf2f4SJacques Vidrine __set_errno(-nlerr->error); 3700cadf2f4SJacques Vidrine break; 3710cadf2f4SJacques Vidrine } 3720cadf2f4SJacques Vidrine } 3730cadf2f4SJacques Vidrine break; 3740cadf2f4SJacques Vidrine } 3750cadf2f4SJacques Vidrine if (result < 0) 3760cadf2f4SJacques Vidrine if (buff){ 3770cadf2f4SJacques Vidrine int saved_errno = errno; 3780cadf2f4SJacques Vidrine free(buff); 3790cadf2f4SJacques Vidrine __set_errno(saved_errno); 3800cadf2f4SJacques Vidrine } 3810cadf2f4SJacques Vidrine *nlhp = (struct nlmsghdr *)buff; 3820cadf2f4SJacques Vidrine return result; 3830cadf2f4SJacques Vidrine } 3840cadf2f4SJacques Vidrine 3850cadf2f4SJacques Vidrine static int 3860cadf2f4SJacques Vidrine nl_getlist(int sd, int seq, 3870cadf2f4SJacques Vidrine int request, 3880cadf2f4SJacques Vidrine struct nlmsg_list **nlm_list, 3890cadf2f4SJacques Vidrine struct nlmsg_list **nlm_end) 3900cadf2f4SJacques Vidrine { 3910cadf2f4SJacques Vidrine struct nlmsghdr *nlh = NULL; 3920cadf2f4SJacques Vidrine int status; 3930cadf2f4SJacques Vidrine int done = 0; 394c19800e8SDoug Rabson int tries = 3; 3950cadf2f4SJacques Vidrine 396c19800e8SDoug Rabson try_again: 3970cadf2f4SJacques Vidrine status = nl_sendreq(sd, request, NLM_F_ROOT|NLM_F_MATCH, &seq); 3980cadf2f4SJacques Vidrine if (status < 0) 3990cadf2f4SJacques Vidrine return status; 4000cadf2f4SJacques Vidrine if (seq == 0) 4010cadf2f4SJacques Vidrine seq = (int)time(NULL); 4020cadf2f4SJacques Vidrine while(!done){ 403c19800e8SDoug Rabson struct pollfd pfd; 404c19800e8SDoug Rabson 405c19800e8SDoug Rabson pfd.fd = sd; 406c19800e8SDoug Rabson pfd.events = POLLIN | POLLPRI; 407c19800e8SDoug Rabson pfd.revents = 0; 408c19800e8SDoug Rabson status = poll(&pfd, 1, 1000); 409c19800e8SDoug Rabson if (status < 0) 410c19800e8SDoug Rabson return status; 411c19800e8SDoug Rabson else if (status == 0) { 412c19800e8SDoug Rabson seq++; 413c19800e8SDoug Rabson if (tries-- > 0) 414c19800e8SDoug Rabson goto try_again; 415c19800e8SDoug Rabson return -1; 416c19800e8SDoug Rabson } 417c19800e8SDoug Rabson 4180cadf2f4SJacques Vidrine status = nl_getmsg(sd, request, seq, &nlh, &done); 4190cadf2f4SJacques Vidrine if (status < 0) 4200cadf2f4SJacques Vidrine return status; 4210cadf2f4SJacques Vidrine if (nlh){ 4220cadf2f4SJacques Vidrine struct nlmsg_list *nlm_next = (struct nlmsg_list *)malloc(sizeof(struct nlmsg_list)); 4230cadf2f4SJacques Vidrine if (nlm_next == NULL){ 4240cadf2f4SJacques Vidrine int saved_errno = errno; 4250cadf2f4SJacques Vidrine free(nlh); 4260cadf2f4SJacques Vidrine __set_errno(saved_errno); 4270cadf2f4SJacques Vidrine status = -1; 4280cadf2f4SJacques Vidrine } else { 4290cadf2f4SJacques Vidrine nlm_next->nlm_next = NULL; 4300cadf2f4SJacques Vidrine nlm_next->nlh = (struct nlmsghdr *)nlh; 4310cadf2f4SJacques Vidrine nlm_next->size = status; 4320cadf2f4SJacques Vidrine nlm_next->seq = seq; 4330cadf2f4SJacques Vidrine if (*nlm_list == NULL){ 4340cadf2f4SJacques Vidrine *nlm_list = nlm_next; 4350cadf2f4SJacques Vidrine *nlm_end = nlm_next; 4360cadf2f4SJacques Vidrine } else { 4370cadf2f4SJacques Vidrine (*nlm_end)->nlm_next = nlm_next; 4380cadf2f4SJacques Vidrine *nlm_end = nlm_next; 4390cadf2f4SJacques Vidrine } 4400cadf2f4SJacques Vidrine } 4410cadf2f4SJacques Vidrine } 4420cadf2f4SJacques Vidrine } 4430cadf2f4SJacques Vidrine return status >= 0 ? seq : status; 4440cadf2f4SJacques Vidrine } 4450cadf2f4SJacques Vidrine 4460cadf2f4SJacques Vidrine /* ---------------------------------------------------------------------- */ 4470cadf2f4SJacques Vidrine static void 4480cadf2f4SJacques Vidrine free_nlmsglist(struct nlmsg_list *nlm0) 4490cadf2f4SJacques Vidrine { 450c19800e8SDoug Rabson struct nlmsg_list *nlm, *nlm_next; 4510cadf2f4SJacques Vidrine int saved_errno; 4520cadf2f4SJacques Vidrine if (!nlm0) 4530cadf2f4SJacques Vidrine return; 4540cadf2f4SJacques Vidrine saved_errno = errno; 455c19800e8SDoug Rabson for (nlm=nlm0; nlm; nlm=nlm_next){ 4560cadf2f4SJacques Vidrine if (nlm->nlh) 4570cadf2f4SJacques Vidrine free(nlm->nlh); 458c19800e8SDoug Rabson nlm_next=nlm->nlm_next; 459c19800e8SDoug Rabson free(nlm); 4600cadf2f4SJacques Vidrine } 4610cadf2f4SJacques Vidrine __set_errno(saved_errno); 4620cadf2f4SJacques Vidrine } 4630cadf2f4SJacques Vidrine 4640cadf2f4SJacques Vidrine static void 4650cadf2f4SJacques Vidrine free_data(void *data, void *ifdata) 4660cadf2f4SJacques Vidrine { 4670cadf2f4SJacques Vidrine int saved_errno = errno; 4680cadf2f4SJacques Vidrine if (data != NULL) free(data); 4690cadf2f4SJacques Vidrine if (ifdata != NULL) free(ifdata); 4700cadf2f4SJacques Vidrine __set_errno(saved_errno); 4710cadf2f4SJacques Vidrine } 4720cadf2f4SJacques Vidrine 4730cadf2f4SJacques Vidrine /* ---------------------------------------------------------------------- */ 4740cadf2f4SJacques Vidrine static void 4750cadf2f4SJacques Vidrine nl_close(int sd) 4760cadf2f4SJacques Vidrine { 4770cadf2f4SJacques Vidrine int saved_errno = errno; 4780cadf2f4SJacques Vidrine if (sd >= 0) __close(sd); 4790cadf2f4SJacques Vidrine __set_errno(saved_errno); 4800cadf2f4SJacques Vidrine } 4810cadf2f4SJacques Vidrine 4820cadf2f4SJacques Vidrine /* ---------------------------------------------------------------------- */ 4830cadf2f4SJacques Vidrine static int 4840cadf2f4SJacques Vidrine nl_open(void) 4850cadf2f4SJacques Vidrine { 4860cadf2f4SJacques Vidrine struct sockaddr_nl nladdr; 4870cadf2f4SJacques Vidrine int sd; 4880cadf2f4SJacques Vidrine 4890cadf2f4SJacques Vidrine sd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 4900cadf2f4SJacques Vidrine if (sd < 0) return -1; 4910cadf2f4SJacques Vidrine memset(&nladdr, 0, sizeof(nladdr)); 4920cadf2f4SJacques Vidrine nladdr.nl_family = AF_NETLINK; 4930cadf2f4SJacques Vidrine if (bind(sd, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0){ 4940cadf2f4SJacques Vidrine nl_close(sd); 4950cadf2f4SJacques Vidrine return -1; 4960cadf2f4SJacques Vidrine } 4970cadf2f4SJacques Vidrine return sd; 4980cadf2f4SJacques Vidrine } 4990cadf2f4SJacques Vidrine 5000cadf2f4SJacques Vidrine /* ====================================================================== */ 501*ae771770SStanislav Sedov ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 502c19800e8SDoug Rabson rk_getifaddrs(struct ifaddrs **ifap) 5030cadf2f4SJacques Vidrine { 5040cadf2f4SJacques Vidrine int sd; 5050cadf2f4SJacques Vidrine struct nlmsg_list *nlmsg_list, *nlmsg_end, *nlm; 5060cadf2f4SJacques Vidrine /* - - - - - - - - - - - - - - - */ 5070cadf2f4SJacques Vidrine int icnt; 5080cadf2f4SJacques Vidrine size_t dlen, xlen, nlen; 5090cadf2f4SJacques Vidrine uint32_t max_ifindex = 0; 5100cadf2f4SJacques Vidrine 5110cadf2f4SJacques Vidrine pid_t pid = getpid(); 5120cadf2f4SJacques Vidrine int seq; 5130cadf2f4SJacques Vidrine int result; 5140cadf2f4SJacques Vidrine int build ; /* 0 or 1 */ 5150cadf2f4SJacques Vidrine 5160cadf2f4SJacques Vidrine /* ---------------------------------- */ 5170cadf2f4SJacques Vidrine /* initialize */ 5180cadf2f4SJacques Vidrine icnt = dlen = xlen = nlen = 0; 5190cadf2f4SJacques Vidrine nlmsg_list = nlmsg_end = NULL; 5200cadf2f4SJacques Vidrine 5210cadf2f4SJacques Vidrine if (ifap) 5220cadf2f4SJacques Vidrine *ifap = NULL; 5230cadf2f4SJacques Vidrine 5240cadf2f4SJacques Vidrine /* ---------------------------------- */ 5250cadf2f4SJacques Vidrine /* open socket and bind */ 5260cadf2f4SJacques Vidrine sd = nl_open(); 5270cadf2f4SJacques Vidrine if (sd < 0) 5280cadf2f4SJacques Vidrine return -1; 5290cadf2f4SJacques Vidrine 5300cadf2f4SJacques Vidrine /* ---------------------------------- */ 5310cadf2f4SJacques Vidrine /* gather info */ 5320cadf2f4SJacques Vidrine if ((seq = nl_getlist(sd, 0, RTM_GETLINK, 5330cadf2f4SJacques Vidrine &nlmsg_list, &nlmsg_end)) < 0){ 5340cadf2f4SJacques Vidrine free_nlmsglist(nlmsg_list); 5350cadf2f4SJacques Vidrine nl_close(sd); 5360cadf2f4SJacques Vidrine return -1; 5370cadf2f4SJacques Vidrine } 5380cadf2f4SJacques Vidrine if ((seq = nl_getlist(sd, seq+1, RTM_GETADDR, 5390cadf2f4SJacques Vidrine &nlmsg_list, &nlmsg_end)) < 0){ 5400cadf2f4SJacques Vidrine free_nlmsglist(nlmsg_list); 5410cadf2f4SJacques Vidrine nl_close(sd); 5420cadf2f4SJacques Vidrine return -1; 5430cadf2f4SJacques Vidrine } 5440cadf2f4SJacques Vidrine 5450cadf2f4SJacques Vidrine /* ---------------------------------- */ 5460cadf2f4SJacques Vidrine /* Estimate size of result buffer and fill it */ 5470cadf2f4SJacques Vidrine for (build=0; build<=1; build++){ 5480cadf2f4SJacques Vidrine struct ifaddrs *ifl = NULL, *ifa = NULL; 5490cadf2f4SJacques Vidrine struct nlmsghdr *nlh, *nlh0; 5500cadf2f4SJacques Vidrine char *data = NULL, *xdata = NULL; 5510cadf2f4SJacques Vidrine void *ifdata = NULL; 5520cadf2f4SJacques Vidrine char *ifname = NULL, **iflist = NULL; 5530cadf2f4SJacques Vidrine uint16_t *ifflist = NULL; 5540cadf2f4SJacques Vidrine struct rtmaddr_ifamap ifamap; 5550cadf2f4SJacques Vidrine 5560cadf2f4SJacques Vidrine if (build){ 5570cadf2f4SJacques Vidrine data = calloc(1, 5580cadf2f4SJacques Vidrine NLMSG_ALIGN(sizeof(struct ifaddrs[icnt])) 5590cadf2f4SJacques Vidrine + dlen + xlen + nlen); 5600cadf2f4SJacques Vidrine ifa = (struct ifaddrs *)data; 5610cadf2f4SJacques Vidrine ifdata = calloc(1, 5620cadf2f4SJacques Vidrine NLMSG_ALIGN(sizeof(char *[max_ifindex+1])) 5630cadf2f4SJacques Vidrine + NLMSG_ALIGN(sizeof(uint16_t [max_ifindex+1]))); 5640cadf2f4SJacques Vidrine if (ifap != NULL) 5650cadf2f4SJacques Vidrine *ifap = (ifdata != NULL) ? ifa : NULL; 5660cadf2f4SJacques Vidrine else{ 5670cadf2f4SJacques Vidrine free_data(data, ifdata); 5680cadf2f4SJacques Vidrine result = 0; 5690cadf2f4SJacques Vidrine break; 5700cadf2f4SJacques Vidrine } 5710cadf2f4SJacques Vidrine if (data == NULL || ifdata == NULL){ 5720cadf2f4SJacques Vidrine free_data(data, ifdata); 5730cadf2f4SJacques Vidrine result = -1; 5740cadf2f4SJacques Vidrine break; 5750cadf2f4SJacques Vidrine } 5760cadf2f4SJacques Vidrine ifl = NULL; 5770cadf2f4SJacques Vidrine data += NLMSG_ALIGN(sizeof(struct ifaddrs)) * icnt; 5780cadf2f4SJacques Vidrine xdata = data + dlen; 5790cadf2f4SJacques Vidrine ifname = xdata + xlen; 5800cadf2f4SJacques Vidrine iflist = ifdata; 5810cadf2f4SJacques Vidrine ifflist = (uint16_t *)(((char *)iflist) + NLMSG_ALIGN(sizeof(char *[max_ifindex+1]))); 5820cadf2f4SJacques Vidrine } 5830cadf2f4SJacques Vidrine 5840cadf2f4SJacques Vidrine for (nlm=nlmsg_list; nlm; nlm=nlm->nlm_next){ 5850cadf2f4SJacques Vidrine int nlmlen = nlm->size; 5860cadf2f4SJacques Vidrine if (!(nlh0 = nlm->nlh)) 5870cadf2f4SJacques Vidrine continue; 5880cadf2f4SJacques Vidrine for (nlh = nlh0; 5890cadf2f4SJacques Vidrine NLMSG_OK(nlh, nlmlen); 5900cadf2f4SJacques Vidrine nlh=NLMSG_NEXT(nlh,nlmlen)){ 5910cadf2f4SJacques Vidrine struct ifinfomsg *ifim = NULL; 5920cadf2f4SJacques Vidrine struct ifaddrmsg *ifam = NULL; 5930cadf2f4SJacques Vidrine struct rtattr *rta; 5940cadf2f4SJacques Vidrine 5950cadf2f4SJacques Vidrine size_t nlm_struct_size = 0; 5960cadf2f4SJacques Vidrine sa_family_t nlm_family = 0; 5970cadf2f4SJacques Vidrine uint32_t nlm_scope = 0, nlm_index = 0; 5980cadf2f4SJacques Vidrine size_t sockaddr_size = 0; 5990cadf2f4SJacques Vidrine uint32_t nlm_prefixlen = 0; 6000cadf2f4SJacques Vidrine size_t rtasize; 6010cadf2f4SJacques Vidrine 6020cadf2f4SJacques Vidrine memset(&ifamap, 0, sizeof(ifamap)); 6030cadf2f4SJacques Vidrine 6040cadf2f4SJacques Vidrine /* check if the message is what we want */ 6050cadf2f4SJacques Vidrine if (nlh->nlmsg_pid != pid || 6060cadf2f4SJacques Vidrine nlh->nlmsg_seq != nlm->seq) 6070cadf2f4SJacques Vidrine continue; 6080cadf2f4SJacques Vidrine if (nlh->nlmsg_type == NLMSG_DONE){ 6090cadf2f4SJacques Vidrine break; /* ok */ 6100cadf2f4SJacques Vidrine } 6110cadf2f4SJacques Vidrine switch (nlh->nlmsg_type){ 6120cadf2f4SJacques Vidrine case RTM_NEWLINK: 6130cadf2f4SJacques Vidrine ifim = (struct ifinfomsg *)NLMSG_DATA(nlh); 6140cadf2f4SJacques Vidrine nlm_struct_size = sizeof(*ifim); 6150cadf2f4SJacques Vidrine nlm_family = ifim->ifi_family; 6160cadf2f4SJacques Vidrine nlm_scope = 0; 6170cadf2f4SJacques Vidrine nlm_index = ifim->ifi_index; 6180cadf2f4SJacques Vidrine nlm_prefixlen = 0; 6190cadf2f4SJacques Vidrine if (build) 6200cadf2f4SJacques Vidrine ifflist[nlm_index] = ifa->ifa_flags = ifim->ifi_flags; 6210cadf2f4SJacques Vidrine break; 6220cadf2f4SJacques Vidrine case RTM_NEWADDR: 6230cadf2f4SJacques Vidrine ifam = (struct ifaddrmsg *)NLMSG_DATA(nlh); 6240cadf2f4SJacques Vidrine nlm_struct_size = sizeof(*ifam); 6250cadf2f4SJacques Vidrine nlm_family = ifam->ifa_family; 6260cadf2f4SJacques Vidrine nlm_scope = ifam->ifa_scope; 6270cadf2f4SJacques Vidrine nlm_index = ifam->ifa_index; 6280cadf2f4SJacques Vidrine nlm_prefixlen = ifam->ifa_prefixlen; 6290cadf2f4SJacques Vidrine if (build) 6300cadf2f4SJacques Vidrine ifa->ifa_flags = ifflist[nlm_index]; 6310cadf2f4SJacques Vidrine break; 6320cadf2f4SJacques Vidrine default: 6330cadf2f4SJacques Vidrine continue; 6340cadf2f4SJacques Vidrine } 6350cadf2f4SJacques Vidrine 6360cadf2f4SJacques Vidrine if (!build){ 6370cadf2f4SJacques Vidrine if (max_ifindex < nlm_index) 6380cadf2f4SJacques Vidrine max_ifindex = nlm_index; 6390cadf2f4SJacques Vidrine } else { 6400cadf2f4SJacques Vidrine if (ifl != NULL) 6410cadf2f4SJacques Vidrine ifl->ifa_next = ifa; 6420cadf2f4SJacques Vidrine } 6430cadf2f4SJacques Vidrine 6440cadf2f4SJacques Vidrine rtasize = NLMSG_PAYLOAD(nlh, nlmlen) - NLMSG_ALIGN(nlm_struct_size); 6450cadf2f4SJacques Vidrine for (rta = (struct rtattr *)(((char *)NLMSG_DATA(nlh)) + NLMSG_ALIGN(nlm_struct_size)); 6460cadf2f4SJacques Vidrine RTA_OK(rta, rtasize); 6470cadf2f4SJacques Vidrine rta = RTA_NEXT(rta, rtasize)){ 6480cadf2f4SJacques Vidrine struct sockaddr **sap = NULL; 6490cadf2f4SJacques Vidrine void *rtadata = RTA_DATA(rta); 6500cadf2f4SJacques Vidrine size_t rtapayload = RTA_PAYLOAD(rta); 6510cadf2f4SJacques Vidrine socklen_t sa_len; 6520cadf2f4SJacques Vidrine 6530cadf2f4SJacques Vidrine switch(nlh->nlmsg_type){ 6540cadf2f4SJacques Vidrine case RTM_NEWLINK: 6550cadf2f4SJacques Vidrine switch(rta->rta_type){ 6560cadf2f4SJacques Vidrine case IFLA_ADDRESS: 6570cadf2f4SJacques Vidrine case IFLA_BROADCAST: 6580cadf2f4SJacques Vidrine if (build){ 6590cadf2f4SJacques Vidrine sap = (rta->rta_type == IFLA_ADDRESS) ? &ifa->ifa_addr : &ifa->ifa_broadaddr; 6600cadf2f4SJacques Vidrine *sap = (struct sockaddr *)data; 6610cadf2f4SJacques Vidrine } 6620cadf2f4SJacques Vidrine sa_len = ifa_sa_len(AF_PACKET, rtapayload); 6630cadf2f4SJacques Vidrine if (rta->rta_type == IFLA_ADDRESS) 6640cadf2f4SJacques Vidrine sockaddr_size = NLMSG_ALIGN(sa_len); 6650cadf2f4SJacques Vidrine if (!build){ 6660cadf2f4SJacques Vidrine dlen += NLMSG_ALIGN(sa_len); 6670cadf2f4SJacques Vidrine } else { 6680cadf2f4SJacques Vidrine memset(*sap, 0, sa_len); 6690cadf2f4SJacques Vidrine ifa_make_sockaddr(AF_PACKET, *sap, rtadata,rtapayload, 0,0); 6700cadf2f4SJacques Vidrine ((struct sockaddr_ll *)*sap)->sll_ifindex = nlm_index; 6710cadf2f4SJacques Vidrine ((struct sockaddr_ll *)*sap)->sll_hatype = ifim->ifi_type; 6720cadf2f4SJacques Vidrine data += NLMSG_ALIGN(sa_len); 6730cadf2f4SJacques Vidrine } 6740cadf2f4SJacques Vidrine break; 6750cadf2f4SJacques Vidrine case IFLA_IFNAME:/* Name of Interface */ 6760cadf2f4SJacques Vidrine if (!build) 6770cadf2f4SJacques Vidrine nlen += NLMSG_ALIGN(rtapayload + 1); 6780cadf2f4SJacques Vidrine else{ 6790cadf2f4SJacques Vidrine ifa->ifa_name = ifname; 6800cadf2f4SJacques Vidrine if (iflist[nlm_index] == NULL) 6810cadf2f4SJacques Vidrine iflist[nlm_index] = ifa->ifa_name; 6820cadf2f4SJacques Vidrine strncpy(ifa->ifa_name, rtadata, rtapayload); 6830cadf2f4SJacques Vidrine ifa->ifa_name[rtapayload] = '\0'; 6840cadf2f4SJacques Vidrine ifname += NLMSG_ALIGN(rtapayload + 1); 6850cadf2f4SJacques Vidrine } 6860cadf2f4SJacques Vidrine break; 6870cadf2f4SJacques Vidrine case IFLA_STATS:/* Statistics of Interface */ 6880cadf2f4SJacques Vidrine if (!build) 6890cadf2f4SJacques Vidrine xlen += NLMSG_ALIGN(rtapayload); 6900cadf2f4SJacques Vidrine else{ 6910cadf2f4SJacques Vidrine ifa->ifa_data = xdata; 6920cadf2f4SJacques Vidrine memcpy(ifa->ifa_data, rtadata, rtapayload); 6930cadf2f4SJacques Vidrine xdata += NLMSG_ALIGN(rtapayload); 6940cadf2f4SJacques Vidrine } 6950cadf2f4SJacques Vidrine break; 6960cadf2f4SJacques Vidrine case IFLA_UNSPEC: 6970cadf2f4SJacques Vidrine break; 6980cadf2f4SJacques Vidrine case IFLA_MTU: 6990cadf2f4SJacques Vidrine break; 7000cadf2f4SJacques Vidrine case IFLA_LINK: 7010cadf2f4SJacques Vidrine break; 7020cadf2f4SJacques Vidrine case IFLA_QDISC: 7030cadf2f4SJacques Vidrine break; 7040cadf2f4SJacques Vidrine default: 705c19800e8SDoug Rabson break; 7060cadf2f4SJacques Vidrine } 7070cadf2f4SJacques Vidrine break; 7080cadf2f4SJacques Vidrine case RTM_NEWADDR: 7090cadf2f4SJacques Vidrine if (nlm_family == AF_PACKET) break; 7100cadf2f4SJacques Vidrine switch(rta->rta_type){ 7110cadf2f4SJacques Vidrine case IFA_ADDRESS: 7120cadf2f4SJacques Vidrine ifamap.address = rtadata; 7130cadf2f4SJacques Vidrine ifamap.address_len = rtapayload; 7140cadf2f4SJacques Vidrine break; 7150cadf2f4SJacques Vidrine case IFA_LOCAL: 7160cadf2f4SJacques Vidrine ifamap.local = rtadata; 7170cadf2f4SJacques Vidrine ifamap.local_len = rtapayload; 7180cadf2f4SJacques Vidrine break; 7190cadf2f4SJacques Vidrine case IFA_BROADCAST: 7200cadf2f4SJacques Vidrine ifamap.broadcast = rtadata; 7210cadf2f4SJacques Vidrine ifamap.broadcast_len = rtapayload; 7220cadf2f4SJacques Vidrine break; 7230cadf2f4SJacques Vidrine #ifdef HAVE_IFADDRS_IFA_ANYCAST 7240cadf2f4SJacques Vidrine case IFA_ANYCAST: 7250cadf2f4SJacques Vidrine ifamap.anycast = rtadata; 7260cadf2f4SJacques Vidrine ifamap.anycast_len = rtapayload; 7270cadf2f4SJacques Vidrine break; 7280cadf2f4SJacques Vidrine #endif 7290cadf2f4SJacques Vidrine case IFA_LABEL: 7300cadf2f4SJacques Vidrine if (!build) 7310cadf2f4SJacques Vidrine nlen += NLMSG_ALIGN(rtapayload + 1); 7320cadf2f4SJacques Vidrine else{ 7330cadf2f4SJacques Vidrine ifa->ifa_name = ifname; 7340cadf2f4SJacques Vidrine if (iflist[nlm_index] == NULL) 7350cadf2f4SJacques Vidrine iflist[nlm_index] = ifname; 7360cadf2f4SJacques Vidrine strncpy(ifa->ifa_name, rtadata, rtapayload); 7370cadf2f4SJacques Vidrine ifa->ifa_name[rtapayload] = '\0'; 7380cadf2f4SJacques Vidrine ifname += NLMSG_ALIGN(rtapayload + 1); 7390cadf2f4SJacques Vidrine } 7400cadf2f4SJacques Vidrine break; 7410cadf2f4SJacques Vidrine case IFA_UNSPEC: 7420cadf2f4SJacques Vidrine break; 7430cadf2f4SJacques Vidrine case IFA_CACHEINFO: 7440cadf2f4SJacques Vidrine break; 7450cadf2f4SJacques Vidrine default: 746c19800e8SDoug Rabson break; 7470cadf2f4SJacques Vidrine } 7480cadf2f4SJacques Vidrine } 7490cadf2f4SJacques Vidrine } 7500cadf2f4SJacques Vidrine if (nlh->nlmsg_type == RTM_NEWADDR && 7510cadf2f4SJacques Vidrine nlm_family != AF_PACKET) { 7520cadf2f4SJacques Vidrine if (!ifamap.local) { 7530cadf2f4SJacques Vidrine ifamap.local = ifamap.address; 7540cadf2f4SJacques Vidrine ifamap.local_len = ifamap.address_len; 7550cadf2f4SJacques Vidrine } 7560cadf2f4SJacques Vidrine if (!ifamap.address) { 7570cadf2f4SJacques Vidrine ifamap.address = ifamap.local; 7580cadf2f4SJacques Vidrine ifamap.address_len = ifamap.local_len; 7590cadf2f4SJacques Vidrine } 7600cadf2f4SJacques Vidrine if (ifamap.address_len != ifamap.local_len || 7610cadf2f4SJacques Vidrine (ifamap.address != NULL && 7620cadf2f4SJacques Vidrine memcmp(ifamap.address, ifamap.local, ifamap.address_len))) { 7630cadf2f4SJacques Vidrine /* p2p; address is peer and local is ours */ 7640cadf2f4SJacques Vidrine ifamap.broadcast = ifamap.address; 7650cadf2f4SJacques Vidrine ifamap.broadcast_len = ifamap.address_len; 7660cadf2f4SJacques Vidrine ifamap.address = ifamap.local; 7670cadf2f4SJacques Vidrine ifamap.address_len = ifamap.local_len; 7680cadf2f4SJacques Vidrine } 7690cadf2f4SJacques Vidrine if (ifamap.address) { 7700cadf2f4SJacques Vidrine #ifndef IFA_NETMASK 7710cadf2f4SJacques Vidrine sockaddr_size = NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len)); 7720cadf2f4SJacques Vidrine #endif 7730cadf2f4SJacques Vidrine if (!build) 7740cadf2f4SJacques Vidrine dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len)); 7750cadf2f4SJacques Vidrine else { 7760cadf2f4SJacques Vidrine ifa->ifa_addr = (struct sockaddr *)data; 7770cadf2f4SJacques Vidrine ifa_make_sockaddr(nlm_family, ifa->ifa_addr, ifamap.address, ifamap.address_len, 7780cadf2f4SJacques Vidrine nlm_scope, nlm_index); 7790cadf2f4SJacques Vidrine data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.address_len)); 7800cadf2f4SJacques Vidrine } 7810cadf2f4SJacques Vidrine } 7820cadf2f4SJacques Vidrine #ifdef IFA_NETMASK 7830cadf2f4SJacques Vidrine if (ifamap.netmask) { 7840cadf2f4SJacques Vidrine if (!build) 7850cadf2f4SJacques Vidrine dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.netmask_len)); 7860cadf2f4SJacques Vidrine else { 7870cadf2f4SJacques Vidrine ifa->ifa_netmask = (struct sockaddr *)data; 7880cadf2f4SJacques Vidrine ifa_make_sockaddr(nlm_family, ifa->ifa_netmask, ifamap.netmask, ifamap.netmask_len, 7890cadf2f4SJacques Vidrine nlm_scope, nlm_index); 7900cadf2f4SJacques Vidrine data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.netmask_len)); 7910cadf2f4SJacques Vidrine } 7920cadf2f4SJacques Vidrine } 7930cadf2f4SJacques Vidrine #endif 7940cadf2f4SJacques Vidrine if (ifamap.broadcast) { 7950cadf2f4SJacques Vidrine if (!build) 7960cadf2f4SJacques Vidrine dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.broadcast_len)); 7970cadf2f4SJacques Vidrine else { 7980cadf2f4SJacques Vidrine ifa->ifa_broadaddr = (struct sockaddr *)data; 7990cadf2f4SJacques Vidrine ifa_make_sockaddr(nlm_family, ifa->ifa_broadaddr, ifamap.broadcast, ifamap.broadcast_len, 8000cadf2f4SJacques Vidrine nlm_scope, nlm_index); 8010cadf2f4SJacques Vidrine data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.broadcast_len)); 8020cadf2f4SJacques Vidrine } 8030cadf2f4SJacques Vidrine } 8040cadf2f4SJacques Vidrine #ifdef HAVE_IFADDRS_IFA_ANYCAST 8050cadf2f4SJacques Vidrine if (ifamap.anycast) { 8060cadf2f4SJacques Vidrine if (!build) 8070cadf2f4SJacques Vidrine dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.anycast_len)); 8080cadf2f4SJacques Vidrine else { 8090cadf2f4SJacques Vidrine ifa->ifa_anycast = (struct sockaddr *)data; 8100cadf2f4SJacques Vidrine ifa_make_sockaddr(nlm_family, ifa->ifa_anyaddr, ifamap.anycast, ifamap.anycast_len, 8110cadf2f4SJacques Vidrine nlm_scope, nlm_index); 8120cadf2f4SJacques Vidrine data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.anycast_len)); 8130cadf2f4SJacques Vidrine } 8140cadf2f4SJacques Vidrine } 8150cadf2f4SJacques Vidrine #endif 8160cadf2f4SJacques Vidrine } 8170cadf2f4SJacques Vidrine if (!build){ 8180cadf2f4SJacques Vidrine #ifndef IFA_NETMASK 8190cadf2f4SJacques Vidrine dlen += sockaddr_size; 8200cadf2f4SJacques Vidrine #endif 8210cadf2f4SJacques Vidrine icnt++; 8220cadf2f4SJacques Vidrine } else { 8230cadf2f4SJacques Vidrine if (ifa->ifa_name == NULL) 8240cadf2f4SJacques Vidrine ifa->ifa_name = iflist[nlm_index]; 8250cadf2f4SJacques Vidrine #ifndef IFA_NETMASK 8260cadf2f4SJacques Vidrine if (ifa->ifa_addr && 8270cadf2f4SJacques Vidrine ifa->ifa_addr->sa_family != AF_UNSPEC && 8280cadf2f4SJacques Vidrine ifa->ifa_addr->sa_family != AF_PACKET){ 8290cadf2f4SJacques Vidrine ifa->ifa_netmask = (struct sockaddr *)data; 8300cadf2f4SJacques Vidrine ifa_make_sockaddr_mask(ifa->ifa_addr->sa_family, ifa->ifa_netmask, nlm_prefixlen); 8310cadf2f4SJacques Vidrine } 8320cadf2f4SJacques Vidrine data += sockaddr_size; 8330cadf2f4SJacques Vidrine #endif 8340cadf2f4SJacques Vidrine ifl = ifa++; 8350cadf2f4SJacques Vidrine } 8360cadf2f4SJacques Vidrine } 8370cadf2f4SJacques Vidrine } 8380cadf2f4SJacques Vidrine if (!build){ 8390cadf2f4SJacques Vidrine if (icnt == 0 && (dlen + nlen + xlen == 0)){ 8400cadf2f4SJacques Vidrine if (ifap != NULL) 8410cadf2f4SJacques Vidrine *ifap = NULL; 8420cadf2f4SJacques Vidrine break; /* cannot found any addresses */ 8430cadf2f4SJacques Vidrine } 8440cadf2f4SJacques Vidrine } 8450cadf2f4SJacques Vidrine else 8460cadf2f4SJacques Vidrine free_data(NULL, ifdata); 8470cadf2f4SJacques Vidrine } 8480cadf2f4SJacques Vidrine 8490cadf2f4SJacques Vidrine /* ---------------------------------- */ 8500cadf2f4SJacques Vidrine /* Finalize */ 8510cadf2f4SJacques Vidrine free_nlmsglist(nlmsg_list); 8520cadf2f4SJacques Vidrine nl_close(sd); 8530cadf2f4SJacques Vidrine return 0; 8540cadf2f4SJacques Vidrine } 8550cadf2f4SJacques Vidrine 856*ae771770SStanislav Sedov void ROKEN_LIB_FUNCTION 857*ae771770SStanislav Sedov rk_freeifaddrs(struct ifaddrs *ifp) 858*ae771770SStanislav Sedov { 859*ae771770SStanislav Sedov /* AF_NETLINK method uses a single allocation for all interfaces */ 860*ae771770SStanislav Sedov free(ifp); 861*ae771770SStanislav Sedov } 862*ae771770SStanislav Sedov 8630cadf2f4SJacques Vidrine #else /* !AF_NETLINK */ 8640cadf2f4SJacques Vidrine 8650cadf2f4SJacques Vidrine /* 8660cadf2f4SJacques Vidrine * The generic SIOCGIFCONF version. 8670cadf2f4SJacques Vidrine */ 8680cadf2f4SJacques Vidrine 8695e9cd1aeSAssar Westerlund static int 8705e9cd1aeSAssar Westerlund getifaddrs2(struct ifaddrs **ifap, 8715e9cd1aeSAssar Westerlund int af, int siocgifconf, int siocgifflags, 8725e9cd1aeSAssar Westerlund size_t ifreq_sz) 8735e9cd1aeSAssar Westerlund { 8745e9cd1aeSAssar Westerlund int ret; 8755e9cd1aeSAssar Westerlund int fd; 8765e9cd1aeSAssar Westerlund size_t buf_size; 8775e9cd1aeSAssar Westerlund char *buf; 8785e9cd1aeSAssar Westerlund struct ifconf ifconf; 8795e9cd1aeSAssar Westerlund char *p; 8805e9cd1aeSAssar Westerlund size_t sz; 8815e9cd1aeSAssar Westerlund struct sockaddr sa_zero; 8825e9cd1aeSAssar Westerlund struct ifreq *ifr; 8834137ff4cSJacques Vidrine struct ifaddrs *start = NULL, **end = &start; 8845e9cd1aeSAssar Westerlund 8855e9cd1aeSAssar Westerlund buf = NULL; 8865e9cd1aeSAssar Westerlund 8875e9cd1aeSAssar Westerlund memset (&sa_zero, 0, sizeof(sa_zero)); 8885e9cd1aeSAssar Westerlund fd = socket(af, SOCK_DGRAM, 0); 8895e9cd1aeSAssar Westerlund if (fd < 0) 8905e9cd1aeSAssar Westerlund return -1; 8915e9cd1aeSAssar Westerlund 8925e9cd1aeSAssar Westerlund buf_size = 8192; 8935e9cd1aeSAssar Westerlund for (;;) { 8945e9cd1aeSAssar Westerlund buf = calloc(1, buf_size); 8955e9cd1aeSAssar Westerlund if (buf == NULL) { 8965e9cd1aeSAssar Westerlund ret = ENOMEM; 8975e9cd1aeSAssar Westerlund goto error_out; 8985e9cd1aeSAssar Westerlund } 8995e9cd1aeSAssar Westerlund ifconf.ifc_len = buf_size; 9005e9cd1aeSAssar Westerlund ifconf.ifc_buf = buf; 9015e9cd1aeSAssar Westerlund 9025e9cd1aeSAssar Westerlund /* 9035e9cd1aeSAssar Westerlund * Solaris returns EINVAL when the buffer is too small. 9045e9cd1aeSAssar Westerlund */ 9055e9cd1aeSAssar Westerlund if (ioctl (fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) { 9065e9cd1aeSAssar Westerlund ret = errno; 9075e9cd1aeSAssar Westerlund goto error_out; 9085e9cd1aeSAssar Westerlund } 9095e9cd1aeSAssar Westerlund /* 9105e9cd1aeSAssar Westerlund * Can the difference between a full and a overfull buf 9115e9cd1aeSAssar Westerlund * be determined? 9125e9cd1aeSAssar Westerlund */ 9135e9cd1aeSAssar Westerlund 9145e9cd1aeSAssar Westerlund if (ifconf.ifc_len < buf_size) 9155e9cd1aeSAssar Westerlund break; 9165e9cd1aeSAssar Westerlund free (buf); 9175e9cd1aeSAssar Westerlund buf_size *= 2; 9185e9cd1aeSAssar Westerlund } 9195e9cd1aeSAssar Westerlund 9205e9cd1aeSAssar Westerlund for (p = ifconf.ifc_buf; 9215e9cd1aeSAssar Westerlund p < ifconf.ifc_buf + ifconf.ifc_len; 9225e9cd1aeSAssar Westerlund p += sz) { 9235e9cd1aeSAssar Westerlund struct ifreq ifreq; 9245e9cd1aeSAssar Westerlund struct sockaddr *sa; 9255e9cd1aeSAssar Westerlund size_t salen; 9265e9cd1aeSAssar Westerlund 9275e9cd1aeSAssar Westerlund ifr = (struct ifreq *)p; 9285e9cd1aeSAssar Westerlund sa = &ifr->ifr_addr; 9295e9cd1aeSAssar Westerlund 9305e9cd1aeSAssar Westerlund sz = ifreq_sz; 9315e9cd1aeSAssar Westerlund salen = sizeof(struct sockaddr); 9325e9cd1aeSAssar Westerlund #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 9335e9cd1aeSAssar Westerlund salen = sa->sa_len; 9345e9cd1aeSAssar Westerlund sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len); 9355e9cd1aeSAssar Westerlund #endif 9365e9cd1aeSAssar Westerlund #ifdef SA_LEN 9375e9cd1aeSAssar Westerlund salen = SA_LEN(sa); 9385e9cd1aeSAssar Westerlund sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa)); 9395e9cd1aeSAssar Westerlund #endif 9405e9cd1aeSAssar Westerlund memset (&ifreq, 0, sizeof(ifreq)); 9415e9cd1aeSAssar Westerlund memcpy (ifreq.ifr_name, ifr->ifr_name, sizeof(ifr->ifr_name)); 9425e9cd1aeSAssar Westerlund 9435e9cd1aeSAssar Westerlund if (ioctl(fd, siocgifflags, &ifreq) < 0) { 9445e9cd1aeSAssar Westerlund ret = errno; 9455e9cd1aeSAssar Westerlund goto error_out; 9465e9cd1aeSAssar Westerlund } 9475e9cd1aeSAssar Westerlund 9485e9cd1aeSAssar Westerlund *end = malloc(sizeof(**end)); 9494137ff4cSJacques Vidrine if (*end == NULL) { 9504137ff4cSJacques Vidrine ret = ENOMEM; 9514137ff4cSJacques Vidrine goto error_out; 9524137ff4cSJacques Vidrine } 9535e9cd1aeSAssar Westerlund 9545e9cd1aeSAssar Westerlund (*end)->ifa_next = NULL; 9555e9cd1aeSAssar Westerlund (*end)->ifa_name = strdup(ifr->ifr_name); 956c19800e8SDoug Rabson if ((*end)->ifa_name == NULL) { 957c19800e8SDoug Rabson ret = ENOMEM; 958c19800e8SDoug Rabson goto error_out; 959c19800e8SDoug Rabson } 9605e9cd1aeSAssar Westerlund (*end)->ifa_flags = ifreq.ifr_flags; 9615e9cd1aeSAssar Westerlund (*end)->ifa_addr = malloc(salen); 962c19800e8SDoug Rabson if ((*end)->ifa_addr == NULL) { 963c19800e8SDoug Rabson ret = ENOMEM; 964c19800e8SDoug Rabson goto error_out; 965c19800e8SDoug Rabson } 9665e9cd1aeSAssar Westerlund memcpy((*end)->ifa_addr, sa, salen); 9675e9cd1aeSAssar Westerlund (*end)->ifa_netmask = NULL; 9685e9cd1aeSAssar Westerlund 9695e9cd1aeSAssar Westerlund #if 0 9705e9cd1aeSAssar Westerlund /* fix these when we actually need them */ 9715e9cd1aeSAssar Westerlund if(ifreq.ifr_flags & IFF_BROADCAST) { 9725e9cd1aeSAssar Westerlund (*end)->ifa_broadaddr = malloc(sizeof(ifr->ifr_broadaddr)); 973c19800e8SDoug Rabson if ((*end)->ifa_broadaddr == NULL) { 974c19800e8SDoug Rabson ret = ENOMEM; 975c19800e8SDoug Rabson goto error_out; 976c19800e8SDoug Rabson } 9775e9cd1aeSAssar Westerlund memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr, 9785e9cd1aeSAssar Westerlund sizeof(ifr->ifr_broadaddr)); 9795e9cd1aeSAssar Westerlund } else if(ifreq.ifr_flags & IFF_POINTOPOINT) { 9805e9cd1aeSAssar Westerlund (*end)->ifa_dstaddr = malloc(sizeof(ifr->ifr_dstaddr)); 981c19800e8SDoug Rabson if ((*end)->ifa_dstaddr == NULL) { 982c19800e8SDoug Rabson ret = ENOMEM; 983c19800e8SDoug Rabson goto error_out; 984c19800e8SDoug Rabson } 9855e9cd1aeSAssar Westerlund memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr, 9865e9cd1aeSAssar Westerlund sizeof(ifr->ifr_dstaddr)); 9875e9cd1aeSAssar Westerlund } else 9885e9cd1aeSAssar Westerlund (*end)->ifa_dstaddr = NULL; 9895e9cd1aeSAssar Westerlund #else 9905e9cd1aeSAssar Westerlund (*end)->ifa_dstaddr = NULL; 9915e9cd1aeSAssar Westerlund #endif 9925e9cd1aeSAssar Westerlund 9935e9cd1aeSAssar Westerlund (*end)->ifa_data = NULL; 9945e9cd1aeSAssar Westerlund 9955e9cd1aeSAssar Westerlund end = &(*end)->ifa_next; 9965e9cd1aeSAssar Westerlund 9975e9cd1aeSAssar Westerlund } 9985e9cd1aeSAssar Westerlund *ifap = start; 999adb0ddaeSAssar Westerlund close(fd); 10005e9cd1aeSAssar Westerlund free(buf); 10015e9cd1aeSAssar Westerlund return 0; 10025e9cd1aeSAssar Westerlund error_out: 1003c19800e8SDoug Rabson rk_freeifaddrs(start); 1004adb0ddaeSAssar Westerlund close(fd); 10055e9cd1aeSAssar Westerlund free(buf); 10065e9cd1aeSAssar Westerlund errno = ret; 10075e9cd1aeSAssar Westerlund return -1; 10085e9cd1aeSAssar Westerlund } 10095e9cd1aeSAssar Westerlund 10104137ff4cSJacques Vidrine #if defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS) 10114137ff4cSJacques Vidrine static int 10124137ff4cSJacques Vidrine getlifaddrs2(struct ifaddrs **ifap, 10134137ff4cSJacques Vidrine int af, int siocgifconf, int siocgifflags, 10144137ff4cSJacques Vidrine size_t ifreq_sz) 10154137ff4cSJacques Vidrine { 10164137ff4cSJacques Vidrine int ret; 10174137ff4cSJacques Vidrine int fd; 10184137ff4cSJacques Vidrine size_t buf_size; 10194137ff4cSJacques Vidrine char *buf; 10204137ff4cSJacques Vidrine struct lifconf ifconf; 10214137ff4cSJacques Vidrine char *p; 10224137ff4cSJacques Vidrine size_t sz; 10234137ff4cSJacques Vidrine struct sockaddr sa_zero; 10244137ff4cSJacques Vidrine struct lifreq *ifr; 10254137ff4cSJacques Vidrine struct ifaddrs *start = NULL, **end = &start; 10264137ff4cSJacques Vidrine 10274137ff4cSJacques Vidrine buf = NULL; 10284137ff4cSJacques Vidrine 10294137ff4cSJacques Vidrine memset (&sa_zero, 0, sizeof(sa_zero)); 10304137ff4cSJacques Vidrine fd = socket(af, SOCK_DGRAM, 0); 10314137ff4cSJacques Vidrine if (fd < 0) 10324137ff4cSJacques Vidrine return -1; 10334137ff4cSJacques Vidrine 10344137ff4cSJacques Vidrine buf_size = 8192; 10354137ff4cSJacques Vidrine for (;;) { 10364137ff4cSJacques Vidrine buf = calloc(1, buf_size); 10374137ff4cSJacques Vidrine if (buf == NULL) { 10384137ff4cSJacques Vidrine ret = ENOMEM; 10394137ff4cSJacques Vidrine goto error_out; 10404137ff4cSJacques Vidrine } 1041c19800e8SDoug Rabson #ifndef __hpux 1042*ae771770SStanislav Sedov ifconf.lifc_family = af; 10434137ff4cSJacques Vidrine ifconf.lifc_flags = 0; 1044c19800e8SDoug Rabson #endif 10454137ff4cSJacques Vidrine ifconf.lifc_len = buf_size; 10464137ff4cSJacques Vidrine ifconf.lifc_buf = buf; 10474137ff4cSJacques Vidrine 10484137ff4cSJacques Vidrine /* 10494137ff4cSJacques Vidrine * Solaris returns EINVAL when the buffer is too small. 10504137ff4cSJacques Vidrine */ 10514137ff4cSJacques Vidrine if (ioctl (fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) { 10524137ff4cSJacques Vidrine ret = errno; 10534137ff4cSJacques Vidrine goto error_out; 10544137ff4cSJacques Vidrine } 10554137ff4cSJacques Vidrine /* 10564137ff4cSJacques Vidrine * Can the difference between a full and a overfull buf 10574137ff4cSJacques Vidrine * be determined? 10584137ff4cSJacques Vidrine */ 10594137ff4cSJacques Vidrine 10604137ff4cSJacques Vidrine if (ifconf.lifc_len < buf_size) 10614137ff4cSJacques Vidrine break; 10624137ff4cSJacques Vidrine free (buf); 10634137ff4cSJacques Vidrine buf_size *= 2; 10644137ff4cSJacques Vidrine } 10654137ff4cSJacques Vidrine 10664137ff4cSJacques Vidrine for (p = ifconf.lifc_buf; 10674137ff4cSJacques Vidrine p < ifconf.lifc_buf + ifconf.lifc_len; 10684137ff4cSJacques Vidrine p += sz) { 10694137ff4cSJacques Vidrine struct lifreq ifreq; 10704137ff4cSJacques Vidrine struct sockaddr_storage *sa; 10714137ff4cSJacques Vidrine size_t salen; 10724137ff4cSJacques Vidrine 10734137ff4cSJacques Vidrine ifr = (struct lifreq *)p; 10744137ff4cSJacques Vidrine sa = &ifr->lifr_addr; 10754137ff4cSJacques Vidrine 10764137ff4cSJacques Vidrine sz = ifreq_sz; 10774137ff4cSJacques Vidrine salen = sizeof(struct sockaddr_storage); 10784137ff4cSJacques Vidrine #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 10794137ff4cSJacques Vidrine salen = sa->sa_len; 10804137ff4cSJacques Vidrine sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len); 10814137ff4cSJacques Vidrine #endif 10824137ff4cSJacques Vidrine #ifdef SA_LEN 10834137ff4cSJacques Vidrine salen = SA_LEN(sa); 10844137ff4cSJacques Vidrine sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa)); 10854137ff4cSJacques Vidrine #endif 10864137ff4cSJacques Vidrine memset (&ifreq, 0, sizeof(ifreq)); 10874137ff4cSJacques Vidrine memcpy (ifreq.lifr_name, ifr->lifr_name, sizeof(ifr->lifr_name)); 10884137ff4cSJacques Vidrine 10894137ff4cSJacques Vidrine if (ioctl(fd, siocgifflags, &ifreq) < 0) { 10904137ff4cSJacques Vidrine ret = errno; 10914137ff4cSJacques Vidrine goto error_out; 10924137ff4cSJacques Vidrine } 10934137ff4cSJacques Vidrine 10944137ff4cSJacques Vidrine *end = malloc(sizeof(**end)); 1095c19800e8SDoug Rabson if (*end == NULL) { 1096c19800e8SDoug Rabson ret = ENOMEM; 1097c19800e8SDoug Rabson goto error_out; 1098c19800e8SDoug Rabson } 10994137ff4cSJacques Vidrine 11004137ff4cSJacques Vidrine (*end)->ifa_next = NULL; 11014137ff4cSJacques Vidrine (*end)->ifa_name = strdup(ifr->lifr_name); 1102c19800e8SDoug Rabson if ((*end)->ifa_name == NULL) { 1103c19800e8SDoug Rabson ret = ENOMEM; 1104c19800e8SDoug Rabson goto error_out; 1105c19800e8SDoug Rabson } 11064137ff4cSJacques Vidrine (*end)->ifa_flags = ifreq.lifr_flags; 11074137ff4cSJacques Vidrine (*end)->ifa_addr = malloc(salen); 1108c19800e8SDoug Rabson if ((*end)->ifa_addr == NULL) { 1109c19800e8SDoug Rabson ret = ENOMEM; 1110c19800e8SDoug Rabson goto error_out; 1111c19800e8SDoug Rabson } 11124137ff4cSJacques Vidrine memcpy((*end)->ifa_addr, sa, salen); 11134137ff4cSJacques Vidrine (*end)->ifa_netmask = NULL; 11144137ff4cSJacques Vidrine 11154137ff4cSJacques Vidrine #if 0 11164137ff4cSJacques Vidrine /* fix these when we actually need them */ 11174137ff4cSJacques Vidrine if(ifreq.ifr_flags & IFF_BROADCAST) { 11184137ff4cSJacques Vidrine (*end)->ifa_broadaddr = malloc(sizeof(ifr->ifr_broadaddr)); 1119c19800e8SDoug Rabson if ((*end)->ifa_broadaddr == NULL) { 1120c19800e8SDoug Rabson ret = ENOMEM; 1121c19800e8SDoug Rabson goto error_out; 1122c19800e8SDoug Rabson } 11234137ff4cSJacques Vidrine memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr, 11244137ff4cSJacques Vidrine sizeof(ifr->ifr_broadaddr)); 11254137ff4cSJacques Vidrine } else if(ifreq.ifr_flags & IFF_POINTOPOINT) { 11264137ff4cSJacques Vidrine (*end)->ifa_dstaddr = malloc(sizeof(ifr->ifr_dstaddr)); 1127c19800e8SDoug Rabson if ((*end)->ifa_dstaddr == NULL) { 1128c19800e8SDoug Rabson ret = ENOMEM; 1129c19800e8SDoug Rabson goto error_out; 1130c19800e8SDoug Rabson } 11314137ff4cSJacques Vidrine memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr, 11324137ff4cSJacques Vidrine sizeof(ifr->ifr_dstaddr)); 11334137ff4cSJacques Vidrine } else 11344137ff4cSJacques Vidrine (*end)->ifa_dstaddr = NULL; 11354137ff4cSJacques Vidrine #else 11364137ff4cSJacques Vidrine (*end)->ifa_dstaddr = NULL; 11374137ff4cSJacques Vidrine #endif 11384137ff4cSJacques Vidrine 11394137ff4cSJacques Vidrine (*end)->ifa_data = NULL; 11404137ff4cSJacques Vidrine 11414137ff4cSJacques Vidrine end = &(*end)->ifa_next; 11424137ff4cSJacques Vidrine 11434137ff4cSJacques Vidrine } 11444137ff4cSJacques Vidrine *ifap = start; 11454137ff4cSJacques Vidrine close(fd); 11464137ff4cSJacques Vidrine free(buf); 11474137ff4cSJacques Vidrine return 0; 11484137ff4cSJacques Vidrine error_out: 1149c19800e8SDoug Rabson rk_freeifaddrs(start); 11504137ff4cSJacques Vidrine close(fd); 11514137ff4cSJacques Vidrine free(buf); 11524137ff4cSJacques Vidrine errno = ret; 11534137ff4cSJacques Vidrine return -1; 11544137ff4cSJacques Vidrine } 11554137ff4cSJacques Vidrine #endif /* defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS) */ 11564137ff4cSJacques Vidrine 1157*ae771770SStanislav Sedov /** 1158*ae771770SStanislav Sedov * Join two struct ifaddrs lists by appending supp to base. 1159*ae771770SStanislav Sedov * Either may be NULL. The new list head (usually base) will be 1160*ae771770SStanislav Sedov * returned. 1161*ae771770SStanislav Sedov */ 1162*ae771770SStanislav Sedov static struct ifaddrs * 1163*ae771770SStanislav Sedov append_ifaddrs(struct ifaddrs *base, struct ifaddrs *supp) { 1164*ae771770SStanislav Sedov if (!base) 1165*ae771770SStanislav Sedov return supp; 1166*ae771770SStanislav Sedov 1167*ae771770SStanislav Sedov if (!supp) 1168*ae771770SStanislav Sedov return base; 1169*ae771770SStanislav Sedov 1170*ae771770SStanislav Sedov while (base->ifa_next) 1171*ae771770SStanislav Sedov base = base->ifa_next; 1172*ae771770SStanislav Sedov 1173*ae771770SStanislav Sedov base->ifa_next = supp; 1174*ae771770SStanislav Sedov 1175*ae771770SStanislav Sedov return base; 1176*ae771770SStanislav Sedov } 1177*ae771770SStanislav Sedov 1178*ae771770SStanislav Sedov ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 1179c19800e8SDoug Rabson rk_getifaddrs(struct ifaddrs **ifap) 11805e9cd1aeSAssar Westerlund { 11815e9cd1aeSAssar Westerlund int ret = -1; 11825e9cd1aeSAssar Westerlund errno = ENXIO; 11835e9cd1aeSAssar Westerlund #if defined(AF_INET6) && defined(SIOCGIF6CONF) && defined(SIOCGIF6FLAGS) 11845e9cd1aeSAssar Westerlund if (ret) 11855e9cd1aeSAssar Westerlund ret = getifaddrs2 (ifap, AF_INET6, SIOCGIF6CONF, SIOCGIF6FLAGS, 11865e9cd1aeSAssar Westerlund sizeof(struct in6_ifreq)); 11875e9cd1aeSAssar Westerlund #endif 11884137ff4cSJacques Vidrine #if defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS) 1189*ae771770SStanislav Sedov /* Do IPv6 and IPv4 queries separately then join the result. 1190*ae771770SStanislav Sedov * 1191*ae771770SStanislav Sedov * HP-UX only returns IPv6 addresses using SIOCGLIFCONF, 1192*ae771770SStanislav Sedov * SIOCGIFCONF has to be used for IPv4 addresses. The result is then 1193*ae771770SStanislav Sedov * merged. 1194*ae771770SStanislav Sedov * 1195*ae771770SStanislav Sedov * Solaris needs particular care, because a SIOCGLIFCONF lookup using 1196*ae771770SStanislav Sedov * AF_UNSPEC can fail in a Zone requiring an AF_INET lookup, so we just 1197*ae771770SStanislav Sedov * do them separately the same as for HP-UX. See 1198*ae771770SStanislav Sedov * http://repo.or.cz/w/heimdal.git/commitdiff/76afc31e9ba2f37e64c70adc006ade9e37e9ef73 1199*ae771770SStanislav Sedov */ 1200*ae771770SStanislav Sedov if (ret) { 1201*ae771770SStanislav Sedov int v6err, v4err; 1202*ae771770SStanislav Sedov struct ifaddrs *v6addrs, *v4addrs; 1203*ae771770SStanislav Sedov 1204*ae771770SStanislav Sedov v6err = getlifaddrs2 (&v6addrs, AF_INET6, SIOCGLIFCONF, SIOCGLIFFLAGS, 12054137ff4cSJacques Vidrine sizeof(struct lifreq)); 1206*ae771770SStanislav Sedov v4err = getifaddrs2 (&v4addrs, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS, 1207*ae771770SStanislav Sedov sizeof(struct ifreq)); 1208*ae771770SStanislav Sedov if (v6err) 1209*ae771770SStanislav Sedov v6addrs = NULL; 1210*ae771770SStanislav Sedov if (v4err) 1211*ae771770SStanislav Sedov v4addrs = NULL; 1212*ae771770SStanislav Sedov 1213*ae771770SStanislav Sedov if (v6addrs) { 1214*ae771770SStanislav Sedov if (v4addrs) 1215*ae771770SStanislav Sedov *ifap = append_ifaddrs(v6addrs, v4addrs); 1216*ae771770SStanislav Sedov else 1217*ae771770SStanislav Sedov *ifap = v6addrs; 1218*ae771770SStanislav Sedov } else if (v4addrs) { 1219*ae771770SStanislav Sedov *ifap = v4addrs; 1220*ae771770SStanislav Sedov } else { 1221*ae771770SStanislav Sedov *ifap = NULL; 1222*ae771770SStanislav Sedov } 1223*ae771770SStanislav Sedov 1224*ae771770SStanislav Sedov ret = (v6err || v4err) ? -1 : 0; 1225*ae771770SStanislav Sedov } 12264137ff4cSJacques Vidrine #endif 12275e9cd1aeSAssar Westerlund #if defined(HAVE_IPV6) && defined(SIOCGIFCONF) 12285e9cd1aeSAssar Westerlund if (ret) 12295e9cd1aeSAssar Westerlund ret = getifaddrs2 (ifap, AF_INET6, SIOCGIFCONF, SIOCGIFFLAGS, 12305e9cd1aeSAssar Westerlund sizeof(struct ifreq)); 12315e9cd1aeSAssar Westerlund #endif 12325e9cd1aeSAssar Westerlund #if defined(AF_INET) && defined(SIOCGIFCONF) && defined(SIOCGIFFLAGS) 12335e9cd1aeSAssar Westerlund if (ret) 12345e9cd1aeSAssar Westerlund ret = getifaddrs2 (ifap, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS, 12355e9cd1aeSAssar Westerlund sizeof(struct ifreq)); 12365e9cd1aeSAssar Westerlund #endif 12375e9cd1aeSAssar Westerlund return ret; 12385e9cd1aeSAssar Westerlund } 12395e9cd1aeSAssar Westerlund 1240*ae771770SStanislav Sedov ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL 1241c19800e8SDoug Rabson rk_freeifaddrs(struct ifaddrs *ifp) 12425e9cd1aeSAssar Westerlund { 12435e9cd1aeSAssar Westerlund struct ifaddrs *p, *q; 12445e9cd1aeSAssar Westerlund 12455e9cd1aeSAssar Westerlund for(p = ifp; p; ) { 12465e9cd1aeSAssar Westerlund free(p->ifa_name); 12475e9cd1aeSAssar Westerlund if(p->ifa_addr) 12485e9cd1aeSAssar Westerlund free(p->ifa_addr); 12495e9cd1aeSAssar Westerlund if(p->ifa_dstaddr) 12505e9cd1aeSAssar Westerlund free(p->ifa_dstaddr); 12515e9cd1aeSAssar Westerlund if(p->ifa_netmask) 12525e9cd1aeSAssar Westerlund free(p->ifa_netmask); 12535e9cd1aeSAssar Westerlund if(p->ifa_data) 12545e9cd1aeSAssar Westerlund free(p->ifa_data); 12555e9cd1aeSAssar Westerlund q = p; 12565e9cd1aeSAssar Westerlund p = p->ifa_next; 12575e9cd1aeSAssar Westerlund free(q); 12585e9cd1aeSAssar Westerlund } 12595e9cd1aeSAssar Westerlund } 12605e9cd1aeSAssar Westerlund 1261*ae771770SStanislav Sedov #endif /* !AF_NETLINK */ 1262*ae771770SStanislav Sedov 12635e9cd1aeSAssar Westerlund #ifdef TEST 12645e9cd1aeSAssar Westerlund 12655e9cd1aeSAssar Westerlund void 12665e9cd1aeSAssar Westerlund print_addr(const char *s, struct sockaddr *sa) 12675e9cd1aeSAssar Westerlund { 12685e9cd1aeSAssar Westerlund int i; 12695e9cd1aeSAssar Westerlund printf(" %s=%d/", s, sa->sa_family); 12705e9cd1aeSAssar Westerlund #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 12715e9cd1aeSAssar Westerlund for(i = 0; i < sa->sa_len - ((long)sa->sa_data - (long)&sa->sa_family); i++) 12725e9cd1aeSAssar Westerlund printf("%02x", ((unsigned char*)sa->sa_data)[i]); 12735e9cd1aeSAssar Westerlund #else 12745e9cd1aeSAssar Westerlund for(i = 0; i < sizeof(sa->sa_data); i++) 12755e9cd1aeSAssar Westerlund printf("%02x", ((unsigned char*)sa->sa_data)[i]); 12765e9cd1aeSAssar Westerlund #endif 12775e9cd1aeSAssar Westerlund printf("\n"); 12785e9cd1aeSAssar Westerlund } 12795e9cd1aeSAssar Westerlund 12805e9cd1aeSAssar Westerlund void 12815e9cd1aeSAssar Westerlund print_ifaddrs(struct ifaddrs *x) 12825e9cd1aeSAssar Westerlund { 12835e9cd1aeSAssar Westerlund struct ifaddrs *p; 12845e9cd1aeSAssar Westerlund 12855e9cd1aeSAssar Westerlund for(p = x; p; p = p->ifa_next) { 12865e9cd1aeSAssar Westerlund printf("%s\n", p->ifa_name); 12875e9cd1aeSAssar Westerlund printf(" flags=%x\n", p->ifa_flags); 12885e9cd1aeSAssar Westerlund if(p->ifa_addr) 12895e9cd1aeSAssar Westerlund print_addr("addr", p->ifa_addr); 12905e9cd1aeSAssar Westerlund if(p->ifa_dstaddr) 12915e9cd1aeSAssar Westerlund print_addr("dstaddr", p->ifa_dstaddr); 12925e9cd1aeSAssar Westerlund if(p->ifa_netmask) 12935e9cd1aeSAssar Westerlund print_addr("netmask", p->ifa_netmask); 12945e9cd1aeSAssar Westerlund printf(" %p\n", p->ifa_data); 12955e9cd1aeSAssar Westerlund } 12965e9cd1aeSAssar Westerlund } 12975e9cd1aeSAssar Westerlund 12985e9cd1aeSAssar Westerlund int 12995e9cd1aeSAssar Westerlund main() 13005e9cd1aeSAssar Westerlund { 13015e9cd1aeSAssar Westerlund struct ifaddrs *a = NULL, *b; 13025e9cd1aeSAssar Westerlund getifaddrs2(&a, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS, sizeof(struct ifreq)); 13035e9cd1aeSAssar Westerlund print_ifaddrs(a); 13045e9cd1aeSAssar Westerlund printf("---\n"); 13055e9cd1aeSAssar Westerlund getifaddrs(&b); 13065e9cd1aeSAssar Westerlund print_ifaddrs(b); 13075e9cd1aeSAssar Westerlund return 0; 13085e9cd1aeSAssar Westerlund } 13095e9cd1aeSAssar Westerlund #endif 1310