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