2 * Copyright (c) 2000 - 2002 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 RCSID("$Id: getifaddrs.c,v 1.9 2002/09/05 03:36:23 assar Exp $");
49 #ifdef HAVE_SYS_SOCKIO_H
50 #include <sys/sockio.h>
51 #endif /* HAVE_SYS_SOCKIO_H */
53 #ifdef HAVE_NETINET_IN6_VAR_H
54 #include <netinet/in6_var.h>
55 #endif /* HAVE_NETINET_IN6_VAR_H */
62 * The linux - AF_NETLINK version of getifaddrs - from Usagi.
63 * Linux does not return v6 addresses from SIOCGIFCONF.
66 /* $USAGI: ifaddrs.c,v 1.18 2002/03/06 01:50:46 yoshfuji Exp $ */
68 /**************************************************************************
70 * Copyright (C)2000 Hideaki YOSHIFUJI, All Rights Reserved.
72 * Redistribution and use in source and binary forms, with or without
73 * modification, are permitted provided that the following conditions
75 * 1. Redistributions of source code must retain the above copyright
76 * notice, this list of conditions and the following disclaimer.
77 * 2. Redistributions in binary form must reproduce the above copyright
78 * notice, this list of conditions and the following disclaimer in the
79 * documentation and/or other materials provided with the distribution.
80 * 3. Neither the name of the author nor the names of its contributors
81 * may be used to endorse or promote products derived from this software
82 * without specific prior written permission.
84 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
85 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
86 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
87 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
88 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
89 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
90 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
91 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
92 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
93 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
105 #include <sys/socket.h>
106 #include <asm/types.h>
107 #include <linux/netlink.h>
108 #include <linux/rtnetlink.h>
109 #include <sys/types.h>
110 #include <sys/socket.h>
111 #include <netpacket/packet.h>
112 #include <net/ethernet.h> /* the L2 protocols */
115 #include <net/if_arp.h>
117 #include <netinet/in.h>
119 #define __set_errno(e) (errno = (e))
120 #define __close(fd) (close(fd))
122 #define ifa_broadaddr ifa_dstaddr
125 /* ====================================================================== */
127 struct nlmsg_list
*nlm_next
;
128 struct nlmsghdr
*nlh
;
133 struct rtmaddr_ifamap
{
140 #ifdef HAVE_IFADDRS_IFA_ANYCAST
149 #ifdef HAVE_IFADDRS_IFA_ANYCAST
154 /* ====================================================================== */
156 ifa_sa_len(sa_family_t family
, int len
)
161 size
= sizeof(struct sockaddr_in
);
164 size
= sizeof(struct sockaddr_in6
);
167 size
= (size_t)(((struct sockaddr_ll
*)NULL
)->sll_addr
) + len
;
168 if (size
< sizeof(struct sockaddr_ll
))
169 size
= sizeof(struct sockaddr_ll
);
172 size
= (size_t)(((struct sockaddr
*)NULL
)->sa_data
) + len
;
173 if (size
< sizeof(struct sockaddr
))
174 size
= sizeof(struct sockaddr
);
180 ifa_make_sockaddr(sa_family_t family
,
183 uint32_t scope
, uint32_t scopeid
)
185 if (sa
== NULL
) return;
188 memcpy(&((struct sockaddr_in
*)sa
)->sin_addr
, (char *)p
, len
);
191 memcpy(&((struct sockaddr_in6
*)sa
)->sin6_addr
, (char *)p
, len
);
192 if (IN6_IS_ADDR_LINKLOCAL(p
) ||
193 IN6_IS_ADDR_MC_LINKLOCAL(p
)){
194 ((struct sockaddr_in6
*)sa
)->sin6_scope_id
= scopeid
;
198 memcpy(((struct sockaddr_ll
*)sa
)->sll_addr
, (char *)p
, len
);
199 ((struct sockaddr_ll
*)sa
)->sll_halen
= len
;
202 memcpy(sa
->sa_data
, p
, len
); /*XXX*/
205 sa
->sa_family
= family
;
206 #ifdef HAVE_SOCKADDR_SA_LEN
207 sa
->sa_len
= ifa_sa_len(family
, len
);
212 static struct sockaddr
*
213 ifa_make_sockaddr_mask(sa_family_t family
,
219 uint32_t max_prefixlen
= 0;
221 if (sa
== NULL
) return NULL
;
224 memset(&((struct sockaddr_in
*)sa
)->sin_addr
, 0, sizeof(((struct sockaddr_in
*)sa
)->sin_addr
));
225 p
= (char *)&((struct sockaddr_in
*)sa
)->sin_addr
;
229 memset(&((struct sockaddr_in6
*)sa
)->sin6_addr
, 0, sizeof(((struct sockaddr_in6
*)sa
)->sin6_addr
));
230 p
= (char *)&((struct sockaddr_in6
*)sa
)->sin6_addr
;
231 #if 0 /* XXX: fill scope-id? */
232 if (IN6_IS_ADDR_LINKLOCAL(p
) ||
233 IN6_IS_ADDR_MC_LINKLOCAL(p
)){
234 ((struct sockaddr_in6
*)sa
)->sin6_scope_id
= scopeid
;
242 sa
->sa_family
= family
;
243 #ifdef HAVE_SOCKADDR_SA_LEN
244 sa
->sa_len
= ifa_sa_len(family
, len
);
247 if (prefixlen
> max_prefixlen
)
248 prefixlen
= max_prefixlen
;
249 for (i
=0; i
<(prefixlen
/ 8); i
++)
252 c
<<= (8 - (prefixlen
% 8));
259 /* ====================================================================== */
261 nl_sendreq(int sd
, int request
, int flags
, int *seq
)
263 char reqbuf
[NLMSG_ALIGN(sizeof(struct nlmsghdr
)) +
264 NLMSG_ALIGN(sizeof(struct rtgenmsg
))];
265 struct sockaddr_nl nladdr
;
266 struct nlmsghdr
*req_hdr
;
267 struct rtgenmsg
*req_msg
;
268 time_t t
= time(NULL
);
271 memset(&reqbuf
, 0, sizeof(reqbuf
));
272 req_hdr
= (struct nlmsghdr
*)reqbuf
;
273 req_msg
= (struct rtgenmsg
*)NLMSG_DATA(req_hdr
);
274 req_hdr
->nlmsg_len
= NLMSG_LENGTH(sizeof(*req_msg
));
275 req_hdr
->nlmsg_type
= request
;
276 req_hdr
->nlmsg_flags
= flags
| NLM_F_REQUEST
;
277 req_hdr
->nlmsg_pid
= 0;
278 req_hdr
->nlmsg_seq
= t
;
279 req_msg
->rtgen_family
= AF_UNSPEC
;
280 memset(&nladdr
, 0, sizeof(nladdr
));
281 nladdr
.nl_family
= AF_NETLINK
;
282 return (sendto(sd
, (void *)req_hdr
, req_hdr
->nlmsg_len
, 0,
283 (struct sockaddr
*)&nladdr
, sizeof(nladdr
)));
287 nl_recvmsg(int sd
, int request
, int seq
,
288 void *buf
, size_t buflen
,
292 struct iovec iov
= { buf
, buflen
};
293 struct sockaddr_nl nladdr
;
297 msg
.msg_name
= (void *)&nladdr
;
298 msg
.msg_namelen
= sizeof(nladdr
);
301 msg
.msg_control
= NULL
;
302 msg
.msg_controllen
= 0;
304 read_len
= recvmsg(sd
, &msg
, 0);
305 if ((read_len
< 0 && errno
== EINTR
) || (msg
.msg_flags
& MSG_TRUNC
))
307 if (flags
) *flags
= msg
.msg_flags
;
314 nl_getmsg(int sd
, int request
, int seq
,
315 struct nlmsghdr
**nlhp
,
319 size_t bufsize
= 65536, lastbufsize
= 0;
321 int result
= 0, read_size
;
323 pid_t pid
= getpid();
325 void *newbuff
= realloc(buff
, bufsize
);
326 if (newbuff
== NULL
|| bufsize
< lastbufsize
) {
331 result
= read_size
= nl_recvmsg(sd
, request
, seq
, buff
, bufsize
, &msg_flags
);
332 if (read_size
< 0 || (msg_flags
& MSG_TRUNC
)){
333 lastbufsize
= bufsize
;
337 if (read_size
== 0) break;
338 nh
= (struct nlmsghdr
*)buff
;
339 for (nh
= (struct nlmsghdr
*)buff
;
340 NLMSG_OK(nh
, read_size
);
341 nh
= (struct nlmsghdr
*)NLMSG_NEXT(nh
, read_size
)){
342 if (nh
->nlmsg_pid
!= pid
||
343 nh
->nlmsg_seq
!= seq
)
345 if (nh
->nlmsg_type
== NLMSG_DONE
){
349 if (nh
->nlmsg_type
== NLMSG_ERROR
){
350 struct nlmsgerr
*nlerr
= (struct nlmsgerr
*)NLMSG_DATA(nh
);
352 if (nh
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
)))
355 __set_errno(-nlerr
->error
);
363 int saved_errno
= errno
;
365 __set_errno(saved_errno
);
367 *nlhp
= (struct nlmsghdr
*)buff
;
372 nl_getlist(int sd
, int seq
,
374 struct nlmsg_list
**nlm_list
,
375 struct nlmsg_list
**nlm_end
)
377 struct nlmsghdr
*nlh
= NULL
;
381 status
= nl_sendreq(sd
, request
, NLM_F_ROOT
|NLM_F_MATCH
, &seq
);
385 seq
= (int)time(NULL
);
387 status
= nl_getmsg(sd
, request
, seq
, &nlh
, &done
);
391 struct nlmsg_list
*nlm_next
= (struct nlmsg_list
*)malloc(sizeof(struct nlmsg_list
));
392 if (nlm_next
== NULL
){
393 int saved_errno
= errno
;
395 __set_errno(saved_errno
);
398 nlm_next
->nlm_next
= NULL
;
399 nlm_next
->nlh
= (struct nlmsghdr
*)nlh
;
400 nlm_next
->size
= status
;
402 if (*nlm_list
== NULL
){
403 *nlm_list
= nlm_next
;
406 (*nlm_end
)->nlm_next
= nlm_next
;
412 return status
>= 0 ? seq
: status
;
415 /* ---------------------------------------------------------------------- */
417 free_nlmsglist(struct nlmsg_list
*nlm0
)
419 struct nlmsg_list
*nlm
;
424 for (nlm
=nlm0
; nlm
; nlm
=nlm
->nlm_next
){
429 __set_errno(saved_errno
);
433 free_data(void *data
, void *ifdata
)
435 int saved_errno
= errno
;
436 if (data
!= NULL
) free(data
);
437 if (ifdata
!= NULL
) free(ifdata
);
438 __set_errno(saved_errno
);
441 /* ---------------------------------------------------------------------- */
445 int saved_errno
= errno
;
446 if (sd
>= 0) __close(sd
);
447 __set_errno(saved_errno
);
450 /* ---------------------------------------------------------------------- */
454 struct sockaddr_nl nladdr
;
457 sd
= socket(PF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
458 if (sd
< 0) return -1;
459 memset(&nladdr
, 0, sizeof(nladdr
));
460 nladdr
.nl_family
= AF_NETLINK
;
461 if (bind(sd
, (struct sockaddr
*)&nladdr
, sizeof(nladdr
)) < 0){
468 /* ====================================================================== */
469 int getifaddrs(struct ifaddrs
**ifap
)
472 struct nlmsg_list
*nlmsg_list
, *nlmsg_end
, *nlm
;
473 /* - - - - - - - - - - - - - - - */
475 size_t dlen
, xlen
, nlen
;
476 uint32_t max_ifindex
= 0;
478 pid_t pid
= getpid();
481 int build
; /* 0 or 1 */
483 /* ---------------------------------- */
485 icnt
= dlen
= xlen
= nlen
= 0;
486 nlmsg_list
= nlmsg_end
= NULL
;
491 /* ---------------------------------- */
492 /* open socket and bind */
497 /* ---------------------------------- */
499 if ((seq
= nl_getlist(sd
, 0, RTM_GETLINK
,
500 &nlmsg_list
, &nlmsg_end
)) < 0){
501 free_nlmsglist(nlmsg_list
);
505 if ((seq
= nl_getlist(sd
, seq
+1, RTM_GETADDR
,
506 &nlmsg_list
, &nlmsg_end
)) < 0){
507 free_nlmsglist(nlmsg_list
);
512 /* ---------------------------------- */
513 /* Estimate size of result buffer and fill it */
514 for (build
=0; build
<=1; build
++){
515 struct ifaddrs
*ifl
= NULL
, *ifa
= NULL
;
516 struct nlmsghdr
*nlh
, *nlh0
;
517 char *data
= NULL
, *xdata
= NULL
;
519 char *ifname
= NULL
, **iflist
= NULL
;
520 uint16_t *ifflist
= NULL
;
521 struct rtmaddr_ifamap ifamap
;
525 NLMSG_ALIGN(sizeof(struct ifaddrs
[icnt
]))
526 + dlen
+ xlen
+ nlen
);
527 ifa
= (struct ifaddrs
*)data
;
529 NLMSG_ALIGN(sizeof(char *[max_ifindex
+1]))
530 + NLMSG_ALIGN(sizeof(uint16_t [max_ifindex
+1])));
532 *ifap
= (ifdata
!= NULL
) ? ifa
: NULL
;
534 free_data(data
, ifdata
);
538 if (data
== NULL
|| ifdata
== NULL
){
539 free_data(data
, ifdata
);
544 data
+= NLMSG_ALIGN(sizeof(struct ifaddrs
)) * icnt
;
546 ifname
= xdata
+ xlen
;
548 ifflist
= (uint16_t *)(((char *)iflist
) + NLMSG_ALIGN(sizeof(char *[max_ifindex
+1])));
551 for (nlm
=nlmsg_list
; nlm
; nlm
=nlm
->nlm_next
){
552 int nlmlen
= nlm
->size
;
553 if (!(nlh0
= nlm
->nlh
))
556 NLMSG_OK(nlh
, nlmlen
);
557 nlh
=NLMSG_NEXT(nlh
,nlmlen
)){
558 struct ifinfomsg
*ifim
= NULL
;
559 struct ifaddrmsg
*ifam
= NULL
;
562 size_t nlm_struct_size
= 0;
563 sa_family_t nlm_family
= 0;
564 uint32_t nlm_scope
= 0, nlm_index
= 0;
565 size_t sockaddr_size
= 0;
566 uint32_t nlm_prefixlen
= 0;
569 memset(&ifamap
, 0, sizeof(ifamap
));
571 /* check if the message is what we want */
572 if (nlh
->nlmsg_pid
!= pid
||
573 nlh
->nlmsg_seq
!= nlm
->seq
)
575 if (nlh
->nlmsg_type
== NLMSG_DONE
){
578 switch (nlh
->nlmsg_type
){
580 ifim
= (struct ifinfomsg
*)NLMSG_DATA(nlh
);
581 nlm_struct_size
= sizeof(*ifim
);
582 nlm_family
= ifim
->ifi_family
;
584 nlm_index
= ifim
->ifi_index
;
587 ifflist
[nlm_index
] = ifa
->ifa_flags
= ifim
->ifi_flags
;
590 ifam
= (struct ifaddrmsg
*)NLMSG_DATA(nlh
);
591 nlm_struct_size
= sizeof(*ifam
);
592 nlm_family
= ifam
->ifa_family
;
593 nlm_scope
= ifam
->ifa_scope
;
594 nlm_index
= ifam
->ifa_index
;
595 nlm_prefixlen
= ifam
->ifa_prefixlen
;
597 ifa
->ifa_flags
= ifflist
[nlm_index
];
604 if (max_ifindex
< nlm_index
)
605 max_ifindex
= nlm_index
;
611 rtasize
= NLMSG_PAYLOAD(nlh
, nlmlen
) - NLMSG_ALIGN(nlm_struct_size
);
612 for (rta
= (struct rtattr
*)(((char *)NLMSG_DATA(nlh
)) + NLMSG_ALIGN(nlm_struct_size
));
613 RTA_OK(rta
, rtasize
);
614 rta
= RTA_NEXT(rta
, rtasize
)){
615 struct sockaddr
**sap
= NULL
;
616 void *rtadata
= RTA_DATA(rta
);
617 size_t rtapayload
= RTA_PAYLOAD(rta
);
620 switch(nlh
->nlmsg_type
){
622 switch(rta
->rta_type
){
626 sap
= (rta
->rta_type
== IFLA_ADDRESS
) ? &ifa
->ifa_addr
: &ifa
->ifa_broadaddr
;
627 *sap
= (struct sockaddr
*)data
;
629 sa_len
= ifa_sa_len(AF_PACKET
, rtapayload
);
630 if (rta
->rta_type
== IFLA_ADDRESS
)
631 sockaddr_size
= NLMSG_ALIGN(sa_len
);
633 dlen
+= NLMSG_ALIGN(sa_len
);
635 memset(*sap
, 0, sa_len
);
636 ifa_make_sockaddr(AF_PACKET
, *sap
, rtadata
,rtapayload
, 0,0);
637 ((struct sockaddr_ll
*)*sap
)->sll_ifindex
= nlm_index
;
638 ((struct sockaddr_ll
*)*sap
)->sll_hatype
= ifim
->ifi_type
;
639 data
+= NLMSG_ALIGN(sa_len
);
642 case IFLA_IFNAME
:/* Name of Interface */
644 nlen
+= NLMSG_ALIGN(rtapayload
+ 1);
646 ifa
->ifa_name
= ifname
;
647 if (iflist
[nlm_index
] == NULL
)
648 iflist
[nlm_index
] = ifa
->ifa_name
;
649 strncpy(ifa
->ifa_name
, rtadata
, rtapayload
);
650 ifa
->ifa_name
[rtapayload
] = '\0';
651 ifname
+= NLMSG_ALIGN(rtapayload
+ 1);
654 case IFLA_STATS
:/* Statistics of Interface */
656 xlen
+= NLMSG_ALIGN(rtapayload
);
658 ifa
->ifa_data
= xdata
;
659 memcpy(ifa
->ifa_data
, rtadata
, rtapayload
);
660 xdata
+= NLMSG_ALIGN(rtapayload
);
675 if (nlm_family
== AF_PACKET
) break;
676 switch(rta
->rta_type
){
678 ifamap
.address
= rtadata
;
679 ifamap
.address_len
= rtapayload
;
682 ifamap
.local
= rtadata
;
683 ifamap
.local_len
= rtapayload
;
686 ifamap
.broadcast
= rtadata
;
687 ifamap
.broadcast_len
= rtapayload
;
689 #ifdef HAVE_IFADDRS_IFA_ANYCAST
691 ifamap
.anycast
= rtadata
;
692 ifamap
.anycast_len
= rtapayload
;
697 nlen
+= NLMSG_ALIGN(rtapayload
+ 1);
699 ifa
->ifa_name
= ifname
;
700 if (iflist
[nlm_index
] == NULL
)
701 iflist
[nlm_index
] = ifname
;
702 strncpy(ifa
->ifa_name
, rtadata
, rtapayload
);
703 ifa
->ifa_name
[rtapayload
] = '\0';
704 ifname
+= NLMSG_ALIGN(rtapayload
+ 1);
715 if (nlh
->nlmsg_type
== RTM_NEWADDR
&&
716 nlm_family
!= AF_PACKET
) {
718 ifamap
.local
= ifamap
.address
;
719 ifamap
.local_len
= ifamap
.address_len
;
721 if (!ifamap
.address
) {
722 ifamap
.address
= ifamap
.local
;
723 ifamap
.address_len
= ifamap
.local_len
;
725 if (ifamap
.address_len
!= ifamap
.local_len
||
726 (ifamap
.address
!= NULL
&&
727 memcmp(ifamap
.address
, ifamap
.local
, ifamap
.address_len
))) {
728 /* p2p; address is peer and local is ours */
729 ifamap
.broadcast
= ifamap
.address
;
730 ifamap
.broadcast_len
= ifamap
.address_len
;
731 ifamap
.address
= ifamap
.local
;
732 ifamap
.address_len
= ifamap
.local_len
;
734 if (ifamap
.address
) {
736 sockaddr_size
= NLMSG_ALIGN(ifa_sa_len(nlm_family
,ifamap
.address_len
));
739 dlen
+= NLMSG_ALIGN(ifa_sa_len(nlm_family
,ifamap
.address_len
));
741 ifa
->ifa_addr
= (struct sockaddr
*)data
;
742 ifa_make_sockaddr(nlm_family
, ifa
->ifa_addr
, ifamap
.address
, ifamap
.address_len
,
743 nlm_scope
, nlm_index
);
744 data
+= NLMSG_ALIGN(ifa_sa_len(nlm_family
, ifamap
.address_len
));
748 if (ifamap
.netmask
) {
750 dlen
+= NLMSG_ALIGN(ifa_sa_len(nlm_family
,ifamap
.netmask_len
));
752 ifa
->ifa_netmask
= (struct sockaddr
*)data
;
753 ifa_make_sockaddr(nlm_family
, ifa
->ifa_netmask
, ifamap
.netmask
, ifamap
.netmask_len
,
754 nlm_scope
, nlm_index
);
755 data
+= NLMSG_ALIGN(ifa_sa_len(nlm_family
, ifamap
.netmask_len
));
759 if (ifamap
.broadcast
) {
761 dlen
+= NLMSG_ALIGN(ifa_sa_len(nlm_family
,ifamap
.broadcast_len
));
763 ifa
->ifa_broadaddr
= (struct sockaddr
*)data
;
764 ifa_make_sockaddr(nlm_family
, ifa
->ifa_broadaddr
, ifamap
.broadcast
, ifamap
.broadcast_len
,
765 nlm_scope
, nlm_index
);
766 data
+= NLMSG_ALIGN(ifa_sa_len(nlm_family
, ifamap
.broadcast_len
));
769 #ifdef HAVE_IFADDRS_IFA_ANYCAST
770 if (ifamap
.anycast
) {
772 dlen
+= NLMSG_ALIGN(ifa_sa_len(nlm_family
,ifamap
.anycast_len
));
774 ifa
->ifa_anycast
= (struct sockaddr
*)data
;
775 ifa_make_sockaddr(nlm_family
, ifa
->ifa_anyaddr
, ifamap
.anycast
, ifamap
.anycast_len
,
776 nlm_scope
, nlm_index
);
777 data
+= NLMSG_ALIGN(ifa_sa_len(nlm_family
, ifamap
.anycast_len
));
784 dlen
+= sockaddr_size
;
788 if (ifa
->ifa_name
== NULL
)
789 ifa
->ifa_name
= iflist
[nlm_index
];
792 ifa
->ifa_addr
->sa_family
!= AF_UNSPEC
&&
793 ifa
->ifa_addr
->sa_family
!= AF_PACKET
){
794 ifa
->ifa_netmask
= (struct sockaddr
*)data
;
795 ifa_make_sockaddr_mask(ifa
->ifa_addr
->sa_family
, ifa
->ifa_netmask
, nlm_prefixlen
);
797 data
+= sockaddr_size
;
804 if (icnt
== 0 && (dlen
+ nlen
+ xlen
== 0)){
807 break; /* cannot found any addresses */
811 free_data(NULL
, ifdata
);
814 /* ---------------------------------- */
816 free_nlmsglist(nlmsg_list
);
821 /* ---------------------------------------------------------------------- */
823 freeifaddrs(struct ifaddrs
*ifa
)
829 #else /* !AF_NETLINK */
832 * The generic SIOCGIFCONF version.
836 getifaddrs2(struct ifaddrs
**ifap
,
837 int af
, int siocgifconf
, int siocgifflags
,
844 struct ifconf ifconf
;
847 struct sockaddr sa_zero
;
849 struct ifaddrs
*start
= NULL
, **end
= &start
;
853 memset (&sa_zero
, 0, sizeof(sa_zero
));
854 fd
= socket(af
, SOCK_DGRAM
, 0);
860 buf
= calloc(1, buf_size
);
865 ifconf
.ifc_len
= buf_size
;
866 ifconf
.ifc_buf
= buf
;
869 * Solaris returns EINVAL when the buffer is too small.
871 if (ioctl (fd
, siocgifconf
, &ifconf
) < 0 && errno
!= EINVAL
) {
876 * Can the difference between a full and a overfull buf
880 if (ifconf
.ifc_len
< buf_size
)
886 for (p
= ifconf
.ifc_buf
;
887 p
< ifconf
.ifc_buf
+ ifconf
.ifc_len
;
893 ifr
= (struct ifreq
*)p
;
897 salen
= sizeof(struct sockaddr
);
898 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
900 sz
= max(sz
, sizeof(ifr
->ifr_name
) + sa
->sa_len
);
904 sz
= max(sz
, sizeof(ifr
->ifr_name
) + SA_LEN(sa
));
906 memset (&ifreq
, 0, sizeof(ifreq
));
907 memcpy (ifreq
.ifr_name
, ifr
->ifr_name
, sizeof(ifr
->ifr_name
));
909 if (ioctl(fd
, siocgifflags
, &ifreq
) < 0) {
914 *end
= malloc(sizeof(**end
));
920 (*end
)->ifa_next
= NULL
;
921 (*end
)->ifa_name
= strdup(ifr
->ifr_name
);
922 (*end
)->ifa_flags
= ifreq
.ifr_flags
;
923 (*end
)->ifa_addr
= malloc(salen
);
924 memcpy((*end
)->ifa_addr
, sa
, salen
);
925 (*end
)->ifa_netmask
= NULL
;
928 /* fix these when we actually need them */
929 if(ifreq
.ifr_flags
& IFF_BROADCAST
) {
930 (*end
)->ifa_broadaddr
= malloc(sizeof(ifr
->ifr_broadaddr
));
931 memcpy((*end
)->ifa_broadaddr
, &ifr
->ifr_broadaddr
,
932 sizeof(ifr
->ifr_broadaddr
));
933 } else if(ifreq
.ifr_flags
& IFF_POINTOPOINT
) {
934 (*end
)->ifa_dstaddr
= malloc(sizeof(ifr
->ifr_dstaddr
));
935 memcpy((*end
)->ifa_dstaddr
, &ifr
->ifr_dstaddr
,
936 sizeof(ifr
->ifr_dstaddr
));
938 (*end
)->ifa_dstaddr
= NULL
;
940 (*end
)->ifa_dstaddr
= NULL
;
943 (*end
)->ifa_data
= NULL
;
945 end
= &(*end
)->ifa_next
;
960 #if defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS)
962 getlifaddrs2(struct ifaddrs
**ifap
,
963 int af
, int siocgifconf
, int siocgifflags
,
970 struct lifconf ifconf
;
973 struct sockaddr sa_zero
;
975 struct ifaddrs
*start
= NULL
, **end
= &start
;
979 memset (&sa_zero
, 0, sizeof(sa_zero
));
980 fd
= socket(af
, SOCK_DGRAM
, 0);
986 buf
= calloc(1, buf_size
);
991 ifconf
.lifc_family
= AF_UNSPEC
;
992 ifconf
.lifc_flags
= 0;
993 ifconf
.lifc_len
= buf_size
;
994 ifconf
.lifc_buf
= buf
;
997 * Solaris returns EINVAL when the buffer is too small.
999 if (ioctl (fd
, siocgifconf
, &ifconf
) < 0 && errno
!= EINVAL
) {
1004 * Can the difference between a full and a overfull buf
1008 if (ifconf
.lifc_len
< buf_size
)
1014 for (p
= ifconf
.lifc_buf
;
1015 p
< ifconf
.lifc_buf
+ ifconf
.lifc_len
;
1017 struct lifreq ifreq
;
1018 struct sockaddr_storage
*sa
;
1021 ifr
= (struct lifreq
*)p
;
1022 sa
= &ifr
->lifr_addr
;
1025 salen
= sizeof(struct sockaddr_storage
);
1026 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
1028 sz
= max(sz
, sizeof(ifr
->ifr_name
) + sa
->sa_len
);
1032 sz
= max(sz
, sizeof(ifr
->ifr_name
) + SA_LEN(sa
));
1034 memset (&ifreq
, 0, sizeof(ifreq
));
1035 memcpy (ifreq
.lifr_name
, ifr
->lifr_name
, sizeof(ifr
->lifr_name
));
1037 if (ioctl(fd
, siocgifflags
, &ifreq
) < 0) {
1042 *end
= malloc(sizeof(**end
));
1044 (*end
)->ifa_next
= NULL
;
1045 (*end
)->ifa_name
= strdup(ifr
->lifr_name
);
1046 (*end
)->ifa_flags
= ifreq
.lifr_flags
;
1047 (*end
)->ifa_addr
= malloc(salen
);
1048 memcpy((*end
)->ifa_addr
, sa
, salen
);
1049 (*end
)->ifa_netmask
= NULL
;
1052 /* fix these when we actually need them */
1053 if(ifreq
.ifr_flags
& IFF_BROADCAST
) {
1054 (*end
)->ifa_broadaddr
= malloc(sizeof(ifr
->ifr_broadaddr
));
1055 memcpy((*end
)->ifa_broadaddr
, &ifr
->ifr_broadaddr
,
1056 sizeof(ifr
->ifr_broadaddr
));
1057 } else if(ifreq
.ifr_flags
& IFF_POINTOPOINT
) {
1058 (*end
)->ifa_dstaddr
= malloc(sizeof(ifr
->ifr_dstaddr
));
1059 memcpy((*end
)->ifa_dstaddr
, &ifr
->ifr_dstaddr
,
1060 sizeof(ifr
->ifr_dstaddr
));
1062 (*end
)->ifa_dstaddr
= NULL
;
1064 (*end
)->ifa_dstaddr
= NULL
;
1067 (*end
)->ifa_data
= NULL
;
1069 end
= &(*end
)->ifa_next
;
1083 #endif /* defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS) */
1086 getifaddrs(struct ifaddrs
**ifap
)
1090 #if defined(AF_INET6) && defined(SIOCGIF6CONF) && defined(SIOCGIF6FLAGS)
1092 ret
= getifaddrs2 (ifap
, AF_INET6
, SIOCGIF6CONF
, SIOCGIF6FLAGS
,
1093 sizeof(struct in6_ifreq
));
1095 #if defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS)
1097 ret
= getlifaddrs2 (ifap
, AF_INET6
, SIOCGLIFCONF
, SIOCGLIFFLAGS
,
1098 sizeof(struct lifreq
));
1100 #if defined(HAVE_IPV6) && defined(SIOCGIFCONF)
1102 ret
= getifaddrs2 (ifap
, AF_INET6
, SIOCGIFCONF
, SIOCGIFFLAGS
,
1103 sizeof(struct ifreq
));
1105 #if defined(AF_INET) && defined(SIOCGIFCONF) && defined(SIOCGIFFLAGS)
1107 ret
= getifaddrs2 (ifap
, AF_INET
, SIOCGIFCONF
, SIOCGIFFLAGS
,
1108 sizeof(struct ifreq
));
1114 freeifaddrs(struct ifaddrs
*ifp
)
1116 struct ifaddrs
*p
, *q
;
1123 free(p
->ifa_dstaddr
);
1125 free(p
->ifa_netmask
);
1134 #endif /* !AF_NETLINK */
1139 print_addr(const char *s
, struct sockaddr
*sa
)
1142 printf(" %s=%d/", s
, sa
->sa_family
);
1143 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
1144 for(i
= 0; i
< sa
->sa_len
- ((long)sa
->sa_data
- (long)&sa
->sa_family
); i
++)
1145 printf("%02x", ((unsigned char*)sa
->sa_data
)[i
]);
1147 for(i
= 0; i
< sizeof(sa
->sa_data
); i
++)
1148 printf("%02x", ((unsigned char*)sa
->sa_data
)[i
]);
1154 print_ifaddrs(struct ifaddrs
*x
)
1158 for(p
= x
; p
; p
= p
->ifa_next
) {
1159 printf("%s\n", p
->ifa_name
);
1160 printf(" flags=%x\n", p
->ifa_flags
);
1162 print_addr("addr", p
->ifa_addr
);
1164 print_addr("dstaddr", p
->ifa_dstaddr
);
1166 print_addr("netmask", p
->ifa_netmask
);
1167 printf(" %p\n", p
->ifa_data
);
1174 struct ifaddrs
*a
= NULL
, *b
;
1175 getifaddrs2(&a
, AF_INET
, SIOCGIFCONF
, SIOCGIFFLAGS
, sizeof(struct ifreq
));