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