Back to index

glibc  2.9
ifaddrs.c
Go to the documentation of this file.
00001 /* getifaddrs -- get names and addresses of all network interfaces
00002    Copyright (C) 2003-2007, 2008 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <alloca.h>
00021 #include <assert.h>
00022 #include <errno.h>
00023 #include <ifaddrs.h>
00024 #include <net/if.h>
00025 #include <netinet/in.h>
00026 #include <netpacket/packet.h>
00027 #include <stdbool.h>
00028 #include <stdint.h>
00029 #include <stdlib.h>
00030 #include <string.h>
00031 #include <sys/ioctl.h>
00032 #include <sys/socket.h>
00033 #include <sysdep.h>
00034 #include <time.h>
00035 #include <unistd.h>
00036 #include <kernel-features.h>
00037 
00038 #include "netlinkaccess.h"
00039 
00040 
00041 /* We don't know if we have NETLINK support compiled in in our
00042    Kernel, so include the old implementation as fallback.  */
00043 #if __ASSUME_NETLINK_SUPPORT == 0
00044 int __no_netlink_support attribute_hidden;
00045 
00046 # define getifaddrs fallback_getifaddrs
00047 # include "sysdeps/gnu/ifaddrs.c"
00048 # undef getifaddrs
00049 #endif
00050 
00051 
00052 /* There is a problem with this type.  The address length for
00053    Infiniband sockets is much longer than the 8 bytes allocated in the
00054    sockaddr_ll definition.  Hence we use here a special
00055    definition.  */
00056 struct sockaddr_ll_max
00057   {
00058     unsigned short int sll_family;
00059     unsigned short int sll_protocol;
00060     int sll_ifindex;
00061     unsigned short int sll_hatype;
00062     unsigned char sll_pkttype;
00063     unsigned char sll_halen;
00064     unsigned char sll_addr[24];
00065   };
00066 
00067 
00068 /* struct to hold the data for one ifaddrs entry, so we can allocate
00069    everything at once.  */
00070 struct ifaddrs_storage
00071 {
00072   struct ifaddrs ifa;
00073   union
00074   {
00075     /* Save space for the biggest of the four used sockaddr types and
00076        avoid a lot of casts.  */
00077     struct sockaddr sa;
00078     struct sockaddr_ll_max sl;
00079     struct sockaddr_in s4;
00080     struct sockaddr_in6 s6;
00081   } addr, netmask, broadaddr;
00082   char name[IF_NAMESIZE + 1];
00083 };
00084 
00085 
00086 void
00087 __netlink_free_handle (struct netlink_handle *h)
00088 {
00089   struct netlink_res *ptr;
00090   int saved_errno = errno;
00091 
00092   ptr = h->nlm_list;
00093   while (ptr != NULL)
00094     {
00095       struct netlink_res *tmpptr;
00096 
00097       tmpptr = ptr->next;
00098       free (ptr);
00099       ptr = tmpptr;
00100     }
00101 
00102   __set_errno (saved_errno);
00103 }
00104 
00105 
00106 static int
00107 __netlink_sendreq (struct netlink_handle *h, int type)
00108 {
00109   struct req
00110   {
00111     struct nlmsghdr nlh;
00112     struct rtgenmsg g;
00113     char pad[0];
00114   } req;
00115   struct sockaddr_nl nladdr;
00116 
00117   if (h->seq == 0)
00118     h->seq = time (NULL);
00119 
00120   req.nlh.nlmsg_len = sizeof (req);
00121   req.nlh.nlmsg_type = type;
00122   req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
00123   req.nlh.nlmsg_pid = 0;
00124   req.nlh.nlmsg_seq = h->seq;
00125   req.g.rtgen_family = AF_UNSPEC;
00126   if (sizeof (req) != offsetof (struct req, pad))
00127     memset (req.pad, '\0', sizeof (req) - offsetof (struct req, pad));
00128 
00129   memset (&nladdr, '\0', sizeof (nladdr));
00130   nladdr.nl_family = AF_NETLINK;
00131 
00132   return TEMP_FAILURE_RETRY (__sendto (h->fd, (void *) &req, sizeof (req), 0,
00133                                    (struct sockaddr *) &nladdr,
00134                                    sizeof (nladdr)));
00135 }
00136 
00137 
00138 int
00139 __netlink_request (struct netlink_handle *h, int type)
00140 {
00141   struct netlink_res *nlm_next;
00142   struct sockaddr_nl nladdr;
00143   struct nlmsghdr *nlmh;
00144   ssize_t read_len;
00145   bool done = false;
00146 
00147 #ifdef PAGE_SIZE
00148   /* Help the compiler optimize out the malloc call if PAGE_SIZE
00149      is constant and smaller or equal to PTHREAD_STACK_MIN/4.  */
00150   const size_t buf_size = PAGE_SIZE;
00151 #else
00152   const size_t buf_size = __getpagesize ();
00153 #endif
00154   bool use_malloc = false;
00155   char *buf;
00156 
00157   if (__libc_use_alloca (buf_size))
00158     buf = alloca (buf_size);
00159   else
00160     {
00161       buf = malloc (buf_size);
00162       if (buf != NULL)
00163        use_malloc = true;
00164       else
00165        goto out_fail;
00166     }
00167 
00168   struct iovec iov = { buf, buf_size };
00169 
00170   if (__netlink_sendreq (h, type) < 0)
00171     goto out_fail;
00172 
00173   while (! done)
00174     {
00175       struct msghdr msg =
00176        {
00177          (void *) &nladdr, sizeof (nladdr),
00178          &iov, 1,
00179          NULL, 0,
00180          0
00181        };
00182 
00183       read_len = TEMP_FAILURE_RETRY (__recvmsg (h->fd, &msg, 0));
00184       if (read_len < 0)
00185        goto out_fail;
00186 
00187       if (nladdr.nl_pid != 0)
00188        continue;
00189 
00190       if (__builtin_expect (msg.msg_flags & MSG_TRUNC, 0))
00191        goto out_fail;
00192 
00193       size_t count = 0;
00194       size_t remaining_len = read_len;
00195       for (nlmh = (struct nlmsghdr *) buf;
00196           NLMSG_OK (nlmh, remaining_len);
00197           nlmh = (struct nlmsghdr *) NLMSG_NEXT (nlmh, remaining_len))
00198        {
00199          if ((pid_t) nlmh->nlmsg_pid != h->pid
00200              || nlmh->nlmsg_seq != h->seq)
00201            continue;
00202 
00203          ++count;
00204          if (nlmh->nlmsg_type == NLMSG_DONE)
00205            {
00206              /* We found the end, leave the loop.  */
00207              done = true;
00208              break;
00209            }
00210          if (nlmh->nlmsg_type == NLMSG_ERROR)
00211            {
00212              struct nlmsgerr *nlerr = (struct nlmsgerr *) NLMSG_DATA (nlmh);
00213              if (nlmh->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
00214               errno = EIO;
00215              else
00216               errno = -nlerr->error;
00217              goto out_fail;
00218            }
00219        }
00220 
00221       /* If there was nothing with the expected nlmsg_pid and nlmsg_seq,
00222         there is no point to record it.  */
00223       if (count == 0)
00224        continue;
00225 
00226       nlm_next = (struct netlink_res *) malloc (sizeof (struct netlink_res)
00227                                           + read_len);
00228       if (nlm_next == NULL)
00229        goto out_fail;
00230       nlm_next->next = NULL;
00231       nlm_next->nlh = memcpy (nlm_next + 1, buf, read_len);
00232       nlm_next->size = read_len;
00233       nlm_next->seq = h->seq;
00234       if (h->nlm_list == NULL)
00235        h->nlm_list = nlm_next;
00236       else
00237        h->end_ptr->next = nlm_next;
00238       h->end_ptr = nlm_next;
00239     }
00240 
00241   if (use_malloc)
00242     free (buf);
00243   return 0;
00244 
00245 out_fail:
00246   if (use_malloc)
00247     free (buf);
00248   return -1;
00249 }
00250 
00251 
00252 void
00253 __netlink_close (struct netlink_handle *h)
00254 {
00255   /* Don't modify errno.  */
00256   INTERNAL_SYSCALL_DECL (err);
00257   (void) INTERNAL_SYSCALL (close, err, 1, h->fd);
00258 }
00259 
00260 
00261 /* Open a NETLINK socket.  */
00262 int
00263 __netlink_open (struct netlink_handle *h)
00264 {
00265   struct sockaddr_nl nladdr;
00266 
00267   h->fd = __socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
00268   if (h->fd < 0)
00269     goto out;
00270 
00271   memset (&nladdr, '\0', sizeof (nladdr));
00272   nladdr.nl_family = AF_NETLINK;
00273   if (__bind (h->fd, (struct sockaddr *) &nladdr, sizeof (nladdr)) < 0)
00274     {
00275     close_and_out:
00276       __netlink_close (h);
00277     out:
00278 #if __ASSUME_NETLINK_SUPPORT == 0
00279       __no_netlink_support = 1;
00280 #endif
00281       return -1;
00282     }
00283   /* Determine the ID the kernel assigned for this netlink connection.
00284      It is not necessarily the PID if there is more than one socket
00285      open.  */
00286   socklen_t addr_len = sizeof (nladdr);
00287   if (__getsockname (h->fd, (struct sockaddr *) &nladdr, &addr_len) < 0)
00288     goto close_and_out;
00289   h->pid = nladdr.nl_pid;
00290   return 0;
00291 }
00292 
00293 
00294 /* We know the number of RTM_NEWLINK entries, so we reserve the first
00295    # of entries for this type. All RTM_NEWADDR entries have an index
00296    pointer to the RTM_NEWLINK entry.  To find the entry, create
00297    a table to map kernel index entries to our index numbers.
00298    Since we get at first all RTM_NEWLINK entries, it can never happen
00299    that a RTM_NEWADDR index is not known to this map.  */
00300 static int
00301 internal_function
00302 map_newlink (int index, struct ifaddrs_storage *ifas, int *map, int max)
00303 {
00304   int i;
00305 
00306   for (i = 0; i < max; i++)
00307     {
00308       if (map[i] == -1)
00309        {
00310          map[i] = index;
00311          if (i > 0)
00312            ifas[i - 1].ifa.ifa_next = &ifas[i].ifa;
00313          return i;
00314        }
00315       else if (map[i] == index)
00316        return i;
00317     }
00318   /* This should never be reached. If this will be reached, we have
00319      a very big problem.  */
00320   abort ();
00321 }
00322 
00323 
00324 /* Create a linked list of `struct ifaddrs' structures, one for each
00325    network interface on the host machine.  If successful, store the
00326    list in *IFAP and 2004, 2005, 2006, return 0.  On errors, return -1 and set `errno'.  */
00327 int
00328 getifaddrs (struct ifaddrs **ifap)
00329 {
00330   struct netlink_handle nh = { 0, 0, 0, NULL, NULL };
00331   struct netlink_res *nlp;
00332   struct ifaddrs_storage *ifas;
00333   unsigned int i, newlink, newaddr, newaddr_idx;
00334   int *map_newlink_data;
00335   size_t ifa_data_size = 0;  /* Size to allocate for all ifa_data.  */
00336   char *ifa_data_ptr;       /* Pointer to the unused part of memory for
00337                             ifa_data.  */
00338   int result = 0;
00339 
00340   *ifap = NULL;
00341 
00342   if (! __no_netlink_support && __netlink_open (&nh) < 0)
00343     {
00344 #if __ASSUME_NETLINK_SUPPORT != 0
00345       return -1;
00346 #endif
00347     }
00348 
00349 #if __ASSUME_NETLINK_SUPPORT == 0
00350   if (__no_netlink_support)
00351     return fallback_getifaddrs (ifap);
00352 #endif
00353 
00354   /* Tell the kernel that we wish to get a list of all
00355      active interfaces, collect all data for every interface.  */
00356   if (__netlink_request (&nh, RTM_GETLINK) < 0)
00357     {
00358       result = -1;
00359       goto exit_free;
00360     }
00361 
00362   /* Now ask the kernel for all addresses which are assigned
00363      to an interface and collect all data for every interface.
00364      Since we store the addresses after the interfaces in the
00365      list, we will later always find the interface before the
00366      corresponding addresses.  */
00367   ++nh.seq;
00368   if (__netlink_request (&nh, RTM_GETADDR) < 0)
00369     {
00370       result = -1;
00371       goto exit_free;
00372     }
00373 
00374   /* Count all RTM_NEWLINK and RTM_NEWADDR entries to allocate
00375      enough memory.  */
00376   newlink = newaddr = 0;
00377   for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
00378     {
00379       struct nlmsghdr *nlh;
00380       size_t size = nlp->size;
00381 
00382       if (nlp->nlh == NULL)
00383        continue;
00384 
00385       /* Walk through all entries we got from the kernel and look, which
00386         message type they contain.  */
00387       for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
00388        {
00389          /* Check if the message is what we want.  */
00390          if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
00391            continue;
00392 
00393          if (nlh->nlmsg_type == NLMSG_DONE)
00394            break;           /* ok */
00395 
00396          if (nlh->nlmsg_type == RTM_NEWLINK)
00397            {
00398              /* A RTM_NEWLINK message can have IFLA_STATS data. We need to
00399                know the size before creating the list to allocate enough
00400                memory.  */
00401              struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
00402              struct rtattr *rta = IFLA_RTA (ifim);
00403              size_t rtasize = IFLA_PAYLOAD (nlh);
00404 
00405              while (RTA_OK (rta, rtasize))
00406               {
00407                 size_t rta_payload = RTA_PAYLOAD (rta);
00408 
00409                 if (rta->rta_type == IFLA_STATS)
00410                   {
00411                     ifa_data_size += rta_payload;
00412                     break;
00413                   }
00414                 else
00415                   rta = RTA_NEXT (rta, rtasize);
00416               }
00417              ++newlink;
00418            }
00419          else if (nlh->nlmsg_type == RTM_NEWADDR)
00420            ++newaddr;
00421        }
00422     }
00423 
00424   /* Return if no interface is up.  */
00425   if ((newlink + newaddr) == 0)
00426     goto exit_free;
00427 
00428   /* Allocate memory for all entries we have and initialize next
00429      pointer.  */
00430   ifas = (struct ifaddrs_storage *) calloc (1,
00431                                        (newlink + newaddr)
00432                                        * sizeof (struct ifaddrs_storage)
00433                                        + ifa_data_size);
00434   if (ifas == NULL)
00435     {
00436       result = -1;
00437       goto exit_free;
00438     }
00439 
00440   /* Table for mapping kernel index to entry in our list.  */
00441   map_newlink_data = alloca (newlink * sizeof (int));
00442   memset (map_newlink_data, '\xff', newlink * sizeof (int));
00443 
00444   ifa_data_ptr = (char *) &ifas[newlink + newaddr];
00445   newaddr_idx = 0;          /* Counter for newaddr index.  */
00446 
00447   /* Walk through the list of data we got from the kernel.  */
00448   for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
00449     {
00450       struct nlmsghdr *nlh;
00451       size_t size = nlp->size;
00452 
00453       if (nlp->nlh == NULL)
00454        continue;
00455 
00456       /* Walk through one message and look at the type: If it is our
00457         message, we need RTM_NEWLINK/RTM_NEWADDR and stop if we reach
00458         the end or we find the end marker (in this case we ignore the
00459         following data.  */
00460       for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
00461        {
00462          int ifa_index = 0;
00463 
00464          /* Check if the message is the one we want */
00465          if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
00466            continue;
00467 
00468          if (nlh->nlmsg_type == NLMSG_DONE)
00469            break;           /* ok */
00470 
00471          if (nlh->nlmsg_type == RTM_NEWLINK)
00472            {
00473              /* We found a new interface. Now extract everything from the
00474                interface data we got and need.  */
00475              struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
00476              struct rtattr *rta = IFLA_RTA (ifim);
00477              size_t rtasize = IFLA_PAYLOAD (nlh);
00478 
00479              /* Interfaces are stored in the first "newlink" entries
00480                of our list, starting in the order as we got from the
00481                kernel.  */
00482              ifa_index = map_newlink (ifim->ifi_index - 1, ifas,
00483                                    map_newlink_data, newlink);
00484              ifas[ifa_index].ifa.ifa_flags = ifim->ifi_flags;
00485 
00486              while (RTA_OK (rta, rtasize))
00487               {
00488                 char *rta_data = RTA_DATA (rta);
00489                 size_t rta_payload = RTA_PAYLOAD (rta);
00490 
00491                 switch (rta->rta_type)
00492                   {
00493                   case IFLA_ADDRESS:
00494                     if (rta_payload <= sizeof (ifas[ifa_index].addr))
00495                      {
00496                        ifas[ifa_index].addr.sl.sll_family = AF_PACKET;
00497                        memcpy (ifas[ifa_index].addr.sl.sll_addr,
00498                               (char *) rta_data, rta_payload);
00499                        ifas[ifa_index].addr.sl.sll_halen = rta_payload;
00500                        ifas[ifa_index].addr.sl.sll_ifindex
00501                          = ifim->ifi_index;
00502                        ifas[ifa_index].addr.sl.sll_hatype = ifim->ifi_type;
00503 
00504                        ifas[ifa_index].ifa.ifa_addr
00505                          = &ifas[ifa_index].addr.sa;
00506                      }
00507                     break;
00508 
00509                   case IFLA_BROADCAST:
00510                     if (rta_payload <= sizeof (ifas[ifa_index].broadaddr))
00511                      {
00512                        ifas[ifa_index].broadaddr.sl.sll_family = AF_PACKET;
00513                        memcpy (ifas[ifa_index].broadaddr.sl.sll_addr,
00514                               (char *) rta_data, rta_payload);
00515                        ifas[ifa_index].broadaddr.sl.sll_halen = rta_payload;
00516                        ifas[ifa_index].broadaddr.sl.sll_ifindex
00517                          = ifim->ifi_index;
00518                        ifas[ifa_index].broadaddr.sl.sll_hatype
00519                          = ifim->ifi_type;
00520 
00521                        ifas[ifa_index].ifa.ifa_broadaddr
00522                          = &ifas[ifa_index].broadaddr.sa;
00523                      }
00524                     break;
00525 
00526                   case IFLA_IFNAME:       /* Name of Interface */
00527                     if ((rta_payload + 1) <= sizeof (ifas[ifa_index].name))
00528                      {
00529                        ifas[ifa_index].ifa.ifa_name = ifas[ifa_index].name;
00530                        *(char *) __mempcpy (ifas[ifa_index].name, rta_data,
00531                                           rta_payload) = '\0';
00532                      }
00533                     break;
00534 
00535                   case IFLA_STATS: /* Statistics of Interface */
00536                     ifas[ifa_index].ifa.ifa_data = ifa_data_ptr;
00537                     ifa_data_ptr += rta_payload;
00538                     memcpy (ifas[ifa_index].ifa.ifa_data, rta_data,
00539                            rta_payload);
00540                     break;
00541 
00542                   case IFLA_UNSPEC:
00543                     break;
00544                   case IFLA_MTU:
00545                     break;
00546                   case IFLA_LINK:
00547                     break;
00548                   case IFLA_QDISC:
00549                     break;
00550                   default:
00551                     break;
00552                   }
00553 
00554                 rta = RTA_NEXT (rta, rtasize);
00555               }
00556            }
00557          else if (nlh->nlmsg_type == RTM_NEWADDR)
00558            {
00559              struct ifaddrmsg *ifam = (struct ifaddrmsg *) NLMSG_DATA (nlh);
00560              struct rtattr *rta = IFA_RTA (ifam);
00561              size_t rtasize = IFA_PAYLOAD (nlh);
00562 
00563              /* New Addresses are stored in the order we got them from
00564                the kernel after the interfaces. Theoretically it is possible
00565                that we have holes in the interface part of the list,
00566                but we always have already the interface for this address.  */
00567              ifa_index = newlink + newaddr_idx;
00568              ifas[ifa_index].ifa.ifa_flags
00569               = ifas[map_newlink (ifam->ifa_index - 1, ifas,
00570                                 map_newlink_data, newlink)].ifa.ifa_flags;
00571              if (ifa_index > 0)
00572               ifas[ifa_index - 1].ifa.ifa_next = &ifas[ifa_index].ifa;
00573              ++newaddr_idx;
00574 
00575              while (RTA_OK (rta, rtasize))
00576               {
00577                 char *rta_data = RTA_DATA (rta);
00578                 size_t rta_payload = RTA_PAYLOAD (rta);
00579 
00580                 switch (rta->rta_type)
00581                   {
00582                   case IFA_ADDRESS:
00583                     {
00584                      struct sockaddr *sa;
00585 
00586                      if (ifas[ifa_index].ifa.ifa_addr != NULL)
00587                        {
00588                          /* In a point-to-poing network IFA_ADDRESS
00589                             contains the destination address, local
00590                             address is supplied in IFA_LOCAL attribute.
00591                             destination address and broadcast address
00592                             are stored in an union, so it doesn't matter
00593                             which name we use.  */
00594                          ifas[ifa_index].ifa.ifa_broadaddr
00595                            = &ifas[ifa_index].broadaddr.sa;
00596                          sa = &ifas[ifa_index].broadaddr.sa;
00597                        }
00598                      else
00599                        {
00600                          ifas[ifa_index].ifa.ifa_addr
00601                            = &ifas[ifa_index].addr.sa;
00602                          sa = &ifas[ifa_index].addr.sa;
00603                        }
00604 
00605                      sa->sa_family = ifam->ifa_family;
00606 
00607                      switch (ifam->ifa_family)
00608                        {
00609                        case AF_INET:
00610                          /* Size must match that of an address for IPv4.  */
00611                          if (rta_payload == 4)
00612                            memcpy (&((struct sockaddr_in *) sa)->sin_addr,
00613                                   rta_data, rta_payload);
00614                          break;
00615 
00616                        case AF_INET6:
00617                          /* Size must match that of an address for IPv6.  */
00618                          if (rta_payload == 16)
00619                            {
00620                             memcpy (&((struct sockaddr_in6 *) sa)->sin6_addr,
00621                                    rta_data, rta_payload);
00622                             if (IN6_IS_ADDR_LINKLOCAL (rta_data)
00623                                 || IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
00624                               ((struct sockaddr_in6 *) sa)->sin6_scope_id
00625                                 = ifam->ifa_index;
00626                            }
00627                          break;
00628 
00629                        default:
00630                          if (rta_payload <= sizeof (ifas[ifa_index].addr))
00631                            memcpy (sa->sa_data, rta_data, rta_payload);
00632                          break;
00633                        }
00634                     }
00635                     break;
00636 
00637                   case IFA_LOCAL:
00638                     if (ifas[ifa_index].ifa.ifa_addr != NULL)
00639                      {
00640                        /* If ifa_addr is set and we get IFA_LOCAL,
00641                           assume we have a point-to-point network.
00642                           Move address to correct field.  */
00643                        ifas[ifa_index].broadaddr = ifas[ifa_index].addr;
00644                        ifas[ifa_index].ifa.ifa_broadaddr
00645                          = &ifas[ifa_index].broadaddr.sa;
00646                        memset (&ifas[ifa_index].addr, '\0',
00647                               sizeof (ifas[ifa_index].addr));
00648                      }
00649 
00650                     ifas[ifa_index].ifa.ifa_addr = &ifas[ifa_index].addr.sa;
00651                     ifas[ifa_index].ifa.ifa_addr->sa_family
00652                      = ifam->ifa_family;
00653 
00654                     switch (ifam->ifa_family)
00655                      {
00656                      case AF_INET:
00657                        /* Size must match that of an address for IPv4.  */
00658                        if (rta_payload == 4)
00659                          memcpy (&ifas[ifa_index].addr.s4.sin_addr,
00660                               rta_data, rta_payload);
00661                        break;
00662 
00663                      case AF_INET6:
00664                        /* Size must match that of an address for IPv6.  */
00665                        if (rta_payload == 16)
00666                          {
00667                            memcpy (&ifas[ifa_index].addr.s6.sin6_addr,
00668                                   rta_data, rta_payload);
00669                            if (IN6_IS_ADDR_LINKLOCAL (rta_data)
00670                               || IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
00671                             ifas[ifa_index].addr.s6.sin6_scope_id =
00672                               ifam->ifa_index;
00673                          }
00674                        break;
00675 
00676                      default:
00677                        if (rta_payload <= sizeof (ifas[ifa_index].addr))
00678                          memcpy (ifas[ifa_index].addr.sa.sa_data,
00679                                 rta_data, rta_payload);
00680                        break;
00681                      }
00682                     break;
00683 
00684                   case IFA_BROADCAST:
00685                     /* We get IFA_BROADCAST, so IFA_LOCAL was too much.  */
00686                     if (ifas[ifa_index].ifa.ifa_broadaddr != NULL)
00687                      memset (&ifas[ifa_index].broadaddr, '\0',
00688                             sizeof (ifas[ifa_index].broadaddr));
00689 
00690                     ifas[ifa_index].ifa.ifa_broadaddr
00691                      = &ifas[ifa_index].broadaddr.sa;
00692                     ifas[ifa_index].ifa.ifa_broadaddr->sa_family
00693                      = ifam->ifa_family;
00694 
00695                     switch (ifam->ifa_family)
00696                      {
00697                      case AF_INET:
00698                        /* Size must match that of an address for IPv4.  */
00699                        if (rta_payload == 4)
00700                          memcpy (&ifas[ifa_index].broadaddr.s4.sin_addr,
00701                                 rta_data, rta_payload);
00702                        break;
00703 
00704                      case AF_INET6:
00705                        /* Size must match that of an address for IPv6.  */
00706                        if (rta_payload == 16)
00707                          {
00708                            memcpy (&ifas[ifa_index].broadaddr.s6.sin6_addr,
00709                                   rta_data, rta_payload);
00710                            if (IN6_IS_ADDR_LINKLOCAL (rta_data)
00711                               || IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
00712                             ifas[ifa_index].broadaddr.s6.sin6_scope_id
00713                               = ifam->ifa_index;
00714                          }
00715                        break;
00716 
00717                      default:
00718                        if (rta_payload <= sizeof (ifas[ifa_index].addr))
00719                          memcpy (&ifas[ifa_index].broadaddr.sa.sa_data,
00720                                 rta_data, rta_payload);
00721                        break;
00722                      }
00723                     break;
00724 
00725                   case IFA_LABEL:
00726                     if (rta_payload + 1 <= sizeof (ifas[ifa_index].name))
00727                      {
00728                        ifas[ifa_index].ifa.ifa_name = ifas[ifa_index].name;
00729                        *(char *) __mempcpy (ifas[ifa_index].name, rta_data,
00730                                           rta_payload) = '\0';
00731                      }
00732                     else
00733                      abort ();
00734                     break;
00735 
00736                   case IFA_UNSPEC:
00737                     break;
00738                   case IFA_CACHEINFO:
00739                     break;
00740                   default:
00741                     break;
00742                   }
00743 
00744                 rta = RTA_NEXT (rta, rtasize);
00745               }
00746 
00747              /* If we didn't get the interface name with the
00748                address, use the name from the interface entry.  */
00749              if (ifas[ifa_index].ifa.ifa_name == NULL)
00750               ifas[ifa_index].ifa.ifa_name
00751                 = ifas[map_newlink (ifam->ifa_index - 1, ifas,
00752                                   map_newlink_data, newlink)].ifa.ifa_name;
00753 
00754              /* Calculate the netmask.  */
00755              if (ifas[ifa_index].ifa.ifa_addr
00756                 && ifas[ifa_index].ifa.ifa_addr->sa_family != AF_UNSPEC
00757                 && ifas[ifa_index].ifa.ifa_addr->sa_family != AF_PACKET)
00758               {
00759                 uint32_t max_prefixlen = 0;
00760                 char *cp = NULL;
00761 
00762                 ifas[ifa_index].ifa.ifa_netmask
00763                   = &ifas[ifa_index].netmask.sa;
00764 
00765                 switch (ifas[ifa_index].ifa.ifa_addr->sa_family)
00766                   {
00767                   case AF_INET:
00768                     cp = (char *) &ifas[ifa_index].netmask.s4.sin_addr;
00769                     max_prefixlen = 32;
00770                     break;
00771 
00772                   case AF_INET6:
00773                     cp = (char *) &ifas[ifa_index].netmask.s6.sin6_addr;
00774                     max_prefixlen = 128;
00775                     break;
00776                   }
00777 
00778                 ifas[ifa_index].ifa.ifa_netmask->sa_family
00779                   = ifas[ifa_index].ifa.ifa_addr->sa_family;
00780 
00781                 if (cp != NULL)
00782                   {
00783                     char c;
00784                     unsigned int preflen;
00785 
00786                     if ((max_prefixlen > 0) &&
00787                        (ifam->ifa_prefixlen > max_prefixlen))
00788                      preflen = max_prefixlen;
00789                     else
00790                      preflen = ifam->ifa_prefixlen;
00791 
00792                     for (i = 0; i < (preflen / 8); i++)
00793                      *cp++ = 0xff;
00794                     c = 0xff;
00795                     c <<= (8 - (preflen % 8));
00796                     *cp = c;
00797                   }
00798               }
00799            }
00800        }
00801     }
00802 
00803   assert (ifa_data_ptr <= (char *) &ifas[newlink + newaddr] + ifa_data_size);
00804 
00805   if (newaddr_idx > 0)
00806     {
00807       for (i = 0; i < newlink; ++i)
00808        if (map_newlink_data[i] == -1)
00809          {
00810            /* We have fewer links then we anticipated.  Adjust the
00811               forward pointer to the first address entry.  */
00812            ifas[i - 1].ifa.ifa_next = &ifas[newlink].ifa;
00813          }
00814 
00815       if (i == 0 && newlink > 0)
00816        /* No valid link, but we allocated memory.  We have to
00817           populate the first entry.  */
00818        memmove (ifas, &ifas[newlink], sizeof (struct ifaddrs_storage));
00819     }
00820 
00821   *ifap = &ifas[0].ifa;
00822 
00823  exit_free:
00824   __netlink_free_handle (&nh);
00825   __netlink_close (&nh);
00826 
00827   return result;
00828 }
00829 libc_hidden_def (getifaddrs)
00830 
00831 
00832 #if __ASSUME_NETLINK_SUPPORT != 0
00833 void
00834 freeifaddrs (struct ifaddrs *ifa)
00835 {
00836   free (ifa);
00837 }
00838 libc_hidden_def (freeifaddrs)
00839 #endif