1 /* getifaddrs -- get names and addresses of all network interfaces
2    Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18 
19 #include <alloca.h>
20 #include <assert.h>
21 #include <errno.h>
22 #include <ifaddrs.h>
23 #include <net/if.h>
24 #include <netinet/in.h>
25 #include <netpacket/packet.h>
26 #include <stdbool.h>
27 #include <stdint.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <sys/ioctl.h>
32 #include <sys/socket.h>
33 #include <time.h>
34 #include <unistd.h>
35 
36 #include "netlinkaccess.h"
37 
38 
39 #ifndef __libc_use_alloca
40 # define __libc_use_alloca(x) (x < __MAX_ALLOCA_CUTOFF)
41 #endif
42 
43 
44 #if __ASSUME_NETLINK_SUPPORT
45 #ifdef __UCLIBC_SUPPORT_AI_ADDRCONFIG__
46 /* struct to hold the data for one ifaddrs entry, so we can allocate
47    everything at once.  */
48 struct ifaddrs_storage
49 {
50   struct ifaddrs ifa;
51   union
52   {
53     /* Save space for the biggest of the four used sockaddr types and
54        avoid a lot of casts.  */
55     struct sockaddr sa;
56     struct sockaddr_ll sl;
57     struct sockaddr_in s4;
58 #ifdef __UCLIBC_HAS_IPV6__
59     struct sockaddr_in6 s6;
60 #endif
61   } addr, netmask, broadaddr;
62   char name[IF_NAMESIZE + 1];
63 };
64 #endif /* __UCLIBC_SUPPORT_AI_ADDRCONFIG__ */
65 
66 
67 void
__netlink_free_handle(struct netlink_handle * h)68 __netlink_free_handle (struct netlink_handle *h)
69 {
70   struct netlink_res *ptr;
71 
72   ptr = h->nlm_list;
73   while (ptr != NULL)
74     {
75       struct netlink_res *tmpptr;
76 
77       tmpptr = ptr->next;
78       free (ptr); /* doesn't affect errno */
79       ptr = tmpptr;
80     }
81 }
82 
83 
84 static int
__netlink_sendreq(struct netlink_handle * h,int type)85 __netlink_sendreq (struct netlink_handle *h, int type)
86 {
87   struct
88   {
89     struct nlmsghdr nlh;
90     struct rtgenmsg g;
91   } req;
92   struct sockaddr_nl nladdr;
93 
94   if (h->seq == 0)
95     h->seq = time (NULL);
96 
97   req.nlh.nlmsg_len = sizeof (req);
98   req.nlh.nlmsg_type = type;
99   req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
100   req.nlh.nlmsg_pid = 0;
101   req.nlh.nlmsg_seq = h->seq;
102   req.g.rtgen_family = AF_UNSPEC;
103 
104   memset (&nladdr, '\0', sizeof (nladdr));
105   nladdr.nl_family = AF_NETLINK;
106 
107   return TEMP_FAILURE_RETRY (sendto (h->fd, (void *) &req, sizeof (req), 0,
108 				       (struct sockaddr *) &nladdr,
109 				       sizeof (nladdr)));
110 }
111 
112 
113 int
__netlink_request(struct netlink_handle * h,int type)114 __netlink_request (struct netlink_handle *h, int type)
115 {
116   struct netlink_res *nlm_next;
117   struct netlink_res **new_nlm_list;
118   static volatile size_t buf_size = 0;
119   size_t this_buf_size;
120   char *buf;
121   struct sockaddr_nl nladdr;
122   struct nlmsghdr *nlmh;
123   ssize_t read_len;
124   bool done = false;
125   bool use_malloc = false;
126 
127   if (__netlink_sendreq (h, type) < 0)
128     return -1;
129 
130   if (buf_size)
131 	  this_buf_size = buf_size;
132   else {
133 #ifdef PAGE_SIZE
134 	  this_buf_size = PAGE_SIZE;
135 #else
136 	  this_buf_size = __pagesize;
137 #endif
138   }
139   if (__libc_use_alloca (this_buf_size))
140     buf = alloca (this_buf_size);
141   else
142     {
143       buf = malloc (this_buf_size);
144       if (buf != NULL)
145 	use_malloc = true;
146       else
147 	goto out_fail;
148     }
149 
150   struct iovec iov = { buf, this_buf_size };
151 
152   if (h->nlm_list != NULL)
153     new_nlm_list = &h->end_ptr->next;
154   else
155     new_nlm_list = &h->nlm_list;
156 
157   while (! done)
158     {
159       struct msghdr msg =
160 	{
161 	  (void *) &nladdr, sizeof (nladdr),
162 	  &iov, 1,
163 	  NULL, 0,
164 	  0
165 	};
166 
167       read_len = TEMP_FAILURE_RETRY (recvmsg (h->fd, &msg, 0));
168       if (read_len < 0)
169 	goto out_fail;
170 
171       if (nladdr.nl_pid != 0)
172 	continue;
173 
174       if (__builtin_expect (msg.msg_flags & MSG_TRUNC, 0))
175 	{
176 	  if (this_buf_size >= SIZE_MAX / 2)
177 	    goto out_fail;
178 
179 	  nlm_next = *new_nlm_list;
180 	  while (nlm_next != NULL)
181 	    {
182 	      struct netlink_res *tmpptr;
183 
184 	      tmpptr = nlm_next->next;
185 	      free (nlm_next);
186 	      nlm_next = tmpptr;
187 	    }
188 	  *new_nlm_list = NULL;
189 
190 	  if (__libc_use_alloca (2 * this_buf_size))
191 	    buf = extend_alloca (buf, this_buf_size, 2 * this_buf_size);
192 	  else
193 	    {
194 	      this_buf_size *= 2;
195 
196 	      char *new_buf = realloc (use_malloc ? buf : NULL, this_buf_size);
197 	      if (new_buf == NULL)
198 		goto out_fail;
199 	      new_buf = buf;
200 
201 	      use_malloc = true;
202 	    }
203 	  buf_size = this_buf_size;
204 
205 	  iov.iov_base = buf;
206 	  iov.iov_len = this_buf_size;
207 
208 	  /* Increase sequence number, so that we can distinguish
209 	     between old and new request messages.  */
210 	  h->seq++;
211 
212 	  if (__netlink_sendreq (h, type) < 0)
213 	    goto out_fail;
214 
215 	  continue;
216 	}
217 
218       size_t count = 0;
219       size_t remaining_len = read_len;
220       for (nlmh = (struct nlmsghdr *) buf;
221 	   NLMSG_OK (nlmh, remaining_len);
222 	   nlmh = (struct nlmsghdr *) NLMSG_NEXT (nlmh, remaining_len))
223 	{
224 	  if ((pid_t) nlmh->nlmsg_pid != h->pid
225 	      || nlmh->nlmsg_seq != h->seq)
226 	    continue;
227 
228 	  ++count;
229 	  if (nlmh->nlmsg_type == NLMSG_DONE)
230 	    {
231 	      /* We found the end, leave the loop.  */
232 	      done = true;
233 	      break;
234 	    }
235 	  if (nlmh->nlmsg_type == NLMSG_ERROR)
236 	    {
237 	      struct nlmsgerr *nlerr = (struct nlmsgerr *) NLMSG_DATA (nlmh);
238 	      if (nlmh->nlmsg_len < NLMSG_LENGTH (sizeof (struct nlmsgerr)))
239 		errno = EIO;
240 	      else
241 		errno = -nlerr->error;
242 	      goto out_fail;
243 	    }
244 	}
245 
246       /* If there was nothing with the expected nlmsg_pid and nlmsg_seq,
247 	 there is no point to record it.  */
248       if (count == 0)
249 	continue;
250 
251       nlm_next = (struct netlink_res *) malloc (sizeof (struct netlink_res)
252 						+ read_len);
253       if (nlm_next == NULL)
254 	goto out_fail;
255       nlm_next->next = NULL;
256       nlm_next->nlh = memcpy (nlm_next + 1, buf, read_len);
257       nlm_next->size = read_len;
258       nlm_next->seq = h->seq;
259       if (h->nlm_list == NULL)
260 	h->nlm_list = nlm_next;
261       else
262 	h->end_ptr->next = nlm_next;
263       h->end_ptr = nlm_next;
264     }
265 
266   if (use_malloc)
267     free (buf);
268   return 0;
269 
270 out_fail:
271   if (use_malloc)
272     free (buf);
273   return -1;
274 }
275 
276 
277 void
__netlink_close(struct netlink_handle * h)278 __netlink_close (struct netlink_handle *h)
279 {
280   /* Don't modify errno.  */
281   int serrno = errno;
282   close(h->fd);
283   __set_errno(serrno);
284 }
285 
286 
287 /* Open a NETLINK socket.  */
288 int
__netlink_open(struct netlink_handle * h)289 __netlink_open (struct netlink_handle *h)
290 {
291   struct sockaddr_nl nladdr;
292 
293   h->fd = socket (PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
294   if (h->fd < 0)
295     goto out;
296 
297   memset (&nladdr, '\0', sizeof (nladdr));
298   nladdr.nl_family = AF_NETLINK;
299   if (bind (h->fd, (struct sockaddr *) &nladdr, sizeof (nladdr)) < 0)
300     {
301     close_and_out:
302       __netlink_close (h);
303     out:
304       return -1;
305     }
306   /* Determine the ID the kernel assigned for this netlink connection.
307      It is not necessarily the PID if there is more than one socket
308      open.  */
309   socklen_t addr_len = sizeof (nladdr);
310   if (getsockname (h->fd, (struct sockaddr *) &nladdr, &addr_len) < 0)
311     goto close_and_out;
312   h->pid = nladdr.nl_pid;
313   return 0;
314 }
315 
316 
317 #ifdef __UCLIBC_SUPPORT_AI_ADDRCONFIG__
318 /* We know the number of RTM_NEWLINK entries, so we reserve the first
319    # of entries for this type. All RTM_NEWADDR entries have an index
320    pointer to the RTM_NEWLINK entry.  To find the entry, create
321    a table to map kernel index entries to our index numbers.
322    Since we get at first all RTM_NEWLINK entries, it can never happen
323    that a RTM_NEWADDR index is not known to this map.  */
324 static int
325 internal_function
map_newlink(int idx,struct ifaddrs_storage * ifas,int * map,int max)326 map_newlink (int idx, struct ifaddrs_storage *ifas, int *map, int max)
327 {
328   int i;
329 
330   for (i = 0; i < max; i++)
331     {
332       if (map[i] == -1)
333 	{
334 	  map[i] = idx;
335 	  if (i > 0)
336 	    ifas[i - 1].ifa.ifa_next = &ifas[i].ifa;
337 	  return i;
338 	}
339       else if (map[i] == idx)
340 	return i;
341     }
342 
343   /* This means interfaces changed inbetween the reading of the
344      RTM_GETLINK and RTM_GETADDR information.  We have to repeat
345      everything.  */
346   return -1;
347 }
348 
349 
350 /* Create a linked list of `struct ifaddrs' structures, one for each
351    network interface on the host machine.  If successful, store the
352    list in *IFAP and return 0.  On errors, return -1 and set `errno'.  */
353 static int
getifaddrs_internal(struct ifaddrs ** ifap)354 getifaddrs_internal (struct ifaddrs **ifap)
355 {
356   struct netlink_handle nh = { 0, 0, 0, NULL, NULL };
357   struct netlink_res *nlp;
358   struct ifaddrs_storage *ifas;
359   unsigned int i, newlink, newaddr, newaddr_idx;
360   int *map_newlink_data;
361   size_t ifa_data_size = 0;  /* Size to allocate for all ifa_data.  */
362   char *ifa_data_ptr;	/* Pointer to the unused part of memory for
363 				ifa_data.  */
364   int result = 0;
365 
366   if (ifap)
367     *ifap = NULL;
368 
369   if (__netlink_open (&nh) < 0)
370     {
371       return -1;
372     }
373 
374   /* Tell the kernel that we wish to get a list of all
375      active interfaces, collect all data for every interface.  */
376   if (__netlink_request (&nh, RTM_GETLINK) < 0)
377     {
378       result = -1;
379       goto exit_free;
380     }
381 
382   /* Now ask the kernel for all addresses which are assigned
383      to an interface and collect all data for every interface.
384      Since we store the addresses after the interfaces in the
385      list, we will later always find the interface before the
386      corresponding addresses.  */
387   ++nh.seq;
388   if (__netlink_request (&nh, RTM_GETADDR) < 0)
389     {
390       result = -1;
391       goto exit_free;
392     }
393 
394   /* Count all RTM_NEWLINK and RTM_NEWADDR entries to allocate
395      enough memory.  */
396   newlink = newaddr = 0;
397   for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
398     {
399       struct nlmsghdr *nlh;
400       size_t size = nlp->size;
401 
402       if (nlp->nlh == NULL)
403 	continue;
404 
405       /* Walk through all entries we got from the kernel and look, which
406 	 message type they contain.  */
407       for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
408 	{
409 	  /* Check if the message is what we want.  */
410 	  if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
411 	    continue;
412 
413 	  if (nlh->nlmsg_type == NLMSG_DONE)
414 	    break;		/* ok */
415 
416 	  if (nlh->nlmsg_type == RTM_NEWLINK)
417 	    {
418 	      /* A RTM_NEWLINK message can have IFLA_STATS data. We need to
419 		 know the size before creating the list to allocate enough
420 		 memory.  */
421 	      struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
422 	      struct rtattr *rta = IFLA_RTA (ifim);
423 	      size_t rtasize = IFLA_PAYLOAD (nlh);
424 
425 	      while (RTA_OK (rta, rtasize))
426 		{
427 		  size_t rta_payload = RTA_PAYLOAD (rta);
428 
429 		  if (rta->rta_type == IFLA_STATS)
430 		    {
431 		      ifa_data_size += rta_payload;
432 		      break;
433 		    }
434 		  else
435 		    rta = RTA_NEXT (rta, rtasize);
436 		}
437 	      ++newlink;
438 	    }
439 	  else if (nlh->nlmsg_type == RTM_NEWADDR)
440 	    ++newaddr;
441 	}
442     }
443 
444   /* Return if no interface is up.  */
445   if ((newlink + newaddr) == 0)
446     goto exit_free;
447 
448   /* Allocate memory for all entries we have and initialize next
449      pointer.  */
450   ifas = calloc (1, (newlink + newaddr) * sizeof (ifas[0]) + ifa_data_size);
451   if (ifas == NULL)
452     {
453       result = -1;
454       goto exit_free;
455     }
456 
457   /* Table for mapping kernel index to entry in our list.  */
458   map_newlink_data = alloca (newlink * sizeof (int));
459   memset (map_newlink_data, '\xff', newlink * sizeof (int));
460 
461   ifa_data_ptr = (char *) &ifas[newlink + newaddr];
462   newaddr_idx = 0;		/* Counter for newaddr index.  */
463 
464   /* Walk through the list of data we got from the kernel.  */
465   for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
466     {
467       struct nlmsghdr *nlh;
468       size_t size = nlp->size;
469 
470       if (nlp->nlh == NULL)
471 	continue;
472 
473       /* Walk through one message and look at the type: If it is our
474 	 message, we need RTM_NEWLINK/RTM_NEWADDR and stop if we reach
475 	 the end or we find the end marker (in this case we ignore the
476 	 following data.  */
477       for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
478 	{
479 	  int ifa_index = 0;
480 
481 	  /* Check if the message is the one we want */
482 	  if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
483 	    continue;
484 
485 	  if (nlh->nlmsg_type == NLMSG_DONE)
486 	    break;		/* ok */
487 
488 	  if (nlh->nlmsg_type == RTM_NEWLINK)
489 	    {
490 	      /* We found a new interface. Now extract everything from the
491 		 interface data we got and need.  */
492 	      struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
493 	      struct rtattr *rta = IFLA_RTA (ifim);
494 	      size_t rtasize = IFLA_PAYLOAD (nlh);
495 
496 	      /* Interfaces are stored in the first "newlink" entries
497 		 of our list, starting in the order as we got from the
498 		 kernel.  */
499 	      ifa_index = map_newlink (ifim->ifi_index - 1, ifas,
500 				       map_newlink_data, newlink);
501 	      if (__builtin_expect (ifa_index == -1, 0))
502 		{
503 		try_again:
504 		  result = -EAGAIN;
505 		  free (ifas);
506 		  goto exit_free;
507 		}
508 	      ifas[ifa_index].ifa.ifa_flags = ifim->ifi_flags;
509 
510 	      while (RTA_OK (rta, rtasize))
511 		{
512 		  char *rta_data = RTA_DATA (rta);
513 		  size_t rta_payload = RTA_PAYLOAD (rta);
514 
515 		  switch (rta->rta_type)
516 		    {
517 		    case IFLA_ADDRESS:
518 		      if (rta_payload <= sizeof (ifas[ifa_index].addr))
519 			{
520 			  ifas[ifa_index].addr.sl.sll_family = AF_PACKET;
521 			  memcpy (ifas[ifa_index].addr.sl.sll_addr,
522 				  (char *) rta_data, rta_payload);
523 			  ifas[ifa_index].addr.sl.sll_halen = rta_payload;
524 			  ifas[ifa_index].addr.sl.sll_ifindex
525 			    = ifim->ifi_index;
526 			  ifas[ifa_index].addr.sl.sll_hatype = ifim->ifi_type;
527 
528 			  ifas[ifa_index].ifa.ifa_addr
529 			    = &ifas[ifa_index].addr.sa;
530 			}
531 		      break;
532 
533 		    case IFLA_BROADCAST:
534 		      if (rta_payload <= sizeof (ifas[ifa_index].broadaddr))
535 			{
536 			  ifas[ifa_index].broadaddr.sl.sll_family = AF_PACKET;
537 			  memcpy (ifas[ifa_index].broadaddr.sl.sll_addr,
538 				  (char *) rta_data, rta_payload);
539 			  ifas[ifa_index].broadaddr.sl.sll_halen = rta_payload;
540 			  ifas[ifa_index].broadaddr.sl.sll_ifindex
541 			    = ifim->ifi_index;
542 			  ifas[ifa_index].broadaddr.sl.sll_hatype
543 			    = ifim->ifi_type;
544 
545 			  ifas[ifa_index].ifa.ifa_broadaddr
546 			    = &ifas[ifa_index].broadaddr.sa;
547 			}
548 		      break;
549 
550 		    case IFLA_IFNAME:	/* Name of Interface */
551 		      if ((rta_payload + 1) <= sizeof (ifas[ifa_index].name))
552 			{
553 			  ifas[ifa_index].ifa.ifa_name = ifas[ifa_index].name;
554 			  *(char *) mempcpy (ifas[ifa_index].name, rta_data,
555 					       rta_payload) = '\0';
556 			}
557 		      break;
558 
559 		    case IFLA_STATS:	/* Statistics of Interface */
560 		      ifas[ifa_index].ifa.ifa_data = ifa_data_ptr;
561 		      ifa_data_ptr += rta_payload;
562 		      memcpy (ifas[ifa_index].ifa.ifa_data, rta_data,
563 			      rta_payload);
564 		      break;
565 
566 		    case IFLA_UNSPEC:
567 		      break;
568 		    case IFLA_MTU:
569 		      break;
570 		    case IFLA_LINK:
571 		      break;
572 		    case IFLA_QDISC:
573 		      break;
574 		    default:
575 		      break;
576 		    }
577 
578 		  rta = RTA_NEXT (rta, rtasize);
579 		}
580 	    }
581 	  else if (nlh->nlmsg_type == RTM_NEWADDR)
582 	    {
583 	      struct ifaddrmsg *ifam = (struct ifaddrmsg *) NLMSG_DATA (nlh);
584 	      struct rtattr *rta = IFA_RTA (ifam);
585 	      size_t rtasize = IFA_PAYLOAD (nlh);
586 
587 	      /* New Addresses are stored in the order we got them from
588 		 the kernel after the interfaces. Theoretically it is possible
589 		 that we have holes in the interface part of the list,
590 		 but we always have already the interface for this address.  */
591 	      ifa_index = newlink + newaddr_idx;
592 	      int idx = map_newlink (ifam->ifa_index - 1, ifas,
593 				     map_newlink_data, newlink);
594 	      if (__builtin_expect (idx == -1, 0))
595 		goto try_again;
596 	      ifas[ifa_index].ifa.ifa_flags = ifas[idx].ifa.ifa_flags;
597 	      if (ifa_index > 0)
598 		ifas[ifa_index - 1].ifa.ifa_next = &ifas[ifa_index].ifa;
599 	      ++newaddr_idx;
600 
601 	      while (RTA_OK (rta, rtasize))
602 		{
603 		  char *rta_data = RTA_DATA (rta);
604 		  size_t rta_payload = RTA_PAYLOAD (rta);
605 
606 		  switch (rta->rta_type)
607 		    {
608 		    case IFA_ADDRESS:
609 		      {
610 			struct sockaddr *sa;
611 
612 			if (ifas[ifa_index].ifa.ifa_addr != NULL)
613 			  {
614 			    /* In a point-to-poing network IFA_ADDRESS
615 			       contains the destination address, local
616 			       address is supplied in IFA_LOCAL attribute.
617 			       destination address and broadcast address
618 			       are stored in an union, so it doesn't matter
619 			       which name we use.  */
620 			    ifas[ifa_index].ifa.ifa_broadaddr
621 			      = &ifas[ifa_index].broadaddr.sa;
622 			    sa = &ifas[ifa_index].broadaddr.sa;
623 			  }
624 			else
625 			  {
626 			    ifas[ifa_index].ifa.ifa_addr
627 			      = &ifas[ifa_index].addr.sa;
628 			    sa = &ifas[ifa_index].addr.sa;
629 			  }
630 
631 			sa->sa_family = ifam->ifa_family;
632 
633 			switch (ifam->ifa_family)
634 			  {
635 			  case AF_INET:
636 			    /* Size must match that of an address for IPv4.  */
637 			    if (rta_payload == 4)
638 			      memcpy (&((struct sockaddr_in *) sa)->sin_addr,
639 				      rta_data, rta_payload);
640 			    break;
641 
642 #ifdef __UCLIBC_HAS_IPV6__
643 			  case AF_INET6:
644 			    /* Size must match that of an address for IPv6.  */
645 			    if (rta_payload == 16)
646 			      {
647 				memcpy (&((struct sockaddr_in6 *) sa)->sin6_addr,
648 					rta_data, rta_payload);
649 				if (IN6_IS_ADDR_LINKLOCAL (rta_data)
650 				    || IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
651 				  ((struct sockaddr_in6 *) sa)->sin6_scope_id
652 				    = ifam->ifa_index;
653 			      }
654 			    break;
655 #endif
656 
657 			  default:
658 			    if (rta_payload <= sizeof (ifas[ifa_index].addr))
659 			      memcpy (sa->sa_data, rta_data, rta_payload);
660 			    break;
661 			  }
662 		      }
663 		      break;
664 
665 		    case IFA_LOCAL:
666 		      if (ifas[ifa_index].ifa.ifa_addr != NULL)
667 			{
668 			  /* If ifa_addr is set and we get IFA_LOCAL,
669 			     assume we have a point-to-point network.
670 			     Move address to correct field.  */
671 			  ifas[ifa_index].broadaddr = ifas[ifa_index].addr;
672 			  ifas[ifa_index].ifa.ifa_broadaddr
673 			    = &ifas[ifa_index].broadaddr.sa;
674 			  memset (&ifas[ifa_index].addr, '\0',
675 				  sizeof (ifas[ifa_index].addr));
676 			}
677 
678 		      ifas[ifa_index].ifa.ifa_addr = &ifas[ifa_index].addr.sa;
679 		      ifas[ifa_index].ifa.ifa_addr->sa_family
680 			= ifam->ifa_family;
681 
682 		      switch (ifam->ifa_family)
683 			{
684 			case AF_INET:
685 			  /* Size must match that of an address for IPv4.  */
686 			  if (rta_payload == 4)
687 			    memcpy (&ifas[ifa_index].addr.s4.sin_addr,
688 				  rta_data, rta_payload);
689 			  break;
690 
691 #ifdef __UCLIBC_HAS_IPV6__
692 			case AF_INET6:
693 			  /* Size must match that of an address for IPv6.  */
694 			  if (rta_payload == 16)
695 			    {
696 			      memcpy (&ifas[ifa_index].addr.s6.sin6_addr,
697 				      rta_data, rta_payload);
698 			      if (IN6_IS_ADDR_LINKLOCAL (rta_data)
699 				  || IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
700 				ifas[ifa_index].addr.s6.sin6_scope_id =
701 				  ifam->ifa_index;
702 			    }
703 			  break;
704 #endif
705 
706 			default:
707 			  if (rta_payload <= sizeof (ifas[ifa_index].addr))
708 			    memcpy (ifas[ifa_index].addr.sa.sa_data,
709 				    rta_data, rta_payload);
710 			  break;
711 			}
712 		      break;
713 
714 		    case IFA_BROADCAST:
715 		      /* We get IFA_BROADCAST, so IFA_LOCAL was too much.  */
716 		      if (ifas[ifa_index].ifa.ifa_broadaddr != NULL)
717 			memset (&ifas[ifa_index].broadaddr, '\0',
718 				sizeof (ifas[ifa_index].broadaddr));
719 
720 		      ifas[ifa_index].ifa.ifa_broadaddr
721 			= &ifas[ifa_index].broadaddr.sa;
722 		      ifas[ifa_index].ifa.ifa_broadaddr->sa_family
723 			= ifam->ifa_family;
724 
725 		      switch (ifam->ifa_family)
726 			{
727 			case AF_INET:
728 			  /* Size must match that of an address for IPv4.  */
729 			  if (rta_payload == 4)
730 			    memcpy (&ifas[ifa_index].broadaddr.s4.sin_addr,
731 				    rta_data, rta_payload);
732 			  break;
733 
734 #ifdef __UCLIBC_HAS_IPV6__
735 			case AF_INET6:
736 			  /* Size must match that of an address for IPv6.  */
737 			  if (rta_payload == 16)
738 			    {
739 			      memcpy (&ifas[ifa_index].broadaddr.s6.sin6_addr,
740 				      rta_data, rta_payload);
741 			      if (IN6_IS_ADDR_LINKLOCAL (rta_data)
742 				  || IN6_IS_ADDR_MC_LINKLOCAL (rta_data))
743 				ifas[ifa_index].broadaddr.s6.sin6_scope_id
744 				  = ifam->ifa_index;
745 			    }
746 			  break;
747 #endif
748 
749 			default:
750 			  if (rta_payload <= sizeof (ifas[ifa_index].addr))
751 			    memcpy (&ifas[ifa_index].broadaddr.sa.sa_data,
752 				    rta_data, rta_payload);
753 			  break;
754 			}
755 		      break;
756 
757 		    case IFA_LABEL:
758 		      if (rta_payload + 1 <= sizeof (ifas[ifa_index].name))
759 			{
760 			  ifas[ifa_index].ifa.ifa_name = ifas[ifa_index].name;
761 			  *(char *) mempcpy (ifas[ifa_index].name, rta_data,
762 					       rta_payload) = '\0';
763 			}
764 		      else
765 			abort ();
766 		      break;
767 
768 		    case IFA_UNSPEC:
769 		      break;
770 		    case IFA_CACHEINFO:
771 		      break;
772 		    default:
773 		      break;
774 		    }
775 
776 		  rta = RTA_NEXT (rta, rtasize);
777 		}
778 
779 	      /* If we didn't get the interface name with the
780 		 address, use the name from the interface entry.  */
781 	      if (ifas[ifa_index].ifa.ifa_name == NULL)
782 		{
783 		  int idx = map_newlink (ifam->ifa_index - 1, ifas,
784 					 map_newlink_data, newlink);
785 		  if (__builtin_expect (idx == -1, 0))
786 		    goto try_again;
787 		  ifas[ifa_index].ifa.ifa_name = ifas[idx].ifa.ifa_name;
788 		}
789 
790 	      /* Calculate the netmask.  */
791 	      if (ifas[ifa_index].ifa.ifa_addr
792 		  && ifas[ifa_index].ifa.ifa_addr->sa_family != AF_UNSPEC
793 		  && ifas[ifa_index].ifa.ifa_addr->sa_family != AF_PACKET)
794 		{
795 		  uint32_t max_prefixlen = 0;
796 		  char *cp = NULL;
797 
798 		  ifas[ifa_index].ifa.ifa_netmask
799 		    = &ifas[ifa_index].netmask.sa;
800 
801 		  switch (ifas[ifa_index].ifa.ifa_addr->sa_family)
802 		    {
803 		    case AF_INET:
804 		      cp = (char *) &ifas[ifa_index].netmask.s4.sin_addr;
805 		      max_prefixlen = 32;
806 		      break;
807 
808 #ifdef __UCLIBC_HAS_IPV6__
809 		    case AF_INET6:
810 		      cp = (char *) &ifas[ifa_index].netmask.s6.sin6_addr;
811 		      max_prefixlen = 128;
812 		      break;
813 #endif
814 		    }
815 
816 		  ifas[ifa_index].ifa.ifa_netmask->sa_family
817 		    = ifas[ifa_index].ifa.ifa_addr->sa_family;
818 
819 		  if (cp != NULL)
820 		    {
821 		      char c;
822 		      unsigned int preflen;
823 
824 		      if ((max_prefixlen > 0) &&
825 			  (ifam->ifa_prefixlen > max_prefixlen))
826 			preflen = max_prefixlen;
827 		      else
828 			preflen = ifam->ifa_prefixlen;
829 
830 		      for (i = 0; i < (preflen / 8); i++)
831 			*cp++ = 0xff;
832 		      c = 0xff;
833 		      c <<= (8 - (preflen % 8));
834 		      *cp = c;
835 		    }
836 		}
837 	    }
838 	}
839     }
840 
841   assert (ifa_data_ptr <= (char *) &ifas[newlink + newaddr] + ifa_data_size);
842 
843   if (newaddr_idx > 0)
844     {
845       for (i = 0; i < newlink; ++i)
846 	if (map_newlink_data[i] == -1)
847 	  {
848 	    /* We have fewer links then we anticipated.  Adjust the
849 	       forward pointer to the first address entry.  */
850 	    ifas[i - 1].ifa.ifa_next = &ifas[newlink].ifa;
851 	  }
852 
853       if (i == 0 && newlink > 0)
854 	/* No valid link, but we allocated memory.  We have to
855 	   populate the first entry.  */
856 	memmove (ifas, &ifas[newlink], sizeof (struct ifaddrs_storage));
857     }
858 
859   if (ifap != NULL)
860     *ifap = &ifas[0].ifa;
861 
862  exit_free:
863   __netlink_free_handle (&nh);
864   __netlink_close (&nh);
865 
866   return result;
867 }
868 
869 
870 /* Create a linked list of `struct ifaddrs' structures, one for each
871    network interface on the host machine.  If successful, store the
872    list in *IFAP and return 0.  On errors, return -1 and set `errno'.  */
873 int
getifaddrs(struct ifaddrs ** ifap)874 getifaddrs (struct ifaddrs **ifap)
875 {
876   int res;
877 
878   do
879     res = getifaddrs_internal (ifap);
880   while (res == -EAGAIN);
881 
882   return res;
883 }
libc_hidden_def(getifaddrs)884 libc_hidden_def(getifaddrs)
885 
886 void
887 freeifaddrs (struct ifaddrs *ifa)
888 {
889   free (ifa);
890 }
891 libc_hidden_def(freeifaddrs)
892 
893 #endif /* __UCLIBC_SUPPORT_AI_ADDRCONFIG__ */
894 
895 #endif /* __ASSUME_NETLINK_SUPPORT */
896