]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libifconfig/libifconfig.c
Merge llvm trunk r321414 to contrib/llvm.
[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  /*
65  * Copyright 1996 Massachusetts Institute of Technology
66  *
67  * Permission to use, copy, modify, and distribute this software and
68  * its documentation for any purpose and without fee is hereby
69  * granted, provided that both the above copyright notice and this
70  * permission notice appear in all copies, that both the above
71  * copyright notice and this permission notice appear in all
72  * supporting documentation, and that the name of M.I.T. not be used
73  * in advertising or publicity pertaining to distribution of the
74  * software without specific, written prior permission.  M.I.T. makes
75  * no representations about the suitability of this software for any
76  * purpose.  It is provided "as is" without express or implied
77  * warranty.
78  *
79  * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
80  * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
81  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
82  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
83  * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
84  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
85  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
86  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
87  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
88  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
89  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
90  * SUCH DAMAGE.
91  *
92  * $FreeBSD$
93  */
94
95 #include <sys/types.h>
96 #include <sys/ioctl.h>
97 #include <sys/sysctl.h>
98
99 #include <net/if.h>
100 #include <net/if_mib.h>
101
102 #include <err.h>
103 #include <errno.h>
104 #include <fcntl.h>
105 #include <stdio.h>
106 #include <stdlib.h>
107 #include <string.h>
108 #include <unistd.h>
109
110 #include "libifconfig.h"
111 #include "libifconfig_internal.h"
112
113
114 ifconfig_handle_t *
115 ifconfig_open(void)
116 {
117         struct ifconfig_handle *h;
118
119         h = calloc(1, sizeof(*h));
120         for (int i = 0; i <= AF_MAX; i++) {
121                 h->sockets[i] = -1;
122         }
123         return (h);
124 }
125
126 void
127 ifconfig_close(ifconfig_handle_t *h)
128 {
129
130         for (int i = 0; i <= AF_MAX; i++) {
131                 if (h->sockets[i] != -1) {
132                         (void)close(h->sockets[i]);
133                 }
134         }
135         free(h);
136 }
137
138 ifconfig_errtype
139 ifconfig_err_errtype(ifconfig_handle_t *h)
140 {
141
142         return (h->error.errtype);
143 }
144
145 int
146 ifconfig_err_errno(ifconfig_handle_t *h)
147 {
148
149         return (h->error.errcode);
150 }
151
152 unsigned long
153 ifconfig_err_ioctlreq(ifconfig_handle_t *h)
154 {
155
156         return (h->error.ioctl_request);
157 }
158
159 int
160 ifconfig_get_description(ifconfig_handle_t *h, const char *name,
161     char **description)
162 {
163         struct ifreq ifr;
164         char *descr;
165         size_t descrlen;
166
167         descr = NULL;
168         descrlen = 64;
169         memset(&ifr, 0, sizeof(ifr));
170         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
171
172         for (;;) {
173                 if ((descr = reallocf(descr, descrlen)) == NULL) {
174                         h->error.errtype = OTHER;
175                         h->error.errcode = ENOMEM;
176                         return (-1);
177                 }
178
179                 ifr.ifr_buffer.buffer = descr;
180                 ifr.ifr_buffer.length = descrlen;
181                 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFDESCR, &ifr) != 0) {
182                         return (-1);
183                 }
184
185                 if (ifr.ifr_buffer.buffer == descr) {
186                         if (strlen(descr) > 0) {
187                                 *description = strdup(descr);
188                                 free(descr);
189                                 return (0);
190                         }
191                 } else if (ifr.ifr_buffer.length > descrlen) {
192                         descrlen = ifr.ifr_buffer.length;
193                         continue;
194                 }
195                 break;
196         }
197         free(descr);
198         h->error.errtype = OTHER;
199         h->error.errcode = 0;
200         return (-1);
201 }
202
203 int
204 ifconfig_set_description(ifconfig_handle_t *h, const char *name,
205     const char *newdescription)
206 {
207         struct ifreq ifr;
208         int desclen;
209
210         memset(&ifr, 0, sizeof(ifr));
211         desclen = strlen(newdescription);
212
213         /*
214          * Unset description if the new description is 0 characters long.
215          * TODO: Decide whether this should be an error condition instead.
216          */
217         if (desclen == 0) {
218                 return (ifconfig_unset_description(h, name));
219         }
220
221         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
222         ifr.ifr_buffer.length = desclen + 1;
223         ifr.ifr_buffer.buffer = strdup(newdescription);
224
225         if (ifr.ifr_buffer.buffer == NULL) {
226                 h->error.errtype = OTHER;
227                 h->error.errcode = ENOMEM;
228                 return (-1);
229         }
230
231         if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFDESCR,
232             &ifr) != 0) {
233                 free(ifr.ifr_buffer.buffer);
234                 return (-1);
235         }
236
237         free(ifr.ifr_buffer.buffer);
238         return (0);
239 }
240
241 int
242 ifconfig_unset_description(ifconfig_handle_t *h, const char *name)
243 {
244         struct ifreq ifr;
245
246         memset(&ifr, 0, sizeof(ifr));
247         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
248         ifr.ifr_buffer.length = 0;
249         ifr.ifr_buffer.buffer = NULL;
250
251         if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFDESCR,
252             &ifr) < 0) {
253                 return (-1);
254         }
255         return (0);
256 }
257
258 int
259 ifconfig_set_name(ifconfig_handle_t *h, const char *name, const char *newname)
260 {
261         struct ifreq ifr;
262         char *tmpname;
263
264         memset(&ifr, 0, sizeof(ifr));
265         tmpname = strdup(newname);
266         if (tmpname == NULL) {
267                 h->error.errtype = OTHER;
268                 h->error.errcode = ENOMEM;
269                 return (-1);
270         }
271
272         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
273         ifr.ifr_data = tmpname;
274         if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFNAME,
275             &ifr) != 0) {
276                 free(tmpname);
277                 return (-1);
278         }
279
280         free(tmpname);
281         return (0);
282 }
283
284 int
285 ifconfig_get_orig_name(ifconfig_handle_t *h, const char *ifname,
286     char **orig_name)
287 {
288         struct ifmibdata ifmd;
289         size_t len;
290         int name[6];
291         int i, maxifno;
292
293         name[0] = CTL_NET;
294         name[1] = PF_LINK;
295         name[2] = NETLINK_GENERIC;
296         name[3] = IFMIB_SYSTEM;
297         name[4] = IFMIB_IFCOUNT;
298
299         len = sizeof maxifno;
300         if (sysctl(name, 5, &maxifno, &len, 0, 0) < 0) {
301                 h->error.errtype = OTHER;
302                 h->error.errcode = errno;
303                 return (-1);
304         }
305
306         name[3] = IFMIB_IFDATA;
307         name[5] = IFDATA_GENERAL;
308         for (i = 1; i <= maxifno; i++) {
309                 len = sizeof ifmd;
310                 name[4] = i;
311                 if (sysctl(name, 6, &ifmd, &len, 0, 0) < 0) {
312                         if (errno == ENOENT)
313                                 continue;
314
315                         goto fail;
316                 }
317
318                 if (strncmp(ifmd.ifmd_name, ifname, IFNAMSIZ) != 0)
319                         continue;
320
321                 len = 0;
322                 name[5] = IFDATA_DRIVERNAME;
323                 if (sysctl(name, 6, NULL, &len, 0, 0) < 0)
324                         goto fail;
325
326                 *orig_name = malloc(len);
327                 if (*orig_name == NULL)
328                         goto fail;
329
330                 if (sysctl(name, 6, *orig_name, &len, 0, 0) < 0) {
331                         free(*orig_name);
332                         *orig_name = NULL;
333                         goto fail;
334                 }
335
336                 return (0);
337         }
338
339 fail:
340         h->error.errtype = OTHER;
341         h->error.errcode = (i <= maxifno) ? errno : ENOENT;
342         return (-1);
343 }
344
345 int
346 ifconfig_set_mtu(ifconfig_handle_t *h, const char *name, const int mtu)
347 {
348         struct ifreq ifr;
349
350         memset(&ifr, 0, sizeof(ifr));
351         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
352         ifr.ifr_mtu = mtu;
353
354         if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFMTU,
355             &ifr) < 0) {
356                 return (-1);
357         }
358
359         return (0);
360 }
361
362 int
363 ifconfig_get_mtu(ifconfig_handle_t *h, const char *name, int *mtu)
364 {
365         struct ifreq ifr;
366
367         memset(&ifr, 0, sizeof(ifr));
368         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
369
370         if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFMTU,
371             &ifr) == -1) {
372                 return (-1);
373         }
374
375         *mtu = ifr.ifr_mtu;
376         return (0);
377 }
378
379 int
380 ifconfig_set_metric(ifconfig_handle_t *h, const char *name, const int mtu)
381 {
382         struct ifreq ifr;
383
384         memset(&ifr, 0, sizeof(ifr));
385         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
386         ifr.ifr_mtu = mtu;
387
388         if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFMETRIC,
389             &ifr) < 0) {
390                 return (-1);
391         }
392
393         return (0);
394 }
395
396 int
397 ifconfig_get_metric(ifconfig_handle_t *h, const char *name, int *metric)
398 {
399         struct ifreq ifr;
400
401         memset(&ifr, 0, sizeof(ifr));
402         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
403
404         if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFMETRIC,
405             &ifr) == -1) {
406                 return (-1);
407         }
408
409         *metric = ifr.ifr_metric;
410         return (0);
411 }
412
413 int
414 ifconfig_set_capability(ifconfig_handle_t *h, const char *name,
415     const int capability)
416 {
417         struct ifreq ifr;
418         struct ifconfig_capabilities ifcap;
419         int flags, value;
420
421         memset(&ifr, 0, sizeof(ifr));
422
423         if (ifconfig_get_capability(h, name,
424             &ifcap) != 0) {
425                 return (-1);
426         }
427
428         value = capability;
429         flags = ifcap.curcap;
430         if (value < 0) {
431                 value = -value;
432                 flags &= ~value;
433         } else {
434                 flags |= value;
435         }
436         flags &= ifcap.reqcap;
437
438         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
439
440         /*
441          * TODO: Verify that it's safe to not have ifr.ifr_curcap
442          * set for this request.
443          */
444         ifr.ifr_reqcap = flags;
445         if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFCAP,
446             &ifr) < 0) {
447                 return (-1);
448         }
449         return (0);
450 }
451
452 int
453 ifconfig_get_capability(ifconfig_handle_t *h, const char *name,
454     struct ifconfig_capabilities *capability)
455 {
456         struct ifreq ifr;
457
458         memset(&ifr, 0, sizeof(ifr));
459         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
460
461         if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFCAP,
462             &ifr) < 0) {
463                 return (-1);
464         }
465         capability->curcap = ifr.ifr_curcap;
466         capability->reqcap = ifr.ifr_reqcap;
467         return (0);
468 }
469
470 int
471 ifconfig_destroy_interface(ifconfig_handle_t *h, const char *name)
472 {
473         struct ifreq ifr;
474
475         memset(&ifr, 0, sizeof(ifr));
476         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
477
478         if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFDESTROY,
479             &ifr) < 0) {
480                 return (-1);
481         }
482         return (0);
483 }
484
485 int
486 ifconfig_create_interface(ifconfig_handle_t *h, const char *name, char **ifname)
487 {
488         struct ifreq ifr;
489
490         memset(&ifr, 0, sizeof(ifr));
491         (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
492
493         /*
494          * TODO:
495          * Insert special snowflake handling here. See GitHub issue #12 for details.
496          * In the meantime, hard-nosupport interfaces that need special handling.
497          */
498         if ((strncmp(name, "wlan",
499             strlen("wlan")) == 0) ||
500             (strncmp(name, "vlan",
501             strlen("vlan")) == 0) ||
502             (strncmp(name, "vxlan",
503             strlen("vxlan")) == 0)) {
504                 h->error.errtype = OTHER;
505                 h->error.errcode = ENOSYS;
506                 return (-1);
507         }
508
509         /* No special handling for this interface type. */
510         if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFCREATE2, &ifr) < 0) {
511                 return (-1);
512         }
513
514         *ifname = strdup(ifr.ifr_name);
515         return (0);
516 }