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