xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/roken/getifaddrs.c (revision d3273b5b76f5afaafe308cead5511dbb8df8c5e9)
1 /*	$NetBSD: getifaddrs.c,v 1.2 2017/01/28 21:31:50 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 2000 - 2002, 2005 Kungliga Tekniska Högskolan
5  * (Royal Institute of Technology, Stockholm, Sweden).
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the Institute nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include <config.h>
37 #include <krb5/roken.h>
38 
39 #ifdef __osf__
40 /* hate */
41 struct rtentry;
42 struct mbuf;
43 #endif
44 #ifdef HAVE_NET_IF_H
45 #include <net/if.h>
46 #endif
47 
48 #ifdef HAVE_SYS_SOCKIO_H
49 #include <sys/sockio.h>
50 #endif /* HAVE_SYS_SOCKIO_H */
51 
52 #ifdef HAVE_NETINET_IN6_VAR_H
53 #include <netinet/in6_var.h>
54 #endif /* HAVE_NETINET_IN6_VAR_H */
55 
56 #include <ifaddrs.h>
57 
58 #ifdef __hpux
59 #define lifconf if_laddrconf
60 #define lifc_len iflc_len
61 #define lifc_buf iflc_buf
62 #define lifc_req iflc_req
63 
64 #define lifreq if_laddrreq
65 #define lifr_addr iflr_addr
66 #define lifr_name iflr_name
67 #define lifr_dstaddr iflr_dstaddr
68 #define lifr_broadaddr iflr_broadaddr
69 #define lifr_flags iflr_flags
70 #define lifr_index iflr_index
71 #endif
72 
73 #ifdef AF_NETLINK
74 
75 /*
76  * The linux - AF_NETLINK version of getifaddrs - from Usagi.
77  * Linux does not return v6 addresses from SIOCGIFCONF.
78  */
79 
80 /* $USAGI: ifaddrs.c,v 1.18 2002/03/06 01:50:46 yoshfuji Exp $ */
81 
82 /**************************************************************************
83  * ifaddrs.c
84  * Copyright (C)2000 Hideaki YOSHIFUJI, All Rights Reserved.
85  *
86  * Redistribution and use in source and binary forms, with or without
87  * modification, are permitted provided that the following conditions
88  * are met:
89  * 1. Redistributions of source code must retain the above copyright
90  *    notice, this list of conditions and the following disclaimer.
91  * 2. Redistributions in binary form must reproduce the above copyright
92  *    notice, this list of conditions and the following disclaimer in the
93  *    documentation and/or other materials provided with the distribution.
94  * 3. Neither the name of the author nor the names of its contributors
95  *    may be used to endorse or promote products derived from this software
96  *    without specific prior written permission.
97  *
98  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
99  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
100  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
101  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
102  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
103  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
104  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
105  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
106  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
107  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
108  * SUCH DAMAGE.
109  */
110 
111 #include "config.h"
112 
113 #include <string.h>
114 #include <time.h>
115 #include <malloc.h>
116 #include <errno.h>
117 #include <unistd.h>
118 
119 #include <sys/socket.h>
120 #include <asm/types.h>
121 #include <linux/netlink.h>
122 #include <linux/rtnetlink.h>
123 #include <sys/types.h>
124 #include <sys/socket.h>
125 #include <sys/poll.h>
126 #include <netpacket/packet.h>
127 #include <net/ethernet.h>     /* the L2 protocols */
128 #include <sys/uio.h>
129 #include <net/if.h>
130 #include <net/if_arp.h>
131 #include <ifaddrs.h>
132 #include <netinet/in.h>
133 
134 #define __set_errno(e) (errno = (e))
135 #define __close(fd) (close(fd))
136 #undef ifa_broadaddr
137 #define ifa_broadaddr ifa_dstaddr
138 #define IFA_NETMASK
139 
140 /* ====================================================================== */
141 struct nlmsg_list{
142     struct nlmsg_list *nlm_next;
143     struct nlmsghdr *nlh;
144     int size;
145     time_t seq;
146 };
147 
148 struct rtmaddr_ifamap {
149   void *address;
150   void *local;
151 #ifdef IFA_NETMASK
152   void *netmask;
153 #endif
154   void *broadcast;
155 #ifdef HAVE_IFADDRS_IFA_ANYCAST
156   void *anycast;
157 #endif
158   int address_len;
159   int local_len;
160 #ifdef IFA_NETMASK
161   int netmask_len;
162 #endif
163   int broadcast_len;
164 #ifdef HAVE_IFADDRS_IFA_ANYCAST
165   int anycast_len;
166 #endif
167 };
168 
169 /* ====================================================================== */
170 static size_t
ifa_sa_len(sa_family_t family,int len)171 ifa_sa_len(sa_family_t family, int len)
172 {
173   size_t size;
174   switch(family){
175   case AF_INET:
176     size = sizeof(struct sockaddr_in);
177     break;
178   case AF_INET6:
179     size = sizeof(struct sockaddr_in6);
180     break;
181   case AF_PACKET:
182     size = (size_t)(((struct sockaddr_ll *)NULL)->sll_addr) + len;
183     if (size < sizeof(struct sockaddr_ll))
184       size = sizeof(struct sockaddr_ll);
185     break;
186   default:
187     size = (size_t)(((struct sockaddr *)NULL)->sa_data) + len;
188     if (size < sizeof(struct sockaddr))
189       size = sizeof(struct sockaddr);
190     break;
191   }
192   return size;
193 }
194 
195 static void
ifa_make_sockaddr(sa_family_t family,struct sockaddr * sa,void * p,size_t len,uint32_t scope,uint32_t scopeid)196 ifa_make_sockaddr(sa_family_t family,
197 		  struct sockaddr *sa,
198 		  void *p, size_t len,
199 		  uint32_t scope, uint32_t scopeid)
200 {
201   if (sa == NULL) return;
202   switch(family){
203   case AF_INET:
204     memcpy(&((struct sockaddr_in*)sa)->sin_addr, (char *)p, len);
205     break;
206   case AF_INET6:
207     memcpy(&((struct sockaddr_in6*)sa)->sin6_addr, (char *)p, len);
208     if (IN6_IS_ADDR_LINKLOCAL(p) ||
209 	IN6_IS_ADDR_MC_LINKLOCAL(p)){
210       ((struct sockaddr_in6*)sa)->sin6_scope_id = scopeid;
211     }
212     break;
213   case AF_PACKET:
214     memcpy(((struct sockaddr_ll*)sa)->sll_addr, (char *)p, len);
215     ((struct sockaddr_ll*)sa)->sll_halen = len;
216     break;
217   default:
218     memcpy(sa->sa_data, p, len);	/*XXX*/
219     break;
220   }
221   sa->sa_family = family;
222 #ifdef HAVE_SOCKADDR_SA_LEN
223   sa->sa_len = ifa_sa_len(family, len);
224 #endif
225 }
226 
227 #ifndef IFA_NETMASK
228 static struct sockaddr *
ifa_make_sockaddr_mask(sa_family_t family,struct sockaddr * sa,uint32_t prefixlen)229 ifa_make_sockaddr_mask(sa_family_t family,
230 		       struct sockaddr *sa,
231 		       uint32_t prefixlen)
232 {
233   int i;
234   char *p = NULL, c;
235   uint32_t max_prefixlen = 0;
236 
237   if (sa == NULL) return NULL;
238   switch(family){
239   case AF_INET:
240     memset(&((struct sockaddr_in*)sa)->sin_addr, 0, sizeof(((struct sockaddr_in*)sa)->sin_addr));
241     p = (char *)&((struct sockaddr_in*)sa)->sin_addr;
242     max_prefixlen = 32;
243     break;
244   case AF_INET6:
245     memset(&((struct sockaddr_in6*)sa)->sin6_addr, 0, sizeof(((struct sockaddr_in6*)sa)->sin6_addr));
246     p = (char *)&((struct sockaddr_in6*)sa)->sin6_addr;
247 #if 0	/* XXX: fill scope-id? */
248     if (IN6_IS_ADDR_LINKLOCAL(p) ||
249 	IN6_IS_ADDR_MC_LINKLOCAL(p)){
250       ((struct sockaddr_in6*)sa)->sin6_scope_id = scopeid;
251     }
252 #endif
253     max_prefixlen = 128;
254     break;
255   default:
256     return NULL;
257   }
258   sa->sa_family = family;
259 #ifdef HAVE_SOCKADDR_SA_LEN
260   sa->sa_len = ifa_sa_len(family, len);
261 #endif
262   if (p){
263     if (prefixlen > max_prefixlen)
264       prefixlen = max_prefixlen;
265     for (i=0; i<(prefixlen / 8); i++)
266       *p++ = 0xff;
267     c = 0xff;
268     c <<= (8 - (prefixlen % 8));
269     *p = c;
270   }
271   return sa;
272 }
273 #endif
274 
275 /* ====================================================================== */
276 static int
nl_sendreq(int sd,int request,int flags,int * seq)277 nl_sendreq(int sd, int request, int flags, int *seq)
278 {
279   char reqbuf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
280 	      NLMSG_ALIGN(sizeof(struct rtgenmsg))];
281   struct sockaddr_nl nladdr;
282   struct nlmsghdr *req_hdr;
283   struct rtgenmsg *req_msg;
284   time_t t = time(NULL);
285 
286   if (seq) *seq = t;
287   memset(&reqbuf, 0, sizeof(reqbuf));
288   req_hdr = (struct nlmsghdr *)reqbuf;
289   req_msg = (struct rtgenmsg *)NLMSG_DATA(req_hdr);
290   req_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*req_msg));
291   req_hdr->nlmsg_type = request;
292   req_hdr->nlmsg_flags = flags | NLM_F_REQUEST;
293   req_hdr->nlmsg_pid = 0;
294   req_hdr->nlmsg_seq = t;
295   req_msg->rtgen_family = AF_UNSPEC;
296   memset(&nladdr, 0, sizeof(nladdr));
297   nladdr.nl_family = AF_NETLINK;
298   return (sendto(sd, (void *)req_hdr, req_hdr->nlmsg_len, 0,
299 		 (struct sockaddr *)&nladdr, sizeof(nladdr)));
300 }
301 
302 static int
nl_recvmsg(int sd,int request,int seq,void * buf,size_t buflen,int * flags)303 nl_recvmsg(int sd, int request, int seq,
304 	   void *buf, size_t buflen,
305 	   int *flags)
306 {
307   struct msghdr msg;
308   struct iovec iov = { buf, buflen };
309   struct sockaddr_nl nladdr;
310   int read_len;
311 
312   for (;;){
313     msg.msg_name = (void *)&nladdr;
314     msg.msg_namelen = sizeof(nladdr);
315     msg.msg_iov = &iov;
316     msg.msg_iovlen = 1;
317     msg.msg_control = NULL;
318     msg.msg_controllen = 0;
319     msg.msg_flags = 0;
320     read_len = recvmsg(sd, &msg, 0);
321     if ((read_len < 0 && errno == EINTR) || (msg.msg_flags & MSG_TRUNC))
322       continue;
323     if (flags) *flags = msg.msg_flags;
324     break;
325   }
326   return read_len;
327 }
328 
329 static int
nl_getmsg(int sd,int request,int seq,struct nlmsghdr ** nlhp,int * done)330 nl_getmsg(int sd, int request, int seq,
331 	  struct nlmsghdr **nlhp,
332 	  int *done)
333 {
334   struct nlmsghdr *nh;
335   size_t bufsize = 65536, lastbufsize = 0;
336   void *buff = NULL;
337   int result = 0, read_size;
338   int msg_flags;
339   pid_t pid = getpid();
340   for (;;){
341     void *newbuff = realloc(buff, bufsize);
342     if (newbuff == NULL || bufsize < lastbufsize) {
343       result = -1;
344       break;
345     }
346     buff = newbuff;
347     result = read_size = nl_recvmsg(sd, request, seq, buff, bufsize, &msg_flags);
348     if (read_size < 0 || (msg_flags & MSG_TRUNC)){
349       lastbufsize = bufsize;
350       bufsize *= 2;
351       continue;
352     }
353     if (read_size == 0) break;
354     nh = (struct nlmsghdr *)buff;
355     for (nh = (struct nlmsghdr *)buff;
356 	 NLMSG_OK(nh, read_size);
357 	 nh = (struct nlmsghdr *)NLMSG_NEXT(nh, read_size)){
358       if (nh->nlmsg_pid != pid ||
359 	  nh->nlmsg_seq != seq)
360 	continue;
361       if (nh->nlmsg_type == NLMSG_DONE){
362 	(*done)++;
363 	break; /* ok */
364       }
365       if (nh->nlmsg_type == NLMSG_ERROR){
366 	struct nlmsgerr *nlerr = (struct nlmsgerr *)NLMSG_DATA(nh);
367 	result = -1;
368 	if (nh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
369 	  __set_errno(EIO);
370 	else
371 	  __set_errno(-nlerr->error);
372 	break;
373       }
374     }
375     break;
376   }
377   if (result < 0)
378     if (buff){
379       int saved_errno = errno;
380       free(buff);
381       __set_errno(saved_errno);
382     }
383   *nlhp = (struct nlmsghdr *)buff;
384   return result;
385 }
386 
387 static int
nl_getlist(int sd,int seq,int request,struct nlmsg_list ** nlm_list,struct nlmsg_list ** nlm_end)388 nl_getlist(int sd, int seq,
389 	   int request,
390 	   struct nlmsg_list **nlm_list,
391 	   struct nlmsg_list **nlm_end)
392 {
393   struct nlmsghdr *nlh = NULL;
394   int status;
395   int done = 0;
396   int tries = 3;
397 
398  try_again:
399   status = nl_sendreq(sd, request, NLM_F_ROOT|NLM_F_MATCH, &seq);
400   if (status < 0)
401     return status;
402   if (seq == 0)
403     seq = (int)time(NULL);
404   while(!done){
405     struct pollfd pfd;
406 
407     pfd.fd = sd;
408     pfd.events = POLLIN | POLLPRI;
409     pfd.revents = 0;
410     status = poll(&pfd, 1, 1000);
411     if (status < 0)
412 	return status;
413     else if (status == 0) {
414 	seq++;
415 	if (tries-- > 0)
416 	    goto try_again;
417 	return -1;
418     }
419 
420     status = nl_getmsg(sd, request, seq, &nlh, &done);
421     if (status < 0)
422       return status;
423     if (nlh){
424       struct nlmsg_list *nlm_next = (struct nlmsg_list *)malloc(sizeof(struct nlmsg_list));
425       if (nlm_next == NULL){
426 	int saved_errno = errno;
427 	free(nlh);
428 	__set_errno(saved_errno);
429 	status = -1;
430       } else {
431 	nlm_next->nlm_next = NULL;
432 	nlm_next->nlh = (struct nlmsghdr *)nlh;
433 	nlm_next->size = status;
434 	nlm_next->seq = seq;
435 	if (*nlm_list == NULL){
436 	  *nlm_list = nlm_next;
437 	  *nlm_end = nlm_next;
438 	} else {
439 	  (*nlm_end)->nlm_next = nlm_next;
440 	  *nlm_end = nlm_next;
441 	}
442       }
443     }
444   }
445   return status >= 0 ? seq : status;
446 }
447 
448 /* ---------------------------------------------------------------------- */
449 static void
free_nlmsglist(struct nlmsg_list * nlm0)450 free_nlmsglist(struct nlmsg_list *nlm0)
451 {
452   struct nlmsg_list *nlm, *nlm_next;
453   int saved_errno;
454   if (!nlm0)
455     return;
456   saved_errno = errno;
457   for (nlm=nlm0; nlm; nlm=nlm_next){
458     if (nlm->nlh)
459       free(nlm->nlh);
460     nlm_next=nlm->nlm_next;
461     free(nlm);
462   }
463   __set_errno(saved_errno);
464 }
465 
466 static void
free_data(void * data,void * ifdata)467 free_data(void *data, void *ifdata)
468 {
469   int saved_errno = errno;
470   if (data != NULL) free(data);
471   if (ifdata != NULL) free(ifdata);
472   __set_errno(saved_errno);
473 }
474 
475 /* ---------------------------------------------------------------------- */
476 static void
nl_close(int sd)477 nl_close(int sd)
478 {
479   int saved_errno = errno;
480   if (sd >= 0) __close(sd);
481   __set_errno(saved_errno);
482 }
483 
484 /* ---------------------------------------------------------------------- */
485 static int
nl_open(void)486 nl_open(void)
487 {
488   struct sockaddr_nl nladdr;
489   int sd;
490 
491   sd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
492   if (sd < 0) return -1;
493   memset(&nladdr, 0, sizeof(nladdr));
494   nladdr.nl_family = AF_NETLINK;
495   if (bind(sd, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0){
496     nl_close(sd);
497     return -1;
498   }
499   return sd;
500 }
501 
502 /* ====================================================================== */
503 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
rk_getifaddrs(struct ifaddrs ** ifap)504 rk_getifaddrs(struct ifaddrs **ifap)
505 {
506   int sd;
507   struct nlmsg_list *nlmsg_list, *nlmsg_end, *nlm;
508   /* - - - - - - - - - - - - - - - */
509   int icnt;
510   size_t dlen, xlen, nlen;
511   uint32_t max_ifindex = 0;
512 
513   pid_t pid = getpid();
514   int seq;
515   int result;
516   int build     ; /* 0 or 1 */
517 
518 /* ---------------------------------- */
519   /* initialize */
520   icnt = dlen = xlen = nlen = 0;
521   nlmsg_list = nlmsg_end = NULL;
522 
523   if (ifap)
524     *ifap = NULL;
525 
526 /* ---------------------------------- */
527   /* open socket and bind */
528   sd = nl_open();
529   if (sd < 0)
530     return -1;
531 
532 /* ---------------------------------- */
533    /* gather info */
534   if ((seq = nl_getlist(sd, 0, RTM_GETLINK,
535 			&nlmsg_list, &nlmsg_end)) < 0){
536     free_nlmsglist(nlmsg_list);
537     nl_close(sd);
538     return -1;
539   }
540   if ((seq = nl_getlist(sd, seq+1, RTM_GETADDR,
541 			&nlmsg_list, &nlmsg_end)) < 0){
542     free_nlmsglist(nlmsg_list);
543     nl_close(sd);
544     return -1;
545   }
546 
547 /* ---------------------------------- */
548   /* Estimate size of result buffer and fill it */
549   for (build=0; build<=1; build++){
550     struct ifaddrs *ifl = NULL, *ifa = NULL;
551     struct nlmsghdr *nlh, *nlh0;
552     char *data = NULL, *xdata = NULL;
553     void *ifdata = NULL;
554     char *ifname = NULL, **iflist = NULL;
555     uint16_t *ifflist = NULL;
556     struct rtmaddr_ifamap ifamap;
557 
558     if (build){
559       data = calloc(1,
560 		    NLMSG_ALIGN(sizeof(struct ifaddrs[icnt]))
561 		    + dlen + xlen + nlen);
562       ifa = (struct ifaddrs *)data;
563       ifdata = calloc(1,
564 		      NLMSG_ALIGN(sizeof(char *[max_ifindex+1]))
565 		      + NLMSG_ALIGN(sizeof(uint16_t [max_ifindex+1])));
566       if (ifap != NULL)
567 	*ifap = (ifdata != NULL) ? ifa : NULL;
568       else{
569 	free_data(data, ifdata);
570 	result = 0;
571 	break;
572       }
573       if (data == NULL || ifdata == NULL){
574 	free_data(data, ifdata);
575 	result = -1;
576 	break;
577       }
578       ifl = NULL;
579       data += NLMSG_ALIGN(sizeof(struct ifaddrs)) * icnt;
580       xdata = data + dlen;
581       ifname = xdata + xlen;
582       iflist = ifdata;
583       ifflist = (uint16_t *)(((char *)iflist) + NLMSG_ALIGN(sizeof(char *[max_ifindex+1])));
584     }
585 
586     for (nlm=nlmsg_list; nlm; nlm=nlm->nlm_next){
587       int nlmlen = nlm->size;
588       if (!(nlh0 = nlm->nlh))
589 	continue;
590       for (nlh = nlh0;
591 	   NLMSG_OK(nlh, nlmlen);
592 	   nlh=NLMSG_NEXT(nlh,nlmlen)){
593 	struct ifinfomsg *ifim = NULL;
594 	struct ifaddrmsg *ifam = NULL;
595 	struct rtattr *rta;
596 
597 	size_t nlm_struct_size = 0;
598 	sa_family_t nlm_family = 0;
599 	uint32_t nlm_scope = 0, nlm_index = 0;
600 	size_t sockaddr_size = 0;
601 	uint32_t nlm_prefixlen = 0;
602 	size_t rtasize;
603 
604 	memset(&ifamap, 0, sizeof(ifamap));
605 
606 	/* check if the message is what we want */
607 	if (nlh->nlmsg_pid != pid ||
608 	    nlh->nlmsg_seq != nlm->seq)
609 	  continue;
610 	if (nlh->nlmsg_type == NLMSG_DONE){
611 	  break; /* ok */
612 	}
613 	switch (nlh->nlmsg_type){
614 	case RTM_NEWLINK:
615 	  ifim = (struct ifinfomsg *)NLMSG_DATA(nlh);
616 	  nlm_struct_size = sizeof(*ifim);
617 	  nlm_family = ifim->ifi_family;
618 	  nlm_scope = 0;
619 	  nlm_index = ifim->ifi_index;
620 	  nlm_prefixlen = 0;
621 	  if (build)
622 	    ifflist[nlm_index] = ifa->ifa_flags = ifim->ifi_flags;
623 	  break;
624 	case RTM_NEWADDR:
625 	  ifam = (struct ifaddrmsg *)NLMSG_DATA(nlh);
626 	  nlm_struct_size = sizeof(*ifam);
627 	  nlm_family = ifam->ifa_family;
628 	  nlm_scope = ifam->ifa_scope;
629 	  nlm_index = ifam->ifa_index;
630 	  nlm_prefixlen = ifam->ifa_prefixlen;
631 	  if (build)
632 	    ifa->ifa_flags = ifflist[nlm_index];
633 	  break;
634 	default:
635 	  continue;
636 	}
637 
638 	if (!build){
639 	  if (max_ifindex < nlm_index)
640 	    max_ifindex = nlm_index;
641 	} else {
642 	  if (ifl != NULL)
643 	    ifl->ifa_next = ifa;
644 	}
645 
646 	rtasize = NLMSG_PAYLOAD(nlh, nlmlen) - NLMSG_ALIGN(nlm_struct_size);
647 	for (rta = (struct rtattr *)(((char *)NLMSG_DATA(nlh)) + NLMSG_ALIGN(nlm_struct_size));
648 	     RTA_OK(rta, rtasize);
649 	     rta = RTA_NEXT(rta, rtasize)){
650 	  struct sockaddr **sap = NULL;
651 	  void *rtadata = RTA_DATA(rta);
652 	  size_t rtapayload = RTA_PAYLOAD(rta);
653 	  socklen_t sa_len;
654 
655 	  switch(nlh->nlmsg_type){
656 	  case RTM_NEWLINK:
657 	    switch(rta->rta_type){
658 	    case IFLA_ADDRESS:
659 	    case IFLA_BROADCAST:
660 	      if (build){
661 		sap = (rta->rta_type == IFLA_ADDRESS) ? &ifa->ifa_addr : &ifa->ifa_broadaddr;
662 		*sap = (struct sockaddr *)data;
663 	      }
664 	      sa_len = ifa_sa_len(AF_PACKET, rtapayload);
665 	      if (rta->rta_type == IFLA_ADDRESS)
666 		sockaddr_size = NLMSG_ALIGN(sa_len);
667 	      if (!build){
668 		dlen += NLMSG_ALIGN(sa_len);
669 	      } else {
670 		memset(*sap, 0, sa_len);
671 		ifa_make_sockaddr(AF_PACKET, *sap, rtadata,rtapayload, 0,0);
672 		((struct sockaddr_ll *)*sap)->sll_ifindex = nlm_index;
673 		((struct sockaddr_ll *)*sap)->sll_hatype = ifim->ifi_type;
674 		data += NLMSG_ALIGN(sa_len);
675 	      }
676 	      break;
677 	    case IFLA_IFNAME:/* Name of Interface */
678 	      if (!build)
679 		nlen += NLMSG_ALIGN(rtapayload + 1);
680 	      else{
681 		ifa->ifa_name = ifname;
682 		if (iflist[nlm_index] == NULL)
683 		  iflist[nlm_index] = ifa->ifa_name;
684 		strncpy(ifa->ifa_name, rtadata, rtapayload);
685 		ifa->ifa_name[rtapayload] = '\0';
686 		ifname += NLMSG_ALIGN(rtapayload + 1);
687 	      }
688 	      break;
689 	    case IFLA_STATS:/* Statistics of Interface */
690 	      if (!build)
691 		xlen += NLMSG_ALIGN(rtapayload);
692 	      else{
693 		ifa->ifa_data = xdata;
694 		memcpy(ifa->ifa_data, rtadata, rtapayload);
695 		xdata += NLMSG_ALIGN(rtapayload);
696 	      }
697 	      break;
698 	    case IFLA_UNSPEC:
699 	      break;
700 	    case IFLA_MTU:
701 	      break;
702 	    case IFLA_LINK:
703 	      break;
704 	    case IFLA_QDISC:
705 	      break;
706 	    default:
707 	      break;
708 	    }
709 	    break;
710 	  case RTM_NEWADDR:
711 	    if (nlm_family == AF_PACKET) break;
712 	    switch(rta->rta_type){
713 	    case IFA_ADDRESS:
714 		ifamap.address = rtadata;
715 		ifamap.address_len = rtapayload;
716 		break;
717 	    case IFA_LOCAL:
718 		ifamap.local = rtadata;
719 		ifamap.local_len = rtapayload;
720 		break;
721 	    case IFA_BROADCAST:
722 		ifamap.broadcast = rtadata;
723 		ifamap.broadcast_len = rtapayload;
724 		break;
725 #ifdef HAVE_IFADDRS_IFA_ANYCAST
726 	    case IFA_ANYCAST:
727 		ifamap.anycast = rtadata;
728 		ifamap.anycast_len = rtapayload;
729 		break;
730 #endif
731 	    case IFA_LABEL:
732 	      if (!build)
733 		nlen += NLMSG_ALIGN(rtapayload + 1);
734 	      else{
735 		ifa->ifa_name = ifname;
736 		if (iflist[nlm_index] == NULL)
737 		  iflist[nlm_index] = ifname;
738 		strncpy(ifa->ifa_name, rtadata, rtapayload);
739 		ifa->ifa_name[rtapayload] = '\0';
740 		ifname += NLMSG_ALIGN(rtapayload + 1);
741 	      }
742 	      break;
743 	    case IFA_UNSPEC:
744 	      break;
745 	    case IFA_CACHEINFO:
746 	      break;
747 	    default:
748 	      break;
749 	    }
750 	  }
751 	}
752 	if (nlh->nlmsg_type == RTM_NEWADDR &&
753 	    nlm_family != AF_PACKET) {
754 	  if (!ifamap.local) {
755 	    ifamap.local = ifamap.address;
756 	    ifamap.local_len = ifamap.address_len;
757 	  }
758 	  if (!ifamap.address) {
759 	    ifamap.address = ifamap.local;
760 	    ifamap.address_len = ifamap.local_len;
761 	  }
762 	  if (ifamap.address_len != ifamap.local_len ||
763 	      (ifamap.address != NULL &&
764 	       memcmp(ifamap.address, ifamap.local, ifamap.address_len))) {
765 	    /* p2p; address is peer and local is ours */
766 	    ifamap.broadcast = ifamap.address;
767 	    ifamap.broadcast_len = ifamap.address_len;
768 	    ifamap.address = ifamap.local;
769 	    ifamap.address_len = ifamap.local_len;
770 	  }
771 	  if (ifamap.address) {
772 #ifndef IFA_NETMASK
773 	    sockaddr_size = NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len));
774 #endif
775 	    if (!build)
776 	      dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len));
777 	    else {
778 	      ifa->ifa_addr = (struct sockaddr *)data;
779 	      ifa_make_sockaddr(nlm_family, ifa->ifa_addr, ifamap.address, ifamap.address_len,
780 				nlm_scope, nlm_index);
781 	      data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.address_len));
782 	    }
783 	  }
784 #ifdef IFA_NETMASK
785 	  if (ifamap.netmask) {
786 	    if (!build)
787 	      dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.netmask_len));
788 	    else {
789 	      ifa->ifa_netmask = (struct sockaddr *)data;
790 	      ifa_make_sockaddr(nlm_family, ifa->ifa_netmask, ifamap.netmask, ifamap.netmask_len,
791 				nlm_scope, nlm_index);
792 	      data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.netmask_len));
793 	    }
794 	  }
795 #endif
796 	  if (ifamap.broadcast) {
797 	    if (!build)
798 	      dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.broadcast_len));
799 	    else {
800 	      ifa->ifa_broadaddr = (struct sockaddr *)data;
801 	      ifa_make_sockaddr(nlm_family, ifa->ifa_broadaddr, ifamap.broadcast, ifamap.broadcast_len,
802 				nlm_scope, nlm_index);
803 	      data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.broadcast_len));
804 	    }
805 	  }
806 #ifdef HAVE_IFADDRS_IFA_ANYCAST
807 	  if (ifamap.anycast) {
808 	    if (!build)
809 	      dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.anycast_len));
810 	    else {
811 	      ifa->ifa_anycast = (struct sockaddr *)data;
812 	      ifa_make_sockaddr(nlm_family, ifa->ifa_anyaddr, ifamap.anycast, ifamap.anycast_len,
813 				nlm_scope, nlm_index);
814 	      data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.anycast_len));
815 	    }
816 	  }
817 #endif
818 	}
819 	if (!build){
820 #ifndef IFA_NETMASK
821 	  dlen += sockaddr_size;
822 #endif
823 	  icnt++;
824 	} else {
825 	  if (ifa->ifa_name == NULL)
826 	    ifa->ifa_name = iflist[nlm_index];
827 #ifndef IFA_NETMASK
828 	  if (ifa->ifa_addr &&
829 	      ifa->ifa_addr->sa_family != AF_UNSPEC &&
830 	      ifa->ifa_addr->sa_family != AF_PACKET){
831 	    ifa->ifa_netmask = (struct sockaddr *)data;
832 	    ifa_make_sockaddr_mask(ifa->ifa_addr->sa_family, ifa->ifa_netmask, nlm_prefixlen);
833 	  }
834 	  data += sockaddr_size;
835 #endif
836 	  ifl = ifa++;
837 	}
838       }
839     }
840     if (!build){
841       if (icnt == 0 && (dlen + nlen + xlen == 0)){
842 	if (ifap != NULL)
843 	  *ifap = NULL;
844 	break; /* cannot found any addresses */
845       }
846     }
847     else
848       free_data(NULL, ifdata);
849   }
850 
851 /* ---------------------------------- */
852   /* Finalize */
853   free_nlmsglist(nlmsg_list);
854   nl_close(sd);
855   return 0;
856 }
857 
858 void ROKEN_LIB_FUNCTION
rk_freeifaddrs(struct ifaddrs * ifp)859 rk_freeifaddrs(struct ifaddrs *ifp)
860 {
861     /* AF_NETLINK method uses a single allocation for all interfaces */
862     free(ifp);
863 }
864 
865 #else /* !AF_NETLINK */
866 
867 /*
868  * The generic SIOCGIFCONF version.
869  */
870 
871 static int
getifaddrs2(struct ifaddrs ** ifap,int af,int siocgifconf,int siocgifflags,size_t ifreq_sz)872 getifaddrs2(struct ifaddrs **ifap,
873 	    int af, int siocgifconf, int siocgifflags,
874 	    size_t ifreq_sz)
875 {
876     int ret;
877     int fd;
878     size_t buf_size;
879     char *buf;
880     struct ifconf ifconf;
881     char *p;
882     size_t sz;
883     struct sockaddr sa_zero;
884     struct ifreq *ifr;
885     struct ifaddrs *start = NULL, **end = &start;
886 
887     buf = NULL;
888 
889     memset (&sa_zero, 0, sizeof(sa_zero));
890     fd = socket(af, SOCK_DGRAM, 0);
891     if (fd < 0)
892 	return -1;
893 
894     buf_size = 8192;
895     for (;;) {
896 	buf = calloc(1, buf_size);
897 	if (buf == NULL) {
898 	    ret = ENOMEM;
899 	    goto error_out;
900 	}
901 	ifconf.ifc_len = buf_size;
902 	ifconf.ifc_buf = buf;
903 
904 	/*
905 	 * Solaris returns EINVAL when the buffer is too small.
906 	 */
907 	if (ioctl (fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) {
908 	    ret = errno;
909 	    goto error_out;
910 	}
911 	/*
912 	 * Can the difference between a full and a overfull buf
913 	 * be determined?
914 	 */
915 
916 	if (ifconf.ifc_len < buf_size)
917 	    break;
918 	free (buf);
919 	buf_size *= 2;
920     }
921 
922     for (p = ifconf.ifc_buf;
923 	 p < ifconf.ifc_buf + ifconf.ifc_len;
924 	 p += sz) {
925 	struct ifreq ifreq;
926 	struct sockaddr *sa;
927 	size_t salen;
928 
929 	ifr = (struct ifreq *)p;
930 	sa  = &ifr->ifr_addr;
931 
932 	sz = ifreq_sz;
933 	salen = sizeof(struct sockaddr);
934 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
935 	salen = sa->sa_len;
936 	sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len);
937 #endif
938 #ifdef SA_LEN
939 	salen = SA_LEN(sa);
940 	sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa));
941 #endif
942 	memset (&ifreq, 0, sizeof(ifreq));
943 	memcpy (ifreq.ifr_name, ifr->ifr_name, sizeof(ifr->ifr_name));
944 
945 	if (ioctl(fd, siocgifflags, &ifreq) < 0) {
946 	    ret = errno;
947 	    goto error_out;
948 	}
949 
950 	*end = malloc(sizeof(**end));
951 	if (*end == NULL) {
952 	    ret = ENOMEM;
953 	    goto error_out;
954 	}
955 
956 	(*end)->ifa_next = NULL;
957 	(*end)->ifa_name = strdup(ifr->ifr_name);
958 	if ((*end)->ifa_name == NULL) {
959 	    ret = ENOMEM;
960 	    goto error_out;
961 	}
962 	(*end)->ifa_flags = ifreq.ifr_flags;
963 	(*end)->ifa_addr = malloc(salen);
964 	if ((*end)->ifa_addr == NULL) {
965 	    ret = ENOMEM;
966 	    goto error_out;
967 	}
968 	memcpy((*end)->ifa_addr, sa, salen);
969 	(*end)->ifa_netmask = NULL;
970 
971 #if 0
972 	/* fix these when we actually need them */
973 	if(ifreq.ifr_flags & IFF_BROADCAST) {
974 	    (*end)->ifa_broadaddr = malloc(sizeof(ifr->ifr_broadaddr));
975 	    if ((*end)->ifa_broadaddr == NULL) {
976 		ret = ENOMEM;
977 		goto error_out;
978 	    }
979 	    memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr,
980 		   sizeof(ifr->ifr_broadaddr));
981 	} else if(ifreq.ifr_flags & IFF_POINTOPOINT) {
982 	    (*end)->ifa_dstaddr = malloc(sizeof(ifr->ifr_dstaddr));
983 	    if ((*end)->ifa_dstaddr == NULL) {
984 		ret = ENOMEM;
985 		goto error_out;
986 	    }
987 	    memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr,
988 		   sizeof(ifr->ifr_dstaddr));
989 	} else
990 	    (*end)->ifa_dstaddr = NULL;
991 #else
992 	    (*end)->ifa_dstaddr = NULL;
993 #endif
994 
995 	(*end)->ifa_data = NULL;
996 
997 	end = &(*end)->ifa_next;
998 
999     }
1000     *ifap = start;
1001     close(fd);
1002     free(buf);
1003     return 0;
1004   error_out:
1005     rk_freeifaddrs(start);
1006     close(fd);
1007     free(buf);
1008     errno = ret;
1009     return -1;
1010 }
1011 
1012 #if defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS)
1013 static int
getlifaddrs2(struct ifaddrs ** ifap,int af,int siocgifconf,int siocgifflags,size_t ifreq_sz)1014 getlifaddrs2(struct ifaddrs **ifap,
1015 	     int af, int siocgifconf, int siocgifflags,
1016 	     size_t ifreq_sz)
1017 {
1018     int ret;
1019     int fd;
1020     size_t buf_size;
1021     char *buf;
1022     struct lifconf ifconf;
1023     char *p;
1024     size_t sz;
1025     struct sockaddr sa_zero;
1026     struct lifreq *ifr;
1027     struct ifaddrs *start = NULL, **end = &start;
1028 
1029     buf = NULL;
1030 
1031     memset (&sa_zero, 0, sizeof(sa_zero));
1032     fd = socket(af, SOCK_DGRAM, 0);
1033     if (fd < 0)
1034 	return -1;
1035 
1036     buf_size = 8192;
1037     for (;;) {
1038 	buf = calloc(1, buf_size);
1039 	if (buf == NULL) {
1040 	    ret = ENOMEM;
1041 	    goto error_out;
1042 	}
1043 #ifndef __hpux
1044 	ifconf.lifc_family = af;
1045 	ifconf.lifc_flags  = 0;
1046 #endif
1047 	ifconf.lifc_len    = buf_size;
1048 	ifconf.lifc_buf    = buf;
1049 
1050 	/*
1051 	 * Solaris returns EINVAL when the buffer is too small.
1052 	 */
1053 	if (ioctl (fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) {
1054 	    ret = errno;
1055 	    goto error_out;
1056 	}
1057 	/*
1058 	 * Can the difference between a full and a overfull buf
1059 	 * be determined?
1060 	 */
1061 
1062 	if (ifconf.lifc_len < buf_size)
1063 	    break;
1064 	free (buf);
1065 	buf_size *= 2;
1066     }
1067 
1068     for (p = ifconf.lifc_buf;
1069 	 p < ifconf.lifc_buf + ifconf.lifc_len;
1070 	 p += sz) {
1071 	struct lifreq ifreq;
1072 	struct sockaddr_storage *sa;
1073 	size_t salen;
1074 
1075 	ifr = (struct lifreq *)p;
1076 	sa  = &ifr->lifr_addr;
1077 
1078 	sz = ifreq_sz;
1079 	salen = sizeof(struct sockaddr_storage);
1080 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
1081 	salen = sa->sa_len;
1082 	sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len);
1083 #endif
1084 #ifdef SA_LEN
1085 	salen = SA_LEN(sa);
1086 	sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa));
1087 #endif
1088 	memset (&ifreq, 0, sizeof(ifreq));
1089 	memcpy (ifreq.lifr_name, ifr->lifr_name, sizeof(ifr->lifr_name));
1090 
1091 	if (ioctl(fd, siocgifflags, &ifreq) < 0) {
1092 	    ret = errno;
1093 	    goto error_out;
1094 	}
1095 
1096 	*end = malloc(sizeof(**end));
1097 	if (*end == NULL) {
1098 	    ret = ENOMEM;
1099 	    goto error_out;
1100 	}
1101 
1102 	(*end)->ifa_next = NULL;
1103 	(*end)->ifa_name = strdup(ifr->lifr_name);
1104 	if ((*end)->ifa_name == NULL) {
1105 	    ret = ENOMEM;
1106 	    goto error_out;
1107 	}
1108 	(*end)->ifa_flags = ifreq.lifr_flags;
1109 	(*end)->ifa_addr = malloc(salen);
1110 	if ((*end)->ifa_addr == NULL) {
1111 	    ret = ENOMEM;
1112 	    goto error_out;
1113 	}
1114 	memcpy((*end)->ifa_addr, sa, salen);
1115 	(*end)->ifa_netmask = NULL;
1116 
1117 #if 0
1118 	/* fix these when we actually need them */
1119 	if(ifreq.ifr_flags & IFF_BROADCAST) {
1120 	    (*end)->ifa_broadaddr = malloc(sizeof(ifr->ifr_broadaddr));
1121 	    if ((*end)->ifa_broadaddr == NULL) {
1122 		ret = ENOMEM;
1123 		goto error_out;
1124 	    }
1125 	    memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr,
1126 		   sizeof(ifr->ifr_broadaddr));
1127 	} else if(ifreq.ifr_flags & IFF_POINTOPOINT) {
1128 	    (*end)->ifa_dstaddr = malloc(sizeof(ifr->ifr_dstaddr));
1129 	    if ((*end)->ifa_dstaddr == NULL) {
1130 		ret = ENOMEM;
1131 		goto error_out;
1132 	    }
1133 	    memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr,
1134 		   sizeof(ifr->ifr_dstaddr));
1135 	} else
1136 	    (*end)->ifa_dstaddr = NULL;
1137 #else
1138 	    (*end)->ifa_dstaddr = NULL;
1139 #endif
1140 
1141 	(*end)->ifa_data = NULL;
1142 
1143 	end = &(*end)->ifa_next;
1144 
1145     }
1146     *ifap = start;
1147     close(fd);
1148     free(buf);
1149     return 0;
1150   error_out:
1151     rk_freeifaddrs(start);
1152     close(fd);
1153     free(buf);
1154     errno = ret;
1155     return -1;
1156 }
1157 #endif /* defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS) */
1158 
1159 /**
1160  * Join two struct ifaddrs lists by appending supp to base.
1161  * Either may be NULL. The new list head (usually base) will be
1162  * returned.
1163  */
1164 static struct ifaddrs *
append_ifaddrs(struct ifaddrs * base,struct ifaddrs * supp)1165 append_ifaddrs(struct ifaddrs *base, struct ifaddrs *supp) {
1166     if (!base)
1167 	return supp;
1168 
1169     if (!supp)
1170 	return base;
1171 
1172     while (base->ifa_next)
1173 	base = base->ifa_next;
1174 
1175     base->ifa_next = supp;
1176 
1177     return base;
1178 }
1179 
1180 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
rk_getifaddrs(struct ifaddrs ** ifap)1181 rk_getifaddrs(struct ifaddrs **ifap)
1182 {
1183     int ret = -1;
1184     errno = ENXIO;
1185 #if defined(AF_INET6) && defined(SIOCGIF6CONF) && defined(SIOCGIF6FLAGS)
1186     if (ret)
1187 	ret = getifaddrs2 (ifap, AF_INET6, SIOCGIF6CONF, SIOCGIF6FLAGS,
1188 			   sizeof(struct in6_ifreq));
1189 #endif
1190 #if defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS)
1191     /* Do IPv6 and IPv4 queries separately then join the result.
1192      *
1193      * HP-UX only returns IPv6 addresses using SIOCGLIFCONF,
1194      * SIOCGIFCONF has to be used for IPv4 addresses. The result is then
1195      * merged.
1196      *
1197      * Solaris needs particular care, because a SIOCGLIFCONF lookup using
1198      * AF_UNSPEC can fail in a Zone requiring an AF_INET lookup, so we just
1199      * do them separately the same as for HP-UX. See
1200      * http://repo.or.cz/w/heimdal.git/commitdiff/76afc31e9ba2f37e64c70adc006ade9e37e9ef73
1201      */
1202     if (ret) {
1203 	int v6err, v4err;
1204 	struct ifaddrs *v6addrs, *v4addrs;
1205 
1206 	v6err = getlifaddrs2 (&v6addrs, AF_INET6, SIOCGLIFCONF, SIOCGLIFFLAGS,
1207 			    sizeof(struct lifreq));
1208 	v4err = getifaddrs2 (&v4addrs, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,
1209 			    sizeof(struct ifreq));
1210 	if (v6err)
1211 	    v6addrs = NULL;
1212 	if (v4err)
1213 	    v4addrs = NULL;
1214 
1215 	if (v6addrs) {
1216 	    if (v4addrs)
1217 		*ifap = append_ifaddrs(v6addrs, v4addrs);
1218 	    else
1219 		*ifap = v6addrs;
1220 	} else if (v4addrs) {
1221 	    *ifap = v4addrs;
1222 	} else {
1223 	    *ifap = NULL;
1224 	}
1225 
1226 	ret = (v6err || v4err) ? -1 : 0;
1227     }
1228 #endif
1229 #if defined(HAVE_IPV6) && defined(SIOCGIFCONF)
1230     if (ret)
1231 	ret = getifaddrs2 (ifap, AF_INET6, SIOCGIFCONF, SIOCGIFFLAGS,
1232 			   sizeof(struct ifreq));
1233 #endif
1234 #if defined(AF_INET) && defined(SIOCGIFCONF) && defined(SIOCGIFFLAGS)
1235     if (ret)
1236 	ret = getifaddrs2 (ifap, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,
1237 			   sizeof(struct ifreq));
1238 #endif
1239     return ret;
1240 }
1241 
1242 ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
rk_freeifaddrs(struct ifaddrs * ifp)1243 rk_freeifaddrs(struct ifaddrs *ifp)
1244 {
1245     struct ifaddrs *p, *q;
1246 
1247     for(p = ifp; p; ) {
1248 	free(p->ifa_name);
1249 	if(p->ifa_addr)
1250 	    free(p->ifa_addr);
1251 	if(p->ifa_dstaddr)
1252 	    free(p->ifa_dstaddr);
1253 	if(p->ifa_netmask)
1254 	    free(p->ifa_netmask);
1255 	if(p->ifa_data)
1256 	    free(p->ifa_data);
1257 	q = p;
1258 	p = p->ifa_next;
1259 	free(q);
1260     }
1261 }
1262 
1263 #endif /* !AF_NETLINK */
1264 
1265 #ifdef TEST
1266 
1267 void
print_addr(const char * s,struct sockaddr * sa)1268 print_addr(const char *s, struct sockaddr *sa)
1269 {
1270     int i;
1271     printf("  %s=%d/", s, sa->sa_family);
1272 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
1273     for(i = 0; i < sa->sa_len - ((long)sa->sa_data - (long)&sa->sa_family); i++)
1274 	printf("%02x", ((unsigned char*)sa->sa_data)[i]);
1275 #else
1276     for(i = 0; i < sizeof(sa->sa_data); i++)
1277 	printf("%02x", ((unsigned char*)sa->sa_data)[i]);
1278 #endif
1279     printf("\n");
1280 }
1281 
1282 void
print_ifaddrs(struct ifaddrs * x)1283 print_ifaddrs(struct ifaddrs *x)
1284 {
1285     struct ifaddrs *p;
1286 
1287     for(p = x; p; p = p->ifa_next) {
1288 	printf("%s\n", p->ifa_name);
1289 	printf("  flags=%x\n", p->ifa_flags);
1290 	if(p->ifa_addr)
1291 	    print_addr("addr", p->ifa_addr);
1292 	if(p->ifa_dstaddr)
1293 	    print_addr("dstaddr", p->ifa_dstaddr);
1294 	if(p->ifa_netmask)
1295 	    print_addr("netmask", p->ifa_netmask);
1296 	printf("  %p\n", p->ifa_data);
1297     }
1298 }
1299 
1300 int
main()1301 main()
1302 {
1303     struct ifaddrs *a = NULL, *b;
1304     getifaddrs2(&a, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS, sizeof(struct ifreq));
1305     print_ifaddrs(a);
1306     printf("---\n");
1307     getifaddrs(&b);
1308     print_ifaddrs(b);
1309     return 0;
1310 }
1311 #endif
1312