1 #include <config.h>
2 #ifdef  HAVE_LINUX_NETLINK_H
3 
4 /* $USAGI: ifaddrs.c,v 1.20 2002/08/23 05:38:00 yoshfuji Exp $ */
5 
6 /*
7  * Copyright (C)2000 YOSHIFUJI Hideaki
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 
24 #include <string.h>
25 #include <time.h>
26 #include <malloc.h>
27 #include <errno.h>
28 #include <unistd.h>
29 
30 #include <sys/socket.h>
31 #include <asm/types.h>
32 #include <linux/netlink.h>
33 #include <linux/rtnetlink.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <netpacket/packet.h>
37 #include <net/ethernet.h>	/* the L2 protocols */
38 #include <sys/uio.h>
39 #include <net/if.h>
40 #include <net/if_arp.h>
41 #include "usagi_ifaddrs.h"
42 #include <netinet/in.h>
43 
44 #ifdef _USAGI_LIBINET6
45 #include "libc-compat.h"
46 #endif
47 
48 #define __set_errno(e)  do { errno = e; } while(0)
49 #define __close(s) 	close(s)
50 
51 
52 /* ====================================================================== */
53 struct nlmsg_list
54 {
55   struct nlmsg_list *nlm_next;
56   struct nlmsghdr *nlh;
57   int size;
58   time_t seq;
59 };
60 
61 struct rtmaddr_ifamap
62 {
63   void *address;
64   void *local;
65 #ifdef IFA_NETMASK
66   void *netmask;
67 #endif
68   void *broadcast;
69 #ifdef HAVE_IFADDRS_IFA_ANYCAST
70   void *anycast;
71 #endif
72   int address_len;
73   int local_len;
74 #ifdef IFA_NETMASK
75   int netmask_len;
76 #endif
77   int broadcast_len;
78 #ifdef HAVE_IFADDRS_IFA_ANYCAST
79   int anycast_len;
80 #endif
81 };
82 
83 /* ====================================================================== */
84 static size_t
ifa_sa_len(sa_family_t family,int len)85 ifa_sa_len (sa_family_t family, int len)
86 {
87   size_t size;
88   switch (family)
89     {
90     case AF_INET:
91       size = sizeof (struct sockaddr_in);
92       break;
93     case AF_INET6:
94       size = sizeof (struct sockaddr_in6);
95       break;
96     case AF_PACKET:
97       size = (size_t) (((struct sockaddr_ll *) NULL)->sll_addr) + len;
98       if (size < sizeof (struct sockaddr_ll))
99 	size = sizeof (struct sockaddr_ll);
100       break;
101     default:
102       size = (size_t) (((struct sockaddr *) NULL)->sa_data) + len;
103       if (size < sizeof (struct sockaddr))
104 	size = sizeof (struct sockaddr);
105     }
106   return size;
107 }
108 
109 static void
ifa_make_sockaddr(sa_family_t family,struct sockaddr * sa,void * p,size_t len,uint32_t scope,uint32_t scopeid)110 ifa_make_sockaddr (sa_family_t family,
111 		   struct sockaddr *sa,
112 		   void *p, size_t len, uint32_t scope, uint32_t scopeid)
113 {
114   if (sa == NULL)
115     return;
116   switch (family)
117     {
118     case AF_INET:
119       memcpy (&((struct sockaddr_in *) sa)->sin_addr, (char *) p, len);
120       break;
121     case AF_INET6:
122       memcpy (&((struct sockaddr_in6 *) sa)->sin6_addr, (char *) p, len);
123       if (IN6_IS_ADDR_LINKLOCAL (p) || IN6_IS_ADDR_MC_LINKLOCAL (p))
124 	{
125 	  ((struct sockaddr_in6 *) sa)->sin6_scope_id = scopeid;
126 	}
127       break;
128     case AF_PACKET:
129       memcpy (((struct sockaddr_ll *) sa)->sll_addr, (char *) p, len);
130       ((struct sockaddr_ll *) sa)->sll_halen = len;
131       break;
132     default:
133       memcpy (sa->sa_data, p, len);
134       /*XXX*/ break;
135     }
136   sa->sa_family = family;
137 #ifdef HAVE_SOCKADDR_SA_LEN
138   sa->sa_len = ifa_sa_len (family, len);
139 #endif
140 }
141 
142 static struct sockaddr *
ifa_make_sockaddr_mask(sa_family_t family,struct sockaddr * sa,uint32_t prefixlen)143 ifa_make_sockaddr_mask (sa_family_t family,
144 			struct sockaddr *sa, uint32_t prefixlen)
145 {
146   int i;
147   char *p = NULL, c;
148   uint32_t max_prefixlen = 0;
149 
150   if (sa == NULL)
151     return NULL;
152   switch (family)
153     {
154     case AF_INET:
155       memset (&((struct sockaddr_in *) sa)->sin_addr, 0,
156 	      sizeof (((struct sockaddr_in *) sa)->sin_addr));
157       p = (char *) &((struct sockaddr_in *) sa)->sin_addr;
158       max_prefixlen = 32;
159       break;
160     case AF_INET6:
161       memset (&((struct sockaddr_in6 *) sa)->sin6_addr, 0,
162 	      sizeof (((struct sockaddr_in6 *) sa)->sin6_addr));
163       p = (char *) &((struct sockaddr_in6 *) sa)->sin6_addr;
164 #if 0				/* XXX: fill scope-id? */
165       if (IN6_IS_ADDR_LINKLOCAL (p) || IN6_IS_ADDR_MC_LINKLOCAL (p))
166 	{
167 	  ((struct sockaddr_in6 *) sa)->sin6_scope_id = scopeid;
168 	}
169 #endif
170       max_prefixlen = 128;
171       break;
172     default:
173       return NULL;
174     }
175   sa->sa_family = family;
176 #ifdef HAVE_SOCKADDR_SA_LEN
177   sa->sa_len = ifa_sa_len (family, len);
178 #endif
179   if (p)
180     {
181       if (prefixlen > max_prefixlen)
182 	prefixlen = max_prefixlen;
183       for (i = 0; i < (prefixlen / 8); i++)
184 	*p++ = 0xff;
185       c = 0xff;
186       c <<= (8 - (prefixlen % 8));
187       *p = c;
188     }
189   return sa;
190 }
191 
192 /* ====================================================================== */
193 static int
nl_sendreq(int sd,int request,int flags,int * seq)194 nl_sendreq (int sd, int request, int flags, int *seq)
195 {
196   char reqbuf[NLMSG_ALIGN (sizeof (struct nlmsghdr)) +
197 	      NLMSG_ALIGN (sizeof (struct rtgenmsg))];
198   struct sockaddr_nl nladdr;
199   struct nlmsghdr *req_hdr;
200   struct rtgenmsg *req_msg;
201   time_t t = time (NULL);
202 
203   if (seq)
204     *seq = t;
205   memset (&reqbuf, 0, sizeof (reqbuf));
206   req_hdr = (struct nlmsghdr *) reqbuf;
207   req_msg = (struct rtgenmsg *) NLMSG_DATA (req_hdr);
208   req_hdr->nlmsg_len = NLMSG_LENGTH (sizeof (*req_msg));
209   req_hdr->nlmsg_type = request;
210   req_hdr->nlmsg_flags = flags | NLM_F_REQUEST;
211   req_hdr->nlmsg_pid = 0;
212   req_hdr->nlmsg_seq = t;
213   req_msg->rtgen_family = AF_UNSPEC;
214   memset (&nladdr, 0, sizeof (nladdr));
215   nladdr.nl_family = AF_NETLINK;
216   return (sendto (sd, (void *) req_hdr, req_hdr->nlmsg_len, 0,
217 		  (struct sockaddr *) &nladdr, sizeof (nladdr)));
218 }
219 
220 static int
nl_recvmsg(int sd,int request,int seq,void * buf,size_t buflen,int * flags)221 nl_recvmsg (int sd, int request, int seq,
222 	    void *buf, size_t buflen, int *flags)
223 {
224   struct msghdr msg;
225   struct iovec iov = { buf, buflen };
226   struct sockaddr_nl nladdr;
227   int read_len;
228 
229   for (;;)
230     {
231       msg.msg_name = (void *) &nladdr;
232       msg.msg_namelen = sizeof (nladdr);
233       msg.msg_iov = &iov;
234       msg.msg_iovlen = 1;
235       msg.msg_control = NULL;
236       msg.msg_controllen = 0;
237       msg.msg_flags = 0;
238       read_len = recvmsg (sd, &msg, 0);
239       if ((read_len < 0 && errno == EINTR) || (msg.msg_flags & MSG_TRUNC))
240 	continue;
241       if (flags)
242 	*flags = msg.msg_flags;
243       break;
244     }
245   return read_len;
246 }
247 
248 static int
nl_getmsg(int sd,int request,int seq,struct nlmsghdr ** nlhp,int * done)249 nl_getmsg (int sd, int request, int seq, struct nlmsghdr **nlhp, int *done)
250 {
251   struct nlmsghdr *nh;
252   size_t bufsize = 65536, lastbufsize = 0;
253   void *buff = NULL;
254   int result = 0, read_size;
255   int msg_flags;
256   pid_t pid = getpid ();
257   for (;;)
258     {
259       void *newbuff = realloc (buff, bufsize);
260       if (newbuff == NULL || bufsize < lastbufsize)
261 	{
262 	  result = -1;
263 	  break;
264 	}
265       buff = newbuff;
266       result = read_size =
267 	nl_recvmsg (sd, request, seq, buff, bufsize, &msg_flags);
268       if (read_size < 0 || (msg_flags & MSG_TRUNC))
269 	{
270 	  lastbufsize = bufsize;
271 	  bufsize *= 2;
272 	  continue;
273 	}
274       if (read_size == 0)
275 	break;
276       nh = (struct nlmsghdr *) buff;
277       for (nh = (struct nlmsghdr *) buff;
278 	   NLMSG_OK (nh, read_size);
279 	   nh = (struct nlmsghdr *) NLMSG_NEXT (nh, read_size))
280 	{
281 	  if (nh->nlmsg_pid != pid || nh->nlmsg_seq != seq)
282 	    continue;
283 	  if (nh->nlmsg_type == NLMSG_DONE)
284 	    {
285 	      (*done)++;
286 	      break;		/* ok */
287 	    }
288 	  if (nh->nlmsg_type == NLMSG_ERROR)
289 	    {
290 	      struct nlmsgerr *nlerr = (struct nlmsgerr *) NLMSG_DATA (nh);
291 	      result = -1;
292 	      if (nh->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
293 		__set_errno (EIO);
294 	      else
295 		__set_errno (-nlerr->error);
296 	      break;
297 	    }
298 	}
299       break;
300     }
301   if (result < 0)
302     if (buff)
303       {
304 	int saved_errno = errno;
305 	free (buff);
306 	__set_errno (saved_errno);
307       }
308   *nlhp = (struct nlmsghdr *) buff;
309   return result;
310 }
311 
312 static int
nl_getlist(int sd,int seq,int request,struct nlmsg_list ** nlm_list,struct nlmsg_list ** nlm_end)313 nl_getlist (int sd, int seq,
314 	    int request,
315 	    struct nlmsg_list **nlm_list, struct nlmsg_list **nlm_end)
316 {
317   struct nlmsghdr *nlh = NULL;
318   int status;
319   int done = 0;
320 
321   status = nl_sendreq (sd, request, NLM_F_ROOT | NLM_F_MATCH, &seq);
322   if (status < 0)
323     return status;
324   if (seq == 0)
325     seq = (int) time (NULL);
326   while (!done)
327     {
328       status = nl_getmsg (sd, request, seq, &nlh, &done);
329       if (status < 0)
330 	return status;
331       if (nlh)
332 	{
333 	  struct nlmsg_list *nlm_next =
334 	    (struct nlmsg_list *) malloc (sizeof (struct nlmsg_list));
335 	  if (nlm_next == NULL)
336 	    {
337 	      int saved_errno = errno;
338 	      free (nlh);
339 	      __set_errno (saved_errno);
340 	      status = -1;
341 	    }
342 	  else
343 	    {
344 	      nlm_next->nlm_next = NULL;
345 	      nlm_next->nlh = (struct nlmsghdr *) nlh;
346 	      nlm_next->size = status;
347 	      nlm_next->seq = seq;
348 	      if (*nlm_list == NULL)
349 		{
350 		  *nlm_list = nlm_next;
351 		  *nlm_end = nlm_next;
352 		}
353 	      else
354 		{
355 		  (*nlm_end)->nlm_next = nlm_next;
356 		  *nlm_end = nlm_next;
357 		}
358 	    }
359 	}
360     }
361   return status >= 0 ? seq : status;
362 }
363 
364 /* ---------------------------------------------------------------------- */
365 static void
free_nlmsglist(struct nlmsg_list * nlm0)366 free_nlmsglist (struct nlmsg_list *nlm0)
367 {
368   struct nlmsg_list *nlm;
369   int saved_errno;
370   if (!nlm0)
371     return;
372   saved_errno = errno;
373   nlm = nlm0;
374   while (nlm)
375     {
376       struct nlmsg_list *old_node = nlm;
377       if (nlm->nlh)
378 	free (nlm->nlh);
379       nlm = nlm->nlm_next;
380       free (old_node);
381     }
382   __set_errno (saved_errno);
383 }
384 
385 static void
free_data(void * data,void * ifdata)386 free_data (void *data, void *ifdata)
387 {
388   int saved_errno = errno;
389   if (data != NULL)
390     free (data);
391   if (ifdata != NULL)
392     free (ifdata);
393   __set_errno (saved_errno);
394 }
395 
396 /* ---------------------------------------------------------------------- */
397 static void
nl_close(int sd)398 nl_close (int sd)
399 {
400   int saved_errno = errno;
401   if (sd >= 0)
402     __close (sd);
403   __set_errno (saved_errno);
404 }
405 
406 /* ---------------------------------------------------------------------- */
407 static int
nl_open(void)408 nl_open (void)
409 {
410   struct sockaddr_nl nladdr;
411   int sd;
412 
413   sd = socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
414   if (sd < 0)
415     return -1;
416   memset (&nladdr, 0, sizeof (nladdr));
417   nladdr.nl_family = AF_NETLINK;
418   if (bind (sd, (struct sockaddr *) &nladdr, sizeof (nladdr)) < 0)
419     {
420       nl_close (sd);
421       return -1;
422     }
423   return sd;
424 }
425 
426 /* ====================================================================== */
427 int
usagi_getifaddrs(struct ifaddrs ** ifap)428 usagi_getifaddrs (struct ifaddrs **ifap)
429 {
430   int sd;
431   struct nlmsg_list *nlmsg_list, *nlmsg_end, *nlm;
432   /* - - - - - - - - - - - - - - - */
433   int icnt;
434   size_t dlen, xlen, nlen;
435   uint32_t max_ifindex = 0;
436 
437   pid_t pid = getpid ();
438   int seq;
439   int result;
440   int build;			/* 0 or 1 */
441 
442 /* ---------------------------------- */
443   /* initialize */
444   icnt = dlen = xlen = nlen = 0;
445   nlmsg_list = nlmsg_end = NULL;
446 
447   if (ifap)
448     *ifap = NULL;
449 
450 /* ---------------------------------- */
451   /* open socket and bind */
452   sd = nl_open ();
453   if (sd < 0)
454     return -1;
455 
456 /* ---------------------------------- */
457   /* gather info */
458   if ((seq = nl_getlist (sd, 0, RTM_GETLINK, &nlmsg_list, &nlmsg_end)) < 0)
459     {
460       free_nlmsglist (nlmsg_list);
461       nl_close (sd);
462       return -1;
463     }
464   if ((seq = nl_getlist (sd, seq + 1, RTM_GETADDR,
465 			 &nlmsg_list, &nlmsg_end)) < 0)
466     {
467       free_nlmsglist (nlmsg_list);
468       nl_close (sd);
469       return -1;
470     }
471 
472 /* ---------------------------------- */
473   /* Estimate size of result buffer and fill it */
474   for (build = 0; build <= 1; build++)
475     {
476       struct ifaddrs *ifl = NULL, *ifa = NULL;
477       struct nlmsghdr *nlh, *nlh0;
478       void *data = NULL, *xdata = NULL, *ifdata = NULL;
479       char *ifname = NULL, **iflist = NULL;
480       uint16_t *ifflist = NULL;
481       struct rtmaddr_ifamap ifamap;
482 
483       if (build)
484 	{
485 	  ifa = data = calloc (1,
486 			       NLMSG_ALIGN (sizeof (struct ifaddrs[icnt]))
487 			       + dlen + xlen + nlen);
488 	  ifdata = calloc (1,
489 			   NLMSG_ALIGN (sizeof (char *[max_ifindex + 1]))
490 			   +
491 			   NLMSG_ALIGN (sizeof (uint16_t[max_ifindex + 1])));
492 	  if (ifap != NULL)
493 	    *ifap = (ifdata != NULL) ? ifa : NULL;
494 	  else
495 	    {
496 	      free_data (data, ifdata);
497 	      result = 0;
498 	      break;
499 	    }
500 	  if (data == NULL || ifdata == NULL)
501 	    {
502 	      free_data (data, ifdata);
503 	      result = -1;
504 	      break;
505 	    }
506 	  ifl = NULL;
507 	  data += NLMSG_ALIGN (sizeof (struct ifaddrs)) * icnt;
508 	  xdata = data + dlen;
509 	  ifname = xdata + xlen;
510 	  iflist = ifdata;
511 	  ifflist =
512 	    ((void *) iflist) +
513 	    NLMSG_ALIGN (sizeof (char *[max_ifindex + 1]));
514 	}
515 
516       for (nlm = nlmsg_list; nlm; nlm = nlm->nlm_next)
517 	{
518 	  int nlmlen = nlm->size;
519 	  if (!(nlh0 = nlm->nlh))
520 	    continue;
521 	  for (nlh = nlh0;
522 	       NLMSG_OK (nlh, nlmlen); nlh = NLMSG_NEXT (nlh, nlmlen))
523 	    {
524 	      struct ifinfomsg *ifim = NULL;
525 	      struct ifaddrmsg *ifam = NULL;
526 	      struct rtattr *rta;
527 
528 	      size_t nlm_struct_size = 0;
529 	      sa_family_t nlm_family = 0;
530 	      uint32_t nlm_scope = 0, nlm_index = 0;
531 #ifndef IFA_NETMASK
532 	      size_t sockaddr_size = 0;
533 	      uint32_t nlm_prefixlen = 0;
534 #endif
535 	      size_t rtasize;
536 
537 	      memset (&ifamap, 0, sizeof (ifamap));
538 
539 	      /* check if the message is what we want */
540 	      if (nlh->nlmsg_pid != pid || nlh->nlmsg_seq != nlm->seq)
541 		continue;
542 	      if (nlh->nlmsg_type == NLMSG_DONE)
543 		{
544 		  break;	/* ok */
545 		}
546 	      switch (nlh->nlmsg_type)
547 		{
548 		case RTM_NEWLINK:
549 		  ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
550 		  nlm_struct_size = sizeof (*ifim);
551 		  nlm_family = ifim->ifi_family;
552 		  nlm_scope = 0;
553 		  nlm_index = ifim->ifi_index;
554 		  nlm_prefixlen = 0;
555 		  if (build)
556 		    ifflist[nlm_index] = ifa->ifa_flags = ifim->ifi_flags;
557 		  break;
558 		case RTM_NEWADDR:
559 		  ifam = (struct ifaddrmsg *) NLMSG_DATA (nlh);
560 		  nlm_struct_size = sizeof (*ifam);
561 		  nlm_family = ifam->ifa_family;
562 		  nlm_scope = ifam->ifa_scope;
563 		  nlm_index = ifam->ifa_index;
564 		  nlm_prefixlen = ifam->ifa_prefixlen;
565 		  if (build)
566 		    ifa->ifa_flags = ifflist[nlm_index];
567 		  break;
568 		default:
569 		  continue;
570 		}
571 
572 	      if (!build)
573 		{
574 		  if (max_ifindex < nlm_index)
575 		    max_ifindex = nlm_index;
576 		}
577 	      else
578 		{
579 		  if (ifl != NULL)
580 		    ifl->ifa_next = ifa;
581 		}
582 
583 	      rtasize =
584 		NLMSG_PAYLOAD (nlh, nlmlen) - NLMSG_ALIGN (nlm_struct_size);
585 	      for (rta =
586 		   (struct rtattr *) (((char *) NLMSG_DATA (nlh)) +
587 				      NLMSG_ALIGN (nlm_struct_size));
588 		   RTA_OK (rta, rtasize); rta = RTA_NEXT (rta, rtasize))
589 		{
590 		  struct sockaddr **sap = NULL;
591 		  void *rtadata = RTA_DATA (rta);
592 		  size_t rtapayload = RTA_PAYLOAD (rta);
593 		  socklen_t sa_len;
594 
595 		  switch (nlh->nlmsg_type)
596 		    {
597 		    case RTM_NEWLINK:
598 		      switch (rta->rta_type)
599 			{
600 			case IFLA_ADDRESS:
601 			case IFLA_BROADCAST:
602 			  if (build)
603 			    {
604 			      sap =
605 				(rta->rta_type ==
606 				 IFLA_ADDRESS) ? &ifa->ifa_addr : &ifa->
607 				ifa_broadaddr;
608 			      *sap = (struct sockaddr *) data;
609 			    }
610 			  sa_len = ifa_sa_len (AF_PACKET, rtapayload);
611 			  if (rta->rta_type == IFLA_ADDRESS)
612 			    sockaddr_size = NLMSG_ALIGN (sa_len);
613 			  if (!build)
614 			    {
615 			      dlen += NLMSG_ALIGN (sa_len);
616 			    }
617 			  else
618 			    {
619 			      memset (*sap, 0, sa_len);
620 			      ifa_make_sockaddr (AF_PACKET, *sap, rtadata,
621 						 rtapayload, 0, 0);
622 			      ((struct sockaddr_ll *) *sap)->sll_ifindex =
623 				nlm_index;
624 			      ((struct sockaddr_ll *) *sap)->sll_hatype =
625 				ifim->ifi_type;
626 			      data += NLMSG_ALIGN (sa_len);
627 			    }
628 			  break;
629 			case IFLA_IFNAME:	/* Name of Interface */
630 			  if (!build)
631 			    nlen += NLMSG_ALIGN (rtapayload + 1);
632 			  else
633 			    {
634 			      ifa->ifa_name = ifname;
635 			      if (iflist[nlm_index] == NULL)
636 				iflist[nlm_index] = ifa->ifa_name;
637 			      strncpy (ifa->ifa_name, rtadata, rtapayload);
638 			      ifa->ifa_name[rtapayload] = '\0';
639 			      ifname += NLMSG_ALIGN (rtapayload + 1);
640 			    }
641 			  break;
642 			case IFLA_STATS:	/* Statistics of Interface */
643 			  if (!build)
644 			    xlen += NLMSG_ALIGN (rtapayload);
645 			  else
646 			    {
647 			      ifa->ifa_data = xdata;
648 			      memcpy (ifa->ifa_data, rtadata, rtapayload);
649 			      xdata += NLMSG_ALIGN (rtapayload);
650 			    }
651 			  break;
652 			case IFLA_UNSPEC:
653 			  break;
654 			case IFLA_MTU:
655 			  break;
656 			case IFLA_LINK:
657 			  break;
658 			case IFLA_QDISC:
659 			  break;
660 			default:
661 			  ;
662 			}
663 		      break;
664 		    case RTM_NEWADDR:
665 		      if (nlm_family == AF_PACKET)
666 			break;
667 		      switch (rta->rta_type)
668 			{
669 			case IFA_ADDRESS:
670 			  ifamap.address = rtadata;
671 			  ifamap.address_len = rtapayload;
672 			  break;
673 			case IFA_LOCAL:
674 			  ifamap.local = rtadata;
675 			  ifamap.local_len = rtapayload;
676 			  break;
677 			case IFA_BROADCAST:
678 			  ifamap.broadcast = rtadata;
679 			  ifamap.broadcast_len = rtapayload;
680 			  break;
681 #ifdef HAVE_IFADDRS_IFA_ANYCAST
682 			case IFA_ANYCAST:
683 			  ifamap.anycast = rtadata;
684 			  ifamap.anycast_len = rtapayload;
685 			  break;
686 #endif
687 			case IFA_LABEL:
688 			  if (!build)
689 			    nlen += NLMSG_ALIGN (rtapayload + 1);
690 			  else
691 			    {
692 			      ifa->ifa_name = ifname;
693 			      if (iflist[nlm_index] == NULL)
694 				iflist[nlm_index] = ifname;
695 			      strncpy (ifa->ifa_name, rtadata, rtapayload);
696 			      ifa->ifa_name[rtapayload] = '\0';
697 			      ifname += NLMSG_ALIGN (rtapayload + 1);
698 			    }
699 			  break;
700 			case IFA_UNSPEC:
701 			  break;
702 			case IFA_CACHEINFO:
703 			  break;
704 			default:
705 			  ;
706 			}
707 		    }
708 		}
709 	      if (nlh->nlmsg_type == RTM_NEWADDR && nlm_family != AF_PACKET)
710 		{
711 		  if (!ifamap.local)
712 		    {
713 		      ifamap.local = ifamap.address;
714 		      ifamap.local_len = ifamap.address_len;
715 		    }
716 		  if (!ifamap.address)
717 		    {
718 		      ifamap.address = ifamap.local;
719 		      ifamap.address_len = ifamap.local_len;
720 		    }
721 		  if (ifamap.address_len != ifamap.local_len ||
722 		      (ifamap.address != NULL &&
723 		       memcmp (ifamap.address, ifamap.local,
724 			       ifamap.address_len)))
725 		    {
726 		      /* p2p; address is peer and local is ours */
727 		      ifamap.broadcast = ifamap.address;
728 		      ifamap.broadcast_len = ifamap.address_len;
729 		      ifamap.address = ifamap.local;
730 		      ifamap.address_len = ifamap.local_len;
731 		    }
732 		  if (ifamap.address)
733 		    {
734 #ifndef IFA_NETMASK
735 		      sockaddr_size =
736 			NLMSG_ALIGN (ifa_sa_len
737 				     (nlm_family, ifamap.address_len));
738 #endif
739 		      if (!build)
740 			dlen +=
741 			  NLMSG_ALIGN (ifa_sa_len
742 				       (nlm_family, ifamap.address_len));
743 		      else
744 			{
745 			  ifa->ifa_addr = (struct sockaddr *) data;
746 			  ifa_make_sockaddr (nlm_family, ifa->ifa_addr,
747 					     ifamap.address,
748 					     ifamap.address_len, nlm_scope,
749 					     nlm_index);
750 			  data +=
751 			    NLMSG_ALIGN (ifa_sa_len
752 					 (nlm_family, ifamap.address_len));
753 			}
754 		    }
755 #ifdef IFA_NETMASK
756 		  if (ifamap.netmask)
757 		    {
758 		      if (!build)
759 			dlen +=
760 			  NLMSG_ALIGN (ifa_sa_len
761 				       (nlm_family, ifamap.netmask_len));
762 		      else
763 			{
764 			  ifa->ifa_netmask = (struct sockaddr *) data;
765 			  ifa_make_sockaddr (nlm_family, ifa->ifa_netmask,
766 					     ifamap.netmask,
767 					     ifamap.netmask_len, nlm_scope,
768 					     nlm_index);
769 			  data +=
770 			    NLMSG_ALIGN (ifa_sa_len
771 					 (nlm_family, ifamap.netmask_len));
772 			}
773 		    }
774 #endif
775 		  if (ifamap.broadcast)
776 		    {
777 		      if (!build)
778 			dlen +=
779 			  NLMSG_ALIGN (ifa_sa_len
780 				       (nlm_family, ifamap.broadcast_len));
781 		      else
782 			{
783 			  ifa->ifa_broadaddr = (struct sockaddr *) data;
784 			  ifa_make_sockaddr (nlm_family, ifa->ifa_broadaddr,
785 					     ifamap.broadcast,
786 					     ifamap.broadcast_len, nlm_scope,
787 					     nlm_index);
788 			  data +=
789 			    NLMSG_ALIGN (ifa_sa_len
790 					 (nlm_family, ifamap.broadcast_len));
791 			}
792 		    }
793 #ifdef HAVE_IFADDRS_IFA_ANYCAST
794 		  if (ifamap.anycast)
795 		    {
796 		      if (!build)
797 			dlen +=
798 			  NLMSG_ALIGN (ifa_sa_len
799 				       (nlm_family, ifamap.anycast_len));
800 		      else
801 			{
802 			  ifa->ifa_anycast = (struct sockaddr *) data;
803 			  ifa_make_sockaddr (nlm_family, ifa->ifa_anyaddr,
804 					     ifamap.anycast,
805 					     ifamap.anycast_len, nlm_scope,
806 					     nlm_index);
807 			  data +=
808 			    NLMSG_ALIGN (ifa_sa_len
809 					 (nlm_family, ifamap.anycast_len));
810 			}
811 		    }
812 #endif
813 		}
814 	      if (!build)
815 		{
816 #ifndef IFA_NETMASK
817 		  dlen += sockaddr_size;
818 #endif
819 		  icnt++;
820 		}
821 	      else
822 		{
823 		  if (ifa->ifa_name == NULL)
824 		    ifa->ifa_name = iflist[nlm_index];
825 #ifndef IFA_NETMASK
826 		  if (ifa->ifa_addr &&
827 		      ifa->ifa_addr->sa_family != AF_UNSPEC &&
828 		      ifa->ifa_addr->sa_family != AF_PACKET)
829 		    {
830 		      ifa->ifa_netmask = (struct sockaddr *) data;
831 		      ifa_make_sockaddr_mask (ifa->ifa_addr->sa_family,
832 					      ifa->ifa_netmask,
833 					      nlm_prefixlen);
834 		    }
835 		  data += sockaddr_size;
836 #endif
837 		  ifl = ifa++;
838 		}
839 	    }
840 	}
841       if (!build)
842 	{
843 	  if (icnt == 0 && (dlen + nlen + xlen == 0))
844 	    {
845 	      if (ifap != NULL)
846 		*ifap = NULL;
847 	      break;		/* cannot found any addresses */
848 	    }
849 	}
850       else
851 	free_data (NULL, ifdata);
852     }
853 
854 /* ---------------------------------- */
855   /* Finalize */
856   free_nlmsglist (nlmsg_list);
857   nl_close (sd);
858   return 0;
859 }
860 
861 /* ---------------------------------------------------------------------- */
862 void
usagi_freeifaddrs(struct ifaddrs * ifa)863 usagi_freeifaddrs (struct ifaddrs *ifa)
864 {
865   free (ifa);
866 }
867 
868 
869 /* **************************************** */
870 
871 #endif  /* HAVE_LINUX_NETLINK_H */
872