Add extra `-shared` to link.so command.
[uclibc-ng.git] / libc / inet / ifaddrs.c
blob72771d35a86b65c94808400fe03a3eeb66fe25f1
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.
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.
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.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
19 #include <alloca.h>
20 #include <assert.h>
21 #include <errno.h>
22 #include <ifaddrs.h>
23 #include <net/if.h>
24 #include <netinet/in.h>
25 #include <netpacket/packet.h>
26 #include <stdbool.h>
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
33 #include <time.h>
34 #include <unistd.h>
36 #include "netlinkaccess.h"
39 #ifndef __libc_use_alloca
40 # define __libc_use_alloca(x) (x < __MAX_ALLOCA_CUTOFF)
41 #endif
44 #if __ASSUME_NETLINK_SUPPORT
45 #ifdef __UCLIBC_SUPPORT_AI_ADDRCONFIG__
46 /* struct to hold the data for one ifaddrs entry, so we can allocate
47 everything at once. */
48 struct ifaddrs_storage
50 struct ifaddrs ifa;
51 union
53 /* Save space for the biggest of the four used sockaddr types and
54 avoid a lot of casts. */
55 struct sockaddr sa;
56 struct sockaddr_ll sl;
57 struct sockaddr_in s4;
58 #ifdef __UCLIBC_HAS_IPV6__
59 struct sockaddr_in6 s6;
60 #endif
61 } addr, netmask, broadaddr;
62 char name[IF_NAMESIZE + 1];
64 #endif /* __UCLIBC_SUPPORT_AI_ADDRCONFIG__ */
67 void
68 __netlink_free_handle (struct netlink_handle *h)
70 struct netlink_res *ptr;
72 ptr = h->nlm_list;
73 while (ptr != NULL)
75 struct netlink_res *tmpptr;
77 tmpptr = ptr->next;
78 free (ptr); /* doesn't affect errno */
79 ptr = tmpptr;
84 static int
85 __netlink_sendreq (struct netlink_handle *h, int type)
87 struct
89 struct nlmsghdr nlh;
90 struct rtgenmsg g;
91 } req;
92 struct sockaddr_nl nladdr;
94 if (h->seq == 0)
95 h->seq = time (NULL);
97 req.nlh.nlmsg_len = sizeof (req);
98 req.nlh.nlmsg_type = type;
99 req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
100 req.nlh.nlmsg_pid = 0;
101 req.nlh.nlmsg_seq = h->seq;
102 req.g.rtgen_family = AF_UNSPEC;
104 memset (&nladdr, '\0', sizeof (nladdr));
105 nladdr.nl_family = AF_NETLINK;
107 return TEMP_FAILURE_RETRY (sendto (h->fd, (void *) &req, sizeof (req), 0,
108 (struct sockaddr *) &nladdr,
109 sizeof (nladdr)));
114 __netlink_request (struct netlink_handle *h, int type)
116 struct netlink_res *nlm_next;
117 struct netlink_res **new_nlm_list;
118 static volatile size_t buf_size = 0;
119 size_t this_buf_size;
120 char *buf;
121 struct sockaddr_nl nladdr;
122 struct nlmsghdr *nlmh;
123 ssize_t read_len;
124 bool done = false;
125 bool use_malloc = false;
127 if (__netlink_sendreq (h, type) < 0)
128 return -1;
130 if (buf_size)
131 this_buf_size = buf_size;
132 else {
133 #ifdef PAGE_SIZE
134 this_buf_size = PAGE_SIZE;
135 #else
136 this_buf_size = __pagesize;
137 #endif
139 if (__libc_use_alloca (this_buf_size))
140 buf = alloca (this_buf_size);
141 else
143 buf = malloc (this_buf_size);
144 if (buf != NULL)
145 use_malloc = true;
146 else
147 goto out_fail;
150 struct iovec iov = { buf, this_buf_size };
152 if (h->nlm_list != NULL)
153 new_nlm_list = &h->end_ptr->next;
154 else
155 new_nlm_list = &h->nlm_list;
157 while (! done)
159 struct msghdr msg =
161 (void *) &nladdr, sizeof (nladdr),
162 &iov, 1,
163 NULL, 0,
167 read_len = TEMP_FAILURE_RETRY (recvmsg (h->fd, &msg, 0));
168 if (read_len < 0)
169 goto out_fail;
171 if (nladdr.nl_pid != 0)
172 continue;
174 if (__builtin_expect (msg.msg_flags & MSG_TRUNC, 0))
176 if (this_buf_size >= SIZE_MAX / 2)
177 goto out_fail;
179 nlm_next = *new_nlm_list;
180 while (nlm_next != NULL)
182 struct netlink_res *tmpptr;
184 tmpptr = nlm_next->next;
185 free (nlm_next);
186 nlm_next = tmpptr;
188 *new_nlm_list = NULL;
190 if (__libc_use_alloca (2 * this_buf_size))
191 buf = extend_alloca (buf, this_buf_size, 2 * this_buf_size);
192 else
194 this_buf_size *= 2;
196 char *new_buf = realloc (use_malloc ? buf : NULL, this_buf_size);
197 if (new_buf == NULL)
198 goto out_fail;
199 new_buf = buf;
201 use_malloc = true;
203 buf_size = this_buf_size;
205 iov.iov_base = buf;
206 iov.iov_len = this_buf_size;
208 /* Increase sequence number, so that we can distinguish
209 between old and new request messages. */
210 h->seq++;
212 if (__netlink_sendreq (h, type) < 0)
213 goto out_fail;
215 continue;
218 size_t count = 0;
219 size_t remaining_len = read_len;
220 for (nlmh = (struct nlmsghdr *) buf;
221 NLMSG_OK (nlmh, remaining_len);
222 nlmh = (struct nlmsghdr *) NLMSG_NEXT (nlmh, remaining_len))
224 if ((pid_t) nlmh->nlmsg_pid != h->pid
225 || nlmh->nlmsg_seq != h->seq)
226 continue;
228 ++count;
229 if (nlmh->nlmsg_type == NLMSG_DONE)
231 /* We found the end, leave the loop. */
232 done = true;
233 break;
235 if (nlmh->nlmsg_type == NLMSG_ERROR)
237 struct nlmsgerr *nlerr = (struct nlmsgerr *) NLMSG_DATA (nlmh);
238 if (nlmh->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
239 errno = EIO;
240 else
241 errno = -nlerr->error;
242 goto out_fail;
246 /* If there was nothing with the expected nlmsg_pid and nlmsg_seq,
247 there is no point to record it. */
248 if (count == 0)
249 continue;
251 nlm_next = (struct netlink_res *) malloc (sizeof (struct netlink_res)
252 + read_len);
253 if (nlm_next == NULL)
254 goto out_fail;
255 nlm_next->next = NULL;
256 nlm_next->nlh = memcpy (nlm_next + 1, buf, read_len);
257 nlm_next->size = read_len;
258 nlm_next->seq = h->seq;
259 if (h->nlm_list == NULL)
260 h->nlm_list = nlm_next;
261 else
262 h->end_ptr->next = nlm_next;
263 h->end_ptr = nlm_next;
266 if (use_malloc)
267 free (buf);
268 return 0;
270 out_fail:
271 if (use_malloc)
272 free (buf);
273 return -1;
277 void
278 __netlink_close (struct netlink_handle *h)
280 /* Don't modify errno. */
281 int serrno = errno;
282 close(h->fd);
283 __set_errno(serrno);
287 /* Open a NETLINK socket. */
289 __netlink_open (struct netlink_handle *h)
291 struct sockaddr_nl nladdr;
293 h->fd = socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
294 if (h->fd < 0)
295 goto out;
297 memset (&nladdr, '\0', sizeof (nladdr));
298 nladdr.nl_family = AF_NETLINK;
299 if (bind (h->fd, (struct sockaddr *) &nladdr, sizeof (nladdr)) < 0)
301 close_and_out:
302 __netlink_close (h);
303 out:
304 return -1;
306 /* Determine the ID the kernel assigned for this netlink connection.
307 It is not necessarily the PID if there is more than one socket
308 open. */
309 socklen_t addr_len = sizeof (nladdr);
310 if (getsockname (h->fd, (struct sockaddr *) &nladdr, &addr_len) < 0)
311 goto close_and_out;
312 h->pid = nladdr.nl_pid;
313 return 0;
317 #ifdef __UCLIBC_SUPPORT_AI_ADDRCONFIG__
318 /* We know the number of RTM_NEWLINK entries, so we reserve the first
319 # of entries for this type. All RTM_NEWADDR entries have an index
320 pointer to the RTM_NEWLINK entry. To find the entry, create
321 a table to map kernel index entries to our index numbers.
322 Since we get at first all RTM_NEWLINK entries, it can never happen
323 that a RTM_NEWADDR index is not known to this map. */
324 static int
325 internal_function
326 map_newlink (int idx, struct ifaddrs_storage *ifas, int *map, int max)
328 int i;
330 for (i = 0; i < max; i++)
332 if (map[i] == -1)
334 map[i] = idx;
335 if (i > 0)
336 ifas[i - 1].ifa.ifa_next = &ifas[i].ifa;
337 return i;
339 else if (map[i] == idx)
340 return i;
343 /* This means interfaces changed inbetween the reading of the
344 RTM_GETLINK and RTM_GETADDR information. We have to repeat
345 everything. */
346 return -1;
350 /* Create a linked list of `struct ifaddrs' structures, one for each
351 network interface on the host machine. If successful, store the
352 list in *IFAP and return 0. On errors, return -1 and set `errno'. */
353 static int
354 getifaddrs_internal (struct ifaddrs **ifap)
356 struct netlink_handle nh = { 0, 0, 0, NULL, NULL };
357 struct netlink_res *nlp;
358 struct ifaddrs_storage *ifas;
359 unsigned int i, newlink, newaddr, newaddr_idx;
360 int *map_newlink_data;
361 size_t ifa_data_size = 0; /* Size to allocate for all ifa_data. */
362 char *ifa_data_ptr; /* Pointer to the unused part of memory for
363 ifa_data. */
364 int result = 0;
366 if (ifap)
367 *ifap = NULL;
369 if (__netlink_open (&nh) < 0)
371 return -1;
374 /* Tell the kernel that we wish to get a list of all
375 active interfaces, collect all data for every interface. */
376 if (__netlink_request (&nh, RTM_GETLINK) < 0)
378 result = -1;
379 goto exit_free;
382 /* Now ask the kernel for all addresses which are assigned
383 to an interface and collect all data for every interface.
384 Since we store the addresses after the interfaces in the
385 list, we will later always find the interface before the
386 corresponding addresses. */
387 ++nh.seq;
388 if (__netlink_request (&nh, RTM_GETADDR) < 0)
390 result = -1;
391 goto exit_free;
394 /* Count all RTM_NEWLINK and RTM_NEWADDR entries to allocate
395 enough memory. */
396 newlink = newaddr = 0;
397 for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
399 struct nlmsghdr *nlh;
400 size_t size = nlp->size;
402 if (nlp->nlh == NULL)
403 continue;
405 /* Walk through all entries we got from the kernel and look, which
406 message type they contain. */
407 for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
409 /* Check if the message is what we want. */
410 if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
411 continue;
413 if (nlh->nlmsg_type == NLMSG_DONE)
414 break; /* ok */
416 if (nlh->nlmsg_type == RTM_NEWLINK)
418 /* A RTM_NEWLINK message can have IFLA_STATS data. We need to
419 know the size before creating the list to allocate enough
420 memory. */
421 struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
422 struct rtattr *rta = IFLA_RTA (ifim);
423 size_t rtasize = IFLA_PAYLOAD (nlh);
425 while (RTA_OK (rta, rtasize))
427 size_t rta_payload = RTA_PAYLOAD (rta);
429 if (rta->rta_type == IFLA_STATS)
431 ifa_data_size += rta_payload;
432 break;
434 else
435 rta = RTA_NEXT (rta, rtasize);
437 ++newlink;
439 else if (nlh->nlmsg_type == RTM_NEWADDR)
440 ++newaddr;
444 /* Return if no interface is up. */
445 if ((newlink + newaddr) == 0)
446 goto exit_free;
448 /* Allocate memory for all entries we have and initialize next
449 pointer. */
450 ifas = calloc (1, (newlink + newaddr) * sizeof (ifas[0]) + ifa_data_size);
451 if (ifas == NULL)
453 result = -1;
454 goto exit_free;
457 /* Table for mapping kernel index to entry in our list. */
458 map_newlink_data = alloca (newlink * sizeof (int));
459 memset (map_newlink_data, '\xff', newlink * sizeof (int));
461 ifa_data_ptr = (char *) &ifas[newlink + newaddr];
462 newaddr_idx = 0; /* Counter for newaddr index. */
464 /* Walk through the list of data we got from the kernel. */
465 for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
467 struct nlmsghdr *nlh;
468 size_t size = nlp->size;
470 if (nlp->nlh == NULL)
471 continue;
473 /* Walk through one message and look at the type: If it is our
474 message, we need RTM_NEWLINK/RTM_NEWADDR and stop if we reach
475 the end or we find the end marker (in this case we ignore the
476 following data. */
477 for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
479 int ifa_index = 0;
481 /* Check if the message is the one we want */
482 if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
483 continue;
485 if (nlh->nlmsg_type == NLMSG_DONE)
486 break; /* ok */
488 if (nlh->nlmsg_type == RTM_NEWLINK)
490 /* We found a new interface. Now extract everything from the
491 interface data we got and need. */
492 struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
493 struct rtattr *rta = IFLA_RTA (ifim);
494 size_t rtasize = IFLA_PAYLOAD (nlh);
496 /* Interfaces are stored in the first "newlink" entries
497 of our list, starting in the order as we got from the
498 kernel. */
499 ifa_index = map_newlink (ifim->ifi_index - 1, ifas,
500 map_newlink_data, newlink);
501 if (__builtin_expect (ifa_index == -1, 0))
503 try_again:
504 result = -EAGAIN;
505 free (ifas);
506 goto exit_free;
508 ifas[ifa_index].ifa.ifa_flags = ifim->ifi_flags;
510 while (RTA_OK (rta, rtasize))
512 char *rta_data = RTA_DATA (rta);
513 size_t rta_payload = RTA_PAYLOAD (rta);
515 switch (rta->rta_type)
517 case IFLA_ADDRESS:
518 if (rta_payload <= sizeof (ifas[ifa_index].addr))
520 ifas[ifa_index].addr.sl.sll_family = AF_PACKET;
521 memcpy (ifas[ifa_index].addr.sl.sll_addr,
522 (char *) rta_data, rta_payload);
523 ifas[ifa_index].addr.sl.sll_halen = rta_payload;
524 ifas[ifa_index].addr.sl.sll_ifindex
525 = ifim->ifi_index;
526 ifas[ifa_index].addr.sl.sll_hatype = ifim->ifi_type;
528 ifas[ifa_index].ifa.ifa_addr
529 = &ifas[ifa_index].addr.sa;
531 break;
533 case IFLA_BROADCAST:
534 if (rta_payload <= sizeof (ifas[ifa_index].broadaddr))
536 ifas[ifa_index].broadaddr.sl.sll_family = AF_PACKET;
537 memcpy (ifas[ifa_index].broadaddr.sl.sll_addr,
538 (char *) rta_data, rta_payload);
539 ifas[ifa_index].broadaddr.sl.sll_halen = rta_payload;
540 ifas[ifa_index].broadaddr.sl.sll_ifindex
541 = ifim->ifi_index;
542 ifas[ifa_index].broadaddr.sl.sll_hatype
543 = ifim->ifi_type;
545 ifas[ifa_index].ifa.ifa_broadaddr
546 = &ifas[ifa_index].broadaddr.sa;
548 break;
550 case IFLA_IFNAME: /* Name of Interface */
551 if ((rta_payload + 1) <= sizeof (ifas[ifa_index].name))
553 ifas[ifa_index].ifa.ifa_name = ifas[ifa_index].name;
554 *(char *) mempcpy (ifas[ifa_index].name, rta_data,
555 rta_payload) = '\0';
557 break;
559 case IFLA_STATS: /* Statistics of Interface */
560 ifas[ifa_index].ifa.ifa_data = ifa_data_ptr;
561 ifa_data_ptr += rta_payload;
562 memcpy (ifas[ifa_index].ifa.ifa_data, rta_data,
563 rta_payload);
564 break;
566 case IFLA_UNSPEC:
567 break;
568 case IFLA_MTU:
569 break;
570 case IFLA_LINK:
571 break;
572 case IFLA_QDISC:
573 break;
574 default:
575 break;
578 rta = RTA_NEXT (rta, rtasize);
581 else if (nlh->nlmsg_type == RTM_NEWADDR)
583 struct ifaddrmsg *ifam = (struct ifaddrmsg *) NLMSG_DATA (nlh);
584 struct rtattr *rta = IFA_RTA (ifam);
585 size_t rtasize = IFA_PAYLOAD (nlh);
587 /* New Addresses are stored in the order we got them from
588 the kernel after the interfaces. Theoretically it is possible
589 that we have holes in the interface part of the list,
590 but we always have already the interface for this address. */
591 ifa_index = newlink + newaddr_idx;
592 int idx = map_newlink (ifam->ifa_index - 1, ifas,
593 map_newlink_data, newlink);
594 if (__builtin_expect (idx == -1, 0))
595 goto try_again;
596 ifas[ifa_index].ifa.ifa_flags = ifas[idx].ifa.ifa_flags;
597 if (ifa_index > 0)
598 ifas[ifa_index - 1].ifa.ifa_next = &ifas[ifa_index].ifa;
599 ++newaddr_idx;
601 while (RTA_OK (rta, rtasize))
603 char *rta_data = RTA_DATA (rta);
604 size_t rta_payload = RTA_PAYLOAD (rta);
606 switch (rta->rta_type)
608 case IFA_ADDRESS:
610 struct sockaddr *sa;
612 if (ifas[ifa_index].ifa.ifa_addr != NULL)
614 /* In a point-to-poing network IFA_ADDRESS
615 contains the destination address, local
616 address is supplied in IFA_LOCAL attribute.
617 destination address and broadcast address
618 are stored in an union, so it doesn't matter
619 which name we use. */
620 ifas[ifa_index].ifa.ifa_broadaddr
621 = &ifas[ifa_index].broadaddr.sa;
622 sa = &ifas[ifa_index].broadaddr.sa;
624 else
626 ifas[ifa_index].ifa.ifa_addr
627 = &ifas[ifa_index].addr.sa;
628 sa = &ifas[ifa_index].addr.sa;
631 sa->sa_family = ifam->ifa_family;
633 switch (ifam->ifa_family)
635 case AF_INET:
636 /* Size must match that of an address for IPv4. */
637 if (rta_payload == 4)
638 memcpy (&((struct sockaddr_in *) sa)->sin_addr,
639 rta_data, rta_payload);
640 break;
642 #ifdef __UCLIBC_HAS_IPV6__
643 case AF_INET6:
644 /* Size must match that of an address for IPv6. */
645 if (rta_payload == 16)
647 memcpy (&((struct sockaddr_in6 *) sa)->sin6_addr,
648 rta_data, rta_payload);
649 if (IN6_IS_ADDR_LINKLOCAL (rta_data)
650 || IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
651 ((struct sockaddr_in6 *) sa)->sin6_scope_id
652 = ifam->ifa_index;
654 break;
655 #endif
657 default:
658 if (rta_payload <= sizeof (ifas[ifa_index].addr))
659 memcpy (sa->sa_data, rta_data, rta_payload);
660 break;
663 break;
665 case IFA_LOCAL:
666 if (ifas[ifa_index].ifa.ifa_addr != NULL)
668 /* If ifa_addr is set and we get IFA_LOCAL,
669 assume we have a point-to-point network.
670 Move address to correct field. */
671 ifas[ifa_index].broadaddr = ifas[ifa_index].addr;
672 ifas[ifa_index].ifa.ifa_broadaddr
673 = &ifas[ifa_index].broadaddr.sa;
674 memset (&ifas[ifa_index].addr, '\0',
675 sizeof (ifas[ifa_index].addr));
678 ifas[ifa_index].ifa.ifa_addr = &ifas[ifa_index].addr.sa;
679 ifas[ifa_index].ifa.ifa_addr->sa_family
680 = ifam->ifa_family;
682 switch (ifam->ifa_family)
684 case AF_INET:
685 /* Size must match that of an address for IPv4. */
686 if (rta_payload == 4)
687 memcpy (&ifas[ifa_index].addr.s4.sin_addr,
688 rta_data, rta_payload);
689 break;
691 #ifdef __UCLIBC_HAS_IPV6__
692 case AF_INET6:
693 /* Size must match that of an address for IPv6. */
694 if (rta_payload == 16)
696 memcpy (&ifas[ifa_index].addr.s6.sin6_addr,
697 rta_data, rta_payload);
698 if (IN6_IS_ADDR_LINKLOCAL (rta_data)
699 || IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
700 ifas[ifa_index].addr.s6.sin6_scope_id =
701 ifam->ifa_index;
703 break;
704 #endif
706 default:
707 if (rta_payload <= sizeof (ifas[ifa_index].addr))
708 memcpy (ifas[ifa_index].addr.sa.sa_data,
709 rta_data, rta_payload);
710 break;
712 break;
714 case IFA_BROADCAST:
715 /* We get IFA_BROADCAST, so IFA_LOCAL was too much. */
716 if (ifas[ifa_index].ifa.ifa_broadaddr != NULL)
717 memset (&ifas[ifa_index].broadaddr, '\0',
718 sizeof (ifas[ifa_index].broadaddr));
720 ifas[ifa_index].ifa.ifa_broadaddr
721 = &ifas[ifa_index].broadaddr.sa;
722 ifas[ifa_index].ifa.ifa_broadaddr->sa_family
723 = ifam->ifa_family;
725 switch (ifam->ifa_family)
727 case AF_INET:
728 /* Size must match that of an address for IPv4. */
729 if (rta_payload == 4)
730 memcpy (&ifas[ifa_index].broadaddr.s4.sin_addr,
731 rta_data, rta_payload);
732 break;
734 #ifdef __UCLIBC_HAS_IPV6__
735 case AF_INET6:
736 /* Size must match that of an address for IPv6. */
737 if (rta_payload == 16)
739 memcpy (&ifas[ifa_index].broadaddr.s6.sin6_addr,
740 rta_data, rta_payload);
741 if (IN6_IS_ADDR_LINKLOCAL (rta_data)
742 || IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
743 ifas[ifa_index].broadaddr.s6.sin6_scope_id
744 = ifam->ifa_index;
746 break;
747 #endif
749 default:
750 if (rta_payload <= sizeof (ifas[ifa_index].addr))
751 memcpy (&ifas[ifa_index].broadaddr.sa.sa_data,
752 rta_data, rta_payload);
753 break;
755 break;
757 case IFA_LABEL:
758 if (rta_payload + 1 <= sizeof (ifas[ifa_index].name))
760 ifas[ifa_index].ifa.ifa_name = ifas[ifa_index].name;
761 *(char *) mempcpy (ifas[ifa_index].name, rta_data,
762 rta_payload) = '\0';
764 else
765 abort ();
766 break;
768 case IFA_UNSPEC:
769 break;
770 case IFA_CACHEINFO:
771 break;
772 default:
773 break;
776 rta = RTA_NEXT (rta, rtasize);
779 /* If we didn't get the interface name with the
780 address, use the name from the interface entry. */
781 if (ifas[ifa_index].ifa.ifa_name == NULL)
783 int idx = map_newlink (ifam->ifa_index - 1, ifas,
784 map_newlink_data, newlink);
785 if (__builtin_expect (idx == -1, 0))
786 goto try_again;
787 ifas[ifa_index].ifa.ifa_name = ifas[idx].ifa.ifa_name;
790 /* Calculate the netmask. */
791 if (ifas[ifa_index].ifa.ifa_addr
792 && ifas[ifa_index].ifa.ifa_addr->sa_family != AF_UNSPEC
793 && ifas[ifa_index].ifa.ifa_addr->sa_family != AF_PACKET)
795 uint32_t max_prefixlen = 0;
796 char *cp = NULL;
798 ifas[ifa_index].ifa.ifa_netmask
799 = &ifas[ifa_index].netmask.sa;
801 switch (ifas[ifa_index].ifa.ifa_addr->sa_family)
803 case AF_INET:
804 cp = (char *) &ifas[ifa_index].netmask.s4.sin_addr;
805 max_prefixlen = 32;
806 break;
808 #ifdef __UCLIBC_HAS_IPV6__
809 case AF_INET6:
810 cp = (char *) &ifas[ifa_index].netmask.s6.sin6_addr;
811 max_prefixlen = 128;
812 break;
813 #endif
816 ifas[ifa_index].ifa.ifa_netmask->sa_family
817 = ifas[ifa_index].ifa.ifa_addr->sa_family;
819 if (cp != NULL)
821 char c;
822 unsigned int preflen;
824 if ((max_prefixlen > 0) &&
825 (ifam->ifa_prefixlen > max_prefixlen))
826 preflen = max_prefixlen;
827 else
828 preflen = ifam->ifa_prefixlen;
830 for (i = 0; i < (preflen / 8); i++)
831 *cp++ = 0xff;
832 c = 0xff;
833 c <<= (8 - (preflen % 8));
834 *cp = c;
841 assert (ifa_data_ptr <= (char *) &ifas[newlink + newaddr] + ifa_data_size);
843 if (newaddr_idx > 0)
845 for (i = 0; i < newlink; ++i)
846 if (map_newlink_data[i] == -1)
848 /* We have fewer links then we anticipated. Adjust the
849 forward pointer to the first address entry. */
850 ifas[i - 1].ifa.ifa_next = &ifas[newlink].ifa;
853 if (i == 0 && newlink > 0)
854 /* No valid link, but we allocated memory. We have to
855 populate the first entry. */
856 memmove (ifas, &ifas[newlink], sizeof (struct ifaddrs_storage));
859 if (ifap != NULL)
860 *ifap = &ifas[0].ifa;
862 exit_free:
863 __netlink_free_handle (&nh);
864 __netlink_close (&nh);
866 return result;
870 /* Create a linked list of `struct ifaddrs' structures, one for each
871 network interface on the host machine. If successful, store the
872 list in *IFAP and return 0. On errors, return -1 and set `errno'. */
874 getifaddrs (struct ifaddrs **ifap)
876 int res;
879 res = getifaddrs_internal (ifap);
880 while (res == -EAGAIN);
882 return res;
884 libc_hidden_def(getifaddrs)
886 void
887 freeifaddrs (struct ifaddrs *ifa)
889 free (ifa);
891 libc_hidden_def(freeifaddrs)
893 #endif /* __UCLIBC_SUPPORT_AI_ADDRCONFIG__ */
895 #endif /* __ASSUME_NETLINK_SUPPORT */