(root)/
glibc-2.38/
sysdeps/
unix/
sysv/
linux/
if_index.c
       1  /* Copyright (C) 1997-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <errno.h>
      19  #include <string.h>
      20  #include <stdio.h>
      21  #include <stdlib.h>
      22  #include <unistd.h>
      23  #include <net/if.h>
      24  #include <sys/socket.h>
      25  #include <sys/ioctl.h>
      26  #include <libc-lock.h>
      27  #include <not-cancel.h>
      28  
      29  #include "netlinkaccess.h"
      30  
      31  
      32  unsigned int
      33  __if_nametoindex (const char *ifname)
      34  {
      35  #ifndef SIOCGIFINDEX
      36    __set_errno (ENOSYS);
      37    return 0;
      38  #else
      39    struct ifreq ifr;
      40    if (strlen (ifname) >= IFNAMSIZ)
      41      {
      42        __set_errno (ENODEV);
      43        return 0;
      44      }
      45  
      46    strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
      47  
      48    int fd = __opensock ();
      49  
      50    if (fd < 0)
      51      return 0;
      52  
      53    if (__ioctl (fd, SIOCGIFINDEX, &ifr) < 0)
      54      {
      55        int saved_errno = errno;
      56        __close_nocancel_nostatus (fd);
      57        if (saved_errno == EINVAL)
      58  	__set_errno (ENOSYS);
      59        return 0;
      60      }
      61    __close_nocancel_nostatus (fd);
      62    return ifr.ifr_ifindex;
      63  #endif
      64  }
      65  libc_hidden_def (__if_nametoindex)
      66  weak_alias (__if_nametoindex, if_nametoindex)
      67  libc_hidden_weak (if_nametoindex)
      68  
      69  
      70  void
      71  __if_freenameindex (struct if_nameindex *ifn)
      72  {
      73    struct if_nameindex *ptr = ifn;
      74    while (ptr->if_name || ptr->if_index)
      75      {
      76        free (ptr->if_name);
      77        ++ptr;
      78      }
      79    free (ifn);
      80  }
      81  libc_hidden_def (__if_freenameindex)
      82  weak_alias (__if_freenameindex, if_freenameindex)
      83  libc_hidden_weak (if_freenameindex)
      84  
      85  
      86  static struct if_nameindex *
      87  if_nameindex_netlink (void)
      88  {
      89    struct netlink_handle nh = { 0, 0, 0, NULL, NULL };
      90    struct if_nameindex *idx = NULL;
      91  
      92    if (__netlink_open (&nh) < 0)
      93      return NULL;
      94  
      95  
      96    /* Tell the kernel that we wish to get a list of all
      97       active interfaces.  Collect all data for every interface.  */
      98    if (__netlink_request (&nh, RTM_GETLINK) < 0)
      99      goto exit_free;
     100  
     101    /* Count the interfaces.  */
     102    unsigned int nifs = 0;
     103    for (struct netlink_res *nlp = nh.nlm_list; nlp; nlp = nlp->next)
     104      {
     105        struct nlmsghdr *nlh;
     106        size_t size = nlp->size;
     107  
     108        if (nlp->nlh == NULL)
     109  	continue;
     110  
     111        /* Walk through all entries we got from the kernel and look, which
     112           message type they contain.  */
     113        for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
     114  	{
     115  	  /* Check if the message is what we want.  */
     116  	  if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
     117  	    continue;
     118  
     119  	  if (nlh->nlmsg_type == NLMSG_DONE)
     120  	    break;		/* ok */
     121  
     122  	  if (nlh->nlmsg_type == RTM_NEWLINK)
     123  	    ++nifs;
     124  	}
     125      }
     126  
     127    idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
     128    if (idx == NULL)
     129      {
     130      nomem:
     131        __set_errno (ENOBUFS);
     132        goto exit_free;
     133      }
     134  
     135    /* Add the interfaces.  */
     136    nifs = 0;
     137    for (struct netlink_res *nlp = nh.nlm_list; nlp; nlp = nlp->next)
     138      {
     139        struct nlmsghdr *nlh;
     140        size_t size = nlp->size;
     141  
     142        if (nlp->nlh == NULL)
     143  	continue;
     144  
     145        /* Walk through all entries we got from the kernel and look, which
     146           message type they contain.  */
     147        for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
     148  	{
     149  	  /* Check if the message is what we want.  */
     150  	  if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
     151  	    continue;
     152  
     153  	  if (nlh->nlmsg_type == NLMSG_DONE)
     154  	    break;		/* ok */
     155  
     156  	  if (nlh->nlmsg_type == RTM_NEWLINK)
     157  	    {
     158  	      struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
     159  	      struct rtattr *rta = IFLA_RTA (ifim);
     160  	      size_t rtasize = IFLA_PAYLOAD (nlh);
     161  
     162  	      idx[nifs].if_index = ifim->ifi_index;
     163  
     164  	      while (RTA_OK (rta, rtasize))
     165  		{
     166  		  char *rta_data = RTA_DATA (rta);
     167  		  size_t rta_payload = RTA_PAYLOAD (rta);
     168  
     169  		  if (rta->rta_type == IFLA_IFNAME)
     170  		    {
     171  		      idx[nifs].if_name = __strndup (rta_data, rta_payload);
     172  		      if (idx[nifs].if_name == NULL)
     173  			{
     174  			  idx[nifs].if_index = 0;
     175  			  __if_freenameindex (idx);
     176  			  idx = NULL;
     177  			  goto nomem;
     178  			}
     179  		      break;
     180  		    }
     181  
     182  		  rta = RTA_NEXT (rta, rtasize);
     183  		}
     184  
     185  	      ++nifs;
     186  	    }
     187  	}
     188      }
     189  
     190    idx[nifs].if_index = 0;
     191    idx[nifs].if_name = NULL;
     192  
     193   exit_free:
     194    __netlink_free_handle (&nh);
     195    __netlink_close (&nh);
     196  
     197    return idx;
     198  }
     199  
     200  
     201  struct if_nameindex *
     202  __if_nameindex (void)
     203  {
     204  #ifndef SIOCGIFINDEX
     205    __set_errno (ENOSYS);
     206    return NULL;
     207  #else
     208    struct if_nameindex *result = if_nameindex_netlink ();
     209    return result;
     210  #endif
     211  }
     212  weak_alias (__if_nameindex, if_nameindex)
     213  libc_hidden_weak (if_nameindex)
     214  
     215  
     216  char *
     217  __if_indextoname (unsigned int ifindex, char ifname[IF_NAMESIZE])
     218  {
     219    /* We may be able to do the conversion directly, rather than searching a
     220       list.  This ioctl is not present in kernels before version 2.1.50.  */
     221    struct ifreq ifr;
     222    int fd;
     223    int status;
     224  
     225    fd = __opensock ();
     226  
     227    if (fd < 0)
     228      return NULL;
     229  
     230    ifr.ifr_ifindex = ifindex;
     231    status = __ioctl (fd, SIOCGIFNAME, &ifr);
     232  
     233    __close_nocancel_nostatus (fd);
     234  
     235    if (status  < 0)
     236      {
     237        if (errno == ENODEV)
     238  	/* POSIX requires ENXIO.  */
     239  	__set_errno (ENXIO);
     240  
     241        return NULL;
     242      }
     243    else
     244      return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
     245  }
     246  weak_alias (__if_indextoname, if_indextoname)
     247  libc_hidden_weak (if_indextoname)