2 * Copyright (c) 2000 - 2002, 2005 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
46 #ifdef HAVE_SYS_SOCKIO_H
47 #include <sys/sockio.h>
48 #endif /* HAVE_SYS_SOCKIO_H */
50 #ifdef HAVE_NETINET_IN6_VAR_H
51 #include <netinet/in6_var.h>
52 #endif /* HAVE_NETINET_IN6_VAR_H */
57 #define lifconf if_laddrconf
58 #define lifc_len iflc_len
59 #define lifc_buf iflc_buf
60 #define lifc_req iflc_req
62 #define lifreq if_laddrreq
63 #define lifr_addr iflr_addr
64 #define lifr_name iflr_name
65 #define lifr_dstaddr iflr_dstaddr
66 #define lifr_broadaddr iflr_broadaddr
67 #define lifr_flags iflr_flags
68 #define lifr_index iflr_index
74 * The linux - AF_NETLINK version of getifaddrs - from Usagi.
75 * Linux does not return v6 addresses from SIOCGIFCONF.
78 /* $USAGI: ifaddrs.c,v 1.18 2002/03/06 01:50:46 yoshfuji Exp $ */
80 /**************************************************************************
82 * Copyright (C)2000 Hideaki YOSHIFUJI, All Rights Reserved.
84 * Redistribution and use in source and binary forms, with or without
85 * modification, are permitted provided that the following conditions
87 * 1. Redistributions of source code must retain the above copyright
88 * notice, this list of conditions and the following disclaimer.
89 * 2. Redistributions in binary form must reproduce the above copyright
90 * notice, this list of conditions and the following disclaimer in the
91 * documentation and/or other materials provided with the distribution.
92 * 3. Neither the name of the author nor the names of its contributors
93 * may be used to endorse or promote products derived from this software
94 * without specific prior written permission.
96 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
97 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
98 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
99 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
100 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
101 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
102 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
103 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
104 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
105 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
117 #include <sys/socket.h>
118 #include <asm/types.h>
119 #include <linux/netlink.h>
120 #include <linux/rtnetlink.h>
121 #include <sys/types.h>
122 #include <sys/socket.h>
123 #include <sys/poll.h>
124 #include <netpacket/packet.h>
125 #include <net/ethernet.h> /* the L2 protocols */
128 #include <net/if_arp.h>
130 #include <netinet/in.h>
132 #define __set_errno(e) (errno = (e))
133 #define __close(fd) (close(fd))
135 #define ifa_broadaddr ifa_dstaddr
138 /* ====================================================================== */
140 struct nlmsg_list
*nlm_next
;
141 struct nlmsghdr
*nlh
;
146 struct rtmaddr_ifamap
{
153 #ifdef HAVE_IFADDRS_IFA_ANYCAST
162 #ifdef HAVE_IFADDRS_IFA_ANYCAST
167 /* ====================================================================== */
169 ifa_sa_len(sa_family_t family
, int len
)
174 size
= sizeof(struct sockaddr_in
);
177 size
= sizeof(struct sockaddr_in6
);
180 size
= (size_t)(((struct sockaddr_ll
*)NULL
)->sll_addr
) + len
;
181 if (size
< sizeof(struct sockaddr_ll
))
182 size
= sizeof(struct sockaddr_ll
);
185 size
= (size_t)(((struct sockaddr
*)NULL
)->sa_data
) + len
;
186 if (size
< sizeof(struct sockaddr
))
187 size
= sizeof(struct sockaddr
);
194 ifa_make_sockaddr(sa_family_t family
,
197 uint32_t scope
, uint32_t scopeid
)
199 if (sa
== NULL
) return;
202 memcpy(&((struct sockaddr_in
*)sa
)->sin_addr
, (char *)p
, len
);
205 memcpy(&((struct sockaddr_in6
*)sa
)->sin6_addr
, (char *)p
, len
);
206 if (IN6_IS_ADDR_LINKLOCAL(p
) ||
207 IN6_IS_ADDR_MC_LINKLOCAL(p
)){
208 ((struct sockaddr_in6
*)sa
)->sin6_scope_id
= scopeid
;
212 memcpy(((struct sockaddr_ll
*)sa
)->sll_addr
, (char *)p
, len
);
213 ((struct sockaddr_ll
*)sa
)->sll_halen
= len
;
216 memcpy(sa
->sa_data
, p
, len
); /*XXX*/
219 sa
->sa_family
= family
;
220 #ifdef HAVE_SOCKADDR_SA_LEN
221 sa
->sa_len
= ifa_sa_len(family
, len
);
226 static struct sockaddr
*
227 ifa_make_sockaddr_mask(sa_family_t family
,
233 uint32_t max_prefixlen
= 0;
235 if (sa
== NULL
) return NULL
;
238 memset(&((struct sockaddr_in
*)sa
)->sin_addr
, 0, sizeof(((struct sockaddr_in
*)sa
)->sin_addr
));
239 p
= (char *)&((struct sockaddr_in
*)sa
)->sin_addr
;
243 memset(&((struct sockaddr_in6
*)sa
)->sin6_addr
, 0, sizeof(((struct sockaddr_in6
*)sa
)->sin6_addr
));
244 p
= (char *)&((struct sockaddr_in6
*)sa
)->sin6_addr
;
245 #if 0 /* XXX: fill scope-id? */
246 if (IN6_IS_ADDR_LINKLOCAL(p
) ||
247 IN6_IS_ADDR_MC_LINKLOCAL(p
)){
248 ((struct sockaddr_in6
*)sa
)->sin6_scope_id
= scopeid
;
256 sa
->sa_family
= family
;
257 #ifdef HAVE_SOCKADDR_SA_LEN
258 sa
->sa_len
= ifa_sa_len(family
, len
);
261 if (prefixlen
> max_prefixlen
)
262 prefixlen
= max_prefixlen
;
263 for (i
=0; i
<(prefixlen
/ 8); i
++)
266 c
<<= (8 - (prefixlen
% 8));
273 /* ====================================================================== */
275 nl_sendreq(int sd
, int request
, int flags
, int *seq
)
277 char reqbuf
[NLMSG_ALIGN(sizeof(struct nlmsghdr
)) +
278 NLMSG_ALIGN(sizeof(struct rtgenmsg
))];
279 struct sockaddr_nl nladdr
;
280 struct nlmsghdr
*req_hdr
;
281 struct rtgenmsg
*req_msg
;
282 time_t t
= time(NULL
);
285 memset(&reqbuf
, 0, sizeof(reqbuf
));
286 req_hdr
= (struct nlmsghdr
*)reqbuf
;
287 req_msg
= (struct rtgenmsg
*)NLMSG_DATA(req_hdr
);
288 req_hdr
->nlmsg_len
= NLMSG_LENGTH(sizeof(*req_msg
));
289 req_hdr
->nlmsg_type
= request
;
290 req_hdr
->nlmsg_flags
= flags
| NLM_F_REQUEST
;
291 req_hdr
->nlmsg_pid
= 0;
292 req_hdr
->nlmsg_seq
= t
;
293 req_msg
->rtgen_family
= AF_UNSPEC
;
294 memset(&nladdr
, 0, sizeof(nladdr
));
295 nladdr
.nl_family
= AF_NETLINK
;
296 return (sendto(sd
, (void *)req_hdr
, req_hdr
->nlmsg_len
, 0,
297 (struct sockaddr
*)&nladdr
, sizeof(nladdr
)));
301 nl_recvmsg(int sd
, int request
, int seq
,
302 void *buf
, size_t buflen
,
306 struct iovec iov
= { buf
, buflen
};
307 struct sockaddr_nl nladdr
;
311 msg
.msg_name
= (void *)&nladdr
;
312 msg
.msg_namelen
= sizeof(nladdr
);
315 msg
.msg_control
= NULL
;
316 msg
.msg_controllen
= 0;
318 read_len
= recvmsg(sd
, &msg
, 0);
319 if ((read_len
< 0 && errno
== EINTR
) || (msg
.msg_flags
& MSG_TRUNC
))
321 if (flags
) *flags
= msg
.msg_flags
;
328 nl_getmsg(int sd
, int request
, int seq
,
329 struct nlmsghdr
**nlhp
,
333 size_t bufsize
= 65536, lastbufsize
= 0;
335 int result
= 0, read_size
;
337 pid_t pid
= getpid();
339 void *newbuff
= realloc(buff
, bufsize
);
340 if (newbuff
== NULL
|| bufsize
< lastbufsize
) {
345 result
= read_size
= nl_recvmsg(sd
, request
, seq
, buff
, bufsize
, &msg_flags
);
346 if (read_size
< 0 || (msg_flags
& MSG_TRUNC
)){
347 lastbufsize
= bufsize
;
351 if (read_size
== 0) break;
352 nh
= (struct nlmsghdr
*)buff
;
353 for (nh
= (struct nlmsghdr
*)buff
;
354 NLMSG_OK(nh
, read_size
);
355 nh
= (struct nlmsghdr
*)NLMSG_NEXT(nh
, read_size
)){
356 if (nh
->nlmsg_pid
!= pid
||
357 nh
->nlmsg_seq
!= seq
)
359 if (nh
->nlmsg_type
== NLMSG_DONE
){
363 if (nh
->nlmsg_type
== NLMSG_ERROR
){
364 struct nlmsgerr
*nlerr
= (struct nlmsgerr
*)NLMSG_DATA(nh
);
366 if (nh
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
)))
369 __set_errno(-nlerr
->error
);
377 int saved_errno
= errno
;
379 __set_errno(saved_errno
);
381 *nlhp
= (struct nlmsghdr
*)buff
;
386 nl_getlist(int sd
, int seq
,
388 struct nlmsg_list
**nlm_list
,
389 struct nlmsg_list
**nlm_end
)
391 struct nlmsghdr
*nlh
= NULL
;
397 status
= nl_sendreq(sd
, request
, NLM_F_ROOT
|NLM_F_MATCH
, &seq
);
401 seq
= (int)time(NULL
);
406 pfd
.events
= POLLIN
| POLLPRI
;
408 status
= poll(&pfd
, 1, 1000);
411 else if (status
== 0) {
418 status
= nl_getmsg(sd
, request
, seq
, &nlh
, &done
);
422 struct nlmsg_list
*nlm_next
= (struct nlmsg_list
*)malloc(sizeof(struct nlmsg_list
));
423 if (nlm_next
== NULL
){
424 int saved_errno
= errno
;
426 __set_errno(saved_errno
);
429 nlm_next
->nlm_next
= NULL
;
430 nlm_next
->nlh
= (struct nlmsghdr
*)nlh
;
431 nlm_next
->size
= status
;
433 if (*nlm_list
== NULL
){
434 *nlm_list
= nlm_next
;
437 (*nlm_end
)->nlm_next
= nlm_next
;
443 return status
>= 0 ? seq
: status
;
446 /* ---------------------------------------------------------------------- */
448 free_nlmsglist(struct nlmsg_list
*nlm0
)
450 struct nlmsg_list
*nlm
, *nlm_next
;
455 for (nlm
=nlm0
; nlm
; nlm
=nlm_next
){
458 nlm_next
=nlm
->nlm_next
;
461 __set_errno(saved_errno
);
465 free_data(void *data
, void *ifdata
)
467 int saved_errno
= errno
;
468 if (data
!= NULL
) free(data
);
469 if (ifdata
!= NULL
) free(ifdata
);
470 __set_errno(saved_errno
);
473 /* ---------------------------------------------------------------------- */
477 int saved_errno
= errno
;
478 if (sd
>= 0) __close(sd
);
479 __set_errno(saved_errno
);
482 /* ---------------------------------------------------------------------- */
486 struct sockaddr_nl nladdr
;
489 sd
= socket(PF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
490 if (sd
< 0) return -1;
491 memset(&nladdr
, 0, sizeof(nladdr
));
492 nladdr
.nl_family
= AF_NETLINK
;
493 if (bind(sd
, (struct sockaddr
*)&nladdr
, sizeof(nladdr
)) < 0){
500 /* ====================================================================== */
501 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
502 rk_getifaddrs(struct ifaddrs
**ifap
)
505 struct nlmsg_list
*nlmsg_list
, *nlmsg_end
, *nlm
;
506 /* - - - - - - - - - - - - - - - */
508 size_t dlen
, xlen
, nlen
;
509 uint32_t max_ifindex
= 0;
511 pid_t pid
= getpid();
514 int build
; /* 0 or 1 */
516 /* ---------------------------------- */
518 icnt
= dlen
= xlen
= nlen
= 0;
519 nlmsg_list
= nlmsg_end
= NULL
;
524 /* ---------------------------------- */
525 /* open socket and bind */
530 /* ---------------------------------- */
532 if ((seq
= nl_getlist(sd
, 0, RTM_GETLINK
,
533 &nlmsg_list
, &nlmsg_end
)) < 0){
534 free_nlmsglist(nlmsg_list
);
538 if ((seq
= nl_getlist(sd
, seq
+1, RTM_GETADDR
,
539 &nlmsg_list
, &nlmsg_end
)) < 0){
540 free_nlmsglist(nlmsg_list
);
545 /* ---------------------------------- */
546 /* Estimate size of result buffer and fill it */
547 for (build
=0; build
<=1; build
++){
548 struct ifaddrs
*ifl
= NULL
, *ifa
= NULL
;
549 struct nlmsghdr
*nlh
, *nlh0
;
550 char *data
= NULL
, *xdata
= NULL
;
552 char *ifname
= NULL
, **iflist
= NULL
;
553 uint16_t *ifflist
= NULL
;
554 struct rtmaddr_ifamap ifamap
;
558 NLMSG_ALIGN(sizeof(struct ifaddrs
[icnt
]))
559 + dlen
+ xlen
+ nlen
);
560 ifa
= (struct ifaddrs
*)data
;
562 NLMSG_ALIGN(sizeof(char *[max_ifindex
+1]))
563 + NLMSG_ALIGN(sizeof(uint16_t [max_ifindex
+1])));
565 *ifap
= (ifdata
!= NULL
) ? ifa
: NULL
;
567 free_data(data
, ifdata
);
571 if (data
== NULL
|| ifdata
== NULL
){
572 free_data(data
, ifdata
);
577 data
+= NLMSG_ALIGN(sizeof(struct ifaddrs
)) * icnt
;
579 ifname
= xdata
+ xlen
;
581 ifflist
= (uint16_t *)(((char *)iflist
) + NLMSG_ALIGN(sizeof(char *[max_ifindex
+1])));
584 for (nlm
=nlmsg_list
; nlm
; nlm
=nlm
->nlm_next
){
585 int nlmlen
= nlm
->size
;
586 if (!(nlh0
= nlm
->nlh
))
589 NLMSG_OK(nlh
, nlmlen
);
590 nlh
=NLMSG_NEXT(nlh
,nlmlen
)){
591 struct ifinfomsg
*ifim
= NULL
;
592 struct ifaddrmsg
*ifam
= NULL
;
595 size_t nlm_struct_size
= 0;
596 sa_family_t nlm_family
= 0;
597 uint32_t nlm_scope
= 0, nlm_index
= 0;
598 size_t sockaddr_size
= 0;
599 uint32_t nlm_prefixlen
= 0;
602 memset(&ifamap
, 0, sizeof(ifamap
));
604 /* check if the message is what we want */
605 if (nlh
->nlmsg_pid
!= pid
||
606 nlh
->nlmsg_seq
!= nlm
->seq
)
608 if (nlh
->nlmsg_type
== NLMSG_DONE
){
611 switch (nlh
->nlmsg_type
){
613 ifim
= (struct ifinfomsg
*)NLMSG_DATA(nlh
);
614 nlm_struct_size
= sizeof(*ifim
);
615 nlm_family
= ifim
->ifi_family
;
617 nlm_index
= ifim
->ifi_index
;
620 ifflist
[nlm_index
] = ifa
->ifa_flags
= ifim
->ifi_flags
;
623 ifam
= (struct ifaddrmsg
*)NLMSG_DATA(nlh
);
624 nlm_struct_size
= sizeof(*ifam
);
625 nlm_family
= ifam
->ifa_family
;
626 nlm_scope
= ifam
->ifa_scope
;
627 nlm_index
= ifam
->ifa_index
;
628 nlm_prefixlen
= ifam
->ifa_prefixlen
;
630 ifa
->ifa_flags
= ifflist
[nlm_index
];
637 if (max_ifindex
< nlm_index
)
638 max_ifindex
= nlm_index
;
644 rtasize
= NLMSG_PAYLOAD(nlh
, nlmlen
) - NLMSG_ALIGN(nlm_struct_size
);
645 for (rta
= (struct rtattr
*)(((char *)NLMSG_DATA(nlh
)) + NLMSG_ALIGN(nlm_struct_size
));
646 RTA_OK(rta
, rtasize
);
647 rta
= RTA_NEXT(rta
, rtasize
)){
648 struct sockaddr
**sap
= NULL
;
649 void *rtadata
= RTA_DATA(rta
);
650 size_t rtapayload
= RTA_PAYLOAD(rta
);
653 switch(nlh
->nlmsg_type
){
655 switch(rta
->rta_type
){
659 sap
= (rta
->rta_type
== IFLA_ADDRESS
) ? &ifa
->ifa_addr
: &ifa
->ifa_broadaddr
;
660 *sap
= (struct sockaddr
*)data
;
662 sa_len
= ifa_sa_len(AF_PACKET
, rtapayload
);
663 if (rta
->rta_type
== IFLA_ADDRESS
)
664 sockaddr_size
= NLMSG_ALIGN(sa_len
);
666 dlen
+= NLMSG_ALIGN(sa_len
);
668 memset(*sap
, 0, sa_len
);
669 ifa_make_sockaddr(AF_PACKET
, *sap
, rtadata
,rtapayload
, 0,0);
670 ((struct sockaddr_ll
*)*sap
)->sll_ifindex
= nlm_index
;
671 ((struct sockaddr_ll
*)*sap
)->sll_hatype
= ifim
->ifi_type
;
672 data
+= NLMSG_ALIGN(sa_len
);
675 case IFLA_IFNAME
:/* Name of Interface */
677 nlen
+= NLMSG_ALIGN(rtapayload
+ 1);
679 ifa
->ifa_name
= ifname
;
680 if (iflist
[nlm_index
] == NULL
)
681 iflist
[nlm_index
] = ifa
->ifa_name
;
682 strncpy(ifa
->ifa_name
, rtadata
, rtapayload
);
683 ifa
->ifa_name
[rtapayload
] = '\0';
684 ifname
+= NLMSG_ALIGN(rtapayload
+ 1);
687 case IFLA_STATS
:/* Statistics of Interface */
689 xlen
+= NLMSG_ALIGN(rtapayload
);
691 ifa
->ifa_data
= xdata
;
692 memcpy(ifa
->ifa_data
, rtadata
, rtapayload
);
693 xdata
+= NLMSG_ALIGN(rtapayload
);
709 if (nlm_family
== AF_PACKET
) break;
710 switch(rta
->rta_type
){
712 ifamap
.address
= rtadata
;
713 ifamap
.address_len
= rtapayload
;
716 ifamap
.local
= rtadata
;
717 ifamap
.local_len
= rtapayload
;
720 ifamap
.broadcast
= rtadata
;
721 ifamap
.broadcast_len
= rtapayload
;
723 #ifdef HAVE_IFADDRS_IFA_ANYCAST
725 ifamap
.anycast
= rtadata
;
726 ifamap
.anycast_len
= rtapayload
;
731 nlen
+= NLMSG_ALIGN(rtapayload
+ 1);
733 ifa
->ifa_name
= ifname
;
734 if (iflist
[nlm_index
] == NULL
)
735 iflist
[nlm_index
] = ifname
;
736 strncpy(ifa
->ifa_name
, rtadata
, rtapayload
);
737 ifa
->ifa_name
[rtapayload
] = '\0';
738 ifname
+= NLMSG_ALIGN(rtapayload
+ 1);
750 if (nlh
->nlmsg_type
== RTM_NEWADDR
&&
751 nlm_family
!= AF_PACKET
) {
753 ifamap
.local
= ifamap
.address
;
754 ifamap
.local_len
= ifamap
.address_len
;
756 if (!ifamap
.address
) {
757 ifamap
.address
= ifamap
.local
;
758 ifamap
.address_len
= ifamap
.local_len
;
760 if (ifamap
.address_len
!= ifamap
.local_len
||
761 (ifamap
.address
!= NULL
&&
762 memcmp(ifamap
.address
, ifamap
.local
, ifamap
.address_len
))) {
763 /* p2p; address is peer and local is ours */
764 ifamap
.broadcast
= ifamap
.address
;
765 ifamap
.broadcast_len
= ifamap
.address_len
;
766 ifamap
.address
= ifamap
.local
;
767 ifamap
.address_len
= ifamap
.local_len
;
769 if (ifamap
.address
) {
771 sockaddr_size
= NLMSG_ALIGN(ifa_sa_len(nlm_family
,ifamap
.address_len
));
774 dlen
+= NLMSG_ALIGN(ifa_sa_len(nlm_family
,ifamap
.address_len
));
776 ifa
->ifa_addr
= (struct sockaddr
*)data
;
777 ifa_make_sockaddr(nlm_family
, ifa
->ifa_addr
, ifamap
.address
, ifamap
.address_len
,
778 nlm_scope
, nlm_index
);
779 data
+= NLMSG_ALIGN(ifa_sa_len(nlm_family
, ifamap
.address_len
));
783 if (ifamap
.netmask
) {
785 dlen
+= NLMSG_ALIGN(ifa_sa_len(nlm_family
,ifamap
.netmask_len
));
787 ifa
->ifa_netmask
= (struct sockaddr
*)data
;
788 ifa_make_sockaddr(nlm_family
, ifa
->ifa_netmask
, ifamap
.netmask
, ifamap
.netmask_len
,
789 nlm_scope
, nlm_index
);
790 data
+= NLMSG_ALIGN(ifa_sa_len(nlm_family
, ifamap
.netmask_len
));
794 if (ifamap
.broadcast
) {
796 dlen
+= NLMSG_ALIGN(ifa_sa_len(nlm_family
,ifamap
.broadcast_len
));
798 ifa
->ifa_broadaddr
= (struct sockaddr
*)data
;
799 ifa_make_sockaddr(nlm_family
, ifa
->ifa_broadaddr
, ifamap
.broadcast
, ifamap
.broadcast_len
,
800 nlm_scope
, nlm_index
);
801 data
+= NLMSG_ALIGN(ifa_sa_len(nlm_family
, ifamap
.broadcast_len
));
804 #ifdef HAVE_IFADDRS_IFA_ANYCAST
805 if (ifamap
.anycast
) {
807 dlen
+= NLMSG_ALIGN(ifa_sa_len(nlm_family
,ifamap
.anycast_len
));
809 ifa
->ifa_anycast
= (struct sockaddr
*)data
;
810 ifa_make_sockaddr(nlm_family
, ifa
->ifa_anyaddr
, ifamap
.anycast
, ifamap
.anycast_len
,
811 nlm_scope
, nlm_index
);
812 data
+= NLMSG_ALIGN(ifa_sa_len(nlm_family
, ifamap
.anycast_len
));
819 dlen
+= sockaddr_size
;
823 if (ifa
->ifa_name
== NULL
)
824 ifa
->ifa_name
= iflist
[nlm_index
];
827 ifa
->ifa_addr
->sa_family
!= AF_UNSPEC
&&
828 ifa
->ifa_addr
->sa_family
!= AF_PACKET
){
829 ifa
->ifa_netmask
= (struct sockaddr
*)data
;
830 ifa_make_sockaddr_mask(ifa
->ifa_addr
->sa_family
, ifa
->ifa_netmask
, nlm_prefixlen
);
832 data
+= sockaddr_size
;
839 if (icnt
== 0 && (dlen
+ nlen
+ xlen
== 0)){
842 break; /* cannot found any addresses */
846 free_data(NULL
, ifdata
);
849 /* ---------------------------------- */
851 free_nlmsglist(nlmsg_list
);
856 void ROKEN_LIB_FUNCTION
857 rk_freeifaddrs(struct ifaddrs
*ifp
)
859 /* AF_NETLINK method uses a single allocation for all interfaces */
863 #else /* !AF_NETLINK */
866 * The generic SIOCGIFCONF version.
870 getifaddrs2(struct ifaddrs
**ifap
,
871 int af
, int siocgifconf
, int siocgifflags
,
878 struct ifconf ifconf
;
881 struct sockaddr sa_zero
;
883 struct ifaddrs
*start
= NULL
, **end
= &start
;
887 memset (&sa_zero
, 0, sizeof(sa_zero
));
888 fd
= socket(af
, SOCK_DGRAM
, 0);
894 buf
= calloc(1, buf_size
);
899 ifconf
.ifc_len
= buf_size
;
900 ifconf
.ifc_buf
= buf
;
903 * Solaris returns EINVAL when the buffer is too small.
905 if (ioctl (fd
, siocgifconf
, &ifconf
) < 0 && errno
!= EINVAL
) {
910 * Can the difference between a full and a overfull buf
914 if (ifconf
.ifc_len
< buf_size
)
920 for (p
= ifconf
.ifc_buf
;
921 p
< ifconf
.ifc_buf
+ ifconf
.ifc_len
;
927 ifr
= (struct ifreq
*)p
;
931 salen
= sizeof(struct sockaddr
);
932 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
934 sz
= max(sz
, sizeof(ifr
->ifr_name
) + sa
->sa_len
);
938 sz
= max(sz
, sizeof(ifr
->ifr_name
) + SA_LEN(sa
));
940 memset (&ifreq
, 0, sizeof(ifreq
));
941 memcpy (ifreq
.ifr_name
, ifr
->ifr_name
, sizeof(ifr
->ifr_name
));
943 if (ioctl(fd
, siocgifflags
, &ifreq
) < 0) {
948 *end
= malloc(sizeof(**end
));
954 (*end
)->ifa_next
= NULL
;
955 (*end
)->ifa_name
= strdup(ifr
->ifr_name
);
956 if ((*end
)->ifa_name
== NULL
) {
960 (*end
)->ifa_flags
= ifreq
.ifr_flags
;
961 (*end
)->ifa_addr
= malloc(salen
);
962 if ((*end
)->ifa_addr
== NULL
) {
966 memcpy((*end
)->ifa_addr
, sa
, salen
);
967 (*end
)->ifa_netmask
= NULL
;
970 /* fix these when we actually need them */
971 if(ifreq
.ifr_flags
& IFF_BROADCAST
) {
972 (*end
)->ifa_broadaddr
= malloc(sizeof(ifr
->ifr_broadaddr
));
973 if ((*end
)->ifa_broadaddr
== NULL
) {
977 memcpy((*end
)->ifa_broadaddr
, &ifr
->ifr_broadaddr
,
978 sizeof(ifr
->ifr_broadaddr
));
979 } else if(ifreq
.ifr_flags
& IFF_POINTOPOINT
) {
980 (*end
)->ifa_dstaddr
= malloc(sizeof(ifr
->ifr_dstaddr
));
981 if ((*end
)->ifa_dstaddr
== NULL
) {
985 memcpy((*end
)->ifa_dstaddr
, &ifr
->ifr_dstaddr
,
986 sizeof(ifr
->ifr_dstaddr
));
988 (*end
)->ifa_dstaddr
= NULL
;
990 (*end
)->ifa_dstaddr
= NULL
;
993 (*end
)->ifa_data
= NULL
;
995 end
= &(*end
)->ifa_next
;
1003 rk_freeifaddrs(start
);
1010 #if defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS)
1012 getlifaddrs2(struct ifaddrs
**ifap
,
1013 int af
, int siocgifconf
, int siocgifflags
,
1020 struct lifconf ifconf
;
1023 struct sockaddr sa_zero
;
1025 struct ifaddrs
*start
= NULL
, **end
= &start
;
1029 memset (&sa_zero
, 0, sizeof(sa_zero
));
1030 fd
= socket(af
, SOCK_DGRAM
, 0);
1036 buf
= calloc(1, buf_size
);
1042 ifconf
.lifc_family
= af
;
1043 ifconf
.lifc_flags
= 0;
1045 ifconf
.lifc_len
= buf_size
;
1046 ifconf
.lifc_buf
= buf
;
1049 * Solaris returns EINVAL when the buffer is too small.
1051 if (ioctl (fd
, siocgifconf
, &ifconf
) < 0 && errno
!= EINVAL
) {
1056 * Can the difference between a full and a overfull buf
1060 if (ifconf
.lifc_len
< buf_size
)
1066 for (p
= ifconf
.lifc_buf
;
1067 p
< ifconf
.lifc_buf
+ ifconf
.lifc_len
;
1069 struct lifreq ifreq
;
1070 struct sockaddr_storage
*sa
;
1073 ifr
= (struct lifreq
*)p
;
1074 sa
= &ifr
->lifr_addr
;
1077 salen
= sizeof(struct sockaddr_storage
);
1078 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
1080 sz
= max(sz
, sizeof(ifr
->ifr_name
) + sa
->sa_len
);
1084 sz
= max(sz
, sizeof(ifr
->ifr_name
) + SA_LEN(sa
));
1086 memset (&ifreq
, 0, sizeof(ifreq
));
1087 memcpy (ifreq
.lifr_name
, ifr
->lifr_name
, sizeof(ifr
->lifr_name
));
1089 if (ioctl(fd
, siocgifflags
, &ifreq
) < 0) {
1094 *end
= malloc(sizeof(**end
));
1100 (*end
)->ifa_next
= NULL
;
1101 (*end
)->ifa_name
= strdup(ifr
->lifr_name
);
1102 if ((*end
)->ifa_name
== NULL
) {
1106 (*end
)->ifa_flags
= ifreq
.lifr_flags
;
1107 (*end
)->ifa_addr
= malloc(salen
);
1108 if ((*end
)->ifa_addr
== NULL
) {
1112 memcpy((*end
)->ifa_addr
, sa
, salen
);
1113 (*end
)->ifa_netmask
= NULL
;
1116 /* fix these when we actually need them */
1117 if(ifreq
.ifr_flags
& IFF_BROADCAST
) {
1118 (*end
)->ifa_broadaddr
= malloc(sizeof(ifr
->ifr_broadaddr
));
1119 if ((*end
)->ifa_broadaddr
== NULL
) {
1123 memcpy((*end
)->ifa_broadaddr
, &ifr
->ifr_broadaddr
,
1124 sizeof(ifr
->ifr_broadaddr
));
1125 } else if(ifreq
.ifr_flags
& IFF_POINTOPOINT
) {
1126 (*end
)->ifa_dstaddr
= malloc(sizeof(ifr
->ifr_dstaddr
));
1127 if ((*end
)->ifa_dstaddr
== NULL
) {
1131 memcpy((*end
)->ifa_dstaddr
, &ifr
->ifr_dstaddr
,
1132 sizeof(ifr
->ifr_dstaddr
));
1134 (*end
)->ifa_dstaddr
= NULL
;
1136 (*end
)->ifa_dstaddr
= NULL
;
1139 (*end
)->ifa_data
= NULL
;
1141 end
= &(*end
)->ifa_next
;
1149 rk_freeifaddrs(start
);
1155 #endif /* defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS) */
1158 * Join two struct ifaddrs lists by appending supp to base.
1159 * Either may be NULL. The new list head (usually base) will be
1162 static struct ifaddrs
*
1163 append_ifaddrs(struct ifaddrs
*base
, struct ifaddrs
*supp
) {
1170 while (base
->ifa_next
)
1171 base
= base
->ifa_next
;
1173 base
->ifa_next
= supp
;
1178 ROKEN_LIB_FUNCTION
int ROKEN_LIB_CALL
1179 rk_getifaddrs(struct ifaddrs
**ifap
)
1183 #if defined(AF_INET6) && defined(SIOCGIF6CONF) && defined(SIOCGIF6FLAGS)
1185 ret
= getifaddrs2 (ifap
, AF_INET6
, SIOCGIF6CONF
, SIOCGIF6FLAGS
,
1186 sizeof(struct in6_ifreq
));
1188 #if defined(HAVE_IPV6) && defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS)
1189 /* Do IPv6 and IPv4 queries separately then join the result.
1191 * HP-UX only returns IPv6 addresses using SIOCGLIFCONF,
1192 * SIOCGIFCONF has to be used for IPv4 addresses. The result is then
1195 * Solaris needs particular care, because a SIOCGLIFCONF lookup using
1196 * AF_UNSPEC can fail in a Zone requiring an AF_INET lookup, so we just
1197 * do them separately the same as for HP-UX. See
1198 * http://repo.or.cz/w/heimdal.git/commitdiff/76afc31e9ba2f37e64c70adc006ade9e37e9ef73
1202 struct ifaddrs
*v6addrs
, *v4addrs
;
1204 v6err
= getlifaddrs2 (&v6addrs
, AF_INET6
, SIOCGLIFCONF
, SIOCGLIFFLAGS
,
1205 sizeof(struct lifreq
));
1206 v4err
= getifaddrs2 (&v4addrs
, AF_INET
, SIOCGIFCONF
, SIOCGIFFLAGS
,
1207 sizeof(struct ifreq
));
1215 *ifap
= append_ifaddrs(v6addrs
, v4addrs
);
1218 } else if (v4addrs
) {
1224 ret
= (v6err
|| v4err
) ? -1 : 0;
1227 #if defined(HAVE_IPV6) && defined(SIOCGIFCONF)
1229 ret
= getifaddrs2 (ifap
, AF_INET6
, SIOCGIFCONF
, SIOCGIFFLAGS
,
1230 sizeof(struct ifreq
));
1232 #if defined(AF_INET) && defined(SIOCGIFCONF) && defined(SIOCGIFFLAGS)
1234 ret
= getifaddrs2 (ifap
, AF_INET
, SIOCGIFCONF
, SIOCGIFFLAGS
,
1235 sizeof(struct ifreq
));
1240 ROKEN_LIB_FUNCTION
void ROKEN_LIB_CALL
1241 rk_freeifaddrs(struct ifaddrs
*ifp
)
1243 struct ifaddrs
*p
, *q
;
1250 free(p
->ifa_dstaddr
);
1252 free(p
->ifa_netmask
);
1261 #endif /* !AF_NETLINK */
1266 print_addr(const char *s
, struct sockaddr
*sa
)
1269 printf(" %s=%d/", s
, sa
->sa_family
);
1270 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
1271 for(i
= 0; i
< sa
->sa_len
- ((long)sa
->sa_data
- (long)&sa
->sa_family
); i
++)
1272 printf("%02x", ((unsigned char*)sa
->sa_data
)[i
]);
1274 for(i
= 0; i
< sizeof(sa
->sa_data
); i
++)
1275 printf("%02x", ((unsigned char*)sa
->sa_data
)[i
]);
1281 print_ifaddrs(struct ifaddrs
*x
)
1285 for(p
= x
; p
; p
= p
->ifa_next
) {
1286 printf("%s\n", p
->ifa_name
);
1287 printf(" flags=%x\n", p
->ifa_flags
);
1289 print_addr("addr", p
->ifa_addr
);
1291 print_addr("dstaddr", p
->ifa_dstaddr
);
1293 print_addr("netmask", p
->ifa_netmask
);
1294 printf(" %p\n", p
->ifa_data
);
1301 struct ifaddrs
*a
= NULL
, *b
;
1302 getifaddrs2(&a
, AF_INET
, SIOCGIFCONF
, SIOCGIFFLAGS
, sizeof(struct ifreq
));