blob: 535f6277fff97910b26dc10b1e723dc40e52857c [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* 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. */
52struct 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
71void
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
88static 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
117int
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
265out_fail:
266 if (use_malloc)
267 free (buf);
268 return -1;
269}
270
271
272void
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. */
283int
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. */
319static int
320internal_function
321map_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'. */
346int
347getifaddrs (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}
848libc_hidden_def(getifaddrs)
849
850void
851freeifaddrs (struct ifaddrs *ifa)
852{
853 free (ifa);
854}
855libc_hidden_def(freeifaddrs)
856
857#endif /* __UCLIBC_SUPPORT_AI_ADDRCONFIG__ */
858
859#endif /* __ASSUME_NETLINK_SUPPORT */