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