1 /* getifaddrs -- get names and addresses of all network interfaces
2 Copyright (C) 2003-2008, 2009, 2010 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, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25 #include <netinet/in.h>
26 #include <netpacket/packet.h>
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
36 #include <kernel-features.h>
38 #include "netlinkaccess.h"
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
44 int __no_netlink_support attribute_hidden
;
46 # define getifaddrs fallback_getifaddrs
47 # include "sysdeps/gnu/ifaddrs.c"
52 /* There is a problem with this type. The address length for
53 Infiniband sockets is much longer than the 8 bytes allocated in the
54 sockaddr_ll definition. Hence we use here a special
56 struct sockaddr_ll_max
58 unsigned short int sll_family
;
59 unsigned short int sll_protocol
;
61 unsigned short int sll_hatype
;
62 unsigned char sll_pkttype
;
63 unsigned char sll_halen
;
64 unsigned char sll_addr
[24];
68 /* struct to hold the data for one ifaddrs entry, so we can allocate
69 everything at once. */
70 struct ifaddrs_storage
75 /* Save space for the biggest of the four used sockaddr types and
76 avoid a lot of casts. */
78 struct sockaddr_ll_max sl
;
79 struct sockaddr_in s4
;
80 struct sockaddr_in6 s6
;
81 } addr
, netmask
, broadaddr
;
82 char name
[IF_NAMESIZE
+ 1];
87 __netlink_free_handle (struct netlink_handle
*h
)
89 struct netlink_res
*ptr
;
90 int saved_errno
= errno
;
95 struct netlink_res
*tmpptr
;
102 __set_errno (saved_errno
);
107 __netlink_sendreq (struct netlink_handle
*h
, int type
)
115 struct sockaddr_nl nladdr
;
118 h
->seq
= time (NULL
);
120 req
.nlh
.nlmsg_len
= sizeof (req
);
121 req
.nlh
.nlmsg_type
= type
;
122 req
.nlh
.nlmsg_flags
= NLM_F_ROOT
| NLM_F_MATCH
| NLM_F_REQUEST
;
123 req
.nlh
.nlmsg_pid
= 0;
124 req
.nlh
.nlmsg_seq
= h
->seq
;
125 req
.g
.rtgen_family
= AF_UNSPEC
;
126 if (sizeof (req
) != offsetof (struct req
, pad
))
127 memset (req
.pad
, '\0', sizeof (req
) - offsetof (struct req
, pad
));
129 memset (&nladdr
, '\0', sizeof (nladdr
));
130 nladdr
.nl_family
= AF_NETLINK
;
132 return TEMP_FAILURE_RETRY (__sendto (h
->fd
, (void *) &req
, sizeof (req
), 0,
133 (struct sockaddr
*) &nladdr
,
139 __netlink_request (struct netlink_handle
*h
, int type
)
141 struct netlink_res
*nlm_next
;
142 struct sockaddr_nl nladdr
;
143 struct nlmsghdr
*nlmh
;
148 /* Help the compiler optimize out the malloc call if PAGE_SIZE
149 is constant and smaller or equal to PTHREAD_STACK_MIN/4. */
150 const size_t buf_size
= PAGE_SIZE
;
152 const size_t buf_size
= __getpagesize ();
154 bool use_malloc
= false;
157 if (__libc_use_alloca (buf_size
))
158 buf
= alloca (buf_size
);
161 buf
= malloc (buf_size
);
168 struct iovec iov
= { buf
, buf_size
};
170 if (__netlink_sendreq (h
, type
) < 0)
177 (void *) &nladdr
, sizeof (nladdr
),
183 read_len
= TEMP_FAILURE_RETRY (__recvmsg (h
->fd
, &msg
, 0));
187 if (nladdr
.nl_pid
!= 0)
190 if (__builtin_expect (msg
.msg_flags
& MSG_TRUNC
, 0))
194 size_t remaining_len
= read_len
;
195 for (nlmh
= (struct nlmsghdr
*) buf
;
196 NLMSG_OK (nlmh
, remaining_len
);
197 nlmh
= (struct nlmsghdr
*) NLMSG_NEXT (nlmh
, remaining_len
))
199 if ((pid_t
) nlmh
->nlmsg_pid
!= h
->pid
200 || nlmh
->nlmsg_seq
!= h
->seq
)
204 if (nlmh
->nlmsg_type
== NLMSG_DONE
)
206 /* We found the end, leave the loop. */
210 if (nlmh
->nlmsg_type
== NLMSG_ERROR
)
212 struct nlmsgerr
*nlerr
= (struct nlmsgerr
*) NLMSG_DATA (nlmh
);
213 if (nlmh
->nlmsg_len
< NLMSG_LENGTH (sizeof (struct nlmsgerr
)))
216 errno
= -nlerr
->error
;
221 /* If there was nothing with the expected nlmsg_pid and nlmsg_seq,
222 there is no point to record it. */
226 nlm_next
= (struct netlink_res
*) malloc (sizeof (struct netlink_res
)
228 if (nlm_next
== NULL
)
230 nlm_next
->next
= NULL
;
231 nlm_next
->nlh
= memcpy (nlm_next
+ 1, buf
, read_len
);
232 nlm_next
->size
= read_len
;
233 nlm_next
->seq
= h
->seq
;
234 if (h
->nlm_list
== NULL
)
235 h
->nlm_list
= nlm_next
;
237 h
->end_ptr
->next
= nlm_next
;
238 h
->end_ptr
= nlm_next
;
253 __netlink_close (struct netlink_handle
*h
)
255 /* Don't modify errno. */
256 INTERNAL_SYSCALL_DECL (err
);
257 (void) INTERNAL_SYSCALL (close
, err
, 1, h
->fd
);
261 /* Open a NETLINK socket. */
263 __netlink_open (struct netlink_handle
*h
)
265 struct sockaddr_nl nladdr
;
267 h
->fd
= __socket (PF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
271 memset (&nladdr
, '\0', sizeof (nladdr
));
272 nladdr
.nl_family
= AF_NETLINK
;
273 if (__bind (h
->fd
, (struct sockaddr
*) &nladdr
, sizeof (nladdr
)) < 0)
278 #if __ASSUME_NETLINK_SUPPORT == 0
279 __no_netlink_support
= 1;
283 /* Determine the ID the kernel assigned for this netlink connection.
284 It is not necessarily the PID if there is more than one socket
286 socklen_t addr_len
= sizeof (nladdr
);
287 if (__getsockname (h
->fd
, (struct sockaddr
*) &nladdr
, &addr_len
) < 0)
289 h
->pid
= nladdr
.nl_pid
;
294 /* We know the number of RTM_NEWLINK entries, so we reserve the first
295 # of entries for this type. All RTM_NEWADDR entries have an index
296 pointer to the RTM_NEWLINK entry. To find the entry, create
297 a table to map kernel index entries to our index numbers.
298 Since we get at first all RTM_NEWLINK entries, it can never happen
299 that a RTM_NEWADDR index is not known to this map. */
302 map_newlink (int index
, struct ifaddrs_storage
*ifas
, int *map
, int max
)
306 for (i
= 0; i
< max
; i
++)
312 ifas
[i
- 1].ifa
.ifa_next
= &ifas
[i
].ifa
;
315 else if (map
[i
] == index
)
319 /* This means interfaces changed inbetween the reading of the
320 RTM_GETLINK and RTM_GETADDR information. We have to repeat
326 /* Create a linked list of `struct ifaddrs' structures, one for each
327 network interface on the host machine. If successful, store the
328 list in *IFAP and return 0. On errors, return -1 and set `errno'. */
330 getifaddrs_internal (struct ifaddrs
**ifap
)
332 struct netlink_handle nh
= { 0, 0, 0, NULL
, NULL
};
333 struct netlink_res
*nlp
;
334 struct ifaddrs_storage
*ifas
;
335 unsigned int i
, newlink
, newaddr
, newaddr_idx
;
336 int *map_newlink_data
;
337 size_t ifa_data_size
= 0; /* Size to allocate for all ifa_data. */
338 char *ifa_data_ptr
; /* Pointer to the unused part of memory for
344 if (! __no_netlink_support
&& __netlink_open (&nh
) < 0)
346 #if __ASSUME_NETLINK_SUPPORT != 0
351 #if __ASSUME_NETLINK_SUPPORT == 0
352 if (__no_netlink_support
)
353 return fallback_getifaddrs (ifap
);
356 /* Tell the kernel that we wish to get a list of all
357 active interfaces, collect all data for every interface. */
358 if (__netlink_request (&nh
, RTM_GETLINK
) < 0)
364 /* Now ask the kernel for all addresses which are assigned
365 to an interface and collect all data for every interface.
366 Since we store the addresses after the interfaces in the
367 list, we will later always find the interface before the
368 corresponding addresses. */
370 if (__netlink_request (&nh
, RTM_GETADDR
) < 0)
376 /* Count all RTM_NEWLINK and RTM_NEWADDR entries to allocate
378 newlink
= newaddr
= 0;
379 for (nlp
= nh
.nlm_list
; nlp
; nlp
= nlp
->next
)
381 struct nlmsghdr
*nlh
;
382 size_t size
= nlp
->size
;
384 if (nlp
->nlh
== NULL
)
387 /* Walk through all entries we got from the kernel and look, which
388 message type they contain. */
389 for (nlh
= nlp
->nlh
; NLMSG_OK (nlh
, size
); nlh
= NLMSG_NEXT (nlh
, size
))
391 /* Check if the message is what we want. */
392 if ((pid_t
) nlh
->nlmsg_pid
!= nh
.pid
|| nlh
->nlmsg_seq
!= nlp
->seq
)
395 if (nlh
->nlmsg_type
== NLMSG_DONE
)
398 if (nlh
->nlmsg_type
== RTM_NEWLINK
)
400 /* A RTM_NEWLINK message can have IFLA_STATS data. We need to
401 know the size before creating the list to allocate enough
403 struct ifinfomsg
*ifim
= (struct ifinfomsg
*) NLMSG_DATA (nlh
);
404 struct rtattr
*rta
= IFLA_RTA (ifim
);
405 size_t rtasize
= IFLA_PAYLOAD (nlh
);
407 while (RTA_OK (rta
, rtasize
))
409 size_t rta_payload
= RTA_PAYLOAD (rta
);
411 if (rta
->rta_type
== IFLA_STATS
)
413 ifa_data_size
+= rta_payload
;
417 rta
= RTA_NEXT (rta
, rtasize
);
421 else if (nlh
->nlmsg_type
== RTM_NEWADDR
)
426 /* Return if no interface is up. */
427 if ((newlink
+ newaddr
) == 0)
430 /* Allocate memory for all entries we have and initialize next
432 ifas
= (struct ifaddrs_storage
*) calloc (1,
434 * sizeof (struct ifaddrs_storage
)
442 /* Table for mapping kernel index to entry in our list. */
443 map_newlink_data
= alloca (newlink
* sizeof (int));
444 memset (map_newlink_data
, '\xff', newlink
* sizeof (int));
446 ifa_data_ptr
= (char *) &ifas
[newlink
+ newaddr
];
447 newaddr_idx
= 0; /* Counter for newaddr index. */
449 /* Walk through the list of data we got from the kernel. */
450 for (nlp
= nh
.nlm_list
; nlp
; nlp
= nlp
->next
)
452 struct nlmsghdr
*nlh
;
453 size_t size
= nlp
->size
;
455 if (nlp
->nlh
== NULL
)
458 /* Walk through one message and look at the type: If it is our
459 message, we need RTM_NEWLINK/RTM_NEWADDR and stop if we reach
460 the end or we find the end marker (in this case we ignore the
462 for (nlh
= nlp
->nlh
; NLMSG_OK (nlh
, size
); nlh
= NLMSG_NEXT (nlh
, size
))
466 /* Check if the message is the one we want */
467 if ((pid_t
) nlh
->nlmsg_pid
!= nh
.pid
|| nlh
->nlmsg_seq
!= nlp
->seq
)
470 if (nlh
->nlmsg_type
== NLMSG_DONE
)
473 if (nlh
->nlmsg_type
== RTM_NEWLINK
)
475 /* We found a new interface. Now extract everything from the
476 interface data we got and need. */
477 struct ifinfomsg
*ifim
= (struct ifinfomsg
*) NLMSG_DATA (nlh
);
478 struct rtattr
*rta
= IFLA_RTA (ifim
);
479 size_t rtasize
= IFLA_PAYLOAD (nlh
);
481 /* Interfaces are stored in the first "newlink" entries
482 of our list, starting in the order as we got from the
484 ifa_index
= map_newlink (ifim
->ifi_index
- 1, ifas
,
485 map_newlink_data
, newlink
);
486 if (__builtin_expect (ifa_index
== -1, 0))
493 ifas
[ifa_index
].ifa
.ifa_flags
= ifim
->ifi_flags
;
495 while (RTA_OK (rta
, rtasize
))
497 char *rta_data
= RTA_DATA (rta
);
498 size_t rta_payload
= RTA_PAYLOAD (rta
);
500 switch (rta
->rta_type
)
503 if (rta_payload
<= sizeof (ifas
[ifa_index
].addr
))
505 ifas
[ifa_index
].addr
.sl
.sll_family
= AF_PACKET
;
506 memcpy (ifas
[ifa_index
].addr
.sl
.sll_addr
,
507 (char *) rta_data
, rta_payload
);
508 ifas
[ifa_index
].addr
.sl
.sll_halen
= rta_payload
;
509 ifas
[ifa_index
].addr
.sl
.sll_ifindex
511 ifas
[ifa_index
].addr
.sl
.sll_hatype
= ifim
->ifi_type
;
513 ifas
[ifa_index
].ifa
.ifa_addr
514 = &ifas
[ifa_index
].addr
.sa
;
519 if (rta_payload
<= sizeof (ifas
[ifa_index
].broadaddr
))
521 ifas
[ifa_index
].broadaddr
.sl
.sll_family
= AF_PACKET
;
522 memcpy (ifas
[ifa_index
].broadaddr
.sl
.sll_addr
,
523 (char *) rta_data
, rta_payload
);
524 ifas
[ifa_index
].broadaddr
.sl
.sll_halen
= rta_payload
;
525 ifas
[ifa_index
].broadaddr
.sl
.sll_ifindex
527 ifas
[ifa_index
].broadaddr
.sl
.sll_hatype
530 ifas
[ifa_index
].ifa
.ifa_broadaddr
531 = &ifas
[ifa_index
].broadaddr
.sa
;
535 case IFLA_IFNAME
: /* Name of Interface */
536 if ((rta_payload
+ 1) <= sizeof (ifas
[ifa_index
].name
))
538 ifas
[ifa_index
].ifa
.ifa_name
= ifas
[ifa_index
].name
;
539 *(char *) __mempcpy (ifas
[ifa_index
].name
, rta_data
,
544 case IFLA_STATS
: /* Statistics of Interface */
545 ifas
[ifa_index
].ifa
.ifa_data
= ifa_data_ptr
;
546 ifa_data_ptr
+= rta_payload
;
547 memcpy (ifas
[ifa_index
].ifa
.ifa_data
, rta_data
,
563 rta
= RTA_NEXT (rta
, rtasize
);
566 else if (nlh
->nlmsg_type
== RTM_NEWADDR
)
568 struct ifaddrmsg
*ifam
= (struct ifaddrmsg
*) NLMSG_DATA (nlh
);
569 struct rtattr
*rta
= IFA_RTA (ifam
);
570 size_t rtasize
= IFA_PAYLOAD (nlh
);
572 /* New Addresses are stored in the order we got them from
573 the kernel after the interfaces. Theoretically it is possible
574 that we have holes in the interface part of the list,
575 but we always have already the interface for this address. */
576 ifa_index
= newlink
+ newaddr_idx
;
577 int idx
= map_newlink (ifam
->ifa_index
- 1, ifas
,
578 map_newlink_data
, newlink
);
579 if (__builtin_expect (idx
== -1, 0))
581 ifas
[ifa_index
].ifa
.ifa_flags
= ifas
[idx
].ifa
.ifa_flags
;
583 ifas
[ifa_index
- 1].ifa
.ifa_next
= &ifas
[ifa_index
].ifa
;
586 while (RTA_OK (rta
, rtasize
))
588 char *rta_data
= RTA_DATA (rta
);
589 size_t rta_payload
= RTA_PAYLOAD (rta
);
591 switch (rta
->rta_type
)
597 if (ifas
[ifa_index
].ifa
.ifa_addr
!= NULL
)
599 /* In a point-to-poing network IFA_ADDRESS
600 contains the destination address, local
601 address is supplied in IFA_LOCAL attribute.
602 destination address and broadcast address
603 are stored in an union, so it doesn't matter
604 which name we use. */
605 ifas
[ifa_index
].ifa
.ifa_broadaddr
606 = &ifas
[ifa_index
].broadaddr
.sa
;
607 sa
= &ifas
[ifa_index
].broadaddr
.sa
;
611 ifas
[ifa_index
].ifa
.ifa_addr
612 = &ifas
[ifa_index
].addr
.sa
;
613 sa
= &ifas
[ifa_index
].addr
.sa
;
616 sa
->sa_family
= ifam
->ifa_family
;
618 switch (ifam
->ifa_family
)
621 /* Size must match that of an address for IPv4. */
622 if (rta_payload
== 4)
623 memcpy (&((struct sockaddr_in
*) sa
)->sin_addr
,
624 rta_data
, rta_payload
);
628 /* Size must match that of an address for IPv6. */
629 if (rta_payload
== 16)
631 memcpy (&((struct sockaddr_in6
*) sa
)->sin6_addr
,
632 rta_data
, rta_payload
);
633 if (IN6_IS_ADDR_LINKLOCAL (rta_data
)
634 || IN6_IS_ADDR_MC_LINKLOCAL (rta_data
))
635 ((struct sockaddr_in6
*) sa
)->sin6_scope_id
641 if (rta_payload
<= sizeof (ifas
[ifa_index
].addr
))
642 memcpy (sa
->sa_data
, rta_data
, rta_payload
);
649 if (ifas
[ifa_index
].ifa
.ifa_addr
!= NULL
)
651 /* If ifa_addr is set and we get IFA_LOCAL,
652 assume we have a point-to-point network.
653 Move address to correct field. */
654 ifas
[ifa_index
].broadaddr
= ifas
[ifa_index
].addr
;
655 ifas
[ifa_index
].ifa
.ifa_broadaddr
656 = &ifas
[ifa_index
].broadaddr
.sa
;
657 memset (&ifas
[ifa_index
].addr
, '\0',
658 sizeof (ifas
[ifa_index
].addr
));
661 ifas
[ifa_index
].ifa
.ifa_addr
= &ifas
[ifa_index
].addr
.sa
;
662 ifas
[ifa_index
].ifa
.ifa_addr
->sa_family
665 switch (ifam
->ifa_family
)
668 /* Size must match that of an address for IPv4. */
669 if (rta_payload
== 4)
670 memcpy (&ifas
[ifa_index
].addr
.s4
.sin_addr
,
671 rta_data
, rta_payload
);
675 /* Size must match that of an address for IPv6. */
676 if (rta_payload
== 16)
678 memcpy (&ifas
[ifa_index
].addr
.s6
.sin6_addr
,
679 rta_data
, rta_payload
);
680 if (IN6_IS_ADDR_LINKLOCAL (rta_data
)
681 || IN6_IS_ADDR_MC_LINKLOCAL (rta_data
))
682 ifas
[ifa_index
].addr
.s6
.sin6_scope_id
=
688 if (rta_payload
<= sizeof (ifas
[ifa_index
].addr
))
689 memcpy (ifas
[ifa_index
].addr
.sa
.sa_data
,
690 rta_data
, rta_payload
);
696 /* We get IFA_BROADCAST, so IFA_LOCAL was too much. */
697 if (ifas
[ifa_index
].ifa
.ifa_broadaddr
!= NULL
)
698 memset (&ifas
[ifa_index
].broadaddr
, '\0',
699 sizeof (ifas
[ifa_index
].broadaddr
));
701 ifas
[ifa_index
].ifa
.ifa_broadaddr
702 = &ifas
[ifa_index
].broadaddr
.sa
;
703 ifas
[ifa_index
].ifa
.ifa_broadaddr
->sa_family
706 switch (ifam
->ifa_family
)
709 /* Size must match that of an address for IPv4. */
710 if (rta_payload
== 4)
711 memcpy (&ifas
[ifa_index
].broadaddr
.s4
.sin_addr
,
712 rta_data
, rta_payload
);
716 /* Size must match that of an address for IPv6. */
717 if (rta_payload
== 16)
719 memcpy (&ifas
[ifa_index
].broadaddr
.s6
.sin6_addr
,
720 rta_data
, rta_payload
);
721 if (IN6_IS_ADDR_LINKLOCAL (rta_data
)
722 || IN6_IS_ADDR_MC_LINKLOCAL (rta_data
))
723 ifas
[ifa_index
].broadaddr
.s6
.sin6_scope_id
729 if (rta_payload
<= sizeof (ifas
[ifa_index
].addr
))
730 memcpy (&ifas
[ifa_index
].broadaddr
.sa
.sa_data
,
731 rta_data
, rta_payload
);
737 if (rta_payload
+ 1 <= sizeof (ifas
[ifa_index
].name
))
739 ifas
[ifa_index
].ifa
.ifa_name
= ifas
[ifa_index
].name
;
740 *(char *) __mempcpy (ifas
[ifa_index
].name
, rta_data
,
755 rta
= RTA_NEXT (rta
, rtasize
);
758 /* If we didn't get the interface name with the
759 address, use the name from the interface entry. */
760 if (ifas
[ifa_index
].ifa
.ifa_name
== NULL
)
762 int idx
= map_newlink (ifam
->ifa_index
- 1, ifas
,
763 map_newlink_data
, newlink
);
764 if (__builtin_expect (idx
== -1, 0))
766 ifas
[ifa_index
].ifa
.ifa_name
= ifas
[idx
].ifa
.ifa_name
;
769 /* Calculate the netmask. */
770 if (ifas
[ifa_index
].ifa
.ifa_addr
771 && ifas
[ifa_index
].ifa
.ifa_addr
->sa_family
!= AF_UNSPEC
772 && ifas
[ifa_index
].ifa
.ifa_addr
->sa_family
!= AF_PACKET
)
774 uint32_t max_prefixlen
= 0;
777 ifas
[ifa_index
].ifa
.ifa_netmask
778 = &ifas
[ifa_index
].netmask
.sa
;
780 switch (ifas
[ifa_index
].ifa
.ifa_addr
->sa_family
)
783 cp
= (char *) &ifas
[ifa_index
].netmask
.s4
.sin_addr
;
788 cp
= (char *) &ifas
[ifa_index
].netmask
.s6
.sin6_addr
;
793 ifas
[ifa_index
].ifa
.ifa_netmask
->sa_family
794 = ifas
[ifa_index
].ifa
.ifa_addr
->sa_family
;
799 unsigned int preflen
;
801 if ((max_prefixlen
> 0) &&
802 (ifam
->ifa_prefixlen
> max_prefixlen
))
803 preflen
= max_prefixlen
;
805 preflen
= ifam
->ifa_prefixlen
;
807 for (i
= 0; i
< (preflen
/ 8); i
++)
810 c
<<= (8 - (preflen
% 8));
818 assert (ifa_data_ptr
<= (char *) &ifas
[newlink
+ newaddr
] + ifa_data_size
);
822 for (i
= 0; i
< newlink
; ++i
)
823 if (map_newlink_data
[i
] == -1)
825 /* We have fewer links then we anticipated. Adjust the
826 forward pointer to the first address entry. */
827 ifas
[i
- 1].ifa
.ifa_next
= &ifas
[newlink
].ifa
;
830 if (i
== 0 && newlink
> 0)
831 /* No valid link, but we allocated memory. We have to
832 populate the first entry. */
833 memmove (ifas
, &ifas
[newlink
], sizeof (struct ifaddrs_storage
));
836 *ifap
= &ifas
[0].ifa
;
839 __netlink_free_handle (&nh
);
840 __netlink_close (&nh
);
846 /* Create a linked list of `struct ifaddrs' structures, one for each
847 network interface on the host machine. If successful, store the
848 list in *IFAP and return 0. On errors, return -1 and set `errno'. */
850 getifaddrs (struct ifaddrs
**ifap
)
855 res
= getifaddrs_internal (ifap
);
856 while (res
== -EAGAIN
);
860 libc_hidden_def (getifaddrs
)
863 #if __ASSUME_NETLINK_SUPPORT != 0
865 freeifaddrs (struct ifaddrs
*ifa
)
869 libc_hidden_def (freeifaddrs
)