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