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