ns-3 Direct Code Execution
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
dce-netdb.cc
Go to the documentation of this file.
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
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 };
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 };
219 {
220  unsigned short int sll_family;
221  unsigned short int sll_protocol;
223  unsigned short int sll_hatype;
224  unsigned char sll_pkttype;
225  unsigned char sll_halen;
226  unsigned char sll_addr[24];
227 };
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
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 }