1 /* getifaddrs -- get names and addresses of all network interfaces
2 Copyright (C) 2003-2008, 2009, 2010, 2011 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
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.
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.
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/>. */
24 #include <netinet/in.h>
25 #include <netpacket/packet.h>
30 #include <sys/ioctl.h>
31 #include <sys/socket.h>
35 #include <kernel-features.h>
37 #include "netlinkaccess.h"
40 /* We don't know if we have NETLINK support compiled into our
41 Kernel, so include the old implementation as fallback. */
42 #if __ASSUME_NETLINK_SUPPORT == 0
43 int __no_netlink_support attribute_hidden
;
45 # define getifaddrs fallback_getifaddrs
46 # include "sysdeps/gnu/ifaddrs.c"
51 /* There is a problem with this type. The address length for
52 Infiniband sockets is much longer than the 8 bytes allocated in the
53 sockaddr_ll definition. Hence we use here a special
55 struct sockaddr_ll_max
57 unsigned short int sll_family
;
58 unsigned short int sll_protocol
;
60 unsigned short int sll_hatype
;
61 unsigned char sll_pkttype
;
62 unsigned char sll_halen
;
63 unsigned char sll_addr
[24];
67 /* struct to hold the data for one ifaddrs entry, so we can allocate
68 everything at once. */
69 struct ifaddrs_storage
74 /* Save space for the biggest of the four used sockaddr types and
75 avoid a lot of casts. */
77 struct sockaddr_ll_max sl
;
78 struct sockaddr_in s4
;
79 struct sockaddr_in6 s6
;
80 } addr
, netmask
, broadaddr
;
81 char name
[IF_NAMESIZE
+ 1];
86 __netlink_free_handle (struct netlink_handle
*h
)
88 struct netlink_res
*ptr
;
89 int saved_errno
= errno
;
94 struct netlink_res
*tmpptr
;
101 __set_errno (saved_errno
);
106 __netlink_sendreq (struct netlink_handle
*h
, int type
)
114 struct sockaddr_nl nladdr
;
117 h
->seq
= time (NULL
);
119 req
.nlh
.nlmsg_len
= sizeof (req
);
120 req
.nlh
.nlmsg_type
= type
;
121 req
.nlh
.nlmsg_flags
= NLM_F_ROOT
| NLM_F_MATCH
| NLM_F_REQUEST
;
122 req
.nlh
.nlmsg_pid
= 0;
123 req
.nlh
.nlmsg_seq
= h
->seq
;
124 req
.g
.rtgen_family
= AF_UNSPEC
;
125 if (sizeof (req
) != offsetof (struct req
, pad
))
126 memset (req
.pad
, '\0', sizeof (req
) - offsetof (struct req
, pad
));
128 memset (&nladdr
, '\0', sizeof (nladdr
));
129 nladdr
.nl_family
= AF_NETLINK
;
131 return TEMP_FAILURE_RETRY (__sendto (h
->fd
, (void *) &req
, sizeof (req
), 0,
132 (struct sockaddr
*) &nladdr
,
138 __netlink_request (struct netlink_handle
*h
, int type
)
140 struct netlink_res
*nlm_next
;
141 struct sockaddr_nl nladdr
;
142 struct nlmsghdr
*nlmh
;
147 /* Help the compiler optimize out the malloc call if PAGE_SIZE
148 is constant and smaller or equal to PTHREAD_STACK_MIN/4. */
149 const size_t buf_size
= PAGE_SIZE
;
151 const size_t buf_size
= __getpagesize ();
153 bool use_malloc
= false;
156 if (__libc_use_alloca (buf_size
))
157 buf
= alloca (buf_size
);
160 buf
= malloc (buf_size
);
167 struct iovec iov
= { buf
, buf_size
};
169 if (__netlink_sendreq (h
, type
) < 0)
176 (void *) &nladdr
, sizeof (nladdr
),
182 read_len
= TEMP_FAILURE_RETRY (__recvmsg (h
->fd
, &msg
, 0));
186 if (nladdr
.nl_pid
!= 0)
189 if (__builtin_expect (msg
.msg_flags
& MSG_TRUNC
, 0))
193 size_t remaining_len
= read_len
;
194 for (nlmh
= (struct nlmsghdr
*) buf
;
195 NLMSG_OK (nlmh
, remaining_len
);
196 nlmh
= (struct nlmsghdr
*) NLMSG_NEXT (nlmh
, remaining_len
))
198 if ((pid_t
) nlmh
->nlmsg_pid
!= h
->pid
199 || nlmh
->nlmsg_seq
!= h
->seq
)
203 if (nlmh
->nlmsg_type
== NLMSG_DONE
)
205 /* We found the end, leave the loop. */
209 if (nlmh
->nlmsg_type
== NLMSG_ERROR
)
211 struct nlmsgerr
*nlerr
= (struct nlmsgerr
*) NLMSG_DATA (nlmh
);
212 if (nlmh
->nlmsg_len
< NLMSG_LENGTH (sizeof (struct nlmsgerr
)))
215 errno
= -nlerr
->error
;
220 /* If there was nothing with the expected nlmsg_pid and nlmsg_seq,
221 there is no point to record it. */
225 nlm_next
= (struct netlink_res
*) malloc (sizeof (struct netlink_res
)
227 if (nlm_next
== NULL
)
229 nlm_next
->next
= NULL
;
230 nlm_next
->nlh
= memcpy (nlm_next
+ 1, buf
, read_len
);
231 nlm_next
->size
= read_len
;
232 nlm_next
->seq
= h
->seq
;
233 if (h
->nlm_list
== NULL
)
234 h
->nlm_list
= nlm_next
;
236 h
->end_ptr
->next
= nlm_next
;
237 h
->end_ptr
= nlm_next
;
252 __netlink_close (struct netlink_handle
*h
)
254 /* Don't modify errno. */
255 INTERNAL_SYSCALL_DECL (err
);
256 (void) INTERNAL_SYSCALL (close
, err
, 1, h
->fd
);
260 /* Open a NETLINK socket. */
262 __netlink_open (struct netlink_handle
*h
)
264 struct sockaddr_nl nladdr
;
266 h
->fd
= __socket (PF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
270 memset (&nladdr
, '\0', sizeof (nladdr
));
271 nladdr
.nl_family
= AF_NETLINK
;
272 if (__bind (h
->fd
, (struct sockaddr
*) &nladdr
, sizeof (nladdr
)) < 0)
277 #if __ASSUME_NETLINK_SUPPORT == 0
278 __no_netlink_support
= 1;
282 /* Determine the ID the kernel assigned for this netlink connection.
283 It is not necessarily the PID if there is more than one socket
285 socklen_t addr_len
= sizeof (nladdr
);
286 if (__getsockname (h
->fd
, (struct sockaddr
*) &nladdr
, &addr_len
) < 0)
288 h
->pid
= nladdr
.nl_pid
;
293 /* We know the number of RTM_NEWLINK entries, so we reserve the first
294 # of entries for this type. All RTM_NEWADDR entries have an index
295 pointer to the RTM_NEWLINK entry. To find the entry, create
296 a table to map kernel index entries to our index numbers.
297 Since we get at first all RTM_NEWLINK entries, it can never happen
298 that a RTM_NEWADDR index is not known to this map. */
301 map_newlink (int index
, struct ifaddrs_storage
*ifas
, int *map
, int max
)
305 for (i
= 0; i
< max
; i
++)
311 ifas
[i
- 1].ifa
.ifa_next
= &ifas
[i
].ifa
;
314 else if (map
[i
] == index
)
318 /* This means interfaces changed inbetween the reading of the
319 RTM_GETLINK and RTM_GETADDR information. We have to repeat
325 /* Create a linked list of `struct ifaddrs' structures, one for each
326 network interface on the host machine. If successful, store the
327 list in *IFAP and return 0. On errors, return -1 and set `errno'. */
329 getifaddrs_internal (struct ifaddrs
**ifap
)
331 struct netlink_handle nh
= { 0, 0, 0, NULL
, NULL
};
332 struct netlink_res
*nlp
;
333 struct ifaddrs_storage
*ifas
;
334 unsigned int i
, newlink
, newaddr
, newaddr_idx
;
335 int *map_newlink_data
;
336 size_t ifa_data_size
= 0; /* Size to allocate for all ifa_data. */
337 char *ifa_data_ptr
; /* Pointer to the unused part of memory for
343 if (! __no_netlink_support
&& __netlink_open (&nh
) < 0)
345 #if __ASSUME_NETLINK_SUPPORT != 0
350 #if __ASSUME_NETLINK_SUPPORT == 0
351 if (__no_netlink_support
)
352 return fallback_getifaddrs (ifap
);
355 /* Tell the kernel that we wish to get a list of all
356 active interfaces, collect all data for every interface. */
357 if (__netlink_request (&nh
, RTM_GETLINK
) < 0)
363 /* Now ask the kernel for all addresses which are assigned
364 to an interface and collect all data for every interface.
365 Since we store the addresses after the interfaces in the
366 list, we will later always find the interface before the
367 corresponding addresses. */
369 if (__netlink_request (&nh
, RTM_GETADDR
) < 0)
375 /* Count all RTM_NEWLINK and RTM_NEWADDR entries to allocate
377 newlink
= newaddr
= 0;
378 for (nlp
= nh
.nlm_list
; nlp
; nlp
= nlp
->next
)
380 struct nlmsghdr
*nlh
;
381 size_t size
= nlp
->size
;
383 if (nlp
->nlh
== NULL
)
386 /* Walk through all entries we got from the kernel and look, which
387 message type they contain. */
388 for (nlh
= nlp
->nlh
; NLMSG_OK (nlh
, size
); nlh
= NLMSG_NEXT (nlh
, size
))
390 /* Check if the message is what we want. */
391 if ((pid_t
) nlh
->nlmsg_pid
!= nh
.pid
|| nlh
->nlmsg_seq
!= nlp
->seq
)
394 if (nlh
->nlmsg_type
== NLMSG_DONE
)
397 if (nlh
->nlmsg_type
== RTM_NEWLINK
)
399 /* A RTM_NEWLINK message can have IFLA_STATS data. We need to
400 know the size before creating the list to allocate enough
402 struct ifinfomsg
*ifim
= (struct ifinfomsg
*) NLMSG_DATA (nlh
);
403 struct rtattr
*rta
= IFLA_RTA (ifim
);
404 size_t rtasize
= IFLA_PAYLOAD (nlh
);
406 while (RTA_OK (rta
, rtasize
))
408 size_t rta_payload
= RTA_PAYLOAD (rta
);
410 if (rta
->rta_type
== IFLA_STATS
)
412 ifa_data_size
+= rta_payload
;
416 rta
= RTA_NEXT (rta
, rtasize
);
420 else if (nlh
->nlmsg_type
== RTM_NEWADDR
)
425 /* Return if no interface is up. */
426 if ((newlink
+ newaddr
) == 0)
429 /* Allocate memory for all entries we have and initialize next
431 ifas
= (struct ifaddrs_storage
*) calloc (1,
433 * sizeof (struct ifaddrs_storage
)
441 /* Table for mapping kernel index to entry in our list. */
442 map_newlink_data
= alloca (newlink
* sizeof (int));
443 memset (map_newlink_data
, '\xff', newlink
* sizeof (int));
445 ifa_data_ptr
= (char *) &ifas
[newlink
+ newaddr
];
446 newaddr_idx
= 0; /* Counter for newaddr index. */
448 /* Walk through the list of data we got from the kernel. */
449 for (nlp
= nh
.nlm_list
; nlp
; nlp
= nlp
->next
)
451 struct nlmsghdr
*nlh
;
452 size_t size
= nlp
->size
;
454 if (nlp
->nlh
== NULL
)
457 /* Walk through one message and look at the type: If it is our
458 message, we need RTM_NEWLINK/RTM_NEWADDR and stop if we reach
459 the end or we find the end marker (in this case we ignore the
461 for (nlh
= nlp
->nlh
; NLMSG_OK (nlh
, size
); nlh
= NLMSG_NEXT (nlh
, size
))
465 /* Check if the message is the one we want */
466 if ((pid_t
) nlh
->nlmsg_pid
!= nh
.pid
|| nlh
->nlmsg_seq
!= nlp
->seq
)
469 if (nlh
->nlmsg_type
== NLMSG_DONE
)
472 if (nlh
->nlmsg_type
== RTM_NEWLINK
)
474 /* We found a new interface. Now extract everything from the
475 interface data we got and need. */
476 struct ifinfomsg
*ifim
= (struct ifinfomsg
*) NLMSG_DATA (nlh
);
477 struct rtattr
*rta
= IFLA_RTA (ifim
);
478 size_t rtasize
= IFLA_PAYLOAD (nlh
);
480 /* Interfaces are stored in the first "newlink" entries
481 of our list, starting in the order as we got from the
483 ifa_index
= map_newlink (ifim
->ifi_index
- 1, ifas
,
484 map_newlink_data
, newlink
);
485 if (__builtin_expect (ifa_index
== -1, 0))
492 ifas
[ifa_index
].ifa
.ifa_flags
= ifim
->ifi_flags
;
494 while (RTA_OK (rta
, rtasize
))
496 char *rta_data
= RTA_DATA (rta
);
497 size_t rta_payload
= RTA_PAYLOAD (rta
);
499 switch (rta
->rta_type
)
502 if (rta_payload
<= sizeof (ifas
[ifa_index
].addr
))
504 ifas
[ifa_index
].addr
.sl
.sll_family
= AF_PACKET
;
505 memcpy (ifas
[ifa_index
].addr
.sl
.sll_addr
,
506 (char *) rta_data
, rta_payload
);
507 ifas
[ifa_index
].addr
.sl
.sll_halen
= rta_payload
;
508 ifas
[ifa_index
].addr
.sl
.sll_ifindex
510 ifas
[ifa_index
].addr
.sl
.sll_hatype
= ifim
->ifi_type
;
512 ifas
[ifa_index
].ifa
.ifa_addr
513 = &ifas
[ifa_index
].addr
.sa
;
518 if (rta_payload
<= sizeof (ifas
[ifa_index
].broadaddr
))
520 ifas
[ifa_index
].broadaddr
.sl
.sll_family
= AF_PACKET
;
521 memcpy (ifas
[ifa_index
].broadaddr
.sl
.sll_addr
,
522 (char *) rta_data
, rta_payload
);
523 ifas
[ifa_index
].broadaddr
.sl
.sll_halen
= rta_payload
;
524 ifas
[ifa_index
].broadaddr
.sl
.sll_ifindex
526 ifas
[ifa_index
].broadaddr
.sl
.sll_hatype
529 ifas
[ifa_index
].ifa
.ifa_broadaddr
530 = &ifas
[ifa_index
].broadaddr
.sa
;
534 case IFLA_IFNAME
: /* Name of Interface */
535 if ((rta_payload
+ 1) <= sizeof (ifas
[ifa_index
].name
))
537 ifas
[ifa_index
].ifa
.ifa_name
= ifas
[ifa_index
].name
;
538 *(char *) __mempcpy (ifas
[ifa_index
].name
, rta_data
,
543 case IFLA_STATS
: /* Statistics of Interface */
544 ifas
[ifa_index
].ifa
.ifa_data
= ifa_data_ptr
;
545 ifa_data_ptr
+= rta_payload
;
546 memcpy (ifas
[ifa_index
].ifa
.ifa_data
, rta_data
,
562 rta
= RTA_NEXT (rta
, rtasize
);
565 else if (nlh
->nlmsg_type
== RTM_NEWADDR
)
567 struct ifaddrmsg
*ifam
= (struct ifaddrmsg
*) NLMSG_DATA (nlh
);
568 struct rtattr
*rta
= IFA_RTA (ifam
);
569 size_t rtasize
= IFA_PAYLOAD (nlh
);
571 /* New Addresses are stored in the order we got them from
572 the kernel after the interfaces. Theoretically it is possible
573 that we have holes in the interface part of the list,
574 but we always have already the interface for this address. */
575 ifa_index
= newlink
+ newaddr_idx
;
576 int idx
= map_newlink (ifam
->ifa_index
- 1, ifas
,
577 map_newlink_data
, newlink
);
578 if (__builtin_expect (idx
== -1, 0))
580 ifas
[ifa_index
].ifa
.ifa_flags
= ifas
[idx
].ifa
.ifa_flags
;
582 ifas
[ifa_index
- 1].ifa
.ifa_next
= &ifas
[ifa_index
].ifa
;
585 while (RTA_OK (rta
, rtasize
))
587 char *rta_data
= RTA_DATA (rta
);
588 size_t rta_payload
= RTA_PAYLOAD (rta
);
590 switch (rta
->rta_type
)
596 if (ifas
[ifa_index
].ifa
.ifa_addr
!= NULL
)
598 /* In a point-to-poing network IFA_ADDRESS
599 contains the destination address, local
600 address is supplied in IFA_LOCAL attribute.
601 destination address and broadcast address
602 are stored in an union, so it doesn't matter
603 which name we use. */
604 ifas
[ifa_index
].ifa
.ifa_broadaddr
605 = &ifas
[ifa_index
].broadaddr
.sa
;
606 sa
= &ifas
[ifa_index
].broadaddr
.sa
;
610 ifas
[ifa_index
].ifa
.ifa_addr
611 = &ifas
[ifa_index
].addr
.sa
;
612 sa
= &ifas
[ifa_index
].addr
.sa
;
615 sa
->sa_family
= ifam
->ifa_family
;
617 switch (ifam
->ifa_family
)
620 /* Size must match that of an address for IPv4. */
621 if (rta_payload
== 4)
622 memcpy (&((struct sockaddr_in
*) sa
)->sin_addr
,
623 rta_data
, rta_payload
);
627 /* Size must match that of an address for IPv6. */
628 if (rta_payload
== 16)
630 memcpy (&((struct sockaddr_in6
*) sa
)->sin6_addr
,
631 rta_data
, rta_payload
);
632 if (IN6_IS_ADDR_LINKLOCAL (rta_data
)
633 || IN6_IS_ADDR_MC_LINKLOCAL (rta_data
))
634 ((struct sockaddr_in6
*) sa
)->sin6_scope_id
640 if (rta_payload
<= sizeof (ifas
[ifa_index
].addr
))
641 memcpy (sa
->sa_data
, rta_data
, rta_payload
);
648 if (ifas
[ifa_index
].ifa
.ifa_addr
!= NULL
)
650 /* If ifa_addr is set and we get IFA_LOCAL,
651 assume we have a point-to-point network.
652 Move address to correct field. */
653 ifas
[ifa_index
].broadaddr
= ifas
[ifa_index
].addr
;
654 ifas
[ifa_index
].ifa
.ifa_broadaddr
655 = &ifas
[ifa_index
].broadaddr
.sa
;
656 memset (&ifas
[ifa_index
].addr
, '\0',
657 sizeof (ifas
[ifa_index
].addr
));
660 ifas
[ifa_index
].ifa
.ifa_addr
= &ifas
[ifa_index
].addr
.sa
;
661 ifas
[ifa_index
].ifa
.ifa_addr
->sa_family
664 switch (ifam
->ifa_family
)
667 /* Size must match that of an address for IPv4. */
668 if (rta_payload
== 4)
669 memcpy (&ifas
[ifa_index
].addr
.s4
.sin_addr
,
670 rta_data
, rta_payload
);
674 /* Size must match that of an address for IPv6. */
675 if (rta_payload
== 16)
677 memcpy (&ifas
[ifa_index
].addr
.s6
.sin6_addr
,
678 rta_data
, rta_payload
);
679 if (IN6_IS_ADDR_LINKLOCAL (rta_data
)
680 || IN6_IS_ADDR_MC_LINKLOCAL (rta_data
))
681 ifas
[ifa_index
].addr
.s6
.sin6_scope_id
=
687 if (rta_payload
<= sizeof (ifas
[ifa_index
].addr
))
688 memcpy (ifas
[ifa_index
].addr
.sa
.sa_data
,
689 rta_data
, rta_payload
);
695 /* We get IFA_BROADCAST, so IFA_LOCAL was too much. */
696 if (ifas
[ifa_index
].ifa
.ifa_broadaddr
!= NULL
)
697 memset (&ifas
[ifa_index
].broadaddr
, '\0',
698 sizeof (ifas
[ifa_index
].broadaddr
));
700 ifas
[ifa_index
].ifa
.ifa_broadaddr
701 = &ifas
[ifa_index
].broadaddr
.sa
;
702 ifas
[ifa_index
].ifa
.ifa_broadaddr
->sa_family
705 switch (ifam
->ifa_family
)
708 /* Size must match that of an address for IPv4. */
709 if (rta_payload
== 4)
710 memcpy (&ifas
[ifa_index
].broadaddr
.s4
.sin_addr
,
711 rta_data
, rta_payload
);
715 /* Size must match that of an address for IPv6. */
716 if (rta_payload
== 16)
718 memcpy (&ifas
[ifa_index
].broadaddr
.s6
.sin6_addr
,
719 rta_data
, rta_payload
);
720 if (IN6_IS_ADDR_LINKLOCAL (rta_data
)
721 || IN6_IS_ADDR_MC_LINKLOCAL (rta_data
))
722 ifas
[ifa_index
].broadaddr
.s6
.sin6_scope_id
728 if (rta_payload
<= sizeof (ifas
[ifa_index
].addr
))
729 memcpy (&ifas
[ifa_index
].broadaddr
.sa
.sa_data
,
730 rta_data
, rta_payload
);
736 if (rta_payload
+ 1 <= sizeof (ifas
[ifa_index
].name
))
738 ifas
[ifa_index
].ifa
.ifa_name
= ifas
[ifa_index
].name
;
739 *(char *) __mempcpy (ifas
[ifa_index
].name
, rta_data
,
754 rta
= RTA_NEXT (rta
, rtasize
);
757 /* If we didn't get the interface name with the
758 address, use the name from the interface entry. */
759 if (ifas
[ifa_index
].ifa
.ifa_name
== NULL
)
761 int idx
= map_newlink (ifam
->ifa_index
- 1, ifas
,
762 map_newlink_data
, newlink
);
763 if (__builtin_expect (idx
== -1, 0))
765 ifas
[ifa_index
].ifa
.ifa_name
= ifas
[idx
].ifa
.ifa_name
;
768 /* Calculate the netmask. */
769 if (ifas
[ifa_index
].ifa
.ifa_addr
770 && ifas
[ifa_index
].ifa
.ifa_addr
->sa_family
!= AF_UNSPEC
771 && ifas
[ifa_index
].ifa
.ifa_addr
->sa_family
!= AF_PACKET
)
773 uint32_t max_prefixlen
= 0;
776 ifas
[ifa_index
].ifa
.ifa_netmask
777 = &ifas
[ifa_index
].netmask
.sa
;
779 switch (ifas
[ifa_index
].ifa
.ifa_addr
->sa_family
)
782 cp
= (char *) &ifas
[ifa_index
].netmask
.s4
.sin_addr
;
787 cp
= (char *) &ifas
[ifa_index
].netmask
.s6
.sin6_addr
;
792 ifas
[ifa_index
].ifa
.ifa_netmask
->sa_family
793 = ifas
[ifa_index
].ifa
.ifa_addr
->sa_family
;
798 unsigned int preflen
;
800 if ((max_prefixlen
> 0) &&
801 (ifam
->ifa_prefixlen
> max_prefixlen
))
802 preflen
= max_prefixlen
;
804 preflen
= ifam
->ifa_prefixlen
;
806 for (i
= 0; i
< (preflen
/ 8); i
++)
809 c
<<= (8 - (preflen
% 8));
817 assert (ifa_data_ptr
<= (char *) &ifas
[newlink
+ newaddr
] + ifa_data_size
);
821 for (i
= 0; i
< newlink
; ++i
)
822 if (map_newlink_data
[i
] == -1)
824 /* We have fewer links then we anticipated. Adjust the
825 forward pointer to the first address entry. */
826 ifas
[i
- 1].ifa
.ifa_next
= &ifas
[newlink
].ifa
;
829 if (i
== 0 && newlink
> 0)
830 /* No valid link, but we allocated memory. We have to
831 populate the first entry. */
832 memmove (ifas
, &ifas
[newlink
], sizeof (struct ifaddrs_storage
));
835 *ifap
= &ifas
[0].ifa
;
838 __netlink_free_handle (&nh
);
839 __netlink_close (&nh
);
845 /* Create a linked list of `struct ifaddrs' structures, one for each
846 network interface on the host machine. If successful, store the
847 list in *IFAP and return 0. On errors, return -1 and set `errno'. */
849 getifaddrs (struct ifaddrs
**ifap
)
854 res
= getifaddrs_internal (ifap
);
855 while (res
== -EAGAIN
);
859 libc_hidden_def (getifaddrs
)
862 #if __ASSUME_NETLINK_SUPPORT != 0
864 freeifaddrs (struct ifaddrs
*ifa
)
868 libc_hidden_def (freeifaddrs
)