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