1/*	$Id: ifaddrs.c 241182 2011-02-17 21:50:03Z $	*/
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, pid_t pid, 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  for (;;)
247    {
248      void *newbuff = realloc (buff, bufsize);
249      if (newbuff == NULL || bufsize < lastbufsize)
250	{
251	  result = -1;
252	  break;
253	}
254      buff = newbuff;
255      result = read_size =
256	nl_recvmsg (sd, request, seq, buff, bufsize, &msg_flags);
257      if (read_size < 0 || (msg_flags & MSG_TRUNC))
258	{
259	  lastbufsize = bufsize;
260	  bufsize *= 2;
261	  continue;
262	}
263      if (read_size == 0)
264	break;
265      nh = (struct nlmsghdr *) buff;
266      for (nh = (struct nlmsghdr *) buff;
267	   NLMSG_OK (nh, read_size);
268	   nh = (struct nlmsghdr *) NLMSG_NEXT (nh, read_size))
269	{
270	  if (nh->nlmsg_pid != pid || nh->nlmsg_seq != seq)
271	    continue;
272	  if (nh->nlmsg_type == NLMSG_DONE)
273	    {
274	      (*done)++;
275	      break;		/* ok */
276	    }
277	  if (nh->nlmsg_type == NLMSG_ERROR)
278	    {
279	      struct nlmsgerr *nlerr = (struct nlmsgerr *) NLMSG_DATA (nh);
280	      result = -1;
281	      if (nh->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
282		__set_errno (EIO);
283	      else
284		__set_errno (-nlerr->error);
285	      break;
286	    }
287	}
288      break;
289    }
290  if (result < 0)
291    if (buff)
292      {
293	int saved_errno = errno;
294	free (buff);
295	__set_errno (saved_errno);
296      }
297  *nlhp = (struct nlmsghdr *) buff;
298  return result;
299}
300
301static int
302nl_getlist (int sd, int seq, pid_t pid,
303	    int request,
304	    struct nlmsg_list **nlm_list, struct nlmsg_list **nlm_end)
305{
306  struct nlmsghdr *nlh = NULL;
307  int status;
308  int done = 0;
309
310  status = nl_sendreq (sd, request, NLM_F_ROOT | NLM_F_MATCH, &seq);
311  if (status < 0)
312    return status;
313  if (seq == 0)
314    seq = (int) time (NULL);
315  while (!done)
316    {
317      status = nl_getmsg (sd, request, seq, pid, &nlh, &done);
318      if (status < 0)
319	return status;
320      if (nlh)
321	{
322	  struct nlmsg_list *nlm_next =
323	    (struct nlmsg_list *) malloc (sizeof (struct nlmsg_list));
324	  if (nlm_next == NULL)
325	    {
326	      int saved_errno = errno;
327	      free (nlh);
328	      __set_errno (saved_errno);
329	      status = -1;
330	    }
331	  else
332	    {
333	      nlm_next->nlm_next = NULL;
334	      nlm_next->nlh = (struct nlmsghdr *) nlh;
335	      nlm_next->size = status;
336	      nlm_next->seq = seq;
337	      if (*nlm_list == NULL)
338		{
339		  *nlm_list = nlm_next;
340		  *nlm_end = nlm_next;
341		}
342	      else
343		{
344		  (*nlm_end)->nlm_next = nlm_next;
345		  *nlm_end = nlm_next;
346		}
347	    }
348	}
349    }
350  return status >= 0 ? seq : status;
351}
352
353/* ---------------------------------------------------------------------- */
354static void
355free_nlmsglist (struct nlmsg_list *nlm0)
356{
357  struct nlmsg_list *nlm, *nlm_next;
358  int saved_errno;
359  if (!nlm0)
360    return;
361  saved_errno = errno;
362  nlm = nlm0;
363  while (nlm)
364    {
365      if (nlm->nlh)
366	free (nlm->nlh);
367      nlm_next = nlm->nlm_next;
368      free(nlm);
369      nlm = nlm_next;
370    }
371  __set_errno (saved_errno);
372}
373
374static void
375free_data (void *data, void *ifdata)
376{
377  int saved_errno = errno;
378  if (data != NULL)
379    free (data);
380  if (ifdata != NULL)
381    free (ifdata);
382  __set_errno (saved_errno);
383}
384
385/* ---------------------------------------------------------------------- */
386static void
387nl_close (int sd)
388{
389  int saved_errno = errno;
390  if (sd >= 0)
391    close (sd);
392  __set_errno (saved_errno);
393}
394
395/* ---------------------------------------------------------------------- */
396static int
397nl_open (pid_t *pid)
398{
399  struct sockaddr_nl nladdr;
400  int sd;
401
402  sd = socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
403  if (sd < 0)
404    return -1;
405  memset (&nladdr, 0, sizeof (nladdr));
406  nladdr.nl_family = AF_NETLINK;
407  if (bind (sd, (struct sockaddr *) &nladdr, sizeof (nladdr)) < 0)
408    {
409      nl_close (sd);
410      return -1;
411    }
412  if (pid)
413    {
414      socklen_t len = sizeof(nladdr);
415      if (getsockname (sd, (struct sockaddr *) &nladdr, &len) < 0)
416        {
417          nl_close (sd);
418          return -1;
419        }
420      *pid = nladdr.nl_pid;
421    }
422  return sd;
423}
424
425/* ====================================================================== */
426int
427getifaddrs (struct ifaddrs **ifap)
428{
429  int sd;
430  struct nlmsg_list *nlmsg_list, *nlmsg_end, *nlm;
431  /* - - - - - - - - - - - - - - - */
432  int icnt;
433  size_t dlen, xlen, nlen;
434  uint32_t max_ifindex = 0;
435
436  pid_t pid;
437  int seq;
438  int result;
439  int build;			/* 0 or 1 */
440
441/* ---------------------------------- */
442  /* initialize */
443  icnt = dlen = xlen = nlen = 0;
444  nlmsg_list = nlmsg_end = NULL;
445
446  if (ifap)
447    *ifap = NULL;
448
449/* ---------------------------------- */
450  /* open socket and bind */
451  sd = nl_open (&pid);
452  if (sd < 0)
453    return -1;
454
455/* ---------------------------------- */
456  /* gather info */
457  if ((seq = nl_getlist (sd, 0, pid, RTM_GETLINK, &nlmsg_list, &nlmsg_end)) < 0)
458    {
459      free_nlmsglist (nlmsg_list);
460      nl_close (sd);
461      return -1;
462    }
463  if ((seq = nl_getlist (sd, seq + 1, pid, RTM_GETADDR,
464			 &nlmsg_list, &nlmsg_end)) < 0)
465    {
466      free_nlmsglist (nlmsg_list);
467      nl_close (sd);
468      return -1;
469    }
470
471/* ---------------------------------- */
472  /* Estimate size of result buffer and fill it */
473  for (build = 0; build <= 1; build++)
474    {
475      struct ifaddrs *ifl = NULL, *ifa = NULL;
476      struct nlmsghdr *nlh, *nlh0;
477      void *data = NULL, *xdata = NULL, *ifdata = NULL;
478      char *ifname = NULL, **iflist = NULL;
479      uint16_t *ifflist = NULL;
480      struct rtmaddr_ifamap ifamap;
481
482      if (build)
483	{
484	  ifa = data = calloc (1,
485			       NLMSG_ALIGN (sizeof (struct ifaddrs[icnt]))
486			       + dlen + xlen + nlen);
487	  ifdata = calloc (1,
488			   NLMSG_ALIGN (sizeof (char *[max_ifindex + 1]))
489			   +
490			   NLMSG_ALIGN (sizeof (uint16_t[max_ifindex + 1])));
491	  if (ifap != NULL)
492	    *ifap = (ifdata != NULL) ? ifa : NULL;
493	  else
494	    {
495	      free_data (data, ifdata);
496	      result = 0;
497	      break;
498	    }
499	  if (data == NULL || ifdata == NULL)
500	    {
501	      free_data (data, ifdata);
502	      result = -1;
503	      break;
504	    }
505	  ifl = NULL;
506	  data += NLMSG_ALIGN (sizeof (struct ifaddrs)) * icnt;
507	  xdata = data + dlen;
508	  ifname = xdata + xlen;
509	  iflist = ifdata;
510	  ifflist =
511	    ((void *) iflist) +
512	    NLMSG_ALIGN (sizeof (char *[max_ifindex + 1]));
513	}
514
515      for (nlm = nlmsg_list; nlm; nlm = nlm->nlm_next)
516	{
517	  int nlmlen = nlm->size;
518	  if (!(nlh0 = nlm->nlh))
519	    continue;
520	  for (nlh = nlh0;
521	       NLMSG_OK (nlh, nlmlen); nlh = NLMSG_NEXT (nlh, nlmlen))
522	    {
523	      struct ifinfomsg *ifim = NULL;
524	      struct ifaddrmsg *ifam = NULL;
525	      struct rtattr *rta;
526
527	      size_t nlm_struct_size = 0;
528	      sa_family_t nlm_family = 0;
529	      uint32_t nlm_scope = 0, nlm_index = 0;
530#ifndef IFA_NETMASK
531	      size_t sockaddr_size = 0;
532	      uint32_t nlm_prefixlen = 0;
533#endif
534	      size_t rtasize;
535
536	      memset (&ifamap, 0, sizeof (ifamap));
537
538	      /* check if the message is what we want */
539	      if (nlh->nlmsg_pid != pid || nlh->nlmsg_seq != nlm->seq)
540		continue;
541	      if (nlh->nlmsg_type == NLMSG_DONE)
542		{
543		  break;	/* ok */
544		}
545	      switch (nlh->nlmsg_type)
546		{
547		case RTM_NEWLINK:
548		  ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
549		  nlm_struct_size = sizeof (*ifim);
550		  nlm_family = ifim->ifi_family;
551		  nlm_scope = 0;
552		  nlm_index = ifim->ifi_index;
553		  nlm_prefixlen = 0;
554		  if (build)
555		    ifflist[nlm_index] = ifa->ifa_flags = ifim->ifi_flags;
556		  break;
557		case RTM_NEWADDR:
558		  ifam = (struct ifaddrmsg *) NLMSG_DATA (nlh);
559		  nlm_struct_size = sizeof (*ifam);
560		  nlm_family = ifam->ifa_family;
561		  nlm_scope = ifam->ifa_scope;
562		  nlm_index = ifam->ifa_index;
563		  nlm_prefixlen = ifam->ifa_prefixlen;
564		  if (build)
565		    ifa->ifa_flags = ifflist[nlm_index];
566		  break;
567		default:
568		  continue;
569		}
570
571	      if (!build)
572		{
573		  if (max_ifindex < nlm_index)
574		    max_ifindex = nlm_index;
575		}
576	      else
577		{
578		  if (ifl != NULL)
579		    ifl->ifa_next = ifa;
580		}
581
582	      rtasize =
583		NLMSG_PAYLOAD (nlh, nlmlen) - NLMSG_ALIGN (nlm_struct_size);
584	      for (rta =
585		   (struct rtattr *) (((char *) NLMSG_DATA (nlh)) +
586				      NLMSG_ALIGN (nlm_struct_size));
587		   RTA_OK (rta, rtasize); rta = RTA_NEXT (rta, rtasize))
588		{
589		  struct sockaddr **sap = NULL;
590		  void *rtadata = RTA_DATA (rta);
591		  size_t rtapayload = RTA_PAYLOAD (rta);
592		  socklen_t sa_len;
593
594		  switch (nlh->nlmsg_type)
595		    {
596		    case RTM_NEWLINK:
597		      switch (rta->rta_type)
598			{
599			case IFLA_ADDRESS:
600			case IFLA_BROADCAST:
601			  if (build)
602			    {
603			      sap =
604				(rta->rta_type ==
605				 IFLA_ADDRESS) ? &ifa->ifa_addr : &ifa->
606				ifa_broadaddr;
607			      *sap = (struct sockaddr *) data;
608			    }
609			  sa_len = ifa_sa_len (AF_PACKET, rtapayload);
610			  if (rta->rta_type == IFLA_ADDRESS)
611			    sockaddr_size = NLMSG_ALIGN (sa_len);
612			  if (!build)
613			    {
614			      dlen += NLMSG_ALIGN (sa_len);
615			    }
616			  else
617			    {
618			      memset (*sap, 0, sa_len);
619			      ifa_make_sockaddr (AF_PACKET, *sap, rtadata,
620						 rtapayload, 0, 0);
621			      ((struct sockaddr_ll *) *sap)->sll_ifindex =
622				nlm_index;
623			      ((struct sockaddr_ll *) *sap)->sll_hatype =
624				ifim->ifi_type;
625			      data += NLMSG_ALIGN (sa_len);
626			    }
627			  break;
628			case IFLA_IFNAME:	/* Name of Interface */
629			  if (!build)
630			    nlen += NLMSG_ALIGN (rtapayload + 1);
631			  else
632			    {
633			      ifa->ifa_name = ifname;
634			      if (iflist[nlm_index] == NULL)
635				iflist[nlm_index] = ifa->ifa_name;
636			      strncpy (ifa->ifa_name, rtadata, rtapayload);
637			      ifa->ifa_name[rtapayload] = '\0';
638			      ifname += NLMSG_ALIGN (rtapayload + 1);
639			    }
640			  break;
641			case IFLA_STATS:	/* Statistics of Interface */
642			  if (!build)
643			    xlen += NLMSG_ALIGN (rtapayload);
644			  else
645			    {
646			      ifa->ifa_data = xdata;
647			      memcpy (ifa->ifa_data, rtadata, rtapayload);
648			      xdata += NLMSG_ALIGN (rtapayload);
649			    }
650			  break;
651			case IFLA_UNSPEC:
652			  break;
653			case IFLA_MTU:
654			  break;
655			case IFLA_LINK:
656			  break;
657			case IFLA_QDISC:
658			  break;
659			default:
660				;
661			}
662		      break;
663		    case RTM_NEWADDR:
664		      if (nlm_family == AF_PACKET)
665			break;
666		      switch (rta->rta_type)
667			{
668			case IFA_ADDRESS:
669			  ifamap.address = rtadata;
670			  ifamap.address_len = rtapayload;
671			  break;
672			case IFA_LOCAL:
673			  ifamap.local = rtadata;
674			  ifamap.local_len = rtapayload;
675			  break;
676			case IFA_BROADCAST:
677			  ifamap.broadcast = rtadata;
678			  ifamap.broadcast_len = rtapayload;
679			  break;
680#ifdef HAVE_IFADDRS_IFA_ANYCAST
681			case IFA_ANYCAST:
682			  ifamap.anycast = rtadata;
683			  ifamap.anycast_len = rtapayload;
684			  break;
685#endif
686			case IFA_LABEL:
687			  if (!build)
688			    nlen += NLMSG_ALIGN (rtapayload + 1);
689			  else
690			    {
691			      ifa->ifa_name = ifname;
692			      if (iflist[nlm_index] == NULL)
693				iflist[nlm_index] = ifname;
694			      strncpy (ifa->ifa_name, rtadata, rtapayload);
695			      ifa->ifa_name[rtapayload] = '\0';
696			      ifname += NLMSG_ALIGN (rtapayload + 1);
697			    }
698			  break;
699			case IFA_UNSPEC:
700			  break;
701			case IFA_CACHEINFO:
702			  break;
703			default:
704				;
705			}
706		    }
707		}
708	      if (nlh->nlmsg_type == RTM_NEWADDR && nlm_family != AF_PACKET)
709		{
710		  if (!ifamap.local)
711		    {
712		      ifamap.local = ifamap.address;
713		      ifamap.local_len = ifamap.address_len;
714		    }
715		  if (!ifamap.address)
716		    {
717		      ifamap.address = ifamap.local;
718		      ifamap.address_len = ifamap.local_len;
719		    }
720		  if (ifamap.address_len != ifamap.local_len ||
721		      (ifamap.address != NULL &&
722		       memcmp (ifamap.address, ifamap.local,
723			       ifamap.address_len)))
724		    {
725		      /* p2p; address is peer and local is ours */
726		      ifamap.broadcast = ifamap.address;
727		      ifamap.broadcast_len = ifamap.address_len;
728		      ifamap.address = ifamap.local;
729		      ifamap.address_len = ifamap.local_len;
730		    }
731		  if (ifamap.address)
732		    {
733#ifndef IFA_NETMASK
734		      sockaddr_size =
735			NLMSG_ALIGN (ifa_sa_len
736				     (nlm_family, ifamap.address_len));
737#endif
738		      if (!build)
739			dlen +=
740			  NLMSG_ALIGN (ifa_sa_len
741				       (nlm_family, ifamap.address_len));
742		      else
743			{
744			  ifa->ifa_addr = (struct sockaddr *) data;
745			  ifa_make_sockaddr (nlm_family, ifa->ifa_addr,
746					     ifamap.address,
747					     ifamap.address_len, nlm_scope,
748					     nlm_index);
749			  data +=
750			    NLMSG_ALIGN (ifa_sa_len
751					 (nlm_family, ifamap.address_len));
752			}
753		    }
754#ifdef IFA_NETMASK
755		  if (ifamap.netmask)
756		    {
757		      if (!build)
758			dlen +=
759			  NLMSG_ALIGN (ifa_sa_len
760				       (nlm_family, ifamap.netmask_len));
761		      else
762			{
763			  ifa->ifa_netmask = (struct sockaddr *) data;
764			  ifa_make_sockaddr (nlm_family, ifa->ifa_netmask,
765					     ifamap.netmask,
766					     ifamap.netmask_len, nlm_scope,
767					     nlm_index);
768			  data +=
769			    NLMSG_ALIGN (ifa_sa_len
770					 (nlm_family, ifamap.netmask_len));
771			}
772		    }
773#endif
774		  if (ifamap.broadcast)
775		    {
776		      if (!build)
777			dlen +=
778			  NLMSG_ALIGN (ifa_sa_len
779				       (nlm_family, ifamap.broadcast_len));
780		      else
781			{
782			  ifa->ifa_broadaddr = (struct sockaddr *) data;
783			  ifa_make_sockaddr (nlm_family, ifa->ifa_broadaddr,
784					     ifamap.broadcast,
785					     ifamap.broadcast_len, nlm_scope,
786					     nlm_index);
787			  data +=
788			    NLMSG_ALIGN (ifa_sa_len
789					 (nlm_family, ifamap.broadcast_len));
790			}
791		    }
792#ifdef HAVE_IFADDRS_IFA_ANYCAST
793		  if (ifamap.anycast)
794		    {
795		      if (!build)
796			dlen +=
797			  NLMSG_ALIGN (ifa_sa_len
798				       (nlm_family, ifamap.anycast_len));
799		      else
800			{
801			  ifa->ifa_anycast = (struct sockaddr *) data;
802			  ifa_make_sockaddr (nlm_family, ifa->ifa_anyaddr,
803					     ifamap.anycast,
804					     ifamap.anycast_len, nlm_scope,
805					     nlm_index);
806			  data +=
807			    NLMSG_ALIGN (ifa_sa_len
808					 (nlm_family, ifamap.anycast_len));
809			}
810		    }
811#endif
812		}
813	      if (!build)
814		{
815#ifndef IFA_NETMASK
816		  dlen += sockaddr_size;
817#endif
818		  icnt++;
819		}
820	      else
821		{
822		  if (ifa->ifa_name == NULL)
823		    ifa->ifa_name = iflist[nlm_index];
824#ifndef IFA_NETMASK
825		  if (ifa->ifa_addr &&
826		      ifa->ifa_addr->sa_family != AF_UNSPEC &&
827		      ifa->ifa_addr->sa_family != AF_PACKET)
828		    {
829		      ifa->ifa_netmask = (struct sockaddr *) data;
830		      ifa_make_sockaddr_mask (ifa->ifa_addr->sa_family,
831					      ifa->ifa_netmask,
832					      nlm_prefixlen);
833		    }
834		  data += sockaddr_size;
835#endif
836		  ifl = ifa++;
837		}
838	    }
839	}
840      if (!build)
841	{
842	  if (icnt == 0 && (dlen + nlen + xlen == 0))
843	    {
844	      if (ifap != NULL)
845		*ifap = NULL;
846	      break;		/* cannot found any addresses */
847	    }
848	}
849      else
850	free_data (NULL, ifdata);
851    }
852
853/* ---------------------------------- */
854  /* Finalize */
855  free_nlmsglist (nlmsg_list);
856  nl_close (sd);
857  return 0;
858}
859
860/* ---------------------------------------------------------------------- */
861void
862freeifaddrs (struct ifaddrs *ifa)
863{
864  free (ifa);
865}
866