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