1 /* $Id: ifaddrs.c 241182 2011-02-17 21:50:03Z $ */
2 /* from USAGI: ifaddrs.c,v 1.20.2.1 2002/12/08 08:22:23 yoshfuji Exp */
5 * Copyright (C)2000 YOSHIFUJI Hideaki
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #define __set_errno(x) errno = (x)
30 #include <sys/socket.h>
31 #include <asm/types.h>
32 #include <linux/netlink.h>
33 #include <linux/rtnetlink.h>
34 #include <sys/types.h>
35 #include <sys/socket.h>
36 #include <netpacket/packet.h>
37 #include <net/ethernet.h> /* the L2 protocols */
40 #include <net/if_arp.h>
42 #include <netinet/in.h>
44 #ifdef _USAGI_LIBINET6
45 #include "libc-compat.h"
48 /* ====================================================================== */
51 struct nlmsg_list
*nlm_next
;
65 #ifdef HAVE_IFADDRS_IFA_ANYCAST
74 #ifdef HAVE_IFADDRS_IFA_ANYCAST
79 /* ====================================================================== */
81 ifa_sa_len (sa_family_t family
, int len
)
87 size
= sizeof (struct sockaddr_in
);
90 size
= sizeof (struct sockaddr_in6
);
93 size
= (size_t) (((struct sockaddr_ll
*) NULL
)->sll_addr
) + len
;
94 if (size
< sizeof (struct sockaddr_ll
))
95 size
= sizeof (struct sockaddr_ll
);
98 size
= (size_t) (((struct sockaddr
*) NULL
)->sa_data
) + len
;
99 if (size
< sizeof (struct sockaddr
))
100 size
= sizeof (struct sockaddr
);
106 ifa_make_sockaddr (sa_family_t family
,
108 void *p
, size_t len
, uint32_t scope
, uint32_t scopeid
)
115 memcpy (&((struct sockaddr_in
*) sa
)->sin_addr
, (char *) p
, len
);
118 memcpy (&((struct sockaddr_in6
*) sa
)->sin6_addr
, (char *) p
, len
);
119 if (IN6_IS_ADDR_LINKLOCAL (p
) || IN6_IS_ADDR_MC_LINKLOCAL (p
))
121 ((struct sockaddr_in6
*) sa
)->sin6_scope_id
= scopeid
;
125 memcpy (((struct sockaddr_ll
*) sa
)->sll_addr
, (char *) p
, len
);
126 ((struct sockaddr_ll
*) sa
)->sll_halen
= len
;
129 memcpy (sa
->sa_data
, p
, len
);
132 sa
->sa_family
= family
;
133 #ifdef HAVE_SOCKADDR_SA_LEN
134 sa
->sa_len
= ifa_sa_len (family
, len
);
138 static struct sockaddr
*
139 ifa_make_sockaddr_mask (sa_family_t family
,
140 struct sockaddr
*sa
, uint32_t prefixlen
)
144 uint32_t max_prefixlen
= 0;
151 memset (&((struct sockaddr_in
*) sa
)->sin_addr
, 0,
152 sizeof (((struct sockaddr_in
*) sa
)->sin_addr
));
153 p
= (char *) &((struct sockaddr_in
*) sa
)->sin_addr
;
157 memset (&((struct sockaddr_in6
*) sa
)->sin6_addr
, 0,
158 sizeof (((struct sockaddr_in6
*) sa
)->sin6_addr
));
159 p
= (char *) &((struct sockaddr_in6
*) sa
)->sin6_addr
;
165 sa
->sa_family
= family
;
166 #ifdef HAVE_SOCKADDR_SA_LEN
167 sa
->sa_len
= ifa_sa_len (family
, len
);
171 if (prefixlen
> max_prefixlen
)
172 prefixlen
= max_prefixlen
;
173 for (i
= 0; i
< (prefixlen
/ 8); i
++)
176 c
<<= (8 - (prefixlen
% 8));
182 /* ====================================================================== */
184 nl_sendreq (int sd
, int request
, int flags
, int *seq
)
186 char reqbuf
[NLMSG_ALIGN (sizeof (struct nlmsghdr
)) +
187 NLMSG_ALIGN (sizeof (struct rtgenmsg
))];
188 struct sockaddr_nl nladdr
;
189 struct nlmsghdr
*req_hdr
;
190 struct rtgenmsg
*req_msg
;
191 time_t t
= time (NULL
);
195 memset (&reqbuf
, 0, sizeof (reqbuf
));
196 req_hdr
= (struct nlmsghdr
*) reqbuf
;
197 req_msg
= (struct rtgenmsg
*) NLMSG_DATA (req_hdr
);
198 req_hdr
->nlmsg_len
= NLMSG_LENGTH (sizeof (*req_msg
));
199 req_hdr
->nlmsg_type
= request
;
200 req_hdr
->nlmsg_flags
= flags
| NLM_F_REQUEST
;
201 req_hdr
->nlmsg_pid
= 0;
202 req_hdr
->nlmsg_seq
= t
;
203 req_msg
->rtgen_family
= AF_UNSPEC
;
204 memset (&nladdr
, 0, sizeof (nladdr
));
205 nladdr
.nl_family
= AF_NETLINK
;
206 return (sendto (sd
, (void *) req_hdr
, req_hdr
->nlmsg_len
, 0,
207 (struct sockaddr
*) &nladdr
, sizeof (nladdr
)));
211 nl_recvmsg (int sd
, int request
, int seq
,
212 void *buf
, size_t buflen
, int *flags
)
215 struct iovec iov
= { buf
, buflen
};
216 struct sockaddr_nl nladdr
;
221 msg
.msg_name
= (void *) &nladdr
;
222 msg
.msg_namelen
= sizeof (nladdr
);
225 msg
.msg_control
= NULL
;
226 msg
.msg_controllen
= 0;
228 read_len
= recvmsg (sd
, &msg
, 0);
229 if ((read_len
< 0 && errno
== EINTR
) || (msg
.msg_flags
& MSG_TRUNC
))
232 *flags
= msg
.msg_flags
;
239 nl_getmsg (int sd
, int request
, int seq
, struct nlmsghdr
**nlhp
, int *done
)
242 size_t bufsize
= 65536, lastbufsize
= 0;
244 int result
= 0, read_size
;
246 pid_t pid
= getpid ();
249 void *newbuff
= realloc (buff
, bufsize
);
250 if (newbuff
== NULL
|| bufsize
< lastbufsize
)
257 nl_recvmsg (sd
, request
, seq
, buff
, bufsize
, &msg_flags
);
258 if (read_size
< 0 || (msg_flags
& MSG_TRUNC
))
260 lastbufsize
= bufsize
;
266 nh
= (struct nlmsghdr
*) buff
;
267 for (nh
= (struct nlmsghdr
*) buff
;
268 NLMSG_OK (nh
, read_size
);
269 nh
= (struct nlmsghdr
*) NLMSG_NEXT (nh
, read_size
))
271 if (nh
->nlmsg_pid
!= pid
|| nh
->nlmsg_seq
!= seq
)
273 if (nh
->nlmsg_type
== NLMSG_DONE
)
278 if (nh
->nlmsg_type
== NLMSG_ERROR
)
280 struct nlmsgerr
*nlerr
= (struct nlmsgerr
*) NLMSG_DATA (nh
);
282 if (nh
->nlmsg_len
< NLMSG_LENGTH (sizeof (struct nlmsgerr
)))
285 __set_errno (-nlerr
->error
);
294 int saved_errno
= errno
;
296 __set_errno (saved_errno
);
298 *nlhp
= (struct nlmsghdr
*) buff
;
303 nl_getlist (int sd
, int seq
,
305 struct nlmsg_list
**nlm_list
, struct nlmsg_list
**nlm_end
)
307 struct nlmsghdr
*nlh
= NULL
;
311 status
= nl_sendreq (sd
, request
, NLM_F_ROOT
| NLM_F_MATCH
, &seq
);
315 seq
= (int) time (NULL
);
318 status
= nl_getmsg (sd
, request
, seq
, &nlh
, &done
);
323 struct nlmsg_list
*nlm_next
=
324 (struct nlmsg_list
*) malloc (sizeof (struct nlmsg_list
));
325 if (nlm_next
== NULL
)
327 int saved_errno
= errno
;
329 __set_errno (saved_errno
);
334 nlm_next
->nlm_next
= NULL
;
335 nlm_next
->nlh
= (struct nlmsghdr
*) nlh
;
336 nlm_next
->size
= status
;
338 if (*nlm_list
== NULL
)
340 *nlm_list
= nlm_next
;
345 (*nlm_end
)->nlm_next
= nlm_next
;
351 return status
>= 0 ? seq
: status
;
354 /* ---------------------------------------------------------------------- */
356 free_nlmsglist (struct nlmsg_list
*nlm0
)
358 struct nlmsg_list
*nlm
, *nlm_next
;
368 nlm_next
= nlm
->nlm_next
;
372 __set_errno (saved_errno
);
376 free_data (void *data
, void *ifdata
)
378 int saved_errno
= errno
;
383 __set_errno (saved_errno
);
386 /* ---------------------------------------------------------------------- */
390 int saved_errno
= errno
;
393 __set_errno (saved_errno
);
396 /* ---------------------------------------------------------------------- */
400 struct sockaddr_nl nladdr
;
403 sd
= socket (PF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
406 memset (&nladdr
, 0, sizeof (nladdr
));
407 nladdr
.nl_family
= AF_NETLINK
;
408 if (bind (sd
, (struct sockaddr
*) &nladdr
, sizeof (nladdr
)) < 0)
416 /* ====================================================================== */
418 getifaddrs_local (struct ifaddrs
**ifap
)
421 struct nlmsg_list
*nlmsg_list
, *nlmsg_end
, *nlm
;
422 /* - - - - - - - - - - - - - - - */
424 size_t dlen
, xlen
, nlen
;
425 uint32_t max_ifindex
= 0;
427 pid_t pid
= getpid ();
430 int build
; /* 0 or 1 */
432 /* ---------------------------------- */
434 icnt
= dlen
= xlen
= nlen
= 0;
435 nlmsg_list
= nlmsg_end
= NULL
;
440 /* ---------------------------------- */
441 /* open socket and bind */
446 /* ---------------------------------- */
448 if ((seq
= nl_getlist (sd
, 0, RTM_GETLINK
, &nlmsg_list
, &nlmsg_end
)) < 0)
450 free_nlmsglist (nlmsg_list
);
454 if ((seq
= nl_getlist (sd
, seq
+ 1, RTM_GETADDR
,
455 &nlmsg_list
, &nlmsg_end
)) < 0)
457 free_nlmsglist (nlmsg_list
);
462 /* ---------------------------------- */
463 /* Estimate size of result buffer and fill it */
464 for (build
= 0; build
<= 1; build
++)
466 struct ifaddrs
*ifl
= NULL
, *ifa
= NULL
;
467 struct nlmsghdr
*nlh
, *nlh0
;
468 void *data
= NULL
, *xdata
= NULL
, *ifdata
= NULL
;
469 char *ifname
= NULL
, **iflist
= NULL
;
470 uint16_t *ifflist
= NULL
;
471 struct rtmaddr_ifamap ifamap
;
475 ifa
= data
= calloc (1,
476 NLMSG_ALIGN (sizeof (struct ifaddrs
[icnt
]))
477 + dlen
+ xlen
+ nlen
);
479 NLMSG_ALIGN (sizeof (char *[max_ifindex
+ 1]))
481 NLMSG_ALIGN (sizeof (uint16_t[max_ifindex
+ 1])));
483 *ifap
= (ifdata
!= NULL
) ? ifa
: NULL
;
486 free_data (data
, ifdata
);
490 if (data
== NULL
|| ifdata
== NULL
)
492 free_data (data
, ifdata
);
497 data
+= NLMSG_ALIGN (sizeof (struct ifaddrs
)) * icnt
;
499 ifname
= xdata
+ xlen
;
503 NLMSG_ALIGN (sizeof (char *[max_ifindex
+ 1]));
506 for (nlm
= nlmsg_list
; nlm
; nlm
= nlm
->nlm_next
)
508 int nlmlen
= nlm
->size
;
509 if (!(nlh0
= nlm
->nlh
))
512 NLMSG_OK (nlh
, nlmlen
); nlh
= NLMSG_NEXT (nlh
, nlmlen
))
514 struct ifinfomsg
*ifim
= NULL
;
515 struct ifaddrmsg
*ifam
= NULL
;
518 size_t nlm_struct_size
= 0;
519 sa_family_t nlm_family
= 0;
520 uint32_t nlm_scope
= 0, nlm_index
= 0;
522 size_t sockaddr_size
= 0;
523 uint32_t nlm_prefixlen
= 0;
527 memset (&ifamap
, 0, sizeof (ifamap
));
529 /* check if the message is what we want */
530 if (nlh
->nlmsg_pid
!= pid
|| nlh
->nlmsg_seq
!= nlm
->seq
)
532 if (nlh
->nlmsg_type
== NLMSG_DONE
)
536 switch (nlh
->nlmsg_type
)
539 ifim
= (struct ifinfomsg
*) NLMSG_DATA (nlh
);
540 nlm_struct_size
= sizeof (*ifim
);
541 nlm_family
= ifim
->ifi_family
;
543 nlm_index
= ifim
->ifi_index
;
546 ifflist
[nlm_index
] = ifa
->ifa_flags
= ifim
->ifi_flags
;
549 ifam
= (struct ifaddrmsg
*) NLMSG_DATA (nlh
);
550 nlm_struct_size
= sizeof (*ifam
);
551 nlm_family
= ifam
->ifa_family
;
552 nlm_scope
= ifam
->ifa_scope
;
553 nlm_index
= ifam
->ifa_index
;
554 nlm_prefixlen
= ifam
->ifa_prefixlen
;
556 ifa
->ifa_flags
= ifflist
[nlm_index
];
564 if (max_ifindex
< nlm_index
)
565 max_ifindex
= nlm_index
;
574 NLMSG_PAYLOAD (nlh
, nlmlen
) - NLMSG_ALIGN (nlm_struct_size
);
576 (struct rtattr
*) (((char *) NLMSG_DATA (nlh
)) +
577 NLMSG_ALIGN (nlm_struct_size
));
578 RTA_OK (rta
, rtasize
); rta
= RTA_NEXT (rta
, rtasize
))
580 struct sockaddr
**sap
= NULL
;
581 void *rtadata
= RTA_DATA (rta
);
582 size_t rtapayload
= RTA_PAYLOAD (rta
);
585 switch (nlh
->nlmsg_type
)
588 switch (rta
->rta_type
)
596 IFLA_ADDRESS
) ? &ifa
->ifa_addr
: &ifa
->
598 *sap
= (struct sockaddr
*) data
;
600 sa_len
= ifa_sa_len (AF_PACKET
, rtapayload
);
601 if (rta
->rta_type
== IFLA_ADDRESS
)
602 sockaddr_size
= NLMSG_ALIGN (sa_len
);
605 dlen
+= NLMSG_ALIGN (sa_len
);
609 memset (*sap
, 0, sa_len
);
610 ifa_make_sockaddr (AF_PACKET
, *sap
, rtadata
,
612 ((struct sockaddr_ll
*) *sap
)->sll_ifindex
=
614 ((struct sockaddr_ll
*) *sap
)->sll_hatype
=
616 data
+= NLMSG_ALIGN (sa_len
);
619 case IFLA_IFNAME
: /* Name of Interface */
621 nlen
+= NLMSG_ALIGN (rtapayload
+ 1);
624 ifa
->ifa_name
= ifname
;
625 if (iflist
[nlm_index
] == NULL
)
626 iflist
[nlm_index
] = ifa
->ifa_name
;
627 strncpy (ifa
->ifa_name
, rtadata
, rtapayload
);
628 ifa
->ifa_name
[rtapayload
] = '\0';
629 ifname
+= NLMSG_ALIGN (rtapayload
+ 1);
632 case IFLA_STATS
: /* Statistics of Interface */
634 xlen
+= NLMSG_ALIGN (rtapayload
);
637 ifa
->ifa_data
= xdata
;
638 memcpy (ifa
->ifa_data
, rtadata
, rtapayload
);
639 xdata
+= NLMSG_ALIGN (rtapayload
);
655 if (nlm_family
== AF_PACKET
)
657 switch (rta
->rta_type
)
660 ifamap
.address
= rtadata
;
661 ifamap
.address_len
= rtapayload
;
664 ifamap
.local
= rtadata
;
665 ifamap
.local_len
= rtapayload
;
668 ifamap
.broadcast
= rtadata
;
669 ifamap
.broadcast_len
= rtapayload
;
671 #ifdef HAVE_IFADDRS_IFA_ANYCAST
673 ifamap
.anycast
= rtadata
;
674 ifamap
.anycast_len
= rtapayload
;
679 nlen
+= NLMSG_ALIGN (rtapayload
+ 1);
682 ifa
->ifa_name
= ifname
;
683 if (iflist
[nlm_index
] == NULL
)
684 iflist
[nlm_index
] = ifname
;
685 strncpy (ifa
->ifa_name
, rtadata
, rtapayload
);
686 ifa
->ifa_name
[rtapayload
] = '\0';
687 ifname
+= NLMSG_ALIGN (rtapayload
+ 1);
699 if (nlh
->nlmsg_type
== RTM_NEWADDR
&& nlm_family
!= AF_PACKET
)
703 ifamap
.local
= ifamap
.address
;
704 ifamap
.local_len
= ifamap
.address_len
;
708 ifamap
.address
= ifamap
.local
;
709 ifamap
.address_len
= ifamap
.local_len
;
711 if (ifamap
.address_len
!= ifamap
.local_len
||
712 (ifamap
.address
!= NULL
&&
713 memcmp (ifamap
.address
, ifamap
.local
,
714 ifamap
.address_len
)))
716 /* p2p; address is peer and local is ours */
717 ifamap
.broadcast
= ifamap
.address
;
718 ifamap
.broadcast_len
= ifamap
.address_len
;
719 ifamap
.address
= ifamap
.local
;
720 ifamap
.address_len
= ifamap
.local_len
;
726 NLMSG_ALIGN (ifa_sa_len
727 (nlm_family
, ifamap
.address_len
));
731 NLMSG_ALIGN (ifa_sa_len
732 (nlm_family
, ifamap
.address_len
));
735 ifa
->ifa_addr
= (struct sockaddr
*) data
;
736 ifa_make_sockaddr (nlm_family
, ifa
->ifa_addr
,
738 ifamap
.address_len
, nlm_scope
,
741 NLMSG_ALIGN (ifa_sa_len
742 (nlm_family
, ifamap
.address_len
));
750 NLMSG_ALIGN (ifa_sa_len
751 (nlm_family
, ifamap
.netmask_len
));
754 ifa
->ifa_netmask
= (struct sockaddr
*) data
;
755 ifa_make_sockaddr (nlm_family
, ifa
->ifa_netmask
,
757 ifamap
.netmask_len
, nlm_scope
,
760 NLMSG_ALIGN (ifa_sa_len
761 (nlm_family
, ifamap
.netmask_len
));
765 if (ifamap
.broadcast
)
769 NLMSG_ALIGN (ifa_sa_len
770 (nlm_family
, ifamap
.broadcast_len
));
773 ifa
->ifa_broadaddr
= (struct sockaddr
*) data
;
774 ifa_make_sockaddr (nlm_family
, ifa
->ifa_broadaddr
,
776 ifamap
.broadcast_len
, nlm_scope
,
779 NLMSG_ALIGN (ifa_sa_len
780 (nlm_family
, ifamap
.broadcast_len
));
783 #ifdef HAVE_IFADDRS_IFA_ANYCAST
788 NLMSG_ALIGN (ifa_sa_len
789 (nlm_family
, ifamap
.anycast_len
));
792 ifa
->ifa_anycast
= (struct sockaddr
*) data
;
793 ifa_make_sockaddr (nlm_family
, ifa
->ifa_anyaddr
,
795 ifamap
.anycast_len
, nlm_scope
,
798 NLMSG_ALIGN (ifa_sa_len
799 (nlm_family
, ifamap
.anycast_len
));
807 dlen
+= sockaddr_size
;
813 if (ifa
->ifa_name
== NULL
)
814 ifa
->ifa_name
= iflist
[nlm_index
];
817 ifa
->ifa_addr
->sa_family
!= AF_UNSPEC
&&
818 ifa
->ifa_addr
->sa_family
!= AF_PACKET
)
820 ifa
->ifa_netmask
= (struct sockaddr
*) data
;
821 ifa_make_sockaddr_mask (ifa
->ifa_addr
->sa_family
,
825 data
+= sockaddr_size
;
833 if (icnt
== 0 && (dlen
+ nlen
+ xlen
== 0))
837 break; /* cannot found any addresses */
841 free_data (NULL
, ifdata
);
844 /* ---------------------------------- */
846 free_nlmsglist (nlmsg_list
);
851 /* ---------------------------------------------------------------------- */
853 freeifaddrs_local (struct ifaddrs
*ifa
)