172445Sassar/* 2178825Sdfr * Copyright (c) 2000 - 2002, 2005 Kungliga Tekniska H�gskolan 372445Sassar * (Royal Institute of Technology, Stockholm, Sweden). 472445Sassar * All rights reserved. 572445Sassar * 672445Sassar * Redistribution and use in source and binary forms, with or without 772445Sassar * modification, are permitted provided that the following conditions 872445Sassar * are met: 972445Sassar * 1072445Sassar * 1. Redistributions of source code must retain the above copyright 1172445Sassar * notice, this list of conditions and the following disclaimer. 1272445Sassar * 1372445Sassar * 2. Redistributions in binary form must reproduce the above copyright 1472445Sassar * notice, this list of conditions and the following disclaimer in the 1572445Sassar * documentation and/or other materials provided with the distribution. 1672445Sassar * 1772445Sassar * 3. Neither the name of the Institute nor the names of its contributors 1872445Sassar * may be used to endorse or promote products derived from this software 1972445Sassar * without specific prior written permission. 2072445Sassar * 2172445Sassar * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2272445Sassar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2372445Sassar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2472445Sassar * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 2572445Sassar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2672445Sassar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2772445Sassar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2872445Sassar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2972445Sassar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3072445Sassar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3172445Sassar * SUCH DAMAGE. 3272445Sassar */ 3372445Sassar 3472445Sassar#ifdef HAVE_CONFIG_H 3572445Sassar#include <config.h> 36178825SdfrRCSID("$Id: getifaddrs.c 21745 2007-07-31 16:11:25Z lha $"); 3772445Sassar#endif 3872445Sassar#include "roken.h" 3972445Sassar 4072445Sassar#ifdef __osf__ 4172445Sassar/* hate */ 4272445Sassarstruct rtentry; 4372445Sassarstruct mbuf; 4472445Sassar#endif 4572445Sassar#ifdef HAVE_NET_IF_H 4672445Sassar#include <net/if.h> 4772445Sassar#endif 4872445Sassar 4972445Sassar#ifdef HAVE_SYS_SOCKIO_H 5072445Sassar#include <sys/sockio.h> 5172445Sassar#endif /* HAVE_SYS_SOCKIO_H */ 5272445Sassar 5372445Sassar#ifdef HAVE_NETINET_IN6_VAR_H 5472445Sassar#include <netinet/in6_var.h> 5572445Sassar#endif /* HAVE_NETINET_IN6_VAR_H */ 5672445Sassar 5772445Sassar#include <ifaddrs.h> 5872445Sassar 59178825Sdfr#ifdef __hpux 60178825Sdfr#define lifconf if_laddrconf 61178825Sdfr#define lifc_len iflc_len 62178825Sdfr#define lifc_buf iflc_buf 63178825Sdfr#define lifc_req iflc_req 64178825Sdfr 65178825Sdfr#define lifreq if_laddrreq 66178825Sdfr#define lifr_addr iflr_addr 67178825Sdfr#define lifr_name iflr_name 68178825Sdfr#define lifr_dstaddr iflr_dstaddr 69178825Sdfr#define lifr_broadaddr iflr_broadaddr 70178825Sdfr#define lifr_flags iflr_flags 71178825Sdfr#define lifr_index iflr_index 72178825Sdfr#endif 73178825Sdfr 74103423Snectar#ifdef AF_NETLINK 75103423Snectar 76103423Snectar/* 77103423Snectar * The linux - AF_NETLINK version of getifaddrs - from Usagi. 78103423Snectar * Linux does not return v6 addresses from SIOCGIFCONF. 79103423Snectar */ 80103423Snectar 81103423Snectar/* $USAGI: ifaddrs.c,v 1.18 2002/03/06 01:50:46 yoshfuji Exp $ */ 82103423Snectar 83103423Snectar/************************************************************************** 84103423Snectar * ifaddrs.c 85103423Snectar * Copyright (C)2000 Hideaki YOSHIFUJI, All Rights Reserved. 86103423Snectar * 87103423Snectar * Redistribution and use in source and binary forms, with or without 88103423Snectar * modification, are permitted provided that the following conditions 89103423Snectar * are met: 90103423Snectar * 1. Redistributions of source code must retain the above copyright 91103423Snectar * notice, this list of conditions and the following disclaimer. 92103423Snectar * 2. Redistributions in binary form must reproduce the above copyright 93103423Snectar * notice, this list of conditions and the following disclaimer in the 94103423Snectar * documentation and/or other materials provided with the distribution. 95103423Snectar * 3. Neither the name of the author nor the names of its contributors 96103423Snectar * may be used to endorse or promote products derived from this software 97103423Snectar * without specific prior written permission. 98103423Snectar * 99103423Snectar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 100103423Snectar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 101103423Snectar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 102103423Snectar * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 103103423Snectar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 104103423Snectar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 105103423Snectar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 106103423Snectar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 107103423Snectar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 108103423Snectar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 109103423Snectar * SUCH DAMAGE. 110103423Snectar */ 111103423Snectar 112103423Snectar#include "config.h" 113103423Snectar 114103423Snectar#include <string.h> 115103423Snectar#include <time.h> 116103423Snectar#include <malloc.h> 117103423Snectar#include <errno.h> 118103423Snectar#include <unistd.h> 119103423Snectar 120103423Snectar#include <sys/socket.h> 121103423Snectar#include <asm/types.h> 122103423Snectar#include <linux/netlink.h> 123103423Snectar#include <linux/rtnetlink.h> 124103423Snectar#include <sys/types.h> 125103423Snectar#include <sys/socket.h> 126178825Sdfr#include <sys/poll.h> 127103423Snectar#include <netpacket/packet.h> 128103423Snectar#include <net/ethernet.h> /* the L2 protocols */ 129103423Snectar#include <sys/uio.h> 130103423Snectar#include <net/if.h> 131103423Snectar#include <net/if_arp.h> 132103423Snectar#include <ifaddrs.h> 133103423Snectar#include <netinet/in.h> 134103423Snectar 135103423Snectar#define __set_errno(e) (errno = (e)) 136103423Snectar#define __close(fd) (close(fd)) 137103423Snectar#undef ifa_broadaddr 138103423Snectar#define ifa_broadaddr ifa_dstaddr 139103423Snectar#define IFA_NETMASK 140103423Snectar 141103423Snectar/* ====================================================================== */ 142103423Snectarstruct nlmsg_list{ 143103423Snectar struct nlmsg_list *nlm_next; 144103423Snectar struct nlmsghdr *nlh; 145103423Snectar int size; 146103423Snectar time_t seq; 147103423Snectar}; 148103423Snectar 149103423Snectarstruct rtmaddr_ifamap { 150103423Snectar void *address; 151103423Snectar void *local; 152103423Snectar#ifdef IFA_NETMASK 153103423Snectar void *netmask; 154103423Snectar#endif 155103423Snectar void *broadcast; 156103423Snectar#ifdef HAVE_IFADDRS_IFA_ANYCAST 157103423Snectar void *anycast; 158103423Snectar#endif 159103423Snectar int address_len; 160103423Snectar int local_len; 161103423Snectar#ifdef IFA_NETMASK 162103423Snectar int netmask_len; 163103423Snectar#endif 164103423Snectar int broadcast_len; 165103423Snectar#ifdef HAVE_IFADDRS_IFA_ANYCAST 166103423Snectar int anycast_len; 167103423Snectar#endif 168103423Snectar}; 169103423Snectar 170103423Snectar/* ====================================================================== */ 171103423Snectarstatic size_t 172103423Snectarifa_sa_len(sa_family_t family, int len) 173103423Snectar{ 174103423Snectar size_t size; 175103423Snectar switch(family){ 176103423Snectar case AF_INET: 177103423Snectar size = sizeof(struct sockaddr_in); 178103423Snectar break; 179103423Snectar case AF_INET6: 180103423Snectar size = sizeof(struct sockaddr_in6); 181103423Snectar break; 182103423Snectar case AF_PACKET: 183103423Snectar size = (size_t)(((struct sockaddr_ll *)NULL)->sll_addr) + len; 184103423Snectar if (size < sizeof(struct sockaddr_ll)) 185103423Snectar size = sizeof(struct sockaddr_ll); 186103423Snectar break; 187103423Snectar default: 188103423Snectar size = (size_t)(((struct sockaddr *)NULL)->sa_data) + len; 189103423Snectar if (size < sizeof(struct sockaddr)) 190103423Snectar size = sizeof(struct sockaddr); 191178825Sdfr break; 192103423Snectar } 193103423Snectar return size; 194103423Snectar} 195103423Snectar 196103423Snectarstatic void 197103423Snectarifa_make_sockaddr(sa_family_t family, 198103423Snectar struct sockaddr *sa, 199103423Snectar void *p, size_t len, 200103423Snectar uint32_t scope, uint32_t scopeid) 201103423Snectar{ 202103423Snectar if (sa == NULL) return; 203103423Snectar switch(family){ 204103423Snectar case AF_INET: 205103423Snectar memcpy(&((struct sockaddr_in*)sa)->sin_addr, (char *)p, len); 206103423Snectar break; 207103423Snectar case AF_INET6: 208103423Snectar memcpy(&((struct sockaddr_in6*)sa)->sin6_addr, (char *)p, len); 209103423Snectar if (IN6_IS_ADDR_LINKLOCAL(p) || 210103423Snectar IN6_IS_ADDR_MC_LINKLOCAL(p)){ 211103423Snectar ((struct sockaddr_in6*)sa)->sin6_scope_id = scopeid; 212103423Snectar } 213103423Snectar break; 214103423Snectar case AF_PACKET: 215103423Snectar memcpy(((struct sockaddr_ll*)sa)->sll_addr, (char *)p, len); 216103423Snectar ((struct sockaddr_ll*)sa)->sll_halen = len; 217103423Snectar break; 218103423Snectar default: 219103423Snectar memcpy(sa->sa_data, p, len); /*XXX*/ 220103423Snectar break; 221103423Snectar } 222103423Snectar sa->sa_family = family; 223103423Snectar#ifdef HAVE_SOCKADDR_SA_LEN 224103423Snectar sa->sa_len = ifa_sa_len(family, len); 225103423Snectar#endif 226103423Snectar} 227103423Snectar 228103423Snectar#ifndef IFA_NETMASK 229103423Snectarstatic struct sockaddr * 230103423Snectarifa_make_sockaddr_mask(sa_family_t family, 231103423Snectar struct sockaddr *sa, 232103423Snectar uint32_t prefixlen) 233103423Snectar{ 234103423Snectar int i; 235103423Snectar char *p = NULL, c; 236103423Snectar uint32_t max_prefixlen = 0; 237103423Snectar 238103423Snectar if (sa == NULL) return NULL; 239103423Snectar switch(family){ 240103423Snectar case AF_INET: 241103423Snectar memset(&((struct sockaddr_in*)sa)->sin_addr, 0, sizeof(((struct sockaddr_in*)sa)->sin_addr)); 242103423Snectar p = (char *)&((struct sockaddr_in*)sa)->sin_addr; 243103423Snectar max_prefixlen = 32; 244103423Snectar break; 245103423Snectar case AF_INET6: 246103423Snectar memset(&((struct sockaddr_in6*)sa)->sin6_addr, 0, sizeof(((struct sockaddr_in6*)sa)->sin6_addr)); 247103423Snectar p = (char *)&((struct sockaddr_in6*)sa)->sin6_addr; 248103423Snectar#if 0 /* XXX: fill scope-id? */ 249103423Snectar if (IN6_IS_ADDR_LINKLOCAL(p) || 250103423Snectar IN6_IS_ADDR_MC_LINKLOCAL(p)){ 251103423Snectar ((struct sockaddr_in6*)sa)->sin6_scope_id = scopeid; 252103423Snectar } 253103423Snectar#endif 254103423Snectar max_prefixlen = 128; 255103423Snectar break; 256103423Snectar default: 257103423Snectar return NULL; 258103423Snectar } 259103423Snectar sa->sa_family = family; 260103423Snectar#ifdef HAVE_SOCKADDR_SA_LEN 261103423Snectar sa->sa_len = ifa_sa_len(family, len); 262103423Snectar#endif 263103423Snectar if (p){ 264103423Snectar if (prefixlen > max_prefixlen) 265103423Snectar prefixlen = max_prefixlen; 266103423Snectar for (i=0; i<(prefixlen / 8); i++) 267103423Snectar *p++ = 0xff; 268103423Snectar c = 0xff; 269103423Snectar c <<= (8 - (prefixlen % 8)); 270103423Snectar *p = c; 271103423Snectar } 272103423Snectar return sa; 273103423Snectar} 274103423Snectar#endif 275103423Snectar 276103423Snectar/* ====================================================================== */ 277103423Snectarstatic int 278103423Snectarnl_sendreq(int sd, int request, int flags, int *seq) 279103423Snectar{ 280103423Snectar char reqbuf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 281103423Snectar NLMSG_ALIGN(sizeof(struct rtgenmsg))]; 282103423Snectar struct sockaddr_nl nladdr; 283103423Snectar struct nlmsghdr *req_hdr; 284103423Snectar struct rtgenmsg *req_msg; 285103423Snectar time_t t = time(NULL); 286103423Snectar 287103423Snectar if (seq) *seq = t; 288103423Snectar memset(&reqbuf, 0, sizeof(reqbuf)); 289103423Snectar req_hdr = (struct nlmsghdr *)reqbuf; 290103423Snectar req_msg = (struct rtgenmsg *)NLMSG_DATA(req_hdr); 291103423Snectar req_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*req_msg)); 292103423Snectar req_hdr->nlmsg_type = request; 293103423Snectar req_hdr->nlmsg_flags = flags | NLM_F_REQUEST; 294103423Snectar req_hdr->nlmsg_pid = 0; 295103423Snectar req_hdr->nlmsg_seq = t; 296103423Snectar req_msg->rtgen_family = AF_UNSPEC; 297103423Snectar memset(&nladdr, 0, sizeof(nladdr)); 298103423Snectar nladdr.nl_family = AF_NETLINK; 299103423Snectar return (sendto(sd, (void *)req_hdr, req_hdr->nlmsg_len, 0, 300103423Snectar (struct sockaddr *)&nladdr, sizeof(nladdr))); 301103423Snectar} 302103423Snectar 303103423Snectarstatic int 304103423Snectarnl_recvmsg(int sd, int request, int seq, 305103423Snectar void *buf, size_t buflen, 306103423Snectar int *flags) 307103423Snectar{ 308103423Snectar struct msghdr msg; 309103423Snectar struct iovec iov = { buf, buflen }; 310103423Snectar struct sockaddr_nl nladdr; 311103423Snectar int read_len; 312103423Snectar 313103423Snectar for (;;){ 314103423Snectar msg.msg_name = (void *)&nladdr; 315103423Snectar msg.msg_namelen = sizeof(nladdr); 316103423Snectar msg.msg_iov = &iov; 317103423Snectar msg.msg_iovlen = 1; 318103423Snectar msg.msg_control = NULL; 319103423Snectar msg.msg_controllen = 0; 320103423Snectar msg.msg_flags = 0; 321103423Snectar read_len = recvmsg(sd, &msg, 0); 322103423Snectar if ((read_len < 0 && errno == EINTR) || (msg.msg_flags & MSG_TRUNC)) 323103423Snectar continue; 324103423Snectar if (flags) *flags = msg.msg_flags; 325103423Snectar break; 326103423Snectar } 327103423Snectar return read_len; 328103423Snectar} 329103423Snectar 330103423Snectarstatic int 331103423Snectarnl_getmsg(int sd, int request, int seq, 332103423Snectar struct nlmsghdr **nlhp, 333103423Snectar int *done) 334103423Snectar{ 335103423Snectar struct nlmsghdr *nh; 336103423Snectar size_t bufsize = 65536, lastbufsize = 0; 337103423Snectar void *buff = NULL; 338103423Snectar int result = 0, read_size; 339103423Snectar int msg_flags; 340103423Snectar pid_t pid = getpid(); 341103423Snectar for (;;){ 342103423Snectar void *newbuff = realloc(buff, bufsize); 343103423Snectar if (newbuff == NULL || bufsize < lastbufsize) { 344103423Snectar result = -1; 345103423Snectar break; 346103423Snectar } 347103423Snectar buff = newbuff; 348103423Snectar result = read_size = nl_recvmsg(sd, request, seq, buff, bufsize, &msg_flags); 349103423Snectar if (read_size < 0 || (msg_flags & MSG_TRUNC)){ 350103423Snectar lastbufsize = bufsize; 351103423Snectar bufsize *= 2; 352103423Snectar continue; 353103423Snectar } 354103423Snectar if (read_size == 0) break; 355103423Snectar nh = (struct nlmsghdr *)buff; 356103423Snectar for (nh = (struct nlmsghdr *)buff; 357103423Snectar NLMSG_OK(nh, read_size); 358103423Snectar nh = (struct nlmsghdr *)NLMSG_NEXT(nh, read_size)){ 359103423Snectar if (nh->nlmsg_pid != pid || 360103423Snectar nh->nlmsg_seq != seq) 361103423Snectar continue; 362103423Snectar if (nh->nlmsg_type == NLMSG_DONE){ 363103423Snectar (*done)++; 364103423Snectar break; /* ok */ 365103423Snectar } 366103423Snectar if (nh->nlmsg_type == NLMSG_ERROR){ 367103423Snectar struct nlmsgerr *nlerr = (struct nlmsgerr *)NLMSG_DATA(nh); 368103423Snectar result = -1; 369103423Snectar if (nh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) 370103423Snectar __set_errno(EIO); 371103423Snectar else 372103423Snectar __set_errno(-nlerr->error); 373103423Snectar break; 374103423Snectar } 375103423Snectar } 376103423Snectar break; 377103423Snectar } 378103423Snectar if (result < 0) 379103423Snectar if (buff){ 380103423Snectar int saved_errno = errno; 381103423Snectar free(buff); 382103423Snectar __set_errno(saved_errno); 383103423Snectar } 384103423Snectar *nlhp = (struct nlmsghdr *)buff; 385103423Snectar return result; 386103423Snectar} 387103423Snectar 38872445Sassarstatic int 389103423Snectarnl_getlist(int sd, int seq, 390103423Snectar int request, 391103423Snectar struct nlmsg_list **nlm_list, 392103423Snectar struct nlmsg_list **nlm_end) 393103423Snectar{ 394103423Snectar struct nlmsghdr *nlh = NULL; 395103423Snectar int status; 396103423Snectar int done = 0; 397178825Sdfr int tries = 3; 398103423Snectar 399178825Sdfr try_again: 400103423Snectar status = nl_sendreq(sd, request, NLM_F_ROOT|NLM_F_MATCH, &seq); 401103423Snectar if (status < 0) 402103423Snectar return status; 403103423Snectar if (seq == 0) 404103423Snectar seq = (int)time(NULL); 405103423Snectar while(!done){ 406178825Sdfr struct pollfd pfd; 407178825Sdfr 408178825Sdfr pfd.fd = sd; 409178825Sdfr pfd.events = POLLIN | POLLPRI; 410178825Sdfr pfd.revents = 0; 411178825Sdfr status = poll(&pfd, 1, 1000); 412178825Sdfr if (status < 0) 413178825Sdfr return status; 414178825Sdfr else if (status == 0) { 415178825Sdfr seq++; 416178825Sdfr if (tries-- > 0) 417178825Sdfr goto try_again; 418178825Sdfr return -1; 419178825Sdfr } 420178825Sdfr 421103423Snectar status = nl_getmsg(sd, request, seq, &nlh, &done); 422103423Snectar if (status < 0) 423103423Snectar return status; 424103423Snectar if (nlh){ 425103423Snectar struct nlmsg_list *nlm_next = (struct nlmsg_list *)malloc(sizeof(struct nlmsg_list)); 426103423Snectar if (nlm_next == NULL){ 427103423Snectar int saved_errno = errno; 428103423Snectar free(nlh); 429103423Snectar __set_errno(saved_errno); 430103423Snectar status = -1; 431103423Snectar } else { 432103423Snectar nlm_next->nlm_next = NULL; 433103423Snectar nlm_next->nlh = (struct nlmsghdr *)nlh; 434103423Snectar nlm_next->size = status; 435103423Snectar nlm_next->seq = seq; 436103423Snectar if (*nlm_list == NULL){ 437103423Snectar *nlm_list = nlm_next; 438103423Snectar *nlm_end = nlm_next; 439103423Snectar } else { 440103423Snectar (*nlm_end)->nlm_next = nlm_next; 441103423Snectar *nlm_end = nlm_next; 442103423Snectar } 443103423Snectar } 444103423Snectar } 445103423Snectar } 446103423Snectar return status >= 0 ? seq : status; 447103423Snectar} 448103423Snectar 449103423Snectar/* ---------------------------------------------------------------------- */ 450103423Snectarstatic void 451103423Snectarfree_nlmsglist(struct nlmsg_list *nlm0) 452103423Snectar{ 453178825Sdfr struct nlmsg_list *nlm, *nlm_next; 454103423Snectar int saved_errno; 455103423Snectar if (!nlm0) 456103423Snectar return; 457103423Snectar saved_errno = errno; 458178825Sdfr for (nlm=nlm0; nlm; nlm=nlm_next){ 459103423Snectar if (nlm->nlh) 460103423Snectar free(nlm->nlh); 461178825Sdfr nlm_next=nlm->nlm_next; 462178825Sdfr free(nlm); 463103423Snectar } 464103423Snectar __set_errno(saved_errno); 465103423Snectar} 466103423Snectar 467103423Snectarstatic void 468103423Snectarfree_data(void *data, void *ifdata) 469103423Snectar{ 470103423Snectar int saved_errno = errno; 471103423Snectar if (data != NULL) free(data); 472103423Snectar if (ifdata != NULL) free(ifdata); 473103423Snectar __set_errno(saved_errno); 474103423Snectar} 475103423Snectar 476103423Snectar/* ---------------------------------------------------------------------- */ 477103423Snectarstatic void 478103423Snectarnl_close(int sd) 479103423Snectar{ 480103423Snectar int saved_errno = errno; 481103423Snectar if (sd >= 0) __close(sd); 482103423Snectar __set_errno(saved_errno); 483103423Snectar} 484103423Snectar 485103423Snectar/* ---------------------------------------------------------------------- */ 486103423Snectarstatic int 487103423Snectarnl_open(void) 488103423Snectar{ 489103423Snectar struct sockaddr_nl nladdr; 490103423Snectar int sd; 491103423Snectar 492103423Snectar sd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 493103423Snectar if (sd < 0) return -1; 494103423Snectar memset(&nladdr, 0, sizeof(nladdr)); 495103423Snectar nladdr.nl_family = AF_NETLINK; 496103423Snectar if (bind(sd, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0){ 497103423Snectar nl_close(sd); 498103423Snectar return -1; 499103423Snectar } 500103423Snectar return sd; 501103423Snectar} 502103423Snectar 503103423Snectar/* ====================================================================== */ 504178825Sdfrint ROKEN_LIB_FUNCTION 505178825Sdfrrk_getifaddrs(struct ifaddrs **ifap) 506103423Snectar{ 507103423Snectar int sd; 508103423Snectar struct nlmsg_list *nlmsg_list, *nlmsg_end, *nlm; 509103423Snectar /* - - - - - - - - - - - - - - - */ 510103423Snectar int icnt; 511103423Snectar size_t dlen, xlen, nlen; 512103423Snectar uint32_t max_ifindex = 0; 513103423Snectar 514103423Snectar pid_t pid = getpid(); 515103423Snectar int seq; 516103423Snectar int result; 517103423Snectar int build ; /* 0 or 1 */ 518103423Snectar 519103423Snectar/* ---------------------------------- */ 520103423Snectar /* initialize */ 521103423Snectar icnt = dlen = xlen = nlen = 0; 522103423Snectar nlmsg_list = nlmsg_end = NULL; 523103423Snectar 524103423Snectar if (ifap) 525103423Snectar *ifap = NULL; 526103423Snectar 527103423Snectar/* ---------------------------------- */ 528103423Snectar /* open socket and bind */ 529103423Snectar sd = nl_open(); 530103423Snectar if (sd < 0) 531103423Snectar return -1; 532103423Snectar 533103423Snectar/* ---------------------------------- */ 534103423Snectar /* gather info */ 535103423Snectar if ((seq = nl_getlist(sd, 0, RTM_GETLINK, 536103423Snectar &nlmsg_list, &nlmsg_end)) < 0){ 537103423Snectar free_nlmsglist(nlmsg_list); 538103423Snectar nl_close(sd); 539103423Snectar return -1; 540103423Snectar } 541103423Snectar if ((seq = nl_getlist(sd, seq+1, RTM_GETADDR, 542103423Snectar &nlmsg_list, &nlmsg_end)) < 0){ 543103423Snectar free_nlmsglist(nlmsg_list); 544103423Snectar nl_close(sd); 545103423Snectar return -1; 546103423Snectar } 547103423Snectar 548103423Snectar/* ---------------------------------- */ 549103423Snectar /* Estimate size of result buffer and fill it */ 550103423Snectar for (build=0; build<=1; build++){ 551103423Snectar struct ifaddrs *ifl = NULL, *ifa = NULL; 552103423Snectar struct nlmsghdr *nlh, *nlh0; 553103423Snectar char *data = NULL, *xdata = NULL; 554103423Snectar void *ifdata = NULL; 555103423Snectar char *ifname = NULL, **iflist = NULL; 556103423Snectar uint16_t *ifflist = NULL; 557103423Snectar struct rtmaddr_ifamap ifamap; 558103423Snectar 559103423Snectar if (build){ 560103423Snectar data = calloc(1, 561103423Snectar NLMSG_ALIGN(sizeof(struct ifaddrs[icnt])) 562103423Snectar + dlen + xlen + nlen); 563103423Snectar ifa = (struct ifaddrs *)data; 564103423Snectar ifdata = calloc(1, 565103423Snectar NLMSG_ALIGN(sizeof(char *[max_ifindex+1])) 566103423Snectar + NLMSG_ALIGN(sizeof(uint16_t [max_ifindex+1]))); 567103423Snectar if (ifap != NULL) 568103423Snectar *ifap = (ifdata != NULL) ? ifa : NULL; 569103423Snectar else{ 570103423Snectar free_data(data, ifdata); 571103423Snectar result = 0; 572103423Snectar break; 573103423Snectar } 574103423Snectar if (data == NULL || ifdata == NULL){ 575103423Snectar free_data(data, ifdata); 576103423Snectar result = -1; 577103423Snectar break; 578103423Snectar } 579103423Snectar ifl = NULL; 580103423Snectar data += NLMSG_ALIGN(sizeof(struct ifaddrs)) * icnt; 581103423Snectar xdata = data + dlen; 582103423Snectar ifname = xdata + xlen; 583103423Snectar iflist = ifdata; 584103423Snectar ifflist = (uint16_t *)(((char *)iflist) + NLMSG_ALIGN(sizeof(char *[max_ifindex+1]))); 585103423Snectar } 586103423Snectar 587103423Snectar for (nlm=nlmsg_list; nlm; nlm=nlm->nlm_next){ 588103423Snectar int nlmlen = nlm->size; 589103423Snectar if (!(nlh0 = nlm->nlh)) 590103423Snectar continue; 591103423Snectar for (nlh = nlh0; 592103423Snectar NLMSG_OK(nlh, nlmlen); 593103423Snectar nlh=NLMSG_NEXT(nlh,nlmlen)){ 594103423Snectar struct ifinfomsg *ifim = NULL; 595103423Snectar struct ifaddrmsg *ifam = NULL; 596103423Snectar struct rtattr *rta; 597103423Snectar 598103423Snectar size_t nlm_struct_size = 0; 599103423Snectar sa_family_t nlm_family = 0; 600103423Snectar uint32_t nlm_scope = 0, nlm_index = 0; 601103423Snectar size_t sockaddr_size = 0; 602103423Snectar uint32_t nlm_prefixlen = 0; 603103423Snectar size_t rtasize; 604103423Snectar 605103423Snectar memset(&ifamap, 0, sizeof(ifamap)); 606103423Snectar 607103423Snectar /* check if the message is what we want */ 608103423Snectar if (nlh->nlmsg_pid != pid || 609103423Snectar nlh->nlmsg_seq != nlm->seq) 610103423Snectar continue; 611103423Snectar if (nlh->nlmsg_type == NLMSG_DONE){ 612103423Snectar break; /* ok */ 613103423Snectar } 614103423Snectar switch (nlh->nlmsg_type){ 615103423Snectar case RTM_NEWLINK: 616103423Snectar ifim = (struct ifinfomsg *)NLMSG_DATA(nlh); 617103423Snectar nlm_struct_size = sizeof(*ifim); 618103423Snectar nlm_family = ifim->ifi_family; 619103423Snectar nlm_scope = 0; 620103423Snectar nlm_index = ifim->ifi_index; 621103423Snectar nlm_prefixlen = 0; 622103423Snectar if (build) 623103423Snectar ifflist[nlm_index] = ifa->ifa_flags = ifim->ifi_flags; 624103423Snectar break; 625103423Snectar case RTM_NEWADDR: 626103423Snectar ifam = (struct ifaddrmsg *)NLMSG_DATA(nlh); 627103423Snectar nlm_struct_size = sizeof(*ifam); 628103423Snectar nlm_family = ifam->ifa_family; 629103423Snectar nlm_scope = ifam->ifa_scope; 630103423Snectar nlm_index = ifam->ifa_index; 631103423Snectar nlm_prefixlen = ifam->ifa_prefixlen; 632103423Snectar if (build) 633103423Snectar ifa->ifa_flags = ifflist[nlm_index]; 634103423Snectar break; 635103423Snectar default: 636103423Snectar continue; 637103423Snectar } 638103423Snectar 639103423Snectar if (!build){ 640103423Snectar if (max_ifindex < nlm_index) 641103423Snectar max_ifindex = nlm_index; 642103423Snectar } else { 643103423Snectar if (ifl != NULL) 644103423Snectar ifl->ifa_next = ifa; 645103423Snectar } 646103423Snectar 647103423Snectar rtasize = NLMSG_PAYLOAD(nlh, nlmlen) - NLMSG_ALIGN(nlm_struct_size); 648103423Snectar for (rta = (struct rtattr *)(((char *)NLMSG_DATA(nlh)) + NLMSG_ALIGN(nlm_struct_size)); 649103423Snectar RTA_OK(rta, rtasize); 650103423Snectar rta = RTA_NEXT(rta, rtasize)){ 651103423Snectar struct sockaddr **sap = NULL; 652103423Snectar void *rtadata = RTA_DATA(rta); 653103423Snectar size_t rtapayload = RTA_PAYLOAD(rta); 654103423Snectar socklen_t sa_len; 655103423Snectar 656103423Snectar switch(nlh->nlmsg_type){ 657103423Snectar case RTM_NEWLINK: 658103423Snectar switch(rta->rta_type){ 659103423Snectar case IFLA_ADDRESS: 660103423Snectar case IFLA_BROADCAST: 661103423Snectar if (build){ 662103423Snectar sap = (rta->rta_type == IFLA_ADDRESS) ? &ifa->ifa_addr : &ifa->ifa_broadaddr; 663103423Snectar *sap = (struct sockaddr *)data; 664103423Snectar } 665103423Snectar sa_len = ifa_sa_len(AF_PACKET, rtapayload); 666103423Snectar if (rta->rta_type == IFLA_ADDRESS) 667103423Snectar sockaddr_size = NLMSG_ALIGN(sa_len); 668103423Snectar if (!build){ 669103423Snectar dlen += NLMSG_ALIGN(sa_len); 670103423Snectar } else { 671103423Snectar memset(*sap, 0, sa_len); 672103423Snectar ifa_make_sockaddr(AF_PACKET, *sap, rtadata,rtapayload, 0,0); 673103423Snectar ((struct sockaddr_ll *)*sap)->sll_ifindex = nlm_index; 674103423Snectar ((struct sockaddr_ll *)*sap)->sll_hatype = ifim->ifi_type; 675103423Snectar data += NLMSG_ALIGN(sa_len); 676103423Snectar } 677103423Snectar break; 678103423Snectar case IFLA_IFNAME:/* Name of Interface */ 679103423Snectar if (!build) 680103423Snectar nlen += NLMSG_ALIGN(rtapayload + 1); 681103423Snectar else{ 682103423Snectar ifa->ifa_name = ifname; 683103423Snectar if (iflist[nlm_index] == NULL) 684103423Snectar iflist[nlm_index] = ifa->ifa_name; 685103423Snectar strncpy(ifa->ifa_name, rtadata, rtapayload); 686103423Snectar ifa->ifa_name[rtapayload] = '\0'; 687103423Snectar ifname += NLMSG_ALIGN(rtapayload + 1); 688103423Snectar } 689103423Snectar break; 690103423Snectar case IFLA_STATS:/* Statistics of Interface */ 691103423Snectar if (!build) 692103423Snectar xlen += NLMSG_ALIGN(rtapayload); 693103423Snectar else{ 694103423Snectar ifa->ifa_data = xdata; 695103423Snectar memcpy(ifa->ifa_data, rtadata, rtapayload); 696103423Snectar xdata += NLMSG_ALIGN(rtapayload); 697103423Snectar } 698103423Snectar break; 699103423Snectar case IFLA_UNSPEC: 700103423Snectar break; 701103423Snectar case IFLA_MTU: 702103423Snectar break; 703103423Snectar case IFLA_LINK: 704103423Snectar break; 705103423Snectar case IFLA_QDISC: 706103423Snectar break; 707103423Snectar default: 708178825Sdfr break; 709103423Snectar } 710103423Snectar break; 711103423Snectar case RTM_NEWADDR: 712103423Snectar if (nlm_family == AF_PACKET) break; 713103423Snectar switch(rta->rta_type){ 714103423Snectar case IFA_ADDRESS: 715103423Snectar ifamap.address = rtadata; 716103423Snectar ifamap.address_len = rtapayload; 717103423Snectar break; 718103423Snectar case IFA_LOCAL: 719103423Snectar ifamap.local = rtadata; 720103423Snectar ifamap.local_len = rtapayload; 721103423Snectar break; 722103423Snectar case IFA_BROADCAST: 723103423Snectar ifamap.broadcast = rtadata; 724103423Snectar ifamap.broadcast_len = rtapayload; 725103423Snectar break; 726103423Snectar#ifdef HAVE_IFADDRS_IFA_ANYCAST 727103423Snectar case IFA_ANYCAST: 728103423Snectar ifamap.anycast = rtadata; 729103423Snectar ifamap.anycast_len = rtapayload; 730103423Snectar break; 731103423Snectar#endif 732103423Snectar case IFA_LABEL: 733103423Snectar if (!build) 734103423Snectar nlen += NLMSG_ALIGN(rtapayload + 1); 735103423Snectar else{ 736103423Snectar ifa->ifa_name = ifname; 737103423Snectar if (iflist[nlm_index] == NULL) 738103423Snectar iflist[nlm_index] = ifname; 739103423Snectar strncpy(ifa->ifa_name, rtadata, rtapayload); 740103423Snectar ifa->ifa_name[rtapayload] = '\0'; 741103423Snectar ifname += NLMSG_ALIGN(rtapayload + 1); 742103423Snectar } 743103423Snectar break; 744103423Snectar case IFA_UNSPEC: 745103423Snectar break; 746103423Snectar case IFA_CACHEINFO: 747103423Snectar break; 748103423Snectar default: 749178825Sdfr break; 750103423Snectar } 751103423Snectar } 752103423Snectar } 753103423Snectar if (nlh->nlmsg_type == RTM_NEWADDR && 754103423Snectar nlm_family != AF_PACKET) { 755103423Snectar if (!ifamap.local) { 756103423Snectar ifamap.local = ifamap.address; 757103423Snectar ifamap.local_len = ifamap.address_len; 758103423Snectar } 759103423Snectar if (!ifamap.address) { 760103423Snectar ifamap.address = ifamap.local; 761103423Snectar ifamap.address_len = ifamap.local_len; 762103423Snectar } 763103423Snectar if (ifamap.address_len != ifamap.local_len || 764103423Snectar (ifamap.address != NULL && 765103423Snectar memcmp(ifamap.address, ifamap.local, ifamap.address_len))) { 766103423Snectar /* p2p; address is peer and local is ours */ 767103423Snectar ifamap.broadcast = ifamap.address; 768103423Snectar ifamap.broadcast_len = ifamap.address_len; 769103423Snectar ifamap.address = ifamap.local; 770103423Snectar ifamap.address_len = ifamap.local_len; 771103423Snectar } 772103423Snectar if (ifamap.address) { 773103423Snectar#ifndef IFA_NETMASK 774103423Snectar sockaddr_size = NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len)); 775103423Snectar#endif 776103423Snectar if (!build) 777103423Snectar dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len)); 778103423Snectar else { 779103423Snectar ifa->ifa_addr = (struct sockaddr *)data; 780103423Snectar ifa_make_sockaddr(nlm_family, ifa->ifa_addr, ifamap.address, ifamap.address_len, 781103423Snectar nlm_scope, nlm_index); 782103423Snectar data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.address_len)); 783103423Snectar } 784103423Snectar } 785103423Snectar#ifdef IFA_NETMASK 786103423Snectar if (ifamap.netmask) { 787103423Snectar if (!build) 788103423Snectar dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.netmask_len)); 789103423Snectar else { 790103423Snectar ifa->ifa_netmask = (struct sockaddr *)data; 791103423Snectar ifa_make_sockaddr(nlm_family, ifa->ifa_netmask, ifamap.netmask, ifamap.netmask_len, 792103423Snectar nlm_scope, nlm_index); 793103423Snectar data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.netmask_len)); 794103423Snectar } 795103423Snectar } 796103423Snectar#endif 797103423Snectar if (ifamap.broadcast) { 798103423Snectar if (!build) 799103423Snectar dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.broadcast_len)); 800103423Snectar else { 801103423Snectar ifa->ifa_broadaddr = (struct sockaddr *)data; 802103423Snectar ifa_make_sockaddr(nlm_family, ifa->ifa_broadaddr, ifamap.broadcast, ifamap.broadcast_len, 803103423Snectar nlm_scope, nlm_index); 804103423Snectar data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.broadcast_len)); 805103423Snectar } 806103423Snectar } 807103423Snectar#ifdef HAVE_IFADDRS_IFA_ANYCAST 808103423Snectar if (ifamap.anycast) { 809103423Snectar if (!build) 810103423Snectar dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.anycast_len)); 811103423Snectar else { 812103423Snectar ifa->ifa_anycast = (struct sockaddr *)data; 813103423Snectar ifa_make_sockaddr(nlm_family, ifa->ifa_anyaddr, ifamap.anycast, ifamap.anycast_len, 814103423Snectar nlm_scope, nlm_index); 815103423Snectar data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.anycast_len)); 816103423Snectar } 817103423Snectar } 818103423Snectar#endif 819103423Snectar } 820103423Snectar if (!build){ 821103423Snectar#ifndef IFA_NETMASK 822103423Snectar dlen += sockaddr_size; 823103423Snectar#endif 824103423Snectar icnt++; 825103423Snectar } else { 826103423Snectar if (ifa->ifa_name == NULL) 827103423Snectar ifa->ifa_name = iflist[nlm_index]; 828103423Snectar#ifndef IFA_NETMASK 829103423Snectar if (ifa->ifa_addr && 830103423Snectar ifa->ifa_addr->sa_family != AF_UNSPEC && 831103423Snectar ifa->ifa_addr->sa_family != AF_PACKET){ 832103423Snectar ifa->ifa_netmask = (struct sockaddr *)data; 833103423Snectar ifa_make_sockaddr_mask(ifa->ifa_addr->sa_family, ifa->ifa_netmask, nlm_prefixlen); 834103423Snectar } 835103423Snectar data += sockaddr_size; 836103423Snectar#endif 837103423Snectar ifl = ifa++; 838103423Snectar } 839103423Snectar } 840103423Snectar } 841103423Snectar if (!build){ 842103423Snectar if (icnt == 0 && (dlen + nlen + xlen == 0)){ 843103423Snectar if (ifap != NULL) 844103423Snectar *ifap = NULL; 845103423Snectar break; /* cannot found any addresses */ 846103423Snectar } 847103423Snectar } 848103423Snectar else 849103423Snectar free_data(NULL, ifdata); 850103423Snectar } 851103423Snectar 852103423Snectar/* ---------------------------------- */ 853103423Snectar /* Finalize */ 854103423Snectar free_nlmsglist(nlmsg_list); 855103423Snectar nl_close(sd); 856103423Snectar return 0; 857103423Snectar} 858103423Snectar 859103423Snectar#else /* !AF_NETLINK */ 860103423Snectar 861103423Snectar/* 862103423Snectar * The generic SIOCGIFCONF version. 863103423Snectar */ 864103423Snectar 865103423Snectarstatic int 86672445Sassargetifaddrs2(struct ifaddrs **ifap, 86772445Sassar int af, int siocgifconf, int siocgifflags, 86872445Sassar size_t ifreq_sz) 86972445Sassar{ 87072445Sassar int ret; 87172445Sassar int fd; 87272445Sassar size_t buf_size; 87372445Sassar char *buf; 87472445Sassar struct ifconf ifconf; 87572445Sassar char *p; 87672445Sassar size_t sz; 87772445Sassar struct sockaddr sa_zero; 87872445Sassar struct ifreq *ifr; 87990926Snectar struct ifaddrs *start = NULL, **end = &start; 88072445Sassar 88172445Sassar buf = NULL; 88272445Sassar 88372445Sassar memset (&sa_zero, 0, sizeof(sa_zero)); 88472445Sassar fd = socket(af, SOCK_DGRAM, 0); 88572445Sassar if (fd < 0) 88672445Sassar return -1; 88772445Sassar 88872445Sassar buf_size = 8192; 88972445Sassar for (;;) { 89072445Sassar buf = calloc(1, buf_size); 89172445Sassar if (buf == NULL) { 89272445Sassar ret = ENOMEM; 89372445Sassar goto error_out; 89472445Sassar } 89572445Sassar ifconf.ifc_len = buf_size; 89672445Sassar ifconf.ifc_buf = buf; 89772445Sassar 89872445Sassar /* 89972445Sassar * Solaris returns EINVAL when the buffer is too small. 90072445Sassar */ 90172445Sassar if (ioctl (fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) { 90272445Sassar ret = errno; 90372445Sassar goto error_out; 90472445Sassar } 90572445Sassar /* 90672445Sassar * Can the difference between a full and a overfull buf 90772445Sassar * be determined? 90872445Sassar */ 90972445Sassar 91072445Sassar if (ifconf.ifc_len < buf_size) 91172445Sassar break; 91272445Sassar free (buf); 91372445Sassar buf_size *= 2; 91472445Sassar } 91572445Sassar 91672445Sassar for (p = ifconf.ifc_buf; 91772445Sassar p < ifconf.ifc_buf + ifconf.ifc_len; 91872445Sassar p += sz) { 91972445Sassar struct ifreq ifreq; 92072445Sassar struct sockaddr *sa; 92172445Sassar size_t salen; 92272445Sassar 92372445Sassar ifr = (struct ifreq *)p; 92472445Sassar sa = &ifr->ifr_addr; 92572445Sassar 92672445Sassar sz = ifreq_sz; 92772445Sassar salen = sizeof(struct sockaddr); 92872445Sassar#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 92972445Sassar salen = sa->sa_len; 93072445Sassar sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len); 93172445Sassar#endif 93272445Sassar#ifdef SA_LEN 93372445Sassar salen = SA_LEN(sa); 93472445Sassar sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa)); 93572445Sassar#endif 93672445Sassar memset (&ifreq, 0, sizeof(ifreq)); 93772445Sassar memcpy (ifreq.ifr_name, ifr->ifr_name, sizeof(ifr->ifr_name)); 93872445Sassar 93972445Sassar if (ioctl(fd, siocgifflags, &ifreq) < 0) { 94072445Sassar ret = errno; 94172445Sassar goto error_out; 94272445Sassar } 94372445Sassar 94472445Sassar *end = malloc(sizeof(**end)); 94590926Snectar if (*end == NULL) { 94690926Snectar ret = ENOMEM; 94790926Snectar goto error_out; 94890926Snectar } 94972445Sassar 95072445Sassar (*end)->ifa_next = NULL; 95172445Sassar (*end)->ifa_name = strdup(ifr->ifr_name); 952178825Sdfr if ((*end)->ifa_name == NULL) { 953178825Sdfr ret = ENOMEM; 954178825Sdfr goto error_out; 955178825Sdfr } 95672445Sassar (*end)->ifa_flags = ifreq.ifr_flags; 95772445Sassar (*end)->ifa_addr = malloc(salen); 958178825Sdfr if ((*end)->ifa_addr == NULL) { 959178825Sdfr ret = ENOMEM; 960178825Sdfr goto error_out; 961178825Sdfr } 96272445Sassar memcpy((*end)->ifa_addr, sa, salen); 96372445Sassar (*end)->ifa_netmask = NULL; 96472445Sassar 96572445Sassar#if 0 96672445Sassar /* fix these when we actually need them */ 96772445Sassar if(ifreq.ifr_flags & IFF_BROADCAST) { 96872445Sassar (*end)->ifa_broadaddr = malloc(sizeof(ifr->ifr_broadaddr)); 969178825Sdfr if ((*end)->ifa_broadaddr == NULL) { 970178825Sdfr ret = ENOMEM; 971178825Sdfr goto error_out; 972178825Sdfr } 97372445Sassar memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr, 97472445Sassar sizeof(ifr->ifr_broadaddr)); 97572445Sassar } else if(ifreq.ifr_flags & IFF_POINTOPOINT) { 97672445Sassar (*end)->ifa_dstaddr = malloc(sizeof(ifr->ifr_dstaddr)); 977178825Sdfr if ((*end)->ifa_dstaddr == NULL) { 978178825Sdfr ret = ENOMEM; 979178825Sdfr goto error_out; 980178825Sdfr } 98172445Sassar memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr, 98272445Sassar sizeof(ifr->ifr_dstaddr)); 98372445Sassar } else 98472445Sassar (*end)->ifa_dstaddr = NULL; 98572445Sassar#else 98672445Sassar (*end)->ifa_dstaddr = NULL; 98772445Sassar#endif 98872445Sassar 98972445Sassar (*end)->ifa_data = NULL; 99072445Sassar 99172445Sassar end = &(*end)->ifa_next; 99272445Sassar 99372445Sassar } 99472445Sassar *ifap = start; 99578527Sassar close(fd); 99672445Sassar free(buf); 99772445Sassar return 0; 99872445Sassar error_out: 999178825Sdfr rk_freeifaddrs(start); 100078527Sassar close(fd); 100172445Sassar free(buf); 100272445Sassar errno = ret; 100372445Sassar return -1; 100472445Sassar} 100572445Sassar 100690926Snectar#if defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS) 100790926Snectarstatic int 100890926Snectargetlifaddrs2(struct ifaddrs **ifap, 100990926Snectar int af, int siocgifconf, int siocgifflags, 101090926Snectar size_t ifreq_sz) 101190926Snectar{ 101290926Snectar int ret; 101390926Snectar int fd; 101490926Snectar size_t buf_size; 101590926Snectar char *buf; 101690926Snectar struct lifconf ifconf; 101790926Snectar char *p; 101890926Snectar size_t sz; 101990926Snectar struct sockaddr sa_zero; 102090926Snectar struct lifreq *ifr; 102190926Snectar struct ifaddrs *start = NULL, **end = &start; 102290926Snectar 102390926Snectar buf = NULL; 102490926Snectar 102590926Snectar memset (&sa_zero, 0, sizeof(sa_zero)); 102690926Snectar fd = socket(af, SOCK_DGRAM, 0); 102790926Snectar if (fd < 0) 102890926Snectar return -1; 102990926Snectar 103090926Snectar buf_size = 8192; 103190926Snectar for (;;) { 103290926Snectar buf = calloc(1, buf_size); 103390926Snectar if (buf == NULL) { 103490926Snectar ret = ENOMEM; 103590926Snectar goto error_out; 103690926Snectar } 1037178825Sdfr#ifndef __hpux 103890926Snectar ifconf.lifc_family = AF_UNSPEC; 103990926Snectar ifconf.lifc_flags = 0; 1040178825Sdfr#endif 104190926Snectar ifconf.lifc_len = buf_size; 104290926Snectar ifconf.lifc_buf = buf; 104390926Snectar 104490926Snectar /* 104590926Snectar * Solaris returns EINVAL when the buffer is too small. 104690926Snectar */ 104790926Snectar if (ioctl (fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) { 104890926Snectar ret = errno; 104990926Snectar goto error_out; 105090926Snectar } 105190926Snectar /* 105290926Snectar * Can the difference between a full and a overfull buf 105390926Snectar * be determined? 105490926Snectar */ 105590926Snectar 105690926Snectar if (ifconf.lifc_len < buf_size) 105790926Snectar break; 105890926Snectar free (buf); 105990926Snectar buf_size *= 2; 106090926Snectar } 106190926Snectar 106290926Snectar for (p = ifconf.lifc_buf; 106390926Snectar p < ifconf.lifc_buf + ifconf.lifc_len; 106490926Snectar p += sz) { 106590926Snectar struct lifreq ifreq; 106690926Snectar struct sockaddr_storage *sa; 106790926Snectar size_t salen; 106890926Snectar 106990926Snectar ifr = (struct lifreq *)p; 107090926Snectar sa = &ifr->lifr_addr; 107190926Snectar 107290926Snectar sz = ifreq_sz; 107390926Snectar salen = sizeof(struct sockaddr_storage); 107490926Snectar#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 107590926Snectar salen = sa->sa_len; 107690926Snectar sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len); 107790926Snectar#endif 107890926Snectar#ifdef SA_LEN 107990926Snectar salen = SA_LEN(sa); 108090926Snectar sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa)); 108190926Snectar#endif 108290926Snectar memset (&ifreq, 0, sizeof(ifreq)); 108390926Snectar memcpy (ifreq.lifr_name, ifr->lifr_name, sizeof(ifr->lifr_name)); 108490926Snectar 108590926Snectar if (ioctl(fd, siocgifflags, &ifreq) < 0) { 108690926Snectar ret = errno; 108790926Snectar goto error_out; 108890926Snectar } 108990926Snectar 109090926Snectar *end = malloc(sizeof(**end)); 1091178825Sdfr if (*end == NULL) { 1092178825Sdfr ret = ENOMEM; 1093178825Sdfr goto error_out; 1094178825Sdfr } 109590926Snectar 109690926Snectar (*end)->ifa_next = NULL; 109790926Snectar (*end)->ifa_name = strdup(ifr->lifr_name); 1098178825Sdfr if ((*end)->ifa_name == NULL) { 1099178825Sdfr ret = ENOMEM; 1100178825Sdfr goto error_out; 1101178825Sdfr } 110290926Snectar (*end)->ifa_flags = ifreq.lifr_flags; 110390926Snectar (*end)->ifa_addr = malloc(salen); 1104178825Sdfr if ((*end)->ifa_addr == NULL) { 1105178825Sdfr ret = ENOMEM; 1106178825Sdfr goto error_out; 1107178825Sdfr } 110890926Snectar memcpy((*end)->ifa_addr, sa, salen); 110990926Snectar (*end)->ifa_netmask = NULL; 111090926Snectar 111190926Snectar#if 0 111290926Snectar /* fix these when we actually need them */ 111390926Snectar if(ifreq.ifr_flags & IFF_BROADCAST) { 111490926Snectar (*end)->ifa_broadaddr = malloc(sizeof(ifr->ifr_broadaddr)); 1115178825Sdfr if ((*end)->ifa_broadaddr == NULL) { 1116178825Sdfr ret = ENOMEM; 1117178825Sdfr goto error_out; 1118178825Sdfr } 111990926Snectar memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr, 112090926Snectar sizeof(ifr->ifr_broadaddr)); 112190926Snectar } else if(ifreq.ifr_flags & IFF_POINTOPOINT) { 112290926Snectar (*end)->ifa_dstaddr = malloc(sizeof(ifr->ifr_dstaddr)); 1123178825Sdfr if ((*end)->ifa_dstaddr == NULL) { 1124178825Sdfr ret = ENOMEM; 1125178825Sdfr goto error_out; 1126178825Sdfr } 112790926Snectar memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr, 112890926Snectar sizeof(ifr->ifr_dstaddr)); 112990926Snectar } else 113090926Snectar (*end)->ifa_dstaddr = NULL; 113190926Snectar#else 113290926Snectar (*end)->ifa_dstaddr = NULL; 113390926Snectar#endif 113490926Snectar 113590926Snectar (*end)->ifa_data = NULL; 113690926Snectar 113790926Snectar end = &(*end)->ifa_next; 113890926Snectar 113990926Snectar } 114090926Snectar *ifap = start; 114190926Snectar close(fd); 114290926Snectar free(buf); 114390926Snectar return 0; 114490926Snectar error_out: 1145178825Sdfr rk_freeifaddrs(start); 114690926Snectar close(fd); 114790926Snectar free(buf); 114890926Snectar errno = ret; 114990926Snectar return -1; 115090926Snectar} 115190926Snectar#endif /* defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS) */ 115290926Snectar 1153178825Sdfrint ROKEN_LIB_FUNCTION 1154178825Sdfrrk_getifaddrs(struct ifaddrs **ifap) 115572445Sassar{ 115672445Sassar int ret = -1; 115772445Sassar errno = ENXIO; 115872445Sassar#if defined(AF_INET6) && defined(SIOCGIF6CONF) && defined(SIOCGIF6FLAGS) 115972445Sassar if (ret) 116072445Sassar ret = getifaddrs2 (ifap, AF_INET6, SIOCGIF6CONF, SIOCGIF6FLAGS, 116172445Sassar sizeof(struct in6_ifreq)); 116272445Sassar#endif 116390926Snectar#if defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS) 116490926Snectar if (ret) 116590926Snectar ret = getlifaddrs2 (ifap, AF_INET6, SIOCGLIFCONF, SIOCGLIFFLAGS, 116690926Snectar sizeof(struct lifreq)); 116790926Snectar#endif 116872445Sassar#if defined(HAVE_IPV6) && defined(SIOCGIFCONF) 116972445Sassar if (ret) 117072445Sassar ret = getifaddrs2 (ifap, AF_INET6, SIOCGIFCONF, SIOCGIFFLAGS, 117172445Sassar sizeof(struct ifreq)); 117272445Sassar#endif 117372445Sassar#if defined(AF_INET) && defined(SIOCGIFCONF) && defined(SIOCGIFFLAGS) 117472445Sassar if (ret) 117572445Sassar ret = getifaddrs2 (ifap, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS, 117672445Sassar sizeof(struct ifreq)); 117772445Sassar#endif 117872445Sassar return ret; 117972445Sassar} 118072445Sassar 1181178825Sdfr#endif /* !AF_NETLINK */ 1182178825Sdfr 1183178825Sdfrvoid ROKEN_LIB_FUNCTION 1184178825Sdfrrk_freeifaddrs(struct ifaddrs *ifp) 118572445Sassar{ 118672445Sassar struct ifaddrs *p, *q; 118772445Sassar 118872445Sassar for(p = ifp; p; ) { 118972445Sassar free(p->ifa_name); 119072445Sassar if(p->ifa_addr) 119172445Sassar free(p->ifa_addr); 119272445Sassar if(p->ifa_dstaddr) 119372445Sassar free(p->ifa_dstaddr); 119472445Sassar if(p->ifa_netmask) 119572445Sassar free(p->ifa_netmask); 119672445Sassar if(p->ifa_data) 119772445Sassar free(p->ifa_data); 119872445Sassar q = p; 119972445Sassar p = p->ifa_next; 120072445Sassar free(q); 120172445Sassar } 120272445Sassar} 120372445Sassar 120472445Sassar#ifdef TEST 120572445Sassar 120672445Sassarvoid 120772445Sassarprint_addr(const char *s, struct sockaddr *sa) 120872445Sassar{ 120972445Sassar int i; 121072445Sassar printf(" %s=%d/", s, sa->sa_family); 121172445Sassar#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 121272445Sassar for(i = 0; i < sa->sa_len - ((long)sa->sa_data - (long)&sa->sa_family); i++) 121372445Sassar printf("%02x", ((unsigned char*)sa->sa_data)[i]); 121472445Sassar#else 121572445Sassar for(i = 0; i < sizeof(sa->sa_data); i++) 121672445Sassar printf("%02x", ((unsigned char*)sa->sa_data)[i]); 121772445Sassar#endif 121872445Sassar printf("\n"); 121972445Sassar} 122072445Sassar 122172445Sassarvoid 122272445Sassarprint_ifaddrs(struct ifaddrs *x) 122372445Sassar{ 122472445Sassar struct ifaddrs *p; 122572445Sassar 122672445Sassar for(p = x; p; p = p->ifa_next) { 122772445Sassar printf("%s\n", p->ifa_name); 122872445Sassar printf(" flags=%x\n", p->ifa_flags); 122972445Sassar if(p->ifa_addr) 123072445Sassar print_addr("addr", p->ifa_addr); 123172445Sassar if(p->ifa_dstaddr) 123272445Sassar print_addr("dstaddr", p->ifa_dstaddr); 123372445Sassar if(p->ifa_netmask) 123472445Sassar print_addr("netmask", p->ifa_netmask); 123572445Sassar printf(" %p\n", p->ifa_data); 123672445Sassar } 123772445Sassar} 123872445Sassar 123972445Sassarint 124072445Sassarmain() 124172445Sassar{ 124272445Sassar struct ifaddrs *a = NULL, *b; 124372445Sassar getifaddrs2(&a, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS, sizeof(struct ifreq)); 124472445Sassar print_ifaddrs(a); 124572445Sassar printf("---\n"); 124672445Sassar getifaddrs(&b); 124772445Sassar print_ifaddrs(b); 124872445Sassar return 0; 124972445Sassar} 125072445Sassar#endif 1251