1 /* Copyright (C) 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005
2    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; see the file COPYING.LIB.  If
17    not, see <http://www.gnu.org/licenses/>.
18 
19    Reworked Dec 2002 by Erik Andersen <andersen@codepoet.org>
20  */
21 
22 #include <string.h>
23 #include <alloca.h>
24 #include <errno.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <net/if.h>
29 #include <sys/socket.h>
30 #include <sys/ioctl.h>
31 #include <not-cancel.h>
32 
33 #include "netlinkaccess.h"
34 
35 extern int __opensock(void) attribute_hidden;
36 
37 unsigned int
if_nametoindex(const char * ifname)38 if_nametoindex(const char* ifname)
39 {
40 #ifndef SIOCGIFINDEX
41   __set_errno (ENOSYS);
42   return 0;
43 #else
44   struct ifreq ifr;
45   int fd = __opensock();
46 
47   if (fd < 0)
48     return 0;
49 
50   strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
51   if (ioctl (fd, SIOCGIFINDEX, &ifr) < 0)
52     {
53       /* close never fails here, fd is just a unconnected socket.
54        *int saved_errno = errno; */
55       close_not_cancel_no_status(fd);
56       /*if (saved_errno == EINVAL)
57        *  __set_errno(ENOSYS); */
58       return 0;
59     }
60 
61   close_not_cancel_no_status(fd);
62   return ifr.ifr_ifindex;
63 #endif
64 }
libc_hidden_def(if_nametoindex)65 libc_hidden_def(if_nametoindex)
66 
67 void
68 if_freenameindex (struct if_nameindex *ifn)
69 {
70   struct if_nameindex *ptr = ifn;
71   while (ptr->if_name || ptr->if_index)
72     {
73       free (ptr->if_name);
74       ++ptr;
75     }
76   free (ifn);
77 }
libc_hidden_def(if_freenameindex)78 libc_hidden_def(if_freenameindex)
79 
80 #if !__ASSUME_NETLINK_SUPPORT
81 struct if_nameindex *
82 if_nameindex (void)
83 {
84 #ifndef SIOCGIFINDEX
85   __set_errno (ENOSYS);
86   return NULL;
87 #else
88   int fd = __opensock ();
89   struct ifconf ifc;
90   unsigned int nifs, i;
91   int rq_len;
92   struct if_nameindex *idx = NULL;
93 # define RQ_IFS	4
94 
95   if (fd < 0)
96     return NULL;
97 
98   ifc.ifc_buf = NULL;
99 
100   /* Guess on the correct buffer size... */
101   rq_len = RQ_IFS * sizeof (struct ifreq);
102 
103   /* Read all the interfaces out of the kernel.  */
104   /* Note: alloca's in this loop are diff from glibc because it's smaller */
105   do
106     {
107       ifc.ifc_buf = extend_alloca (ifc.ifc_buf, rq_len, 2 * rq_len);
108       ifc.ifc_len = rq_len;
109 
110       if (ioctl (fd, SIOCGIFCONF, &ifc) < 0)
111 	{
112 	  close_not_cancel_no_status (fd);
113 	  return NULL;
114 	}
115     }
116   while (ifc.ifc_len == rq_len);
117 
118   nifs = ifc.ifc_len / sizeof(struct ifreq);
119 
120   idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
121   if (idx == NULL)
122     {
123       close_not_cancel_no_status (fd);
124       __set_errno(ENOBUFS);
125       return NULL;
126     }
127 
128   for (i = 0; i < nifs; ++i)
129     {
130       struct ifreq *ifr = &ifc.ifc_req[i];
131       idx[i].if_name = strdup (ifr->ifr_name);
132       if (idx[i].if_name == NULL
133 	  || ioctl (fd, SIOCGIFINDEX, ifr) < 0)
134 	{
135 	  int saved_errno = errno;
136 	  unsigned int j;
137 
138 	  for (j =  0; j < i; ++j)
139 	    free (idx[j].if_name);
140 	  free(idx);
141 	  close_not_cancel_no_status (fd);
142 	  if (saved_errno == EINVAL)
143 	    saved_errno = ENOSYS;
144 	  else if (saved_errno == ENOMEM)
145 	    saved_errno = ENOBUFS;
146 	  __set_errno (saved_errno);
147 	  return NULL;
148 	}
149       idx[i].if_index = ifr->ifr_ifindex;
150     }
151 
152   idx[i].if_index = 0;
153   idx[i].if_name = NULL;
154 
155   close_not_cancel_no_status (fd);
156   return idx;
157 #endif
158 }
159 #else
160 struct if_nameindex *
161 if_nameindex (void)
162 {
163   unsigned int nifs = 0;
164   struct netlink_handle nh = { 0, 0, 0, NULL, NULL };
165   struct if_nameindex *idx = NULL;
166   struct netlink_res *nlp;
167 
168   if (__netlink_open (&nh) < 0)
169     return NULL;
170 
171 
172   /* Tell the kernel that we wish to get a list of all
173      active interfaces.  Collect all data for every interface.  */
174   if (__netlink_request (&nh, RTM_GETLINK) < 0)
175     goto exit_free;
176 
177   /* Count the interfaces.  */
178   for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
179     {
180       struct nlmsghdr *nlh;
181       size_t size = nlp->size;
182 
183       if (nlp->nlh == NULL)
184 	continue;
185 
186       /* Walk through all entries we got from the kernel and look, which
187          message type they contain.  */
188       for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
189 	{
190 	  /* Check if the message is what we want.  */
191 	  if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
192 	    continue;
193 
194 	  if (nlh->nlmsg_type == NLMSG_DONE)
195 	    break;		/* ok */
196 
197 	  if (nlh->nlmsg_type == RTM_NEWLINK)
198 	    ++nifs;
199 	}
200     }
201 
202   idx = malloc ((nifs + 1) * sizeof (struct if_nameindex));
203   if (idx == NULL)
204     {
205     nomem:
206       __set_errno (ENOBUFS);
207       goto exit_free;
208     }
209 
210   /* Add the interfaces.  */
211   nifs = 0;
212   for (nlp = nh.nlm_list; nlp; nlp = nlp->next)
213     {
214       struct nlmsghdr *nlh;
215       size_t size = nlp->size;
216 
217       if (nlp->nlh == NULL)
218 	continue;
219 
220       /* Walk through all entries we got from the kernel and look, which
221          message type they contain.  */
222       for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size))
223 	{
224 	  /* Check if the message is what we want.  */
225 	  if ((pid_t) nlh->nlmsg_pid != nh.pid || nlh->nlmsg_seq != nlp->seq)
226 	    continue;
227 
228 	  if (nlh->nlmsg_type == NLMSG_DONE)
229 	    break;		/* ok */
230 
231 	  if (nlh->nlmsg_type == RTM_NEWLINK)
232 	    {
233 	      struct ifinfomsg *ifim = (struct ifinfomsg *) NLMSG_DATA (nlh);
234 	      struct rtattr *rta = IFLA_RTA (ifim);
235 	      size_t rtasize = IFLA_PAYLOAD (nlh);
236 
237 	      idx[nifs].if_index = ifim->ifi_index;
238 
239 	      while (RTA_OK (rta, rtasize))
240 		{
241 		  char *rta_data = RTA_DATA (rta);
242 		  size_t rta_payload = RTA_PAYLOAD (rta);
243 
244 		  if (rta->rta_type == IFLA_IFNAME)
245 		    {
246 		      idx[nifs].if_name = strndup (rta_data, rta_payload);
247 		      if (idx[nifs].if_name == NULL)
248 			{
249 			  idx[nifs].if_index = 0;
250 			  if_freenameindex (idx);
251 			  idx = NULL;
252 			  goto nomem;
253 			}
254 		      break;
255 		    }
256 
257 		  rta = RTA_NEXT (rta, rtasize);
258 		}
259 
260 	      ++nifs;
261 	    }
262 	}
263     }
264 
265   idx[nifs].if_index = 0;
266   idx[nifs].if_name = NULL;
267 
268  exit_free:
269   __netlink_free_handle (&nh);
270   __netlink_close (&nh);
271 
272   return idx;
273 }
274 #endif
libc_hidden_def(if_nameindex)275 libc_hidden_def(if_nameindex)
276 
277 char *
278 if_indextoname (unsigned int ifindex, char *ifname)
279 {
280 #if !defined SIOCGIFINDEX
281   __set_errno (ENOSYS);
282   return NULL;
283 #else
284 # ifdef SIOCGIFNAME
285   /* Use ioctl to avoid searching the list. */
286   struct ifreq ifr;
287   int fd;
288 
289   fd = __opensock ();
290 
291   if (fd < 0)
292     return NULL;
293 
294   ifr.ifr_ifindex = ifindex;
295   if (ioctl (fd, SIOCGIFNAME, &ifr) < 0)
296     {
297       int serrno = errno;
298       close_not_cancel_no_status (fd);
299       if (serrno == ENODEV)
300 	/* POSIX requires ENXIO.  */
301 	serrno = ENXIO;
302       __set_errno (serrno);
303       return NULL;
304   }
305   close_not_cancel_no_status (fd);
306 
307   return strncpy (ifname, ifr.ifr_name, IFNAMSIZ);
308 # else
309   struct if_nameindex *idx;
310   struct if_nameindex *p;
311   char *result = NULL;
312 
313   idx = if_nameindex();
314 
315   if (idx != NULL)
316     {
317       for (p = idx; p->if_index || p->if_name; ++p)
318 	if (p->if_index == ifindex)
319 	  {
320 	    result = strncpy (ifname, p->if_name, IFNAMSIZ);
321 	    break;
322 	  }
323 
324       if_freenameindex (idx);
325 
326       if (result == NULL)
327 	__set_errno (ENXIO);
328     }
329   return result;
330 # endif
331 #endif
332 }
333 
334