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