Blame sysdeps/unix/sysv/linux/if_index.c

Packit 6c4009
/* Copyright (C) 1997-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <alloca.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <net/if.h>
Packit 6c4009
#include <sys/socket.h>
Packit 6c4009
#include <sys/ioctl.h>
Packit 6c4009
#include <libc-lock.h>
Packit 6c4009
#include <not-cancel.h>
Packit 6c4009
Packit 6c4009
#include "netlinkaccess.h"
Packit 6c4009
Packit 6c4009
Packit 6c4009
unsigned int
Packit 6c4009
__if_nametoindex (const char *ifname)
Packit 6c4009
{
Packit 6c4009
#ifndef SIOCGIFINDEX
Packit 6c4009
  __set_errno (ENOSYS);
Packit 6c4009
  return 0;
Packit 6c4009
#else
Packit 6c4009
  struct ifreq ifr;
Packit 6c4009
  if (strlen (ifname) >= IFNAMSIZ)
Packit 6c4009
    {
Packit 6c4009
      __set_errno (ENODEV);
Packit 6c4009
      return 0;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
Packit Service 79bd23
Packit Service 79bd23
  int fd = __opensock ();
Packit Service 79bd23
Packit Service 79bd23
  if (fd < 0)
Packit Service 79bd23
    return 0;
Packit Service 79bd23
Packit 6c4009
  if (__ioctl (fd, SIOCGIFINDEX, &ifr) < 0)
Packit 6c4009
    {
Packit 6c4009
      int saved_errno = errno;
Packit 6c4009
      __close_nocancel_nostatus (fd);
Packit 6c4009
      if (saved_errno == EINVAL)
Packit 6c4009
	__set_errno (ENOSYS);
Packit 6c4009
      return 0;
Packit 6c4009
    }
Packit 6c4009
  __close_nocancel_nostatus (fd);
Packit 6c4009
  return ifr.ifr_ifindex;
Packit 6c4009
#endif
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (__if_nametoindex)
Packit 6c4009
weak_alias (__if_nametoindex, if_nametoindex)
Packit 6c4009
libc_hidden_weak (if_nametoindex)
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
__if_freenameindex (struct if_nameindex *ifn)
Packit 6c4009
{
Packit 6c4009
  struct if_nameindex *ptr = ifn;
Packit 6c4009
  while (ptr->if_name || ptr->if_index)
Packit 6c4009
    {
Packit 6c4009
      free (ptr->if_name);
Packit 6c4009
      ++ptr;
Packit 6c4009
    }
Packit 6c4009
  free (ifn);
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (__if_freenameindex)
Packit 6c4009
weak_alias (__if_freenameindex, if_freenameindex)
Packit 6c4009
libc_hidden_weak (if_freenameindex)
Packit 6c4009
Packit 6c4009
Packit 6c4009
static struct if_nameindex *
Packit 6c4009
if_nameindex_netlink (void)
Packit 6c4009
{
Packit 6c4009
  struct netlink_handle nh = { 0, 0, 0, NULL, NULL };
Packit 6c4009
  struct if_nameindex *idx = NULL;
Packit 6c4009
Packit 6c4009
  if (__netlink_open (&nh) < 0)
Packit 6c4009
    return NULL;
Packit 6c4009
Packit 6c4009
Packit 6c4009
  /* Tell the kernel that we wish to get a list of all
Packit 6c4009
     active interfaces.  Collect all data for every interface.  */
Packit 6c4009
  if (__netlink_request (&nh, RTM_GETLINK) < 0)
Packit 6c4009
    goto exit_free;
Packit 6c4009
Packit 6c4009
  /* Count the interfaces.  */
Packit 6c4009
  unsigned int nifs = 0;
Packit 6c4009
  for (struct netlink_res *nlp = nh.nlm_list; nlp; nlp = nlp->next)
Packit 6c4009
    {
Packit 6c4009
      struct nlmsghdr *nlh;
Packit 6c4009
      size_t size = nlp->size;
Packit 6c4009
Packit 6c4009
      if (nlp->nlh == NULL)
Packit 6c4009
	continue;
Packit 6c4009
Packit 6c4009
      /* Walk through all entries we got from the kernel and look, which
Packit 6c4009
         message type they contain.  */
Packit 6c4009
      for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
Packit 6c4009
	{
Packit 6c4009
	  /* Check if the message is what we want.  */
Packit 6c4009
	  if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
Packit 6c4009
	    continue;
Packit 6c4009
Packit 6c4009
	  if (nlh->nlmsg_type == NLMSG_DONE)
Packit 6c4009
	    break;		/* ok */
Packit 6c4009
Packit 6c4009
	  if (nlh->nlmsg_type == RTM_NEWLINK)
Packit 6c4009
	    ++nifs;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
Packit 6c4009
  if (idx == NULL)
Packit 6c4009
    {
Packit 6c4009
    nomem:
Packit 6c4009
      __set_errno (ENOBUFS);
Packit 6c4009
      goto exit_free;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Add the interfaces.  */
Packit 6c4009
  nifs = 0;
Packit 6c4009
  for (struct netlink_res *nlp = nh.nlm_list; nlp; nlp = nlp->next)
Packit 6c4009
    {
Packit 6c4009
      struct nlmsghdr *nlh;
Packit 6c4009
      size_t size = nlp->size;
Packit 6c4009
Packit 6c4009
      if (nlp->nlh == NULL)
Packit 6c4009
	continue;
Packit 6c4009
Packit 6c4009
      /* Walk through all entries we got from the kernel and look, which
Packit 6c4009
         message type they contain.  */
Packit 6c4009
      for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
Packit 6c4009
	{
Packit 6c4009
	  /* Check if the message is what we want.  */
Packit 6c4009
	  if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
Packit 6c4009
	    continue;
Packit 6c4009
Packit 6c4009
	  if (nlh->nlmsg_type == NLMSG_DONE)
Packit 6c4009
	    break;		/* ok */
Packit 6c4009
Packit 6c4009
	  if (nlh->nlmsg_type == RTM_NEWLINK)
Packit 6c4009
	    {
Packit 6c4009
	      struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
Packit 6c4009
	      struct rtattr *rta = IFLA_RTA (ifim);
Packit 6c4009
	      size_t rtasize = IFLA_PAYLOAD (nlh);
Packit 6c4009
Packit 6c4009
	      idx[nifs].if_index = ifim->ifi_index;
Packit 6c4009
Packit 6c4009
	      while (RTA_OK (rta, rtasize))
Packit 6c4009
		{
Packit 6c4009
		  char *rta_data = RTA_DATA (rta);
Packit 6c4009
		  size_t rta_payload = RTA_PAYLOAD (rta);
Packit 6c4009
Packit 6c4009
		  if (rta->rta_type == IFLA_IFNAME)
Packit 6c4009
		    {
Packit 6c4009
		      idx[nifs].if_name = __strndup (rta_data, rta_payload);
Packit 6c4009
		      if (idx[nifs].if_name == NULL)
Packit 6c4009
			{
Packit 6c4009
			  idx[nifs].if_index = 0;
Packit 6c4009
			  __if_freenameindex (idx);
Packit 6c4009
			  idx = NULL;
Packit 6c4009
			  goto nomem;
Packit 6c4009
			}
Packit 6c4009
		      break;
Packit 6c4009
		    }
Packit 6c4009
Packit 6c4009
		  rta = RTA_NEXT (rta, rtasize);
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      ++nifs;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  idx[nifs].if_index = 0;
Packit 6c4009
  idx[nifs].if_name = NULL;
Packit 6c4009
Packit 6c4009
 exit_free:
Packit 6c4009
  __netlink_free_handle (&nh);
Packit 6c4009
  __netlink_close (&nh);
Packit 6c4009
Packit 6c4009
  return idx;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
struct if_nameindex *
Packit 6c4009
__if_nameindex (void)
Packit 6c4009
{
Packit 6c4009
#ifndef SIOCGIFINDEX
Packit 6c4009
  __set_errno (ENOSYS);
Packit 6c4009
  return NULL;
Packit 6c4009
#else
Packit 6c4009
  struct if_nameindex *result = if_nameindex_netlink ();
Packit 6c4009
  return result;
Packit 6c4009
#endif
Packit 6c4009
}
Packit 6c4009
weak_alias (__if_nameindex, if_nameindex)
Packit 6c4009
libc_hidden_weak (if_nameindex)
Packit 6c4009
Packit 6c4009
Packit 6c4009
char *
Packit 6c4009
__if_indextoname (unsigned int ifindex, char *ifname)
Packit 6c4009
{
Packit 6c4009
  /* We may be able to do the conversion directly, rather than searching a
Packit 6c4009
     list.  This ioctl is not present in kernels before version 2.1.50.  */
Packit 6c4009
  struct ifreq ifr;
Packit 6c4009
  int fd;
Packit 6c4009
  int status;
Packit 6c4009
Packit 6c4009
  fd = __opensock ();
Packit 6c4009
Packit 6c4009
  if (fd < 0)
Packit 6c4009
    return NULL;
Packit 6c4009
Packit 6c4009
  ifr.ifr_ifindex = ifindex;
Packit 6c4009
  status = __ioctl (fd, SIOCGIFNAME, &ifr);
Packit 6c4009
Packit 6c4009
  __close_nocancel_nostatus (fd);
Packit 6c4009
Packit 6c4009
  if (status  < 0)
Packit 6c4009
    {
Packit 6c4009
      if (errno == ENODEV)
Packit 6c4009
	/* POSIX requires ENXIO.  */
Packit 6c4009
	__set_errno (ENXIO);
Packit 6c4009
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
Packit 6c4009
}
Packit 6c4009
weak_alias (__if_indextoname, if_indextoname)
Packit 6c4009
libc_hidden_weak (if_indextoname)