1  /* Find network interface names and index numbers.  Hurd version.
       2     Copyright (C) 2000-2023 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     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <error.h>
      20  #include <net/if.h>
      21  #include <string.h>
      22  #include <sys/ioctl.h>
      23  #include <unistd.h>
      24  
      25  #include <hurd.h>
      26  #include <hurd/ioctl.h>
      27  #include <hurd/pfinet.h>
      28  
      29  /* Return the interface index corresponding to interface IFNAME.
      30     On error, return 0.  */
      31  unsigned int
      32  __if_nametoindex (const char *ifname)
      33  {
      34    struct ifreq ifr;
      35    int fd = __socket (AF_INET, SOCK_DGRAM, 0);
      36  
      37    if (fd < 0)
      38      return 0;
      39  
      40    if (strlen (ifname) >= IFNAMSIZ)
      41      return __hurd_fail (ENODEV), 0;
      42  
      43    strncpy (ifr.ifr_name, ifname, IFNAMSIZ);
      44    if (__ioctl (fd, SIOCGIFINDEX, &ifr) < 0)
      45      {
      46        int saved_errno = errno;
      47        __close (fd);
      48        if (saved_errno == EINVAL || saved_errno == ENOTTY)
      49          __hurd_fail (ENOSYS);
      50        return 0;
      51      }
      52    __close (fd);
      53    return ifr.ifr_ifindex;
      54  }
      55  libc_hidden_def (__if_nametoindex)
      56  weak_alias (__if_nametoindex, if_nametoindex)
      57  libc_hidden_weak (if_nametoindex)
      58  
      59  /* Free the structure IFN returned by if_nameindex.  */
      60  void
      61  __if_freenameindex (struct if_nameindex *ifn)
      62  {
      63    struct if_nameindex *ptr = ifn;
      64    while (ptr->if_name || ptr->if_index)
      65      {
      66        free (ptr->if_name);
      67        ++ptr;
      68      }
      69    free (ifn);
      70  }
      71  libc_hidden_def (__if_freenameindex)
      72  weak_alias (__if_freenameindex, if_freenameindex)
      73  libc_hidden_weak (if_freenameindex)
      74  
      75  /* Return an array of if_nameindex structures, one for each network
      76     interface present, plus one indicating the end of the array.  On
      77     error, return NULL.  */
      78  struct if_nameindex *
      79  __if_nameindex (void)
      80  {
      81    error_t err = 0;
      82    char data[2048];
      83    file_t server;
      84    int fd = __socket (AF_INET, SOCK_DGRAM, 0);
      85    struct ifconf ifc;
      86    unsigned int nifs, i;
      87    struct if_nameindex *idx = NULL;
      88  
      89    ifc.ifc_buf = data;
      90  
      91    if (fd < 0)
      92      return NULL;
      93  
      94    server = _hurd_socket_server (PF_INET, 0);
      95    if (server == MACH_PORT_NULL)
      96      nifs = 0;
      97    else
      98      {
      99        mach_msg_type_number_t len = sizeof data;
     100        err = __pfinet_siocgifconf (server, -1, &ifc.ifc_buf, &len);
     101        if (err == MACH_SEND_INVALID_DEST || err == MIG_SERVER_DIED)
     102  	{
     103  	  /* On the first use of the socket server during the operation,
     104  	     allow for the old server port dying.  */
     105  	  server = _hurd_socket_server (PF_INET, 1);
     106  	  if (server == MACH_PORT_NULL)
     107  	    goto out;
     108  	  err = __pfinet_siocgifconf (server, -1, &ifc.ifc_buf, &len);
     109  	}
     110        if (err)
     111  	goto out;
     112  
     113        ifc.ifc_len = len;
     114        nifs = len / sizeof (struct ifreq);
     115      }
     116  
     117    idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
     118    if (idx == NULL)
     119      {
     120        err = ENOBUFS;
     121        goto out;
     122      }
     123  
     124    for (i = 0; i < nifs; ++i)
     125      {
     126        struct ifreq *ifr = &ifc.ifc_req[i];
     127        idx[i].if_name = __strdup (ifr->ifr_name);
     128        if (idx[i].if_name == NULL
     129            || __ioctl (fd, SIOCGIFINDEX, ifr) < 0)
     130          {
     131            unsigned int j;
     132            err = errno;
     133  
     134            for (j =  0; j < i; ++j)
     135              free (idx[j].if_name);
     136            free (idx);
     137  	  idx = NULL;
     138  
     139            if (err == EINVAL)
     140              err = ENOSYS;
     141            else if (err == ENOMEM)
     142              err = ENOBUFS;
     143            goto out;
     144          }
     145        idx[i].if_index = ifr->ifr_ifindex;
     146      }
     147  
     148    idx[i].if_index = 0;
     149    idx[i].if_name = NULL;
     150  
     151   out:
     152    __close (fd);
     153    if (data != ifc.ifc_buf)
     154      __vm_deallocate (__mach_task_self (), (vm_address_t) ifc.ifc_buf,
     155  		     ifc.ifc_len);
     156    __set_errno (err);
     157    return idx;
     158  }
     159  weak_alias (__if_nameindex, if_nameindex)
     160  libc_hidden_weak (if_nameindex)
     161  
     162  /* Store the name of the interface corresponding to index IFINDEX in
     163     IFNAME (which has space for at least IFNAMSIZ characters).  Return
     164     IFNAME, or NULL on error.  */
     165  char *
     166  __if_indextoname (unsigned int ifindex, char ifname[IF_NAMESIZE])
     167  {
     168    struct ifreq ifr;
     169    int fd = __socket (AF_INET, SOCK_DGRAM, 0);
     170  
     171    if (fd < 0)
     172      return NULL;
     173  
     174    ifr.ifr_ifindex = ifindex;
     175    if (__ioctl (fd, SIOCGIFNAME, &ifr) < 0)
     176      {
     177        int saved_errno = errno;
     178        __close (fd);
     179        if (saved_errno == EINVAL || saved_errno == ENOTTY)
     180          __hurd_fail (ENOSYS);
     181        else if (saved_errno == ENODEV)
     182  	__hurd_fail (ENXIO);
     183        return NULL;
     184      }
     185    __close (fd);
     186    return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
     187  }
     188  weak_alias (__if_indextoname, if_indextoname)
     189  libc_hidden_weak (if_indextoname)
     190  
     191  #if 0
     192  void
     193  __protocol_available (int *have_inet, int *have_inet6)
     194  {
     195    *have_inet = _hurd_socket_server (PF_INET, 0) != MACH_PORT_NULL;
     196    *have_inet6 = _hurd_socket_server (PF_INET6, 0) != MACH_PORT_NULL;
     197  }
     198  #endif