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