model/dce-netdb.cc
author Hajime Tazaki <tazaki@sfc.wide.ad.jp>
Sun, 10 Nov 2013 00:37:22 +0900
changeset 526 73285fae30f9
parent 367 be749a6bbde0
child 704 5a2e3ff9f1db
permissions -rw-r--r--
Bug 1765 - DCE can't use TapBridge if built via bake
     1 #include "dce-netdb.h"
     2 #include "utils.h"
     3 #include "dce-stdlib.h"
     4 #include "dce-string.h"
     5 #include "ns3/assert.h"
     6 #include "ns3/log.h"
     7 #include "ns3/ipv4-address.h"
     8 #include <string.h>
     9 #include "process.h"
    10 #include "errno.h"
    11 #include <net/if.h>
    12 #include <netinet/in.h>
    13 #include <sys/types.h>
    14 #include <ifaddrs.h>
    15 #include <linux/netlink.h>
    16 #include <linux/rtnetlink.h>
    17 #include "sys/dce-socket.h"
    18 #include "dce-unistd.h"
    19 #include "dce-signal.h"
    20 
    21 NS_LOG_COMPONENT_DEFINE ("DceNetdb");
    22 
    23 using namespace ns3;
    24 
    25 struct hostent * dce_gethostbyname (const char *name)
    26 {
    27   NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << name);
    28   NS_ASSERT (Current () != 0);
    29   static struct hostent host;
    30   static uint32_t addr;
    31   static char *alias_end = 0;
    32   static char *addr_list[2];
    33 
    34 
    35   Ipv4Address ipv4 = Ipv4Address (name);
    36   addr = htonl (ipv4.Get ());
    37 
    38   //XXX: We do not implement dns lookup here for now. We just
    39   // interpret simple ip strings.
    40 
    41   host.h_name = (char *)name;
    42   host.h_addrtype = AF_INET;
    43   host.h_aliases = &alias_end;
    44   host.h_length = 4;
    45   host.h_addr_list = addr_list;
    46   addr_list[0] = (char *)&addr;
    47   addr_list[1] = 0;
    48   return &host;
    49 }
    50 struct hostent * dce_gethostbyname2 (const char *name, int af)
    51 {
    52   NS_ASSERT (af == AF_INET);
    53   return dce_gethostbyname (name);
    54 }
    55 int dce_getaddrinfo (const char *node, const char *service,
    56                      const struct addrinfo *hints,
    57                      struct addrinfo **res)
    58 {
    59   NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << ((NULL == node) ? "" : node) << ((NULL == service) ? "" : service) << hints << res);
    60   NS_ASSERT (Current () != 0);
    61   struct addrinfo *tmp = 0;
    62   int status = ::getaddrinfo (node, service, hints, &tmp);
    63   // copy outgoing data structure so that the memory is allocated from the calling process memory pool.
    64   struct addrinfo *cur, *prev, *head;
    65   head = 0;
    66   prev = 0;
    67   for (cur = tmp; cur != 0; cur = cur->ai_next)
    68     {
    69       struct addrinfo *copy = (struct addrinfo*)dce_malloc (sizeof(struct addrinfo));
    70       memcpy (copy, cur, sizeof (struct addrinfo));
    71       copy->ai_addr = (struct sockaddr*)dce_malloc (cur->ai_addrlen);
    72       if (cur->ai_canonname != 0)
    73         {
    74           copy->ai_canonname = dce_strdup (cur->ai_canonname);
    75         }
    76       else
    77         {
    78           copy->ai_canonname = 0;
    79         }
    80       memcpy (copy->ai_addr, cur->ai_addr, cur->ai_addrlen);
    81       if (prev != 0)
    82         {
    83           prev->ai_next = copy;
    84         }
    85       else
    86         {
    87           head = copy;
    88         }
    89       prev = copy;
    90     }
    91   if (prev != 0)
    92     {
    93       prev->ai_next = 0;
    94     }
    95   if (status == 0)
    96     {
    97       *res = head;
    98     }
    99   else
   100     {
   101       *res = 0;
   102     }
   103   ::freeaddrinfo (tmp);
   104   return status;
   105 }
   106 void dce_freeaddrinfo (struct addrinfo *res)
   107 {
   108   NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << res);
   109   NS_ASSERT (Current () != 0);
   110   struct addrinfo *cur, *next;
   111   for (cur = res; cur != 0; cur = next)
   112     {
   113       next = cur->ai_next;
   114       dce_free (cur->ai_addr);
   115       if (cur->ai_canonname != 0)
   116         {
   117           dce_free (cur->ai_canonname);
   118         }
   119       dce_free (cur);
   120     }
   121 }
   122 const char * dce_gai_strerror (int errcode)
   123 {
   124   NS_LOG_FUNCTION (Current () << UtilsGetNodeId () << errcode);
   125   NS_ASSERT (Current () != 0);
   126   return ::gai_strerror (errcode);
   127 }
   128 int dce_getnameinfo (const struct sockaddr *sa, socklen_t salen, char *host,
   129                      socklen_t hostlen, char *serv, socklen_t servlen, unsigned int flags)
   130 {
   131   NS_LOG_FUNCTION (Current ());
   132 
   133   if ((0 == sa) || (0 == salen))
   134     {
   135       Current ()->err = EINVAL;
   136       return EAI_SYSTEM;
   137     }
   138 
   139   switch (sa->sa_family)
   140     {
   141     case AF_INET:
   142       {
   143         if (salen < sizeof (struct sockaddr_in))
   144           {
   145             Current ()->err = EINVAL;
   146             return EAI_SYSTEM;
   147           }
   148         const struct sockaddr_in *inAddr = (const struct sockaddr_in *) sa;
   149 
   150         if (0 != serv)
   151           {
   152             int r = snprintf (serv, servlen, "%d",  htons (inAddr->sin_port));
   153 
   154             if (r > (int)servlen)
   155               {
   156                 return EAI_OVERFLOW;
   157               }
   158             if (r < 0)
   159               {
   160                 Current ()->err = errno;
   161                 return EAI_SYSTEM;
   162               }
   163           }
   164         if  (0 != host)
   165           {
   166             Ipv4Address ipv4 = Ipv4Address (htonl (inAddr->sin_addr.s_addr));
   167             std::ostringstream oss;
   168             ipv4.Print (oss);
   169 
   170             int r = snprintf (host, hostlen, "%s", oss.str ().c_str ());
   171 
   172             if (r > (int)hostlen)
   173               {
   174                 return EAI_OVERFLOW;
   175               }
   176             if (r < 0)
   177               {
   178                 Current ()->err = errno;
   179                 return EAI_SYSTEM;
   180               }
   181           }
   182         return 0;
   183       }
   184       break;
   185 
   186     default:
   187       return EAI_FAMILY;
   188     }
   189 
   190   return 0; // XXX : cheater
   191 }
   192 
   193 void dce_herror (const char *string)
   194 {
   195   NS_LOG_FUNCTION (Current () << UtilsGetNodeId ());
   196   NS_ASSERT (Current () != 0);
   197 
   198   fprintf (*Current ()->process->pstderr, "%s : %s\n", string, "ERROR");
   199 }
   200 
   201 // Copy from glibc source
   202 // eglibc-2.11.1/sysdeps/unix/sysv/linux/ifaddr.c
   203 struct netlink_res
   204 {
   205   struct netlink_res *next;
   206   struct nlmsghdr *nlh;
   207   size_t size;                  /* Size of response.  */
   208   uint32_t seq;                 /* sequential number we used.  */
   209 };
   210 struct netlink_handle
   211 {
   212   int fd;                       /* Netlink file descriptor.  */
   213   pid_t pid;                    /* Process ID.  */
   214   uint32_t seq;                 /* The sequence number we use currently.  */
   215   struct netlink_res *nlm_list; /* Pointer to list of responses.  */
   216   struct netlink_res *end_ptr;  /* For faster append of new entries.  */
   217 };
   218 struct sockaddr_ll_max
   219 {
   220   unsigned short int sll_family;
   221   unsigned short int sll_protocol;
   222   int sll_ifindex;
   223   unsigned short int sll_hatype;
   224   unsigned char sll_pkttype;
   225   unsigned char sll_halen;
   226   unsigned char sll_addr[24];
   227 };
   228 struct ifaddrs_storage
   229 {
   230   struct ifaddrs ifa;
   231   union
   232   {
   233     /* Save space for the biggest of the four used sockaddr types and
   234        avoid a lot of casts.  */
   235     struct sockaddr sa;
   236     struct sockaddr_ll_max sl;
   237     struct sockaddr_in s4;
   238     struct sockaddr_in6 s6;
   239   } addr, netmask, broadaddr;
   240   char name[IF_NAMESIZE + 1];
   241 };
   242 #define PAGE_SIZE 4096
   243 static int
   244 netlink_request (struct netlink_handle *h, int type)
   245 {
   246   int ret;
   247   struct sockaddr_nl snl;
   248   struct netlink_res *nlm_next;
   249   struct sockaddr_nl nladdr;
   250   struct nlmsghdr *nlmh;
   251   ssize_t read_len;
   252   bool done = false;
   253 
   254   struct
   255   {
   256     struct nlmsghdr nlh;
   257     struct rtgenmsg g;
   258   } req;
   259 
   260   memset (&snl, 0, sizeof snl);
   261   snl.nl_family = AF_NETLINK;
   262 
   263   memset (&req, 0, sizeof req);
   264   req.nlh.nlmsg_len = sizeof req;
   265   req.nlh.nlmsg_type = type;
   266   req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
   267   req.nlh.nlmsg_pid = h->pid;
   268   req.nlh.nlmsg_seq = ++h->seq;
   269   req.g.rtgen_family = AF_UNSPEC;
   270 
   271   ret = dce_sendto (h->fd, (void *) &req, sizeof req, 0,
   272                     (struct sockaddr *) &snl, sizeof snl);
   273   if (ret < 0)
   274     {
   275       return -1;
   276     }
   277 
   278   char *buf;
   279   const size_t buf_size = PAGE_SIZE;
   280   buf = (char *)dce_malloc (buf_size);
   281   if (!buf)
   282     {
   283       return -1;
   284     }
   285   struct iovec iov =
   286   {
   287     buf, buf_size
   288   };
   289 
   290   while (!done)
   291     {
   292       struct msghdr msg =
   293       {
   294         (void *) &nladdr, sizeof (nladdr),
   295         &iov, 1,
   296         NULL, 0,
   297         0
   298       };
   299 
   300       read_len = dce_recvmsg (h->fd, &msg, 0);
   301       if (read_len < 0)
   302         {
   303           goto out_fail;
   304         }
   305 
   306       if (nladdr.nl_pid != 0)
   307         {
   308           continue;
   309         }
   310 
   311       if (__builtin_expect (msg.msg_flags & MSG_TRUNC, 0))
   312         {
   313           goto out_fail;
   314         }
   315 
   316       size_t count = 0;
   317       size_t remaining_len = read_len;
   318       for (nlmh = (struct nlmsghdr *) buf;
   319            NLMSG_OK (nlmh, remaining_len);
   320            nlmh = (struct nlmsghdr *) NLMSG_NEXT (nlmh, remaining_len))
   321         {
   322           if ((pid_t) nlmh->nlmsg_pid != h->pid
   323               || nlmh->nlmsg_seq != h->seq)
   324             {
   325               continue;
   326             }
   327 
   328           ++count;
   329           if (nlmh->nlmsg_type == NLMSG_DONE)
   330             {
   331               /* We found the end, leave the loop.  */
   332               done = true;
   333               break;
   334             }
   335           if (nlmh->nlmsg_type == NLMSG_ERROR)
   336             {
   337               struct nlmsgerr *nlerr = (struct nlmsgerr *) NLMSG_DATA (nlmh);
   338               if (nlmh->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
   339                 {
   340                   errno = EIO;
   341                 }
   342               else
   343                 {
   344                   errno = -nlerr->error;
   345                 }
   346               goto out_fail;
   347             }
   348         }
   349 
   350       /* If there was nothing with the expected nlmsg_pid and nlmsg_seq,
   351          there is no point to record it.  */
   352       if (count == 0)
   353         {
   354           continue;
   355         }
   356 
   357       nlm_next = (struct netlink_res *) malloc (sizeof (struct netlink_res)
   358                                                 + read_len);
   359       if (nlm_next == NULL)
   360         {
   361           goto out_fail;
   362         }
   363       nlm_next->next = NULL;
   364       nlm_next->nlh = (struct nlmsghdr *)memcpy (nlm_next + 1, buf, read_len);
   365       nlm_next->size = read_len;
   366       nlm_next->seq = h->seq;
   367       if (h->nlm_list == NULL)
   368         {
   369           h->nlm_list = nlm_next;
   370         }
   371       else
   372         {
   373           h->end_ptr->next = nlm_next;
   374         }
   375       h->end_ptr = nlm_next;
   376     }
   377 
   378   dce_free (buf);
   379   return 0;
   380 
   381 out_fail:
   382   dce_free (buf);
   383   return -1;
   384 }
   385 
   386 static int
   387 map_newlink (int index, struct ifaddrs_storage *ifas, int *map, int max)
   388 {
   389   int i;
   390 
   391   for (i = 0; i < max; i++)
   392     {
   393       if (map[i] == -1)
   394         {
   395           map[i] = index;
   396           if (i > 0)
   397             {
   398               ifas[i - 1].ifa.ifa_next = &ifas[i].ifa;
   399             }
   400           return i;
   401         }
   402       else if (map[i] == index)
   403         {
   404           return i;
   405         }
   406     }
   407   /* This should never be reached. If this will be reached, we have
   408      a very big problem.  */
   409   dce_abort ();
   410 }
   411 
   412 static void
   413 __netlink_free_handle (struct netlink_handle *h)
   414 {
   415   struct netlink_res *ptr;
   416   int saved_errno = errno;
   417 
   418   ptr = h->nlm_list;
   419   while (ptr != NULL)
   420     {
   421       struct netlink_res *tmpptr;
   422 
   423       tmpptr = ptr->next;
   424       free (ptr);
   425       ptr = tmpptr;
   426     }
   427 
   428   Current ()->err = saved_errno;
   429 }
   430 
   431 /*
   432  * Try to emulate netlink socket query to work both ns3 stack and
   433  * linux stack.
   434  */
   435 int
   436 dce_getifaddrs (struct ifaddrs **ifap)
   437 {
   438   struct netlink_handle nh =
   439   {
   440     0, 0, 0, NULL, NULL
   441   };
   442   struct sockaddr_nl nladdr;
   443   struct netlink_res *nlp;
   444   struct ifaddrs_storage *ifas;
   445   unsigned int i, newlink, newaddr, newaddr_idx;
   446   int *map_newlink_data;
   447   size_t ifa_data_size = 0;  /* Size to allocate for all ifa_data.  */
   448   char *ifa_data_ptr;   /* Pointer to the unused part of memory for
   449                            ifa_data.  */
   450   int result = 0;
   451 
   452   nh.fd = dce_socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
   453   if (nh.fd < 0)
   454     {
   455       Current ()->err = EINVAL;
   456       return -1;
   457     }
   458 
   459   memset (&nladdr, 0, sizeof (nladdr));
   460   nladdr.nl_family = AF_NETLINK;
   461   if (dce_bind (nh.fd, (struct sockaddr *) &nladdr, sizeof (nladdr)) < 0)
   462     {
   463       dce_close (nh.fd);
   464       Current ()->err = EINVAL;
   465       return -1;
   466     }
   467   socklen_t addr_len = sizeof (nladdr);
   468   if (dce_getsockname (nh.fd, (struct sockaddr *) &nladdr, &addr_len) < 0)
   469     {
   470       dce_close (nh.fd);
   471       Current ()->err = EINVAL;
   472       return -1;
   473     }
   474   nh.pid = nladdr.nl_pid;
   475 
   476 
   477   if (netlink_request (&nh, RTM_GETLINK) < 0)
   478     {
   479       dce_close (nh.fd);
   480       Current ()->err = EINVAL;
   481       return -1;
   482     }
   483 
   484   ++nh.seq;
   485   if (netlink_request (&nh, RTM_GETADDR) < 0)
   486     {
   487       dce_close (nh.fd);
   488       Current ()->err = EINVAL;
   489       return -1;
   490     }
   491 
   492 
   493 
   494   newlink = newaddr = 0;
   495   for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
   496     {
   497       struct nlmsghdr *nlh;
   498       size_t size = nlp->size;
   499 
   500       if (nlp->nlh == NULL)
   501         {
   502           continue;
   503         }
   504 
   505       /* Walk through all entries we got from the kernel and look, which
   506          message type they contain.  */
   507       for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
   508         {
   509           /* Check if the message is what we want.  */
   510           if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
   511             {
   512               continue;
   513             }
   514 
   515           if (nlh->nlmsg_type == NLMSG_DONE)
   516             {
   517               break;            /* ok */
   518 
   519             }
   520           if (nlh->nlmsg_type == RTM_NEWLINK)
   521             {
   522               /* A RTM_NEWLINK message can have IFLA_STATS data. We need to
   523                  know the size before creating the list to allocate enough
   524                  memory.  */
   525               struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
   526               struct rtattr *rta = IFLA_RTA (ifim);
   527               size_t rtasize = IFLA_PAYLOAD (nlh);
   528 
   529               while (RTA_OK (rta, rtasize))
   530                 {
   531                   size_t rta_payload = RTA_PAYLOAD (rta);
   532 
   533                   if (rta->rta_type == IFLA_STATS)
   534                     {
   535                       ifa_data_size += rta_payload;
   536                       break;
   537                     }
   538                   else
   539                     {
   540                       rta = RTA_NEXT (rta, rtasize);
   541                     }
   542                 }
   543               ++newlink;
   544             }
   545           else if (nlh->nlmsg_type == RTM_NEWADDR)
   546             {
   547               ++newaddr;
   548             }
   549         }
   550     }
   551 
   552   /* Return if no interface is up.  */
   553   if ((newlink + newaddr) == 0)
   554     {
   555       goto exit_free;
   556     }
   557 
   558   /* Allocate memory for all entries we have and initialize next
   559      pointer.  */
   560   ifas = (struct ifaddrs_storage *) calloc (1,
   561                                             (newlink + newaddr)
   562                                             * sizeof (struct ifaddrs_storage)
   563                                             + ifa_data_size);
   564   if (ifas == NULL)
   565     {
   566       result = -1;
   567       goto exit_free;
   568     }
   569 
   570   /* Table for mapping kernel index to entry in our list.  */
   571   map_newlink_data = (int *)alloca (newlink * sizeof (int));
   572   memset (map_newlink_data, '\xff', newlink * sizeof (int));
   573 
   574   ifa_data_ptr = (char *) &ifas[newlink + newaddr];
   575   newaddr_idx = 0;              /* Counter for newaddr index.  */
   576 
   577   /* Walk through the list of data we got from the kernel.  */
   578   for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
   579     {
   580       struct nlmsghdr *nlh;
   581       size_t size = nlp->size;
   582 
   583       if (nlp->nlh == NULL)
   584         {
   585           continue;
   586         }
   587 
   588       /* Walk through one message and look at the type: If it is our
   589          message, we need RTM_NEWLINK/RTM_NEWADDR and stop if we reach
   590          the end or we find the end marker (in this case we ignore the
   591          following data.  */
   592       for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
   593         {
   594           int ifa_index = 0;
   595 
   596           /* Check if the message is the one we want */
   597           if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
   598             {
   599               continue;
   600             }
   601 
   602           if (nlh->nlmsg_type == NLMSG_DONE)
   603             {
   604               break;            /* ok */
   605 
   606             }
   607           if (nlh->nlmsg_type == RTM_NEWLINK)
   608             {
   609               /* We found a new interface. Now extract everything from the
   610                  interface data we got and need.  */
   611               struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
   612               struct rtattr *rta = IFLA_RTA (ifim);
   613               size_t rtasize = IFLA_PAYLOAD (nlh);
   614 
   615               /* Interfaces are stored in the first "newlink" entries
   616                  of our list, starting in the order as we got from the
   617                  kernel.  */
   618               ifa_index = map_newlink (ifim->ifi_index - 1, ifas,
   619                                        map_newlink_data, newlink);
   620               ifas[ifa_index].ifa.ifa_flags = ifim->ifi_flags;
   621 
   622               while (RTA_OK (rta, rtasize))
   623                 {
   624                   char *rta_data = (char *)RTA_DATA (rta);
   625                   size_t rta_payload = RTA_PAYLOAD (rta);
   626 
   627                   switch (rta->rta_type)
   628                     {
   629                     case IFLA_ADDRESS:
   630                       if (rta_payload <= sizeof (ifas[ifa_index].addr))
   631                         {
   632                           ifas[ifa_index].addr.sl.sll_family = AF_PACKET;
   633                           memcpy (ifas[ifa_index].addr.sl.sll_addr,
   634                                   (char *) rta_data, rta_payload);
   635                           ifas[ifa_index].addr.sl.sll_halen = rta_payload;
   636                           ifas[ifa_index].addr.sl.sll_ifindex
   637                             = ifim->ifi_index;
   638                           ifas[ifa_index].addr.sl.sll_hatype = ifim->ifi_type;
   639 
   640                           ifas[ifa_index].ifa.ifa_addr
   641                             = &ifas[ifa_index].addr.sa;
   642                         }
   643                       break;
   644 
   645                     case IFLA_BROADCAST:
   646                       if (rta_payload <= sizeof (ifas[ifa_index].broadaddr))
   647                         {
   648                           ifas[ifa_index].broadaddr.sl.sll_family = AF_PACKET;
   649                           memcpy (ifas[ifa_index].broadaddr.sl.sll_addr,
   650                                   (char *) rta_data, rta_payload);
   651                           ifas[ifa_index].broadaddr.sl.sll_halen = rta_payload;
   652                           ifas[ifa_index].broadaddr.sl.sll_ifindex
   653                             = ifim->ifi_index;
   654                           ifas[ifa_index].broadaddr.sl.sll_hatype
   655                             = ifim->ifi_type;
   656 
   657                           ifas[ifa_index].ifa.ifa_broadaddr
   658                             = &ifas[ifa_index].broadaddr.sa;
   659                         }
   660                       break;
   661 
   662                     case IFLA_IFNAME:   /* Name of Interface */
   663                       if ((rta_payload + 1) <= sizeof (ifas[ifa_index].name))
   664                         {
   665                           ifas[ifa_index].ifa.ifa_name = ifas[ifa_index].name;
   666                           *(char *) __mempcpy (ifas[ifa_index].name, rta_data,
   667                                                rta_payload) = '\0';
   668                         }
   669                       break;
   670 
   671                     case IFLA_STATS:    /* Statistics of Interface */
   672                       ifas[ifa_index].ifa.ifa_data = ifa_data_ptr;
   673                       ifa_data_ptr += rta_payload;
   674                       memcpy (ifas[ifa_index].ifa.ifa_data, rta_data,
   675                               rta_payload);
   676                       break;
   677 
   678                     case IFLA_UNSPEC:
   679                       break;
   680                     case IFLA_MTU:
   681                       break;
   682                     case IFLA_LINK:
   683                       break;
   684                     case IFLA_QDISC:
   685                       break;
   686                     default:
   687                       break;
   688                     }
   689 
   690                   rta = RTA_NEXT (rta, rtasize);
   691                 }
   692             }
   693           else if (nlh->nlmsg_type == RTM_NEWADDR)
   694             {
   695               struct ifaddrmsg *ifam = (struct ifaddrmsg *) NLMSG_DATA (nlh);
   696               struct rtattr *rta = IFA_RTA (ifam);
   697               size_t rtasize = IFA_PAYLOAD (nlh);
   698 
   699               /* New Addresses are stored in the order we got them from
   700                  the kernel after the interfaces. Theoretically it is possible
   701                  that we have holes in the interface part of the list,
   702                  but we always have already the interface for this address.  */
   703               ifa_index = newlink + newaddr_idx;
   704               ifas[ifa_index].ifa.ifa_flags
   705                 = ifas[map_newlink (ifam->ifa_index - 1, ifas,
   706                                     map_newlink_data, newlink)].ifa.ifa_flags;
   707               if (ifa_index > 0)
   708                 {
   709                   ifas[ifa_index - 1].ifa.ifa_next = &ifas[ifa_index].ifa;
   710                 }
   711               ++newaddr_idx;
   712 
   713               while (RTA_OK (rta, rtasize))
   714                 {
   715                   char *rta_data = (char *)RTA_DATA (rta);
   716                   size_t rta_payload = RTA_PAYLOAD (rta);
   717 
   718                   switch (rta->rta_type)
   719                     {
   720                     case IFA_ADDRESS:
   721                       {
   722                         struct sockaddr *sa;
   723 
   724                         if (ifas[ifa_index].ifa.ifa_addr != NULL)
   725                           {
   726                             /* In a point-to-poing network IFA_ADDRESS
   727                                contains the destination address, local
   728                                address is supplied in IFA_LOCAL attribute.
   729                                destination address and broadcast address
   730                                are stored in an union, so it doesn't matter
   731                                which name we use.  */
   732                             ifas[ifa_index].ifa.ifa_broadaddr
   733                               = &ifas[ifa_index].broadaddr.sa;
   734                             sa = &ifas[ifa_index].broadaddr.sa;
   735                           }
   736                         else
   737                           {
   738                             ifas[ifa_index].ifa.ifa_addr
   739                               = &ifas[ifa_index].addr.sa;
   740                             sa = &ifas[ifa_index].addr.sa;
   741                           }
   742 
   743                         sa->sa_family = ifam->ifa_family;
   744 
   745                         switch (ifam->ifa_family)
   746                           {
   747                           case AF_INET:
   748                             /* Size must match that of an address for IPv4.  */
   749                             if (rta_payload == 4)
   750                               {
   751                                 memcpy (&((struct sockaddr_in *) sa)->sin_addr,
   752                                         rta_data, rta_payload);
   753                               }
   754                             break;
   755 
   756                           case AF_INET6:
   757                             /* Size must match that of an address for IPv6.  */
   758                             if (rta_payload == 16)
   759                               {
   760                                 memcpy (&((struct sockaddr_in6 *) sa)->sin6_addr,
   761                                         rta_data, rta_payload);
   762                                 if (IN6_IS_ADDR_LINKLOCAL (rta_data)
   763                                     || IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
   764                                   {
   765                                     ((struct sockaddr_in6 *) sa)->sin6_scope_id
   766                                       = ifam->ifa_index;
   767                                   }
   768                               }
   769                             break;
   770 
   771                           default:
   772                             if (rta_payload <= sizeof (ifas[ifa_index].addr))
   773                               {
   774                                 memcpy (sa->sa_data, rta_data, rta_payload);
   775                               }
   776                             break;
   777                           }
   778                       }
   779                       break;
   780 
   781                     case IFA_LOCAL:
   782                       if (ifas[ifa_index].ifa.ifa_addr != NULL)
   783                         {
   784                           /* If ifa_addr is set and we get IFA_LOCAL,
   785                              assume we have a point-to-point network.
   786                              Move address to correct field.  */
   787                           ifas[ifa_index].broadaddr = ifas[ifa_index].addr;
   788                           ifas[ifa_index].ifa.ifa_broadaddr
   789                             = &ifas[ifa_index].broadaddr.sa;
   790                           memset (&ifas[ifa_index].addr, '\0',
   791                                   sizeof (ifas[ifa_index].addr));
   792                         }
   793 
   794                       ifas[ifa_index].ifa.ifa_addr = &ifas[ifa_index].addr.sa;
   795                       ifas[ifa_index].ifa.ifa_addr->sa_family
   796                         = ifam->ifa_family;
   797 
   798                       switch (ifam->ifa_family)
   799                         {
   800                         case AF_INET:
   801                           /* Size must match that of an address for IPv4.  */
   802                           if (rta_payload == 4)
   803                             {
   804                               memcpy (&ifas[ifa_index].addr.s4.sin_addr,
   805                                       rta_data, rta_payload);
   806                             }
   807                           break;
   808 
   809                         case AF_INET6:
   810                           /* Size must match that of an address for IPv6.  */
   811                           if (rta_payload == 16)
   812                             {
   813                               memcpy (&ifas[ifa_index].addr.s6.sin6_addr,
   814                                       rta_data, rta_payload);
   815                               if (IN6_IS_ADDR_LINKLOCAL (rta_data)
   816                                   || IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
   817                                 {
   818                                   ifas[ifa_index].addr.s6.sin6_scope_id =
   819                                     ifam->ifa_index;
   820                                 }
   821                             }
   822                           break;
   823 
   824                         default:
   825                           if (rta_payload <= sizeof (ifas[ifa_index].addr))
   826                             {
   827                               memcpy (ifas[ifa_index].addr.sa.sa_data,
   828                                       rta_data, rta_payload);
   829                             }
   830                           break;
   831                         }
   832                       break;
   833 
   834                     case IFA_BROADCAST:
   835                       /* We get IFA_BROADCAST, so IFA_LOCAL was too much.  */
   836                       if (ifas[ifa_index].ifa.ifa_broadaddr != NULL)
   837                         {
   838                           memset (&ifas[ifa_index].broadaddr, '\0',
   839                                   sizeof (ifas[ifa_index].broadaddr));
   840                         }
   841 
   842                       ifas[ifa_index].ifa.ifa_broadaddr
   843                         = &ifas[ifa_index].broadaddr.sa;
   844                       ifas[ifa_index].ifa.ifa_broadaddr->sa_family
   845                         = ifam->ifa_family;
   846 
   847                       switch (ifam->ifa_family)
   848                         {
   849                         case AF_INET:
   850                           /* Size must match that of an address for IPv4.  */
   851                           if (rta_payload == 4)
   852                             {
   853                               memcpy (&ifas[ifa_index].broadaddr.s4.sin_addr,
   854                                       rta_data, rta_payload);
   855                             }
   856                           break;
   857 
   858                         case AF_INET6:
   859                           /* Size must match that of an address for IPv6.  */
   860                           if (rta_payload == 16)
   861                             {
   862                               memcpy (&ifas[ifa_index].broadaddr.s6.sin6_addr,
   863                                       rta_data, rta_payload);
   864                               if (IN6_IS_ADDR_LINKLOCAL (rta_data)
   865                                   || IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
   866                                 {
   867                                   ifas[ifa_index].broadaddr.s6.sin6_scope_id
   868                                     = ifam->ifa_index;
   869                                 }
   870                             }
   871                           break;
   872 
   873                         default:
   874                           if (rta_payload <= sizeof (ifas[ifa_index].addr))
   875                             {
   876                               memcpy (&ifas[ifa_index].broadaddr.sa.sa_data,
   877                                       rta_data, rta_payload);
   878                             }
   879                           break;
   880                         }
   881                       break;
   882 
   883                     case IFA_LABEL:
   884                       if (rta_payload + 1 <= sizeof (ifas[ifa_index].name))
   885                         {
   886                           ifas[ifa_index].ifa.ifa_name = ifas[ifa_index].name;
   887                           *(char *) __mempcpy (ifas[ifa_index].name, rta_data,
   888                                                rta_payload) = '\0';
   889                         }
   890                       else
   891                         {
   892                           abort ();
   893                         }
   894                       break;
   895 
   896                     case IFA_UNSPEC:
   897                       break;
   898                     case IFA_CACHEINFO:
   899                       break;
   900                     default:
   901                       break;
   902                     }
   903 
   904                   rta = RTA_NEXT (rta, rtasize);
   905                 }
   906 
   907               /* If we didn't get the interface name with the
   908                  address, use the name from the interface entry.  */
   909               if (ifas[ifa_index].ifa.ifa_name == NULL)
   910                 {
   911                   ifas[ifa_index].ifa.ifa_name
   912                     = ifas[map_newlink (ifam->ifa_index - 1, ifas,
   913                                         map_newlink_data, newlink)].ifa.ifa_name;
   914                 }
   915 
   916               /* Calculate the netmask.  */
   917               if (ifas[ifa_index].ifa.ifa_addr
   918                   && ifas[ifa_index].ifa.ifa_addr->sa_family != AF_UNSPEC
   919                   && ifas[ifa_index].ifa.ifa_addr->sa_family != AF_PACKET)
   920                 {
   921                   uint32_t max_prefixlen = 0;
   922                   char *cp = NULL;
   923 
   924                   ifas[ifa_index].ifa.ifa_netmask
   925                     = &ifas[ifa_index].netmask.sa;
   926 
   927                   switch (ifas[ifa_index].ifa.ifa_addr->sa_family)
   928                     {
   929                     case AF_INET:
   930                       cp = (char *) &ifas[ifa_index].netmask.s4.sin_addr;
   931                       max_prefixlen = 32;
   932                       break;
   933 
   934                     case AF_INET6:
   935                       cp = (char *) &ifas[ifa_index].netmask.s6.sin6_addr;
   936                       max_prefixlen = 128;
   937                       break;
   938                     }
   939 
   940                   ifas[ifa_index].ifa.ifa_netmask->sa_family
   941                     = ifas[ifa_index].ifa.ifa_addr->sa_family;
   942 
   943                   if (cp != NULL)
   944                     {
   945                       char c;
   946                       unsigned int preflen;
   947 
   948                       if ((max_prefixlen > 0)
   949                           && (ifam->ifa_prefixlen > max_prefixlen))
   950                         {
   951                           preflen = max_prefixlen;
   952                         }
   953                       else
   954                         {
   955                           preflen = ifam->ifa_prefixlen;
   956                         }
   957 
   958                       for (i = 0; i < (preflen / 8); i++)
   959                         {
   960                           *cp++ = 0xff;
   961                         }
   962                       c = 0xff;
   963                       c <<= (8 - (preflen % 8));
   964                       *cp = c;
   965                     }
   966                 }
   967             }
   968         }
   969     }
   970 
   971   NS_ASSERT (ifa_data_ptr <= (char *) &ifas[newlink + newaddr] + ifa_data_size);
   972 
   973   if (newaddr_idx > 0)
   974     {
   975       for (i = 0; i < newlink; ++i)
   976         {
   977           if (map_newlink_data[i] == -1)
   978             {
   979               /* We have fewer links then we anticipated.  Adjust the
   980                  forward pointer to the first address entry.  */
   981               ifas[i - 1].ifa.ifa_next = &ifas[newlink].ifa;
   982             }
   983         }
   984 
   985       if (i == 0 && newlink > 0)
   986         {
   987           /* No valid link, but we allocated memory.  We have to
   988              populate the first entry.  */
   989           memmove (ifas, &ifas[newlink], sizeof (struct ifaddrs_storage));
   990         }
   991     }
   992 
   993   *ifap = &ifas[0].ifa;
   994 
   995 exit_free:
   996   __netlink_free_handle (&nh);
   997   dce_close (nh.fd);
   998 
   999   return 0;
  1000 }