]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/unix/sysv/linux/ifaddrs.c
Update.
[thirdparty/glibc.git] / sysdeps / unix / sysv / linux / ifaddrs.c
1 /* getifaddrs -- get names and addresses of all network interfaces
2 Copyright (C) 2003, 2004 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 "netlinkaccess.h"
36
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
41 int __no_netlink_support attribute_hidden;
42
43 # define getifaddrs fallback_getifaddrs
44 # include "sysdeps/gnu/ifaddrs.c"
45 # undef getifaddrs
46 #endif
47
48
49 /* struct to hold the data for one ifaddrs entry, so we can allocate
50 everything at once. */
51 struct 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
67 void
68 __netlink_free_handle (struct netlink_handle *h)
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
78 tmpptr = ptr->next;
79 free (ptr);
80 ptr = tmpptr;
81 }
82
83 __set_errno (saved_errno);
84 }
85
86
87 int
88 __netlink_sendreq (struct netlink_handle *h, int type)
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
110 return TEMP_FAILURE_RETRY (__sendto (h->fd, (void *) &req, sizeof (req), 0,
111 (struct sockaddr *) &nladdr,
112 sizeof (nladdr)));
113 }
114
115
116 int
117 __netlink_receive (struct netlink_handle *h)
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
137 read_len = TEMP_FAILURE_RETRY (__recvmsg (h->fd, &msg, 0));
138 if (read_len < 0)
139 return -1;
140
141 if (msg.msg_flags & MSG_TRUNC)
142 return -1;
143
144 nlm_next = (struct netlink_res *) malloc (sizeof (struct netlink_res)
145 + read_len);
146 if (nlm_next == NULL)
147 return -1;
148 nlm_next->next = NULL;
149 nlm_next->nlh = memcpy (nlm_next + 1, buf, read_len);
150 nlm_next->size = read_len;
151 nlm_next->seq = h->seq;
152 if (h->nlm_list == NULL)
153 h->nlm_list = nlm_next;
154 else
155 h->end_ptr->next = nlm_next;
156 h->end_ptr = nlm_next;
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 {
162 if (nladdr.nl_pid != 0 || (pid_t) nlmh->nlmsg_pid != h->pid
163 || nlmh->nlmsg_seq != h->seq)
164 continue;
165
166 if (nlmh->nlmsg_type == NLMSG_DONE)
167 {
168 /* We found the end, leave the loop. */
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
187 void
188 __netlink_close (struct netlink_handle *h)
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. */
197 int
198 __netlink_open (struct netlink_handle *h)
199 {
200 struct sockaddr_nl nladdr;
201
202 h->fd = __socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
203 if (h->fd < 0)
204 goto out;
205
206 memset (&nladdr, '\0', sizeof (nladdr));
207 nladdr.nl_family = AF_NETLINK;
208 if (__bind (h->fd, (struct sockaddr *) &nladdr, sizeof (nladdr)) < 0)
209 {
210 close_and_out:
211 __netlink_close (h);
212 out:
213 #if __ASSUME_NETLINK_SUPPORT == 0
214 __no_netlink_support = 1;
215 #endif
216 return -1;
217 }
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;
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. */
235 static int
236 internal_function
237 map_newlink (int index, struct ifaddrs_storage *ifas, int *map, int max)
238 {
239 int i;
240
241 for (i = 0; i < max; i++)
242 {
243 if (map[i] == -1)
244 {
245 map[i] = index;
246 if (i > 0)
247 ifas[i - 1].ifa.ifa_next = &ifas[i].ifa;
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
254 a very big problem. */
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'. */
262 int
263 getifaddrs (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. */
273 int result = 0;
274
275 if (ifap)
276 *ifap = NULL;
277
278 if (! __no_netlink_support && __netlink_open (&nh) < 0)
279 {
280 #if __ASSUME_NETLINK_SUPPORT != 0
281 return -1;
282 #endif
283 }
284
285 #if __ASSUME_NETLINK_SUPPORT == 0
286 if (__no_netlink_support)
287 return fallback_getifaddrs (ifap);
288 #endif
289
290 /* Tell the kernel that we wish to get a list of all
291 active interfaces. */
292 if (__netlink_sendreq (&nh, RTM_GETLINK) < 0)
293 {
294 result = -1;
295 goto exit_close;
296 }
297 /* Collect all data for every interface. */
298 if (__netlink_receive (&nh) < 0)
299 {
300 result = -1;
301 goto exit_free;
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;
310 if (__netlink_sendreq (&nh, RTM_GETADDR) < 0
311 /* Collect all data for every interface. */
312 || __netlink_receive (&nh) < 0)
313 {
314 result = -1;
315 goto exit_free;
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 {
333 /* Check if the message is what we want. */
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)
370 goto exit_free;
371
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 {
380 result = -1;
381 goto exit_free;
382 }
383
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
388 ifa_data_ptr = (char *) &ifas[newlink + newaddr];
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
408 /* Check if the message is the one we want */
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 */
414
415 if (nlh->nlmsg_type == RTM_NEWLINK)
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
423 /* Interfaces are stored in the first "newlink" entries
424 of our list, starting in the order as we got from the
425 kernel. */
426 ifa_index = map_newlink (ifim->ifi_index - 1, ifas,
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:
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 }
451 break;
452
453 case IFLA_BROADCAST:
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;
464
465 ifas[ifa_index].ifa.ifa_broadaddr
466 = &ifas[ifa_index].broadaddr.sa;
467 }
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;
474 *(char *) __mempcpy (ifas[ifa_index].name, rta_data,
475 rta_payload) = '\0';
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
508 the kernel after the interfaces. Theoretically it is possible
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
513 = ifas[map_newlink (ifam->ifa_index - 1, ifas,
514 map_newlink_data, newlink)].ifa.ifa_flags;
515 if (ifa_index > 0)
516 ifas[ifa_index - 1].ifa.ifa_next = &ifas[ifa_index].ifa;
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:
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);
558 break;
559
560 case AF_INET6:
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 }
571 break;
572
573 default:
574 if (rta_payload <= sizeof (ifas[ifa_index].addr))
575 memcpy (sa->sa_data, rta_data, rta_payload);
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:
601 /* Size must match that of an address for IPv4. */
602 if (rta_payload == 4)
603 memcpy (&ifas[ifa_index].addr.s4.sin_addr,
604 rta_data, rta_payload);
605 break;
606
607 case AF_INET6:
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 }
618 break;
619
620 default:
621 if (rta_payload <= sizeof (ifas[ifa_index].addr))
622 memcpy (ifas[ifa_index].addr.sa.sa_data,
623 rta_data, rta_payload);
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:
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);
646 break;
647
648 case AF_INET6:
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 }
659 break;
660
661 default:
662 if (rta_payload <= sizeof (ifas[ifa_index].addr))
663 memcpy (&ifas[ifa_index].broadaddr.sa.sa_data,
664 rta_data, rta_payload);
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;
673 *(char *) __mempcpy (ifas[ifa_index].name, rta_data,
674 rta_payload) = '\0';
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
695 = ifas[map_newlink (ifam->ifa_index - 1, ifas,
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
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
765 if (ifap != NULL)
766 *ifap = &ifas[0].ifa;
767
768 exit_free:
769 __netlink_free_handle (&nh);
770
771 exit_close:
772 __netlink_close (&nh);
773
774 return result;
775 }
776 libc_hidden_def (getifaddrs)
777
778
779 #if __ASSUME_NETLINK_SUPPORT != 0
780 void
781 freeifaddrs (struct ifaddrs *ifa)
782 {
783 free (ifa);
784 }
785 libc_hidden_def (freeifaddrs)
786 #endif