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