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.
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>
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
36 #include "netlinkaccess.h"
39 #ifndef __libc_use_alloca
40 # define __libc_use_alloca(x) (x < __MAX_ALLOCA_CUTOFF)
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
53 /* Save space for the biggest of the four used sockaddr types and
54 avoid a lot of casts. */
56 struct sockaddr_ll sl
;
57 struct sockaddr_in s4
;
58 #ifdef __UCLIBC_HAS_IPV6__
59 struct sockaddr_in6 s6
;
61 } addr
, netmask
, broadaddr
;
62 char name
[IF_NAMESIZE
+ 1];
64 #endif /* __UCLIBC_SUPPORT_AI_ADDRCONFIG__ */
68 __netlink_free_handle (struct netlink_handle
*h
)
70 struct netlink_res
*ptr
;
75 struct netlink_res
*tmpptr
;
78 free (ptr
); /* doesn't affect errno */
85 __netlink_sendreq (struct netlink_handle
*h
, int type
)
92 struct sockaddr_nl nladdr
;
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
;
104 memset (&nladdr
, '\0', sizeof (nladdr
));
105 nladdr
.nl_family
= AF_NETLINK
;
107 return TEMP_FAILURE_RETRY (sendto (h
->fd
, (void *) &req
, sizeof (req
), 0,
108 (struct sockaddr
*) &nladdr
,
114 __netlink_request (struct netlink_handle
*h
, int type
)
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
;
121 struct sockaddr_nl nladdr
;
122 struct nlmsghdr
*nlmh
;
125 bool use_malloc
= false;
127 if (__netlink_sendreq (h
, type
) < 0)
131 this_buf_size
= buf_size
;
134 this_buf_size
= PAGE_SIZE
;
136 this_buf_size
= __pagesize
;
139 if (__libc_use_alloca (this_buf_size
))
140 buf
= alloca (this_buf_size
);
143 buf
= malloc (this_buf_size
);
150 struct iovec iov
= { buf
, this_buf_size
};
152 if (h
->nlm_list
!= NULL
)
153 new_nlm_list
= &h
->end_ptr
->next
;
155 new_nlm_list
= &h
->nlm_list
;
161 (void *) &nladdr
, sizeof (nladdr
),
167 read_len
= TEMP_FAILURE_RETRY (recvmsg (h
->fd
, &msg
, 0));
171 if (nladdr
.nl_pid
!= 0)
174 if (__builtin_expect (msg
.msg_flags
& MSG_TRUNC
, 0))
176 if (this_buf_size
>= SIZE_MAX
/ 2)
179 nlm_next
= *new_nlm_list
;
180 while (nlm_next
!= NULL
)
182 struct netlink_res
*tmpptr
;
184 tmpptr
= nlm_next
->next
;
188 *new_nlm_list
= NULL
;
190 if (__libc_use_alloca (2 * this_buf_size
))
191 buf
= extend_alloca (buf
, this_buf_size
, 2 * this_buf_size
);
196 char *new_buf
= realloc (use_malloc
? buf
: NULL
, this_buf_size
);
203 buf_size
= this_buf_size
;
206 iov
.iov_len
= this_buf_size
;
208 /* Increase sequence number, so that we can distinguish
209 between old and new request messages. */
212 if (__netlink_sendreq (h
, type
) < 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
))
224 if ((pid_t
) nlmh
->nlmsg_pid
!= h
->pid
225 || nlmh
->nlmsg_seq
!= h
->seq
)
229 if (nlmh
->nlmsg_type
== NLMSG_DONE
)
231 /* We found the end, leave the loop. */
235 if (nlmh
->nlmsg_type
== NLMSG_ERROR
)
237 struct nlmsgerr
*nlerr
= (struct nlmsgerr
*) NLMSG_DATA (nlmh
);
238 if (nlmh
->nlmsg_len
< NLMSG_LENGTH (sizeof (struct nlmsgerr
)))
241 errno
= -nlerr
->error
;
246 /* If there was nothing with the expected nlmsg_pid and nlmsg_seq,
247 there is no point to record it. */
251 nlm_next
= (struct netlink_res
*) malloc (sizeof (struct netlink_res
)
253 if (nlm_next
== NULL
)
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
;
262 h
->end_ptr
->next
= nlm_next
;
263 h
->end_ptr
= nlm_next
;
278 __netlink_close (struct netlink_handle
*h
)
280 /* Don't modify errno. */
287 /* Open a NETLINK socket. */
289 __netlink_open (struct netlink_handle
*h
)
291 struct sockaddr_nl nladdr
;
293 h
->fd
= socket (PF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
297 memset (&nladdr
, '\0', sizeof (nladdr
));
298 nladdr
.nl_family
= AF_NETLINK
;
299 if (bind (h
->fd
, (struct sockaddr
*) &nladdr
, sizeof (nladdr
)) < 0)
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
309 socklen_t addr_len
= sizeof (nladdr
);
310 if (getsockname (h
->fd
, (struct sockaddr
*) &nladdr
, &addr_len
) < 0)
312 h
->pid
= nladdr
.nl_pid
;
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. */
326 map_newlink (int idx
, struct ifaddrs_storage
*ifas
, int *map
, int max
)
330 for (i
= 0; i
< max
; i
++)
336 ifas
[i
- 1].ifa
.ifa_next
= &ifas
[i
].ifa
;
339 else if (map
[i
] == idx
)
343 /* This means interfaces changed inbetween the reading of the
344 RTM_GETLINK and RTM_GETADDR information. We have to repeat
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'. */
354 getifaddrs_internal (struct ifaddrs
**ifap
)
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
369 if (__netlink_open (&nh
) < 0)
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)
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. */
388 if (__netlink_request (&nh
, RTM_GETADDR
) < 0)
394 /* Count all RTM_NEWLINK and RTM_NEWADDR entries to allocate
396 newlink
= newaddr
= 0;
397 for (nlp
= nh
.nlm_list
; nlp
; nlp
= nlp
->next
)
399 struct nlmsghdr
*nlh
;
400 size_t size
= nlp
->size
;
402 if (nlp
->nlh
== NULL
)
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
))
409 /* Check if the message is what we want. */
410 if ((pid_t
) nlh
->nlmsg_pid
!= nh
.pid
|| nlh
->nlmsg_seq
!= nlp
->seq
)
413 if (nlh
->nlmsg_type
== NLMSG_DONE
)
416 if (nlh
->nlmsg_type
== RTM_NEWLINK
)
418 /* A RTM_NEWLINK message can have IFLA_STATS data. We need to
419 know the size before creating the list to allocate enough
421 struct ifinfomsg
*ifim
= (struct ifinfomsg
*) NLMSG_DATA (nlh
);
422 struct rtattr
*rta
= IFLA_RTA (ifim
);
423 size_t rtasize
= IFLA_PAYLOAD (nlh
);
425 while (RTA_OK (rta
, rtasize
))
427 size_t rta_payload
= RTA_PAYLOAD (rta
);
429 if (rta
->rta_type
== IFLA_STATS
)
431 ifa_data_size
+= rta_payload
;
435 rta
= RTA_NEXT (rta
, rtasize
);
439 else if (nlh
->nlmsg_type
== RTM_NEWADDR
)
444 /* Return if no interface is up. */
445 if ((newlink
+ newaddr
) == 0)
448 /* Allocate memory for all entries we have and initialize next
450 ifas
= calloc (1, (newlink
+ newaddr
) * sizeof (ifas
[0]) + ifa_data_size
);
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));
461 ifa_data_ptr
= (char *) &ifas
[newlink
+ newaddr
];
462 newaddr_idx
= 0; /* Counter for newaddr index. */
464 /* Walk through the list of data we got from the kernel. */
465 for (nlp
= nh
.nlm_list
; nlp
; nlp
= nlp
->next
)
467 struct nlmsghdr
*nlh
;
468 size_t size
= nlp
->size
;
470 if (nlp
->nlh
== NULL
)
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
477 for (nlh
= nlp
->nlh
; NLMSG_OK (nlh
, size
); nlh
= NLMSG_NEXT (nlh
, size
))
481 /* Check if the message is the one we want */
482 if ((pid_t
) nlh
->nlmsg_pid
!= nh
.pid
|| nlh
->nlmsg_seq
!= nlp
->seq
)
485 if (nlh
->nlmsg_type
== NLMSG_DONE
)
488 if (nlh
->nlmsg_type
== RTM_NEWLINK
)
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
);
496 /* Interfaces are stored in the first "newlink" entries
497 of our list, starting in the order as we got from the
499 ifa_index
= map_newlink (ifim
->ifi_index
- 1, ifas
,
500 map_newlink_data
, newlink
);
501 if (__builtin_expect (ifa_index
== -1, 0))
508 ifas
[ifa_index
].ifa
.ifa_flags
= ifim
->ifi_flags
;
510 while (RTA_OK (rta
, rtasize
))
512 char *rta_data
= RTA_DATA (rta
);
513 size_t rta_payload
= RTA_PAYLOAD (rta
);
515 switch (rta
->rta_type
)
518 if (rta_payload
<= sizeof (ifas
[ifa_index
].addr
))
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
526 ifas
[ifa_index
].addr
.sl
.sll_hatype
= ifim
->ifi_type
;
528 ifas
[ifa_index
].ifa
.ifa_addr
529 = &ifas
[ifa_index
].addr
.sa
;
534 if (rta_payload
<= sizeof (ifas
[ifa_index
].broadaddr
))
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
542 ifas
[ifa_index
].broadaddr
.sl
.sll_hatype
545 ifas
[ifa_index
].ifa
.ifa_broadaddr
546 = &ifas
[ifa_index
].broadaddr
.sa
;
550 case IFLA_IFNAME
: /* Name of Interface */
551 if ((rta_payload
+ 1) <= sizeof (ifas
[ifa_index
].name
))
553 ifas
[ifa_index
].ifa
.ifa_name
= ifas
[ifa_index
].name
;
554 *(char *) mempcpy (ifas
[ifa_index
].name
, rta_data
,
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
,
578 rta
= RTA_NEXT (rta
, rtasize
);
581 else if (nlh
->nlmsg_type
== RTM_NEWADDR
)
583 struct ifaddrmsg
*ifam
= (struct ifaddrmsg
*) NLMSG_DATA (nlh
);
584 struct rtattr
*rta
= IFA_RTA (ifam
);
585 size_t rtasize
= IFA_PAYLOAD (nlh
);
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))
596 ifas
[ifa_index
].ifa
.ifa_flags
= ifas
[idx
].ifa
.ifa_flags
;
598 ifas
[ifa_index
- 1].ifa
.ifa_next
= &ifas
[ifa_index
].ifa
;
601 while (RTA_OK (rta
, rtasize
))
603 char *rta_data
= RTA_DATA (rta
);
604 size_t rta_payload
= RTA_PAYLOAD (rta
);
606 switch (rta
->rta_type
)
612 if (ifas
[ifa_index
].ifa
.ifa_addr
!= NULL
)
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
;
626 ifas
[ifa_index
].ifa
.ifa_addr
627 = &ifas
[ifa_index
].addr
.sa
;
628 sa
= &ifas
[ifa_index
].addr
.sa
;
631 sa
->sa_family
= ifam
->ifa_family
;
633 switch (ifam
->ifa_family
)
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
);
642 #ifdef __UCLIBC_HAS_IPV6__
644 /* Size must match that of an address for IPv6. */
645 if (rta_payload
== 16)
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
658 if (rta_payload
<= sizeof (ifas
[ifa_index
].addr
))
659 memcpy (sa
->sa_data
, rta_data
, rta_payload
);
666 if (ifas
[ifa_index
].ifa
.ifa_addr
!= NULL
)
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
));
678 ifas
[ifa_index
].ifa
.ifa_addr
= &ifas
[ifa_index
].addr
.sa
;
679 ifas
[ifa_index
].ifa
.ifa_addr
->sa_family
682 switch (ifam
->ifa_family
)
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
);
691 #ifdef __UCLIBC_HAS_IPV6__
693 /* Size must match that of an address for IPv6. */
694 if (rta_payload
== 16)
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
=
707 if (rta_payload
<= sizeof (ifas
[ifa_index
].addr
))
708 memcpy (ifas
[ifa_index
].addr
.sa
.sa_data
,
709 rta_data
, rta_payload
);
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
));
720 ifas
[ifa_index
].ifa
.ifa_broadaddr
721 = &ifas
[ifa_index
].broadaddr
.sa
;
722 ifas
[ifa_index
].ifa
.ifa_broadaddr
->sa_family
725 switch (ifam
->ifa_family
)
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
);
734 #ifdef __UCLIBC_HAS_IPV6__
736 /* Size must match that of an address for IPv6. */
737 if (rta_payload
== 16)
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
750 if (rta_payload
<= sizeof (ifas
[ifa_index
].addr
))
751 memcpy (&ifas
[ifa_index
].broadaddr
.sa
.sa_data
,
752 rta_data
, rta_payload
);
758 if (rta_payload
+ 1 <= sizeof (ifas
[ifa_index
].name
))
760 ifas
[ifa_index
].ifa
.ifa_name
= ifas
[ifa_index
].name
;
761 *(char *) mempcpy (ifas
[ifa_index
].name
, rta_data
,
776 rta
= RTA_NEXT (rta
, rtasize
);
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
)
783 int idx
= map_newlink (ifam
->ifa_index
- 1, ifas
,
784 map_newlink_data
, newlink
);
785 if (__builtin_expect (idx
== -1, 0))
787 ifas
[ifa_index
].ifa
.ifa_name
= ifas
[idx
].ifa
.ifa_name
;
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
)
795 uint32_t max_prefixlen
= 0;
798 ifas
[ifa_index
].ifa
.ifa_netmask
799 = &ifas
[ifa_index
].netmask
.sa
;
801 switch (ifas
[ifa_index
].ifa
.ifa_addr
->sa_family
)
804 cp
= (char *) &ifas
[ifa_index
].netmask
.s4
.sin_addr
;
808 #ifdef __UCLIBC_HAS_IPV6__
810 cp
= (char *) &ifas
[ifa_index
].netmask
.s6
.sin6_addr
;
816 ifas
[ifa_index
].ifa
.ifa_netmask
->sa_family
817 = ifas
[ifa_index
].ifa
.ifa_addr
->sa_family
;
822 unsigned int preflen
;
824 if ((max_prefixlen
> 0) &&
825 (ifam
->ifa_prefixlen
> max_prefixlen
))
826 preflen
= max_prefixlen
;
828 preflen
= ifam
->ifa_prefixlen
;
830 for (i
= 0; i
< (preflen
/ 8); i
++)
833 c
<<= (8 - (preflen
% 8));
841 assert (ifa_data_ptr
<= (char *) &ifas
[newlink
+ newaddr
] + ifa_data_size
);
845 for (i
= 0; i
< newlink
; ++i
)
846 if (map_newlink_data
[i
] == -1)
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
;
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
));
860 *ifap
= &ifas
[0].ifa
;
863 __netlink_free_handle (&nh
);
864 __netlink_close (&nh
);
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'. */
874 getifaddrs (struct ifaddrs
**ifap
)
879 res
= getifaddrs_internal (ifap
);
880 while (res
== -EAGAIN
);
884 libc_hidden_def(getifaddrs
)
887 freeifaddrs (struct ifaddrs
*ifa
)
891 libc_hidden_def(freeifaddrs
)
893 #endif /* __UCLIBC_SUPPORT_AI_ADDRCONFIG__ */
895 #endif /* __ASSUME_NETLINK_SUPPORT */