OSDN Git Service

535f6277fff97910b26dc10b1e723dc40e52857c
[uclinux-h8/uClibc.git] / libc / inet / ifaddrs.c
1 /* getifaddrs -- get names and addresses of all network interfaces
2    Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #define __FORCE_GLIBC
21 #include <features.h>
22 #include <alloca.h>
23 #include <assert.h>
24 #include <errno.h>
25 #include <ifaddrs.h>
26 #include <net/if.h>
27 #include <netinet/in.h>
28 #include <netpacket/packet.h>
29 #include <stdbool.h>
30 #include <stdint.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <sys/ioctl.h>
35 #include <sys/socket.h>
36 #include <libc-internal.h>
37 #include <time.h>
38 #include <unistd.h>
39
40 #include "netlinkaccess.h"
41
42
43 #ifndef __libc_use_alloca
44 # define __libc_use_alloca(x) (x < __MAX_ALLOCA_CUTOFF)
45 #endif
46
47
48 #if __ASSUME_NETLINK_SUPPORT
49 #ifdef __UCLIBC_SUPPORT_AI_ADDRCONFIG__
50 /* struct to hold the data for one ifaddrs entry, so we can allocate
51    everything at once.  */
52 struct ifaddrs_storage
53 {
54   struct ifaddrs ifa;
55   union
56   {
57     /* Save space for the biggest of the four used sockaddr types and
58        avoid a lot of casts.  */
59     struct sockaddr sa;
60     struct sockaddr_ll sl;
61     struct sockaddr_in s4;
62 #ifdef __UCLIBC_HAS_IPV6__
63     struct sockaddr_in6 s6;
64 #endif
65   } addr, netmask, broadaddr;
66   char name[IF_NAMESIZE + 1];
67 };
68 #endif /* __UCLIBC_SUPPORT_AI_ADDRCONFIG__ */
69
70
71 void
72 __netlink_free_handle (struct netlink_handle *h)
73 {
74   struct netlink_res *ptr;
75
76   ptr = h->nlm_list;
77   while (ptr != NULL)
78     {
79       struct netlink_res *tmpptr;
80
81       tmpptr = ptr->next;
82       free (ptr); /* doesn't affect errno */
83       ptr = tmpptr;
84     }
85 }
86
87
88 static int
89 __netlink_sendreq (struct netlink_handle *h, int type)
90 {
91   struct
92   {
93     struct nlmsghdr nlh;
94     struct rtgenmsg g;
95   } req;
96   struct sockaddr_nl nladdr;
97
98   if (h->seq == 0)
99     h->seq = time (NULL);
100
101   req.nlh.nlmsg_len = sizeof (req);
102   req.nlh.nlmsg_type = type;
103   req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
104   req.nlh.nlmsg_pid = 0;
105   req.nlh.nlmsg_seq = h->seq;
106   req.g.rtgen_family = AF_UNSPEC;
107
108   memset (&nladdr, '\0', sizeof (nladdr));
109   nladdr.nl_family = AF_NETLINK;
110
111   return TEMP_FAILURE_RETRY (sendto (h->fd, (void *) &req, sizeof (req), 0,
112                                        (struct sockaddr *) &nladdr,
113                                        sizeof (nladdr)));
114 }
115
116
117 int
118 __netlink_request (struct netlink_handle *h, int type)
119 {
120   struct netlink_res *nlm_next;
121   struct netlink_res **new_nlm_list;
122   static volatile size_t buf_size = 4096;
123   char *buf;
124   struct sockaddr_nl nladdr;
125   struct nlmsghdr *nlmh;
126   ssize_t read_len;
127   bool done = false;
128   bool use_malloc = false;
129
130   if (__netlink_sendreq (h, type) < 0)
131     return -1;
132
133   size_t this_buf_size = buf_size;
134   if (__libc_use_alloca (this_buf_size))
135     buf = alloca (this_buf_size);
136   else
137     {
138       buf = malloc (this_buf_size);
139       if (buf != NULL)
140         use_malloc = true;
141       else
142         goto out_fail;
143     }
144
145   struct iovec iov = { buf, this_buf_size };
146
147   if (h->nlm_list != NULL)
148     new_nlm_list = &h->end_ptr->next;
149   else
150     new_nlm_list = &h->nlm_list;
151
152   while (! done)
153     {
154       struct msghdr msg =
155         {
156           (void *) &nladdr, sizeof (nladdr),
157           &iov, 1,
158           NULL, 0,
159           0
160         };
161
162       read_len = TEMP_FAILURE_RETRY (recvmsg (h->fd, &msg, 0));
163       if (read_len < 0)
164         goto out_fail;
165
166       if (nladdr.nl_pid != 0)
167         continue;
168
169       if (__builtin_expect (msg.msg_flags & MSG_TRUNC, 0))
170         {
171           if (this_buf_size >= SIZE_MAX / 2)
172             goto out_fail;
173
174           nlm_next = *new_nlm_list;
175           while (nlm_next != NULL)
176             {
177               struct netlink_res *tmpptr;
178
179               tmpptr = nlm_next->next;
180               free (nlm_next);
181               nlm_next = tmpptr;
182             }
183           *new_nlm_list = NULL;
184
185           if (__libc_use_alloca (2 * this_buf_size))
186             buf = extend_alloca (buf, this_buf_size, 2 * this_buf_size);
187           else
188             {
189               this_buf_size *= 2;
190
191               char *new_buf = realloc (use_malloc ? buf : NULL, this_buf_size);
192               if (new_buf == NULL)
193                 goto out_fail;
194               new_buf = buf;
195
196               use_malloc = true;
197             }
198           buf_size = this_buf_size;
199
200           iov.iov_base = buf;
201           iov.iov_len = this_buf_size;
202
203           /* Increase sequence number, so that we can distinguish
204              between old and new request messages.  */
205           h->seq++;
206
207           if (__netlink_sendreq (h, type) < 0)
208             goto out_fail;
209
210           continue;
211         }
212
213       size_t count = 0;
214       size_t remaining_len = read_len;
215       for (nlmh = (struct nlmsghdr *) buf;
216            NLMSG_OK (nlmh, remaining_len);
217            nlmh = (struct nlmsghdr *) NLMSG_NEXT (nlmh, remaining_len))
218         {
219           if ((pid_t) nlmh->nlmsg_pid != h->pid
220               || nlmh->nlmsg_seq != h->seq)
221             continue;
222
223           ++count;
224           if (nlmh->nlmsg_type == NLMSG_DONE)
225             {
226               /* We found the end, leave the loop.  */
227               done = true;
228               break;
229             }
230           if (nlmh->nlmsg_type == NLMSG_ERROR)
231             {
232               struct nlmsgerr *nlerr = (struct nlmsgerr *) NLMSG_DATA (nlmh);
233               if (nlmh->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
234                 errno = EIO;
235               else
236                 errno = -nlerr->error;
237               goto out_fail;
238             }
239         }
240
241       /* If there was nothing with the expected nlmsg_pid and nlmsg_seq,
242          there is no point to record it.  */
243       if (count == 0)
244         continue;
245
246       nlm_next = (struct netlink_res *) malloc (sizeof (struct netlink_res)
247                                                 + read_len);
248       if (nlm_next == NULL)
249         goto out_fail;
250       nlm_next->next = NULL;
251       nlm_next->nlh = memcpy (nlm_next + 1, buf, read_len);
252       nlm_next->size = read_len;
253       nlm_next->seq = h->seq;
254       if (h->nlm_list == NULL)
255         h->nlm_list = nlm_next;
256       else
257         h->end_ptr->next = nlm_next;
258       h->end_ptr = nlm_next;
259     }
260
261   if (use_malloc)
262     free (buf);
263   return 0;
264
265 out_fail:
266   if (use_malloc)
267     free (buf);
268   return -1;
269 }
270
271
272 void
273 __netlink_close (struct netlink_handle *h)
274 {
275   /* Don't modify errno.  */
276   int serrno = errno;
277   close(h->fd);
278   __set_errno(serrno);
279 }
280
281
282 /* Open a NETLINK socket.  */
283 int
284 __netlink_open (struct netlink_handle *h)
285 {
286   struct sockaddr_nl nladdr;
287
288   h->fd = socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
289   if (h->fd < 0)
290     goto out;
291
292   memset (&nladdr, '\0', sizeof (nladdr));
293   nladdr.nl_family = AF_NETLINK;
294   if (bind (h->fd, (struct sockaddr *) &nladdr, sizeof (nladdr)) < 0)
295     {
296     close_and_out:
297       __netlink_close (h);
298     out:
299       return -1;
300     }
301   /* Determine the ID the kernel assigned for this netlink connection.
302      It is not necessarily the PID if there is more than one socket
303      open.  */
304   socklen_t addr_len = sizeof (nladdr);
305   if (getsockname (h->fd, (struct sockaddr *) &nladdr, &addr_len) < 0)
306     goto close_and_out;
307   h->pid = nladdr.nl_pid;
308   return 0;
309 }
310
311
312 #ifdef __UCLIBC_SUPPORT_AI_ADDRCONFIG__
313 /* We know the number of RTM_NEWLINK entries, so we reserve the first
314    # of entries for this type. All RTM_NEWADDR entries have an index
315    pointer to the RTM_NEWLINK entry.  To find the entry, create
316    a table to map kernel index entries to our index numbers.
317    Since we get at first all RTM_NEWLINK entries, it can never happen
318    that a RTM_NEWADDR index is not known to this map.  */
319 static int
320 internal_function
321 map_newlink (int idx, struct ifaddrs_storage *ifas, int *map, int max)
322 {
323   int i;
324
325   for (i = 0; i < max; i++)
326     {
327       if (map[i] == -1)
328         {
329           map[i] = idx;
330           if (i > 0)
331             ifas[i - 1].ifa.ifa_next = &ifas[i].ifa;
332           return i;
333         }
334       else if (map[i] == idx)
335         return i;
336     }
337   /* This should never be reached. If this will be reached, we have
338      a very big problem.  */
339   abort ();
340 }
341
342
343 /* Create a linked list of `struct ifaddrs' structures, one for each
344    network interface on the host machine.  If successful, store the
345    list in *IFAP and return 0.  On errors, return -1 and set `errno'.  */
346 int
347 getifaddrs (struct ifaddrs **ifap)
348 {
349   struct netlink_handle nh = { 0, 0, 0, NULL, NULL };
350   struct netlink_res *nlp;
351   struct ifaddrs_storage *ifas;
352   unsigned int i, newlink, newaddr, newaddr_idx;
353   int *map_newlink_data;
354   size_t ifa_data_size = 0;  /* Size to allocate for all ifa_data.  */
355   char *ifa_data_ptr;   /* Pointer to the unused part of memory for
356                                 ifa_data.  */
357   int result = 0;
358
359   if (ifap)
360     *ifap = NULL;
361
362   if (__netlink_open (&nh) < 0)
363     {
364       return -1;
365     }
366
367   /* Tell the kernel that we wish to get a list of all
368      active interfaces, collect all data for every interface.  */
369   if (__netlink_request (&nh, RTM_GETLINK) < 0)
370     {
371       result = -1;
372       goto exit_free;
373     }
374
375   /* Now ask the kernel for all addresses which are assigned
376      to an interface and collect all data for every interface.
377      Since we store the addresses after the interfaces in the
378      list, we will later always find the interface before the
379      corresponding addresses.  */
380   ++nh.seq;
381   if (__netlink_request (&nh, RTM_GETADDR) < 0)
382     {
383       result = -1;
384       goto exit_free;
385     }
386
387   /* Count all RTM_NEWLINK and RTM_NEWADDR entries to allocate
388      enough memory.  */
389   newlink = newaddr = 0;
390   for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
391     {
392       struct nlmsghdr *nlh;
393       size_t size = nlp->size;
394
395       if (nlp->nlh == NULL)
396         continue;
397
398       /* Walk through all entries we got from the kernel and look, which
399          message type they contain.  */
400       for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
401         {
402           /* Check if the message is what we want.  */
403           if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
404             continue;
405
406           if (nlh->nlmsg_type == NLMSG_DONE)
407             break;              /* ok */
408
409           if (nlh->nlmsg_type == RTM_NEWLINK)
410             {
411               /* A RTM_NEWLINK message can have IFLA_STATS data. We need to
412                  know the size before creating the list to allocate enough
413                  memory.  */
414               struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
415               struct rtattr *rta = IFLA_RTA (ifim);
416               size_t rtasize = IFLA_PAYLOAD (nlh);
417
418               while (RTA_OK (rta, rtasize))
419                 {
420                   size_t rta_payload = RTA_PAYLOAD (rta);
421
422                   if (rta->rta_type == IFLA_STATS)
423                     {
424                       ifa_data_size += rta_payload;
425                       break;
426                     }
427                   else
428                     rta = RTA_NEXT (rta, rtasize);
429                 }
430               ++newlink;
431             }
432           else if (nlh->nlmsg_type == RTM_NEWADDR)
433             ++newaddr;
434         }
435     }
436
437   /* Return if no interface is up.  */
438   if ((newlink + newaddr) == 0)
439     goto exit_free;
440
441   /* Allocate memory for all entries we have and initialize next
442      pointer.  */
443   ifas = calloc (1, (newlink + newaddr) * sizeof (ifas[0]) + ifa_data_size);
444   if (ifas == NULL)
445     {
446       result = -1;
447       goto exit_free;
448     }
449
450   /* Table for mapping kernel index to entry in our list.  */
451   map_newlink_data = alloca (newlink * sizeof (int));
452   memset (map_newlink_data, '\xff', newlink * sizeof (int));
453
454   ifa_data_ptr = (char *) &ifas[newlink + newaddr];
455   newaddr_idx = 0;              /* Counter for newaddr index.  */
456
457   /* Walk through the list of data we got from the kernel.  */
458   for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
459     {
460       struct nlmsghdr *nlh;
461       size_t size = nlp->size;
462
463       if (nlp->nlh == NULL)
464         continue;
465
466       /* Walk through one message and look at the type: If it is our
467          message, we need RTM_NEWLINK/RTM_NEWADDR and stop if we reach
468          the end or we find the end marker (in this case we ignore the
469          following data.  */
470       for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
471         {
472           int ifa_index = 0;
473
474           /* Check if the message is the one we want */
475           if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
476             continue;
477
478           if (nlh->nlmsg_type == NLMSG_DONE)
479             break;              /* ok */
480
481           if (nlh->nlmsg_type == RTM_NEWLINK)
482             {
483               /* We found a new interface. Now extract everything from the
484                  interface data we got and need.  */
485               struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
486               struct rtattr *rta = IFLA_RTA (ifim);
487               size_t rtasize = IFLA_PAYLOAD (nlh);
488
489               /* Interfaces are stored in the first "newlink" entries
490                  of our list, starting in the order as we got from the
491                  kernel.  */
492               ifa_index = map_newlink (ifim->ifi_index - 1, ifas,
493                                        map_newlink_data, newlink);
494               ifas[ifa_index].ifa.ifa_flags = ifim->ifi_flags;
495
496               while (RTA_OK (rta, rtasize))
497                 {
498                   char *rta_data = RTA_DATA (rta);
499                   size_t rta_payload = RTA_PAYLOAD (rta);
500
501                   switch (rta->rta_type)
502                     {
503                     case IFLA_ADDRESS:
504                       if (rta_payload <= sizeof (ifas[ifa_index].addr))
505                         {
506                           ifas[ifa_index].addr.sl.sll_family = AF_PACKET;
507                           memcpy (ifas[ifa_index].addr.sl.sll_addr,
508                                   (char *) rta_data, rta_payload);
509                           ifas[ifa_index].addr.sl.sll_halen = rta_payload;
510                           ifas[ifa_index].addr.sl.sll_ifindex
511                             = ifim->ifi_index;
512                           ifas[ifa_index].addr.sl.sll_hatype = ifim->ifi_type;
513
514                           ifas[ifa_index].ifa.ifa_addr
515                             = &ifas[ifa_index].addr.sa;
516                         }
517                       break;
518
519                     case IFLA_BROADCAST:
520                       if (rta_payload <= sizeof (ifas[ifa_index].broadaddr))
521                         {
522                           ifas[ifa_index].broadaddr.sl.sll_family = AF_PACKET;
523                           memcpy (ifas[ifa_index].broadaddr.sl.sll_addr,
524                                   (char *) rta_data, rta_payload);
525                           ifas[ifa_index].broadaddr.sl.sll_halen = rta_payload;
526                           ifas[ifa_index].broadaddr.sl.sll_ifindex
527                             = ifim->ifi_index;
528                           ifas[ifa_index].broadaddr.sl.sll_hatype
529                             = ifim->ifi_type;
530
531                           ifas[ifa_index].ifa.ifa_broadaddr
532                             = &ifas[ifa_index].broadaddr.sa;
533                         }
534                       break;
535
536                     case IFLA_IFNAME:   /* Name of Interface */
537                       if ((rta_payload + 1) <= sizeof (ifas[ifa_index].name))
538                         {
539                           ifas[ifa_index].ifa.ifa_name = ifas[ifa_index].name;
540                           *(char *) mempcpy (ifas[ifa_index].name, rta_data,
541                                                rta_payload) = '\0';
542                         }
543                       break;
544
545                     case IFLA_STATS:    /* Statistics of Interface */
546                       ifas[ifa_index].ifa.ifa_data = ifa_data_ptr;
547                       ifa_data_ptr += rta_payload;
548                       memcpy (ifas[ifa_index].ifa.ifa_data, rta_data,
549                               rta_payload);
550                       break;
551
552                     case IFLA_UNSPEC:
553                       break;
554                     case IFLA_MTU:
555                       break;
556                     case IFLA_LINK:
557                       break;
558                     case IFLA_QDISC:
559                       break;
560                     default:
561                       break;
562                     }
563
564                   rta = RTA_NEXT (rta, rtasize);
565                 }
566             }
567           else if (nlh->nlmsg_type == RTM_NEWADDR)
568             {
569               struct ifaddrmsg *ifam = (struct ifaddrmsg *) NLMSG_DATA (nlh);
570               struct rtattr *rta = IFA_RTA (ifam);
571               size_t rtasize = IFA_PAYLOAD (nlh);
572
573               /* New Addresses are stored in the order we got them from
574                  the kernel after the interfaces. Theoretically it is possible
575                  that we have holes in the interface part of the list,
576                  but we always have already the interface for this address.  */
577               ifa_index = newlink + newaddr_idx;
578               ifas[ifa_index].ifa.ifa_flags
579                 = ifas[map_newlink (ifam->ifa_index - 1, ifas,
580                                     map_newlink_data, newlink)].ifa.ifa_flags;
581               if (ifa_index > 0)
582                 ifas[ifa_index - 1].ifa.ifa_next = &ifas[ifa_index].ifa;
583               ++newaddr_idx;
584
585               while (RTA_OK (rta, rtasize))
586                 {
587                   char *rta_data = RTA_DATA (rta);
588                   size_t rta_payload = RTA_PAYLOAD (rta);
589
590                   switch (rta->rta_type)
591                     {
592                     case IFA_ADDRESS:
593                       {
594                         struct sockaddr *sa;
595
596                         if (ifas[ifa_index].ifa.ifa_addr != NULL)
597                           {
598                             /* In a point-to-poing network IFA_ADDRESS
599                                contains the destination address, local
600                                address is supplied in IFA_LOCAL attribute.
601                                destination address and broadcast address
602                                are stored in an union, so it doesn't matter
603                                which name we use.  */
604                             ifas[ifa_index].ifa.ifa_broadaddr
605                               = &ifas[ifa_index].broadaddr.sa;
606                             sa = &ifas[ifa_index].broadaddr.sa;
607                           }
608                         else
609                           {
610                             ifas[ifa_index].ifa.ifa_addr
611                               = &ifas[ifa_index].addr.sa;
612                             sa = &ifas[ifa_index].addr.sa;
613                           }
614
615                         sa->sa_family = ifam->ifa_family;
616
617                         switch (ifam->ifa_family)
618                           {
619                           case AF_INET:
620                             /* Size must match that of an address for IPv4.  */
621                             if (rta_payload == 4)
622                               memcpy (&((struct sockaddr_in *) sa)->sin_addr,
623                                       rta_data, rta_payload);
624                             break;
625
626 #ifdef __UCLIBC_HAS_IPV6__
627                           case AF_INET6:
628                             /* Size must match that of an address for IPv6.  */
629                             if (rta_payload == 16)
630                               {
631                                 memcpy (&((struct sockaddr_in6 *) sa)->sin6_addr,
632                                         rta_data, rta_payload);
633                                 if (IN6_IS_ADDR_LINKLOCAL (rta_data)
634                                     || IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
635                                   ((struct sockaddr_in6 *) sa)->sin6_scope_id
636                                     = ifam->ifa_index;
637                               }
638                             break;
639 #endif
640
641                           default:
642                             if (rta_payload <= sizeof (ifas[ifa_index].addr))
643                               memcpy (sa->sa_data, rta_data, rta_payload);
644                             break;
645                           }
646                       }
647                       break;
648
649                     case IFA_LOCAL:
650                       if (ifas[ifa_index].ifa.ifa_addr != NULL)
651                         {
652                           /* If ifa_addr is set and we get IFA_LOCAL,
653                              assume we have a point-to-point network.
654                              Move address to correct field.  */
655                           ifas[ifa_index].broadaddr = ifas[ifa_index].addr;
656                           ifas[ifa_index].ifa.ifa_broadaddr
657                             = &ifas[ifa_index].broadaddr.sa;
658                           memset (&ifas[ifa_index].addr, '\0',
659                                   sizeof (ifas[ifa_index].addr));
660                         }
661
662                       ifas[ifa_index].ifa.ifa_addr = &ifas[ifa_index].addr.sa;
663                       ifas[ifa_index].ifa.ifa_addr->sa_family
664                         = ifam->ifa_family;
665
666                       switch (ifam->ifa_family)
667                         {
668                         case AF_INET:
669                           /* Size must match that of an address for IPv4.  */
670                           if (rta_payload == 4)
671                             memcpy (&ifas[ifa_index].addr.s4.sin_addr,
672                                   rta_data, rta_payload);
673                           break;
674
675 #ifdef __UCLIBC_HAS_IPV6__
676                         case AF_INET6:
677                           /* Size must match that of an address for IPv6.  */
678                           if (rta_payload == 16)
679                             {
680                               memcpy (&ifas[ifa_index].addr.s6.sin6_addr,
681                                       rta_data, rta_payload);
682                               if (IN6_IS_ADDR_LINKLOCAL (rta_data)
683                                   || IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
684                                 ifas[ifa_index].addr.s6.sin6_scope_id =
685                                   ifam->ifa_index;
686                             }
687                           break;
688 #endif
689
690                         default:
691                           if (rta_payload <= sizeof (ifas[ifa_index].addr))
692                             memcpy (ifas[ifa_index].addr.sa.sa_data,
693                                     rta_data, rta_payload);
694                           break;
695                         }
696                       break;
697
698                     case IFA_BROADCAST:
699                       /* We get IFA_BROADCAST, so IFA_LOCAL was too much.  */
700                       if (ifas[ifa_index].ifa.ifa_broadaddr != NULL)
701                         memset (&ifas[ifa_index].broadaddr, '\0',
702                                 sizeof (ifas[ifa_index].broadaddr));
703
704                       ifas[ifa_index].ifa.ifa_broadaddr
705                         = &ifas[ifa_index].broadaddr.sa;
706                       ifas[ifa_index].ifa.ifa_broadaddr->sa_family
707                         = ifam->ifa_family;
708
709                       switch (ifam->ifa_family)
710                         {
711                         case AF_INET:
712                           /* Size must match that of an address for IPv4.  */
713                           if (rta_payload == 4)
714                             memcpy (&ifas[ifa_index].broadaddr.s4.sin_addr,
715                                     rta_data, rta_payload);
716                           break;
717
718 #ifdef __UCLIBC_HAS_IPV6__
719                         case AF_INET6:
720                           /* Size must match that of an address for IPv6.  */
721                           if (rta_payload == 16)
722                             {
723                               memcpy (&ifas[ifa_index].broadaddr.s6.sin6_addr,
724                                       rta_data, rta_payload);
725                               if (IN6_IS_ADDR_LINKLOCAL (rta_data)
726                                   || IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
727                                 ifas[ifa_index].broadaddr.s6.sin6_scope_id
728                                   = ifam->ifa_index;
729                             }
730                           break;
731 #endif
732
733                         default:
734                           if (rta_payload <= sizeof (ifas[ifa_index].addr))
735                             memcpy (&ifas[ifa_index].broadaddr.sa.sa_data,
736                                     rta_data, rta_payload);
737                           break;
738                         }
739                       break;
740
741                     case IFA_LABEL:
742                       if (rta_payload + 1 <= sizeof (ifas[ifa_index].name))
743                         {
744                           ifas[ifa_index].ifa.ifa_name = ifas[ifa_index].name;
745                           *(char *) mempcpy (ifas[ifa_index].name, rta_data,
746                                                rta_payload) = '\0';
747                         }
748                       else
749                         abort ();
750                       break;
751
752                     case IFA_UNSPEC:
753                       break;
754                     case IFA_CACHEINFO:
755                       break;
756                     default:
757                       break;
758                     }
759
760                   rta = RTA_NEXT (rta, rtasize);
761                 }
762
763               /* If we didn't get the interface name with the
764                  address, use the name from the interface entry.  */
765               if (ifas[ifa_index].ifa.ifa_name == NULL)
766                 ifas[ifa_index].ifa.ifa_name
767                   = ifas[map_newlink (ifam->ifa_index - 1, ifas,
768                                       map_newlink_data, newlink)].ifa.ifa_name;
769
770               /* Calculate the netmask.  */
771               if (ifas[ifa_index].ifa.ifa_addr
772                   && ifas[ifa_index].ifa.ifa_addr->sa_family != AF_UNSPEC
773                   && ifas[ifa_index].ifa.ifa_addr->sa_family != AF_PACKET)
774                 {
775                   uint32_t max_prefixlen = 0;
776                   char *cp = NULL;
777
778                   ifas[ifa_index].ifa.ifa_netmask
779                     = &ifas[ifa_index].netmask.sa;
780
781                   switch (ifas[ifa_index].ifa.ifa_addr->sa_family)
782                     {
783                     case AF_INET:
784                       cp = (char *) &ifas[ifa_index].netmask.s4.sin_addr;
785                       max_prefixlen = 32;
786                       break;
787
788 #ifdef __UCLIBC_HAS_IPV6__
789                     case AF_INET6:
790                       cp = (char *) &ifas[ifa_index].netmask.s6.sin6_addr;
791                       max_prefixlen = 128;
792                       break;
793 #endif
794                     }
795
796                   ifas[ifa_index].ifa.ifa_netmask->sa_family
797                     = ifas[ifa_index].ifa.ifa_addr->sa_family;
798
799                   if (cp != NULL)
800                     {
801                       char c;
802                       unsigned int preflen;
803
804                       if ((max_prefixlen > 0) &&
805                           (ifam->ifa_prefixlen > max_prefixlen))
806                         preflen = max_prefixlen;
807                       else
808                         preflen = ifam->ifa_prefixlen;
809
810                       for (i = 0; i < (preflen / 8); i++)
811                         *cp++ = 0xff;
812                       c = 0xff;
813                       c <<= (8 - (preflen % 8));
814                       *cp = c;
815                     }
816                 }
817             }
818         }
819     }
820
821   assert (ifa_data_ptr <= (char *) &ifas[newlink + newaddr] + ifa_data_size);
822
823   if (newaddr_idx > 0)
824     {
825       for (i = 0; i < newlink; ++i)
826         if (map_newlink_data[i] == -1)
827           {
828             /* We have fewer links then we anticipated.  Adjust the
829                forward pointer to the first address entry.  */
830             ifas[i - 1].ifa.ifa_next = &ifas[newlink].ifa;
831           }
832
833       if (i == 0 && newlink > 0)
834         /* No valid link, but we allocated memory.  We have to
835            populate the first entry.  */
836         memmove (ifas, &ifas[newlink], sizeof (struct ifaddrs_storage));
837     }
838
839   if (ifap != NULL)
840     *ifap = &ifas[0].ifa;
841
842  exit_free:
843   __netlink_free_handle (&nh);
844   __netlink_close (&nh);
845
846   return result;
847 }
848 libc_hidden_def(getifaddrs)
849
850 void
851 freeifaddrs (struct ifaddrs *ifa)
852 {
853   free (ifa);
854 }
855 libc_hidden_def(freeifaddrs)
856
857 #endif /* __UCLIBC_SUPPORT_AI_ADDRCONFIG__ */
858
859 #endif /* __ASSUME_NETLINK_SUPPORT */