1 #include <config.h>
2 #ifdef HAVE_LINUX_NETLINK_H
3
4 /* $USAGI: ifaddrs.c,v 1.20 2002/08/23 05:38:00 yoshfuji Exp $ */
5
6 /*
7 * Copyright (C)2000 YOSHIFUJI Hideaki
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 #include <string.h>
25 #include <time.h>
26 #include <malloc.h>
27 #include <errno.h>
28 #include <unistd.h>
29
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 */
38 #include <sys/uio.h>
39 #include <net/if.h>
40 #include <net/if_arp.h>
41 #include "usagi_ifaddrs.h"
42 #include <netinet/in.h>
43
44 #ifdef _USAGI_LIBINET6
45 #include "libc-compat.h"
46 #endif
47
48 #define __set_errno(e) do { errno = e; } while(0)
49 #define __close(s) close(s)
50
51
52 /* ====================================================================== */
53 struct nlmsg_list
54 {
55 struct nlmsg_list *nlm_next;
56 struct nlmsghdr *nlh;
57 int size;
58 time_t seq;
59 };
60
61 struct rtmaddr_ifamap
62 {
63 void *address;
64 void *local;
65 #ifdef IFA_NETMASK
66 void *netmask;
67 #endif
68 void *broadcast;
69 #ifdef HAVE_IFADDRS_IFA_ANYCAST
70 void *anycast;
71 #endif
72 int address_len;
73 int local_len;
74 #ifdef IFA_NETMASK
75 int netmask_len;
76 #endif
77 int broadcast_len;
78 #ifdef HAVE_IFADDRS_IFA_ANYCAST
79 int anycast_len;
80 #endif
81 };
82
83 /* ====================================================================== */
84 static size_t
ifa_sa_len(sa_family_t family,int len)85 ifa_sa_len (sa_family_t family, int len)
86 {
87 size_t size;
88 switch (family)
89 {
90 case AF_INET:
91 size = sizeof (struct sockaddr_in);
92 break;
93 case AF_INET6:
94 size = sizeof (struct sockaddr_in6);
95 break;
96 case AF_PACKET:
97 size = (size_t) (((struct sockaddr_ll *) NULL)->sll_addr) + len;
98 if (size < sizeof (struct sockaddr_ll))
99 size = sizeof (struct sockaddr_ll);
100 break;
101 default:
102 size = (size_t) (((struct sockaddr *) NULL)->sa_data) + len;
103 if (size < sizeof (struct sockaddr))
104 size = sizeof (struct sockaddr);
105 }
106 return size;
107 }
108
109 static void
ifa_make_sockaddr(sa_family_t family,struct sockaddr * sa,void * p,size_t len,uint32_t scope,uint32_t scopeid)110 ifa_make_sockaddr (sa_family_t family,
111 struct sockaddr *sa,
112 void *p, size_t len, uint32_t scope, uint32_t scopeid)
113 {
114 if (sa == NULL)
115 return;
116 switch (family)
117 {
118 case AF_INET:
119 memcpy (&((struct sockaddr_in *) sa)->sin_addr, (char *) p, len);
120 break;
121 case AF_INET6:
122 memcpy (&((struct sockaddr_in6 *) sa)->sin6_addr, (char *) p, len);
123 if (IN6_IS_ADDR_LINKLOCAL (p) || IN6_IS_ADDR_MC_LINKLOCAL (p))
124 {
125 ((struct sockaddr_in6 *) sa)->sin6_scope_id = scopeid;
126 }
127 break;
128 case AF_PACKET:
129 memcpy (((struct sockaddr_ll *) sa)->sll_addr, (char *) p, len);
130 ((struct sockaddr_ll *) sa)->sll_halen = len;
131 break;
132 default:
133 memcpy (sa->sa_data, p, len);
134 /*XXX*/ break;
135 }
136 sa->sa_family = family;
137 #ifdef HAVE_SOCKADDR_SA_LEN
138 sa->sa_len = ifa_sa_len (family, len);
139 #endif
140 }
141
142 static struct sockaddr *
ifa_make_sockaddr_mask(sa_family_t family,struct sockaddr * sa,uint32_t prefixlen)143 ifa_make_sockaddr_mask (sa_family_t family,
144 struct sockaddr *sa, uint32_t prefixlen)
145 {
146 int i;
147 char *p = NULL, c;
148 uint32_t max_prefixlen = 0;
149
150 if (sa == NULL)
151 return NULL;
152 switch (family)
153 {
154 case AF_INET:
155 memset (&((struct sockaddr_in *) sa)->sin_addr, 0,
156 sizeof (((struct sockaddr_in *) sa)->sin_addr));
157 p = (char *) &((struct sockaddr_in *) sa)->sin_addr;
158 max_prefixlen = 32;
159 break;
160 case AF_INET6:
161 memset (&((struct sockaddr_in6 *) sa)->sin6_addr, 0,
162 sizeof (((struct sockaddr_in6 *) sa)->sin6_addr));
163 p = (char *) &((struct sockaddr_in6 *) sa)->sin6_addr;
164 #if 0 /* XXX: fill scope-id? */
165 if (IN6_IS_ADDR_LINKLOCAL (p) || IN6_IS_ADDR_MC_LINKLOCAL (p))
166 {
167 ((struct sockaddr_in6 *) sa)->sin6_scope_id = scopeid;
168 }
169 #endif
170 max_prefixlen = 128;
171 break;
172 default:
173 return NULL;
174 }
175 sa->sa_family = family;
176 #ifdef HAVE_SOCKADDR_SA_LEN
177 sa->sa_len = ifa_sa_len (family, len);
178 #endif
179 if (p)
180 {
181 if (prefixlen > max_prefixlen)
182 prefixlen = max_prefixlen;
183 for (i = 0; i < (prefixlen / 8); i++)
184 *p++ = 0xff;
185 c = 0xff;
186 c <<= (8 - (prefixlen % 8));
187 *p = c;
188 }
189 return sa;
190 }
191
192 /* ====================================================================== */
193 static int
nl_sendreq(int sd,int request,int flags,int * seq)194 nl_sendreq (int sd, int request, int flags, int *seq)
195 {
196 char reqbuf[NLMSG_ALIGN (sizeof (struct nlmsghdr)) +
197 NLMSG_ALIGN (sizeof (struct rtgenmsg))];
198 struct sockaddr_nl nladdr;
199 struct nlmsghdr *req_hdr;
200 struct rtgenmsg *req_msg;
201 time_t t = time (NULL);
202
203 if (seq)
204 *seq = t;
205 memset (&reqbuf, 0, sizeof (reqbuf));
206 req_hdr = (struct nlmsghdr *) reqbuf;
207 req_msg = (struct rtgenmsg *) NLMSG_DATA (req_hdr);
208 req_hdr->nlmsg_len = NLMSG_LENGTH (sizeof (*req_msg));
209 req_hdr->nlmsg_type = request;
210 req_hdr->nlmsg_flags = flags | NLM_F_REQUEST;
211 req_hdr->nlmsg_pid = 0;
212 req_hdr->nlmsg_seq = t;
213 req_msg->rtgen_family = AF_UNSPEC;
214 memset (&nladdr, 0, sizeof (nladdr));
215 nladdr.nl_family = AF_NETLINK;
216 return (sendto (sd, (void *) req_hdr, req_hdr->nlmsg_len, 0,
217 (struct sockaddr *) &nladdr, sizeof (nladdr)));
218 }
219
220 static int
nl_recvmsg(int sd,int request,int seq,void * buf,size_t buflen,int * flags)221 nl_recvmsg (int sd, int request, int seq,
222 void *buf, size_t buflen, int *flags)
223 {
224 struct msghdr msg;
225 struct iovec iov = { buf, buflen };
226 struct sockaddr_nl nladdr;
227 int read_len;
228
229 for (;;)
230 {
231 msg.msg_name = (void *) &nladdr;
232 msg.msg_namelen = sizeof (nladdr);
233 msg.msg_iov = &iov;
234 msg.msg_iovlen = 1;
235 msg.msg_control = NULL;
236 msg.msg_controllen = 0;
237 msg.msg_flags = 0;
238 read_len = recvmsg (sd, &msg, 0);
239 if ((read_len < 0 && errno == EINTR) || (msg.msg_flags & MSG_TRUNC))
240 continue;
241 if (flags)
242 *flags = msg.msg_flags;
243 break;
244 }
245 return read_len;
246 }
247
248 static int
nl_getmsg(int sd,int request,int seq,struct nlmsghdr ** nlhp,int * done)249 nl_getmsg (int sd, int request, int seq, struct nlmsghdr **nlhp, int *done)
250 {
251 struct nlmsghdr *nh;
252 size_t bufsize = 65536, lastbufsize = 0;
253 void *buff = NULL;
254 int result = 0, read_size;
255 int msg_flags;
256 pid_t pid = getpid ();
257 for (;;)
258 {
259 void *newbuff = realloc (buff, bufsize);
260 if (newbuff == NULL || bufsize < lastbufsize)
261 {
262 result = -1;
263 break;
264 }
265 buff = newbuff;
266 result = read_size =
267 nl_recvmsg (sd, request, seq, buff, bufsize, &msg_flags);
268 if (read_size < 0 || (msg_flags & MSG_TRUNC))
269 {
270 lastbufsize = bufsize;
271 bufsize *= 2;
272 continue;
273 }
274 if (read_size == 0)
275 break;
276 nh = (struct nlmsghdr *) buff;
277 for (nh = (struct nlmsghdr *) buff;
278 NLMSG_OK (nh, read_size);
279 nh = (struct nlmsghdr *) NLMSG_NEXT (nh, read_size))
280 {
281 if (nh->nlmsg_pid != pid || nh->nlmsg_seq != seq)
282 continue;
283 if (nh->nlmsg_type == NLMSG_DONE)
284 {
285 (*done)++;
286 break; /* ok */
287 }
288 if (nh->nlmsg_type == NLMSG_ERROR)
289 {
290 struct nlmsgerr *nlerr = (struct nlmsgerr *) NLMSG_DATA (nh);
291 result = -1;
292 if (nh->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
293 __set_errno (EIO);
294 else
295 __set_errno (-nlerr->error);
296 break;
297 }
298 }
299 break;
300 }
301 if (result < 0)
302 if (buff)
303 {
304 int saved_errno = errno;
305 free (buff);
306 __set_errno (saved_errno);
307 }
308 *nlhp = (struct nlmsghdr *) buff;
309 return result;
310 }
311
312 static int
nl_getlist(int sd,int seq,int request,struct nlmsg_list ** nlm_list,struct nlmsg_list ** nlm_end)313 nl_getlist (int sd, int seq,
314 int request,
315 struct nlmsg_list **nlm_list, struct nlmsg_list **nlm_end)
316 {
317 struct nlmsghdr *nlh = NULL;
318 int status;
319 int done = 0;
320
321 status = nl_sendreq (sd, request, NLM_F_ROOT | NLM_F_MATCH, &seq);
322 if (status < 0)
323 return status;
324 if (seq == 0)
325 seq = (int) time (NULL);
326 while (!done)
327 {
328 status = nl_getmsg (sd, request, seq, &nlh, &done);
329 if (status < 0)
330 return status;
331 if (nlh)
332 {
333 struct nlmsg_list *nlm_next =
334 (struct nlmsg_list *) malloc (sizeof (struct nlmsg_list));
335 if (nlm_next == NULL)
336 {
337 int saved_errno = errno;
338 free (nlh);
339 __set_errno (saved_errno);
340 status = -1;
341 }
342 else
343 {
344 nlm_next->nlm_next = NULL;
345 nlm_next->nlh = (struct nlmsghdr *) nlh;
346 nlm_next->size = status;
347 nlm_next->seq = seq;
348 if (*nlm_list == NULL)
349 {
350 *nlm_list = nlm_next;
351 *nlm_end = nlm_next;
352 }
353 else
354 {
355 (*nlm_end)->nlm_next = nlm_next;
356 *nlm_end = nlm_next;
357 }
358 }
359 }
360 }
361 return status >= 0 ? seq : status;
362 }
363
364 /* ---------------------------------------------------------------------- */
365 static void
free_nlmsglist(struct nlmsg_list * nlm0)366 free_nlmsglist (struct nlmsg_list *nlm0)
367 {
368 struct nlmsg_list *nlm;
369 int saved_errno;
370 if (!nlm0)
371 return;
372 saved_errno = errno;
373 nlm = nlm0;
374 while (nlm)
375 {
376 struct nlmsg_list *old_node = nlm;
377 if (nlm->nlh)
378 free (nlm->nlh);
379 nlm = nlm->nlm_next;
380 free (old_node);
381 }
382 __set_errno (saved_errno);
383 }
384
385 static void
free_data(void * data,void * ifdata)386 free_data (void *data, void *ifdata)
387 {
388 int saved_errno = errno;
389 if (data != NULL)
390 free (data);
391 if (ifdata != NULL)
392 free (ifdata);
393 __set_errno (saved_errno);
394 }
395
396 /* ---------------------------------------------------------------------- */
397 static void
nl_close(int sd)398 nl_close (int sd)
399 {
400 int saved_errno = errno;
401 if (sd >= 0)
402 __close (sd);
403 __set_errno (saved_errno);
404 }
405
406 /* ---------------------------------------------------------------------- */
407 static int
nl_open(void)408 nl_open (void)
409 {
410 struct sockaddr_nl nladdr;
411 int sd;
412
413 sd = socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
414 if (sd < 0)
415 return -1;
416 memset (&nladdr, 0, sizeof (nladdr));
417 nladdr.nl_family = AF_NETLINK;
418 if (bind (sd, (struct sockaddr *) &nladdr, sizeof (nladdr)) < 0)
419 {
420 nl_close (sd);
421 return -1;
422 }
423 return sd;
424 }
425
426 /* ====================================================================== */
427 int
usagi_getifaddrs(struct ifaddrs ** ifap)428 usagi_getifaddrs (struct ifaddrs **ifap)
429 {
430 int sd;
431 struct nlmsg_list *nlmsg_list, *nlmsg_end, *nlm;
432 /* - - - - - - - - - - - - - - - */
433 int icnt;
434 size_t dlen, xlen, nlen;
435 uint32_t max_ifindex = 0;
436
437 pid_t pid = getpid ();
438 int seq;
439 int result;
440 int build; /* 0 or 1 */
441
442 /* ---------------------------------- */
443 /* initialize */
444 icnt = dlen = xlen = nlen = 0;
445 nlmsg_list = nlmsg_end = NULL;
446
447 if (ifap)
448 *ifap = NULL;
449
450 /* ---------------------------------- */
451 /* open socket and bind */
452 sd = nl_open ();
453 if (sd < 0)
454 return -1;
455
456 /* ---------------------------------- */
457 /* gather info */
458 if ((seq = nl_getlist (sd, 0, RTM_GETLINK, &nlmsg_list, &nlmsg_end)) < 0)
459 {
460 free_nlmsglist (nlmsg_list);
461 nl_close (sd);
462 return -1;
463 }
464 if ((seq = nl_getlist (sd, seq + 1, RTM_GETADDR,
465 &nlmsg_list, &nlmsg_end)) < 0)
466 {
467 free_nlmsglist (nlmsg_list);
468 nl_close (sd);
469 return -1;
470 }
471
472 /* ---------------------------------- */
473 /* Estimate size of result buffer and fill it */
474 for (build = 0; build <= 1; build++)
475 {
476 struct ifaddrs *ifl = NULL, *ifa = NULL;
477 struct nlmsghdr *nlh, *nlh0;
478 void *data = NULL, *xdata = NULL, *ifdata = NULL;
479 char *ifname = NULL, **iflist = NULL;
480 uint16_t *ifflist = NULL;
481 struct rtmaddr_ifamap ifamap;
482
483 if (build)
484 {
485 ifa = data = calloc (1,
486 NLMSG_ALIGN (sizeof (struct ifaddrs[icnt]))
487 + dlen + xlen + nlen);
488 ifdata = calloc (1,
489 NLMSG_ALIGN (sizeof (char *[max_ifindex + 1]))
490 +
491 NLMSG_ALIGN (sizeof (uint16_t[max_ifindex + 1])));
492 if (ifap != NULL)
493 *ifap = (ifdata != NULL) ? ifa : NULL;
494 else
495 {
496 free_data (data, ifdata);
497 result = 0;
498 break;
499 }
500 if (data == NULL || ifdata == NULL)
501 {
502 free_data (data, ifdata);
503 result = -1;
504 break;
505 }
506 ifl = NULL;
507 data += NLMSG_ALIGN (sizeof (struct ifaddrs)) * icnt;
508 xdata = data + dlen;
509 ifname = xdata + xlen;
510 iflist = ifdata;
511 ifflist =
512 ((void *) iflist) +
513 NLMSG_ALIGN (sizeof (char *[max_ifindex + 1]));
514 }
515
516 for (nlm = nlmsg_list; nlm; nlm = nlm->nlm_next)
517 {
518 int nlmlen = nlm->size;
519 if (!(nlh0 = nlm->nlh))
520 continue;
521 for (nlh = nlh0;
522 NLMSG_OK (nlh, nlmlen); nlh = NLMSG_NEXT (nlh, nlmlen))
523 {
524 struct ifinfomsg *ifim = NULL;
525 struct ifaddrmsg *ifam = NULL;
526 struct rtattr *rta;
527
528 size_t nlm_struct_size = 0;
529 sa_family_t nlm_family = 0;
530 uint32_t nlm_scope = 0, nlm_index = 0;
531 #ifndef IFA_NETMASK
532 size_t sockaddr_size = 0;
533 uint32_t nlm_prefixlen = 0;
534 #endif
535 size_t rtasize;
536
537 memset (&ifamap, 0, sizeof (ifamap));
538
539 /* check if the message is what we want */
540 if (nlh->nlmsg_pid != pid || nlh->nlmsg_seq != nlm->seq)
541 continue;
542 if (nlh->nlmsg_type == NLMSG_DONE)
543 {
544 break; /* ok */
545 }
546 switch (nlh->nlmsg_type)
547 {
548 case RTM_NEWLINK:
549 ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
550 nlm_struct_size = sizeof (*ifim);
551 nlm_family = ifim->ifi_family;
552 nlm_scope = 0;
553 nlm_index = ifim->ifi_index;
554 nlm_prefixlen = 0;
555 if (build)
556 ifflist[nlm_index] = ifa->ifa_flags = ifim->ifi_flags;
557 break;
558 case RTM_NEWADDR:
559 ifam = (struct ifaddrmsg *) NLMSG_DATA (nlh);
560 nlm_struct_size = sizeof (*ifam);
561 nlm_family = ifam->ifa_family;
562 nlm_scope = ifam->ifa_scope;
563 nlm_index = ifam->ifa_index;
564 nlm_prefixlen = ifam->ifa_prefixlen;
565 if (build)
566 ifa->ifa_flags = ifflist[nlm_index];
567 break;
568 default:
569 continue;
570 }
571
572 if (!build)
573 {
574 if (max_ifindex < nlm_index)
575 max_ifindex = nlm_index;
576 }
577 else
578 {
579 if (ifl != NULL)
580 ifl->ifa_next = ifa;
581 }
582
583 rtasize =
584 NLMSG_PAYLOAD (nlh, nlmlen) - NLMSG_ALIGN (nlm_struct_size);
585 for (rta =
586 (struct rtattr *) (((char *) NLMSG_DATA (nlh)) +
587 NLMSG_ALIGN (nlm_struct_size));
588 RTA_OK (rta, rtasize); rta = RTA_NEXT (rta, rtasize))
589 {
590 struct sockaddr **sap = NULL;
591 void *rtadata = RTA_DATA (rta);
592 size_t rtapayload = RTA_PAYLOAD (rta);
593 socklen_t sa_len;
594
595 switch (nlh->nlmsg_type)
596 {
597 case RTM_NEWLINK:
598 switch (rta->rta_type)
599 {
600 case IFLA_ADDRESS:
601 case IFLA_BROADCAST:
602 if (build)
603 {
604 sap =
605 (rta->rta_type ==
606 IFLA_ADDRESS) ? &ifa->ifa_addr : &ifa->
607 ifa_broadaddr;
608 *sap = (struct sockaddr *) data;
609 }
610 sa_len = ifa_sa_len (AF_PACKET, rtapayload);
611 if (rta->rta_type == IFLA_ADDRESS)
612 sockaddr_size = NLMSG_ALIGN (sa_len);
613 if (!build)
614 {
615 dlen += NLMSG_ALIGN (sa_len);
616 }
617 else
618 {
619 memset (*sap, 0, sa_len);
620 ifa_make_sockaddr (AF_PACKET, *sap, rtadata,
621 rtapayload, 0, 0);
622 ((struct sockaddr_ll *) *sap)->sll_ifindex =
623 nlm_index;
624 ((struct sockaddr_ll *) *sap)->sll_hatype =
625 ifim->ifi_type;
626 data += NLMSG_ALIGN (sa_len);
627 }
628 break;
629 case IFLA_IFNAME: /* Name of Interface */
630 if (!build)
631 nlen += NLMSG_ALIGN (rtapayload + 1);
632 else
633 {
634 ifa->ifa_name = ifname;
635 if (iflist[nlm_index] == NULL)
636 iflist[nlm_index] = ifa->ifa_name;
637 strncpy (ifa->ifa_name, rtadata, rtapayload);
638 ifa->ifa_name[rtapayload] = '\0';
639 ifname += NLMSG_ALIGN (rtapayload + 1);
640 }
641 break;
642 case IFLA_STATS: /* Statistics of Interface */
643 if (!build)
644 xlen += NLMSG_ALIGN (rtapayload);
645 else
646 {
647 ifa->ifa_data = xdata;
648 memcpy (ifa->ifa_data, rtadata, rtapayload);
649 xdata += NLMSG_ALIGN (rtapayload);
650 }
651 break;
652 case IFLA_UNSPEC:
653 break;
654 case IFLA_MTU:
655 break;
656 case IFLA_LINK:
657 break;
658 case IFLA_QDISC:
659 break;
660 default:
661 ;
662 }
663 break;
664 case RTM_NEWADDR:
665 if (nlm_family == AF_PACKET)
666 break;
667 switch (rta->rta_type)
668 {
669 case IFA_ADDRESS:
670 ifamap.address = rtadata;
671 ifamap.address_len = rtapayload;
672 break;
673 case IFA_LOCAL:
674 ifamap.local = rtadata;
675 ifamap.local_len = rtapayload;
676 break;
677 case IFA_BROADCAST:
678 ifamap.broadcast = rtadata;
679 ifamap.broadcast_len = rtapayload;
680 break;
681 #ifdef HAVE_IFADDRS_IFA_ANYCAST
682 case IFA_ANYCAST:
683 ifamap.anycast = rtadata;
684 ifamap.anycast_len = rtapayload;
685 break;
686 #endif
687 case IFA_LABEL:
688 if (!build)
689 nlen += NLMSG_ALIGN (rtapayload + 1);
690 else
691 {
692 ifa->ifa_name = ifname;
693 if (iflist[nlm_index] == NULL)
694 iflist[nlm_index] = ifname;
695 strncpy (ifa->ifa_name, rtadata, rtapayload);
696 ifa->ifa_name[rtapayload] = '\0';
697 ifname += NLMSG_ALIGN (rtapayload + 1);
698 }
699 break;
700 case IFA_UNSPEC:
701 break;
702 case IFA_CACHEINFO:
703 break;
704 default:
705 ;
706 }
707 }
708 }
709 if (nlh->nlmsg_type == RTM_NEWADDR && nlm_family != AF_PACKET)
710 {
711 if (!ifamap.local)
712 {
713 ifamap.local = ifamap.address;
714 ifamap.local_len = ifamap.address_len;
715 }
716 if (!ifamap.address)
717 {
718 ifamap.address = ifamap.local;
719 ifamap.address_len = ifamap.local_len;
720 }
721 if (ifamap.address_len != ifamap.local_len ||
722 (ifamap.address != NULL &&
723 memcmp (ifamap.address, ifamap.local,
724 ifamap.address_len)))
725 {
726 /* p2p; address is peer and local is ours */
727 ifamap.broadcast = ifamap.address;
728 ifamap.broadcast_len = ifamap.address_len;
729 ifamap.address = ifamap.local;
730 ifamap.address_len = ifamap.local_len;
731 }
732 if (ifamap.address)
733 {
734 #ifndef IFA_NETMASK
735 sockaddr_size =
736 NLMSG_ALIGN (ifa_sa_len
737 (nlm_family, ifamap.address_len));
738 #endif
739 if (!build)
740 dlen +=
741 NLMSG_ALIGN (ifa_sa_len
742 (nlm_family, ifamap.address_len));
743 else
744 {
745 ifa->ifa_addr = (struct sockaddr *) data;
746 ifa_make_sockaddr (nlm_family, ifa->ifa_addr,
747 ifamap.address,
748 ifamap.address_len, nlm_scope,
749 nlm_index);
750 data +=
751 NLMSG_ALIGN (ifa_sa_len
752 (nlm_family, ifamap.address_len));
753 }
754 }
755 #ifdef IFA_NETMASK
756 if (ifamap.netmask)
757 {
758 if (!build)
759 dlen +=
760 NLMSG_ALIGN (ifa_sa_len
761 (nlm_family, ifamap.netmask_len));
762 else
763 {
764 ifa->ifa_netmask = (struct sockaddr *) data;
765 ifa_make_sockaddr (nlm_family, ifa->ifa_netmask,
766 ifamap.netmask,
767 ifamap.netmask_len, nlm_scope,
768 nlm_index);
769 data +=
770 NLMSG_ALIGN (ifa_sa_len
771 (nlm_family, ifamap.netmask_len));
772 }
773 }
774 #endif
775 if (ifamap.broadcast)
776 {
777 if (!build)
778 dlen +=
779 NLMSG_ALIGN (ifa_sa_len
780 (nlm_family, ifamap.broadcast_len));
781 else
782 {
783 ifa->ifa_broadaddr = (struct sockaddr *) data;
784 ifa_make_sockaddr (nlm_family, ifa->ifa_broadaddr,
785 ifamap.broadcast,
786 ifamap.broadcast_len, nlm_scope,
787 nlm_index);
788 data +=
789 NLMSG_ALIGN (ifa_sa_len
790 (nlm_family, ifamap.broadcast_len));
791 }
792 }
793 #ifdef HAVE_IFADDRS_IFA_ANYCAST
794 if (ifamap.anycast)
795 {
796 if (!build)
797 dlen +=
798 NLMSG_ALIGN (ifa_sa_len
799 (nlm_family, ifamap.anycast_len));
800 else
801 {
802 ifa->ifa_anycast = (struct sockaddr *) data;
803 ifa_make_sockaddr (nlm_family, ifa->ifa_anyaddr,
804 ifamap.anycast,
805 ifamap.anycast_len, nlm_scope,
806 nlm_index);
807 data +=
808 NLMSG_ALIGN (ifa_sa_len
809 (nlm_family, ifamap.anycast_len));
810 }
811 }
812 #endif
813 }
814 if (!build)
815 {
816 #ifndef IFA_NETMASK
817 dlen += sockaddr_size;
818 #endif
819 icnt++;
820 }
821 else
822 {
823 if (ifa->ifa_name == NULL)
824 ifa->ifa_name = iflist[nlm_index];
825 #ifndef IFA_NETMASK
826 if (ifa->ifa_addr &&
827 ifa->ifa_addr->sa_family != AF_UNSPEC &&
828 ifa->ifa_addr->sa_family != AF_PACKET)
829 {
830 ifa->ifa_netmask = (struct sockaddr *) data;
831 ifa_make_sockaddr_mask (ifa->ifa_addr->sa_family,
832 ifa->ifa_netmask,
833 nlm_prefixlen);
834 }
835 data += sockaddr_size;
836 #endif
837 ifl = ifa++;
838 }
839 }
840 }
841 if (!build)
842 {
843 if (icnt == 0 && (dlen + nlen + xlen == 0))
844 {
845 if (ifap != NULL)
846 *ifap = NULL;
847 break; /* cannot found any addresses */
848 }
849 }
850 else
851 free_data (NULL, ifdata);
852 }
853
854 /* ---------------------------------- */
855 /* Finalize */
856 free_nlmsglist (nlmsg_list);
857 nl_close (sd);
858 return 0;
859 }
860
861 /* ---------------------------------------------------------------------- */
862 void
usagi_freeifaddrs(struct ifaddrs * ifa)863 usagi_freeifaddrs (struct ifaddrs *ifa)
864 {
865 free (ifa);
866 }
867
868
869 /* **************************************** */
870
871 #endif /* HAVE_LINUX_NETLINK_H */
872