]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libifconfig/libifconfig.c
Merge llvm, clang, lld, lldb, compiler-rt and libc++ r304222, and update
[FreeBSD/FreeBSD.git] / lib / libifconfig / libifconfig.c
1 /*
2  * Copyright (c) 2016, Marie Helene Kvello-Aune
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * thislist of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation and/or
13  * other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  * may be used to endorse or promote products derived from this software without
17  * specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  * $FreeBSD$
31  */
32
33 /*
34  * Copyright (c) 1983, 1993
35  *  The Regents of the University of California.  All rights reserved.
36  *
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions
39  * are met:
40  * 1. Redistributions of source code must retain the above copyright
41  *    notice, this list of conditions and the following disclaimer.
42  * 2. Redistributions in binary form must reproduce the above copyright
43  *    notice, this list of conditions and the following disclaimer in the
44  *    documentation and/or other materials provided with the distribution.
45  * 3. Neither the name of the University nor the names of its contributors
46  *    may be used to endorse or promote products derived from this software
47  *    without specific prior written permission.
48  *
49  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59  * SUCH DAMAGE.
60  *
61  * $FreeBSD$
62  */
63
64 #include <sys/ioctl.h>
65
66 #include <net/if.h>
67
68 #include <err.h>
69 #include <errno.h>
70 #include <fcntl.h>
71 #include <stdio.h>
72 #include <stdlib.h>
73 #include <string.h>
74 #include <unistd.h>
75
76 #include "libifconfig.h"
77 #include "libifconfig_internal.h"
78
79
80 ifconfig_handle_t *
81 ifconfig_open(void)
82 {
83         struct ifconfig_handle *h;
84
85         h = calloc(1, sizeof(*h));
86         for (int i = 0; i <= AF_MAX; i++) {
87                 h->sockets[i] = -1;
88         }
89         return (h);
90 }
91
92 void
93 ifconfig_close(ifconfig_handle_t *h)
94 {
95
96         for (int i = 0; i <= AF_MAX; i++) {
97                 if (h->sockets[i] != -1) {
98                         (void)close(h->sockets[i]);
99                 }
100         }
101         free(h);
102 }
103
104 ifconfig_errtype
105 ifconfig_err_errtype(ifconfig_handle_t *h)
106 {
107
108         return (h->error.errtype);
109 }
110
111 int
112 ifconfig_err_errno(ifconfig_handle_t *h)
113 {
114
115         return (h->error.errcode);
116 }
117
118 unsigned long
119 ifconfig_err_ioctlreq(ifconfig_handle_t *h)
120 {
121
122         return (h->error.ioctl_request);
123 }
124
125 int
126 ifconfig_get_description(ifconfig_handle_t *h, const char *name,
127     char **description)
128 {
129         struct ifreq ifr;
130         char *descr;
131         size_t descrlen;
132
133         descr = NULL;
134         descrlen = 64;
135         memset(&ifr, 0, sizeof(ifr));
136         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
137
138         for (;;) {
139                 if ((descr = reallocf(descr, descrlen)) == NULL) {
140                         h->error.errtype = OTHER;
141                         h->error.errcode = ENOMEM;
142                         return (-1);
143                 }
144
145                 ifr.ifr_buffer.buffer = descr;
146                 ifr.ifr_buffer.length = descrlen;
147                 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFDESCR, &ifr) != 0) {
148                         return (-1);
149                 }
150
151                 if (ifr.ifr_buffer.buffer == descr) {
152                         if (strlen(descr) > 0) {
153                                 *description = strdup(descr);
154                                 free(descr);
155                                 return (0);
156                         }
157                 } else if (ifr.ifr_buffer.length > descrlen) {
158                         descrlen = ifr.ifr_buffer.length;
159                         continue;
160                 }
161                 break;
162         }
163         free(descr);
164         h->error.errtype = OTHER;
165         h->error.errcode = 0;
166         return (-1);
167 }
168
169 int
170 ifconfig_set_description(ifconfig_handle_t *h, const char *name,
171     const char *newdescription)
172 {
173         struct ifreq ifr;
174         int desclen;
175
176         memset(&ifr, 0, sizeof(ifr));
177         desclen = strlen(newdescription);
178
179         /*
180          * Unset description if the new description is 0 characters long.
181          * TODO: Decide whether this should be an error condition instead.
182          */
183         if (desclen == 0) {
184                 return (ifconfig_unset_description(h, name));
185         }
186
187         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
188         ifr.ifr_buffer.length = desclen + 1;
189         ifr.ifr_buffer.buffer = strdup(newdescription);
190
191         if (ifr.ifr_buffer.buffer == NULL) {
192                 h->error.errtype = OTHER;
193                 h->error.errcode = ENOMEM;
194                 return (-1);
195         }
196
197         if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFDESCR,
198             &ifr) != 0) {
199                 free(ifr.ifr_buffer.buffer);
200                 return (-1);
201         }
202
203         free(ifr.ifr_buffer.buffer);
204         return (0);
205 }
206
207 int
208 ifconfig_unset_description(ifconfig_handle_t *h, const char *name)
209 {
210         struct ifreq ifr;
211
212         memset(&ifr, 0, sizeof(ifr));
213         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
214         ifr.ifr_buffer.length = 0;
215         ifr.ifr_buffer.buffer = NULL;
216
217         if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFDESCR,
218             &ifr) < 0) {
219                 return (-1);
220         }
221         return (0);
222 }
223
224 int
225 ifconfig_set_name(ifconfig_handle_t *h, const char *name, const char *newname)
226 {
227         struct ifreq ifr;
228         char *tmpname;
229
230         memset(&ifr, 0, sizeof(ifr));
231         tmpname = strdup(newname);
232         if (tmpname == NULL) {
233                 h->error.errtype = OTHER;
234                 h->error.errcode = ENOMEM;
235                 return (-1);
236         }
237
238         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
239         ifr.ifr_data = tmpname;
240         if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFNAME,
241             &ifr) != 0) {
242                 free(tmpname);
243                 return (-1);
244         }
245
246         free(tmpname);
247         return (0);
248 }
249
250 int
251 ifconfig_set_mtu(ifconfig_handle_t *h, const char *name, const int mtu)
252 {
253         struct ifreq ifr;
254
255         memset(&ifr, 0, sizeof(ifr));
256         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
257         ifr.ifr_mtu = mtu;
258
259         if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFMTU,
260             &ifr) < 0) {
261                 return (-1);
262         }
263
264         return (0);
265 }
266
267 int
268 ifconfig_get_mtu(ifconfig_handle_t *h, const char *name, int *mtu)
269 {
270         struct ifreq ifr;
271
272         memset(&ifr, 0, sizeof(ifr));
273         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
274
275         if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFMTU,
276             &ifr) == -1) {
277                 return (-1);
278         }
279
280         *mtu = ifr.ifr_mtu;
281         return (0);
282 }
283
284 int
285 ifconfig_set_metric(ifconfig_handle_t *h, const char *name, const int mtu)
286 {
287         struct ifreq ifr;
288
289         memset(&ifr, 0, sizeof(ifr));
290         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
291         ifr.ifr_mtu = mtu;
292
293         if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFMETRIC,
294             &ifr) < 0) {
295                 return (-1);
296         }
297
298         return (0);
299 }
300
301 int
302 ifconfig_get_metric(ifconfig_handle_t *h, const char *name, int *metric)
303 {
304         struct ifreq ifr;
305
306         memset(&ifr, 0, sizeof(ifr));
307         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
308
309         if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFMETRIC,
310             &ifr) == -1) {
311                 return (-1);
312         }
313
314         *metric = ifr.ifr_metric;
315         return (0);
316 }
317
318 int
319 ifconfig_set_capability(ifconfig_handle_t *h, const char *name,
320     const int capability)
321 {
322         struct ifreq ifr;
323         struct ifconfig_capabilities ifcap;
324         int flags, value;
325
326         memset(&ifr, 0, sizeof(ifr));
327
328         if (ifconfig_get_capability(h, name,
329             &ifcap) != 0) {
330                 return (-1);
331         }
332
333         value = capability;
334         flags = ifcap.curcap;
335         if (value < 0) {
336                 value = -value;
337                 flags &= ~value;
338         } else {
339                 flags |= value;
340         }
341         flags &= ifcap.reqcap;
342
343         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
344
345         /*
346          * TODO: Verify that it's safe to not have ifr.ifr_curcap
347          * set for this request.
348          */
349         ifr.ifr_reqcap = flags;
350         if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFCAP,
351             &ifr) < 0) {
352                 return (-1);
353         }
354         return (0);
355 }
356
357 int
358 ifconfig_get_capability(ifconfig_handle_t *h, const char *name,
359     struct ifconfig_capabilities *capability)
360 {
361         struct ifreq ifr;
362
363         memset(&ifr, 0, sizeof(ifr));
364         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
365
366         if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFCAP,
367             &ifr) < 0) {
368                 return (-1);
369         }
370         capability->curcap = ifr.ifr_curcap;
371         capability->reqcap = ifr.ifr_reqcap;
372         return (0);
373 }
374
375 int
376 ifconfig_destroy_interface(ifconfig_handle_t *h, const char *name)
377 {
378         struct ifreq ifr;
379
380         memset(&ifr, 0, sizeof(ifr));
381         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
382
383         if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFDESTROY,
384             &ifr) < 0) {
385                 return (-1);
386         }
387         return (0);
388 }
389
390 int
391 ifconfig_create_interface(ifconfig_handle_t *h, const char *name, char **ifname)
392 {
393         struct ifreq ifr;
394
395         memset(&ifr, 0, sizeof(ifr));
396         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
397
398         /*
399          * TODO:
400          * Insert special snowflake handling here. See GitHub issue #12 for details.
401          * In the meantime, hard-nosupport interfaces that need special handling.
402          */
403         if ((strncmp(name, "wlan",
404             strlen("wlan")) == 0) ||
405             (strncmp(name, "vlan",
406             strlen("vlan")) == 0) ||
407             (strncmp(name, "vxlan",
408             strlen("vxlan")) == 0)) {
409                 h->error.errtype = OTHER;
410                 h->error.errcode = ENOSYS;
411                 return (-1);
412         }
413
414         /* No special handling for this interface type. */
415         if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFCREATE2, &ifr) < 0) {
416                 return (-1);
417         }
418
419         *ifname = strdup(ifr.ifr_name);
420         return (0);
421 }