xref: /freebsd-src/lib/libifconfig/libifconfig.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
1ec214349SKristof Provost /*
2ec214349SKristof Provost  * Copyright (c) 1983, 1993
3ec214349SKristof Provost  *  The Regents of the University of California.  All rights reserved.
4b1d757bcSAlan Somers  * Copyright (c) 2016-2017, Marie Helene Kvello-Aune.  All rights reserved.
5ec214349SKristof Provost  *
6ec214349SKristof Provost  * Redistribution and use in source and binary forms, with or without
7ec214349SKristof Provost  * modification, are permitted provided that the following conditions
8ec214349SKristof Provost  * are met:
9ec214349SKristof Provost  * 1. Redistributions of source code must retain the above copyright
10ec214349SKristof Provost  *    notice, this list of conditions and the following disclaimer.
11ec214349SKristof Provost  * 2. Redistributions in binary form must reproduce the above copyright
12ec214349SKristof Provost  *    notice, this list of conditions and the following disclaimer in the
13ec214349SKristof Provost  *    documentation and/or other materials provided with the distribution.
14fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
15ec214349SKristof Provost  *    may be used to endorse or promote products derived from this software
16ec214349SKristof Provost  *    without specific prior written permission.
17ec214349SKristof Provost  *
18ec214349SKristof Provost  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19ec214349SKristof Provost  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20ec214349SKristof Provost  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21ec214349SKristof Provost  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22ec214349SKristof Provost  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23ec214349SKristof Provost  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24ec214349SKristof Provost  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25ec214349SKristof Provost  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26ec214349SKristof Provost  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27ec214349SKristof Provost  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28ec214349SKristof Provost  * SUCH DAMAGE.
29ec214349SKristof Provost  */
30ec214349SKristof Provost 
31c2803f1aSAndriy Voskoboinyk #include <sys/types.h>
32ec214349SKristof Provost #include <sys/ioctl.h>
33c2803f1aSAndriy Voskoboinyk #include <sys/sysctl.h>
34ec214349SKristof Provost 
35ec214349SKristof Provost #include <net/if.h>
36c2803f1aSAndriy Voskoboinyk #include <net/if_mib.h>
37b1d757bcSAlan Somers #include <netinet/in.h>
38b1d757bcSAlan Somers #include <netinet6/in6_var.h>
39b1d757bcSAlan Somers #include <netinet6/nd6.h>
40ec214349SKristof Provost 
41ec214349SKristof Provost #include <err.h>
42ec214349SKristof Provost #include <errno.h>
43ec214349SKristof Provost #include <fcntl.h>
44b1d757bcSAlan Somers #include <ifaddrs.h>
45b1d757bcSAlan Somers #include <stdbool.h>
46ec214349SKristof Provost #include <stdio.h>
47ec214349SKristof Provost #include <stdlib.h>
48ec214349SKristof Provost #include <string.h>
49ec214349SKristof Provost #include <unistd.h>
50ec214349SKristof Provost 
51b1d757bcSAlan Somers #include <net/if_vlan_var.h>
52b1d757bcSAlan Somers 
53ec214349SKristof Provost #include "libifconfig.h"
54ec214349SKristof Provost #include "libifconfig_internal.h"
55ec214349SKristof Provost 
56b1d757bcSAlan Somers #define NOTAG    ((u_short) -1)
57b1d757bcSAlan Somers 
58b1d757bcSAlan Somers static bool
isnd6defif(ifconfig_handle_t * h,const char * name)59b1d757bcSAlan Somers isnd6defif(ifconfig_handle_t *h, const char *name)
60b1d757bcSAlan Somers {
61b1d757bcSAlan Somers 	struct in6_ndifreq ndifreq;
62b1d757bcSAlan Somers 	unsigned int ifindex;
63b1d757bcSAlan Somers 
64b1d757bcSAlan Somers 	memset(&ndifreq, 0, sizeof(ndifreq));
65b1d757bcSAlan Somers 	strlcpy(ndifreq.ifname, name, sizeof(ndifreq.ifname));
66b1d757bcSAlan Somers 	ifindex = if_nametoindex(ndifreq.ifname);
67b1d757bcSAlan Somers 	if (ifconfig_ioctlwrap(h, AF_INET6, SIOCGDEFIFACE_IN6, &ndifreq) < 0) {
68b1d757bcSAlan Somers 		return (false);
69b1d757bcSAlan Somers 	}
70b1d757bcSAlan Somers 	h->error.errtype = OK;
71b1d757bcSAlan Somers 	return (ndifreq.ifindex == ifindex);
72b1d757bcSAlan Somers }
73ec214349SKristof Provost 
74ec214349SKristof Provost ifconfig_handle_t *
ifconfig_open(void)75ec214349SKristof Provost ifconfig_open(void)
76ec214349SKristof Provost {
77b1d757bcSAlan Somers 	ifconfig_handle_t *h;
78ec214349SKristof Provost 
799a2ff315SKristof Provost 	h = calloc(1, sizeof(*h));
80b1d757bcSAlan Somers 
81b1d757bcSAlan Somers 	if (h == NULL) {
82b1d757bcSAlan Somers 		return (NULL);
83b1d757bcSAlan Somers 	}
84ec214349SKristof Provost 	for (int i = 0; i <= AF_MAX; i++) {
85ec214349SKristof Provost 		h->sockets[i] = -1;
86ec214349SKristof Provost 	}
87b1d757bcSAlan Somers 
88ec214349SKristof Provost 	return (h);
89ec214349SKristof Provost }
90ec214349SKristof Provost 
91ec214349SKristof Provost void
ifconfig_close(ifconfig_handle_t * h)92ec214349SKristof Provost ifconfig_close(ifconfig_handle_t *h)
93ec214349SKristof Provost {
949a2ff315SKristof Provost 
95ec214349SKristof Provost 	for (int i = 0; i <= AF_MAX; i++) {
96ec214349SKristof Provost 		if (h->sockets[i] != -1) {
97ec214349SKristof Provost 			(void)close(h->sockets[i]);
98ec214349SKristof Provost 		}
99ec214349SKristof Provost 	}
100b1d757bcSAlan Somers 	freeifaddrs(h->ifap);
101ec214349SKristof Provost 	free(h);
102ec214349SKristof Provost }
103ec214349SKristof Provost 
104ec214349SKristof Provost ifconfig_errtype
ifconfig_err_errtype(ifconfig_handle_t * h)105ec214349SKristof Provost ifconfig_err_errtype(ifconfig_handle_t *h)
106ec214349SKristof Provost {
1079a2ff315SKristof Provost 
108ec214349SKristof Provost 	return (h->error.errtype);
109ec214349SKristof Provost }
110ec214349SKristof Provost 
111ec214349SKristof Provost int
ifconfig_err_errno(ifconfig_handle_t * h)112ec214349SKristof Provost ifconfig_err_errno(ifconfig_handle_t *h)
113ec214349SKristof Provost {
1149a2ff315SKristof Provost 
115ec214349SKristof Provost 	return (h->error.errcode);
116ec214349SKristof Provost }
117ec214349SKristof Provost 
118ec214349SKristof Provost unsigned long
ifconfig_err_ioctlreq(ifconfig_handle_t * h)119ec214349SKristof Provost ifconfig_err_ioctlreq(ifconfig_handle_t *h)
120ec214349SKristof Provost {
1219a2ff315SKristof Provost 
122ec214349SKristof Provost 	return (h->error.ioctl_request);
123ec214349SKristof Provost }
124ec214349SKristof Provost 
125ec214349SKristof Provost int
ifconfig_foreach_iface(ifconfig_handle_t * h,ifconfig_foreach_func_t cb,void * udata)126b1d757bcSAlan Somers ifconfig_foreach_iface(ifconfig_handle_t *h,
127b1d757bcSAlan Somers     ifconfig_foreach_func_t cb, void *udata)
128b1d757bcSAlan Somers {
129b1d757bcSAlan Somers 	int ret;
130b1d757bcSAlan Somers 
131b1d757bcSAlan Somers 	ret = ifconfig_getifaddrs(h);
132b1d757bcSAlan Somers 	if (ret == 0) {
133b1d757bcSAlan Somers 		struct ifaddrs *ifa;
134b1d757bcSAlan Somers 		char *ifname = NULL;
135b1d757bcSAlan Somers 
136b1d757bcSAlan Somers 		for (ifa = h->ifap; ifa; ifa = ifa->ifa_next) {
137b1d757bcSAlan Somers 			if (ifname != ifa->ifa_name) {
138b1d757bcSAlan Somers 				ifname = ifa->ifa_name;
139b1d757bcSAlan Somers 				cb(h, ifa, udata);
140b1d757bcSAlan Somers 			}
141b1d757bcSAlan Somers 		}
142b1d757bcSAlan Somers 	}
143b1d757bcSAlan Somers 	/* Free ifaddrs so we don't accidentally cache stale data */
144b1d757bcSAlan Somers 	freeifaddrs(h->ifap);
145b1d757bcSAlan Somers 	h->ifap = NULL;
146b1d757bcSAlan Somers 
147b1d757bcSAlan Somers 	return (ret);
148b1d757bcSAlan Somers }
149b1d757bcSAlan Somers 
150b1d757bcSAlan Somers void
ifconfig_foreach_ifaddr(ifconfig_handle_t * h,struct ifaddrs * ifa,ifconfig_foreach_func_t cb,void * udata)151b1d757bcSAlan Somers ifconfig_foreach_ifaddr(ifconfig_handle_t *h, struct ifaddrs *ifa,
152b1d757bcSAlan Somers     ifconfig_foreach_func_t cb, void *udata)
153b1d757bcSAlan Somers {
154b1d757bcSAlan Somers 	struct ifaddrs *ift;
155b1d757bcSAlan Somers 
156b1d757bcSAlan Somers 	for (ift = ifa;
157b1d757bcSAlan Somers 	    ift != NULL &&
158b1d757bcSAlan Somers 	    ift->ifa_addr != NULL &&
159b1d757bcSAlan Somers 	    strcmp(ift->ifa_name, ifa->ifa_name) == 0;
160b1d757bcSAlan Somers 	    ift = ift->ifa_next) {
161b1d757bcSAlan Somers 		cb(h, ift, udata);
162b1d757bcSAlan Somers 	}
163b1d757bcSAlan Somers }
164b1d757bcSAlan Somers 
165b1d757bcSAlan Somers int
ifconfig_get_description(ifconfig_handle_t * h,const char * name,char ** description)1669a2ff315SKristof Provost ifconfig_get_description(ifconfig_handle_t *h, const char *name,
1679a2ff315SKristof Provost     char **description)
168ec214349SKristof Provost {
169ec214349SKristof Provost 	struct ifreq ifr;
1709a2ff315SKristof Provost 	char *descr;
1719a2ff315SKristof Provost 	size_t descrlen;
172ec214349SKristof Provost 
1739a2ff315SKristof Provost 	descr = NULL;
1749a2ff315SKristof Provost 	descrlen = 64;
1759a2ff315SKristof Provost 	memset(&ifr, 0, sizeof(ifr));
176ec214349SKristof Provost 	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1779a2ff315SKristof Provost 
178ec214349SKristof Provost 	for (;;) {
179ec214349SKristof Provost 		if ((descr = reallocf(descr, descrlen)) == NULL) {
180ec214349SKristof Provost 			h->error.errtype = OTHER;
181ec214349SKristof Provost 			h->error.errcode = ENOMEM;
182ec214349SKristof Provost 			return (-1);
183ec214349SKristof Provost 		}
184ec214349SKristof Provost 
185ec214349SKristof Provost 		ifr.ifr_buffer.buffer = descr;
186ec214349SKristof Provost 		ifr.ifr_buffer.length = descrlen;
1879a2ff315SKristof Provost 		if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFDESCR, &ifr) != 0) {
188b1d757bcSAlan Somers 			free(descr);
189ec214349SKristof Provost 			return (-1);
190ec214349SKristof Provost 		}
191ec214349SKristof Provost 
192ec214349SKristof Provost 		if (ifr.ifr_buffer.buffer == descr) {
193ec214349SKristof Provost 			if (strlen(descr) > 0) {
194ec214349SKristof Provost 				*description = strdup(descr);
195ec214349SKristof Provost 				free(descr);
196b1d757bcSAlan Somers 
197b1d757bcSAlan Somers 				if (description == NULL) {
198b1d757bcSAlan Somers 					h->error.errtype = OTHER;
199b1d757bcSAlan Somers 					h->error.errcode = ENOMEM;
200b1d757bcSAlan Somers 					return (-1);
201b1d757bcSAlan Somers 				}
202b1d757bcSAlan Somers 
203ec214349SKristof Provost 				return (0);
204ec214349SKristof Provost 			}
205ec214349SKristof Provost 		} else if (ifr.ifr_buffer.length > descrlen) {
206ec214349SKristof Provost 			descrlen = ifr.ifr_buffer.length;
207ec214349SKristof Provost 			continue;
208ec214349SKristof Provost 		}
209ec214349SKristof Provost 		break;
210ec214349SKristof Provost 	}
211ec214349SKristof Provost 	free(descr);
212ec214349SKristof Provost 	h->error.errtype = OTHER;
213ec214349SKristof Provost 	h->error.errcode = 0;
214ec214349SKristof Provost 	return (-1);
215ec214349SKristof Provost }
216ec214349SKristof Provost 
217ec214349SKristof Provost int
ifconfig_set_description(ifconfig_handle_t * h,const char * name,const char * newdescription)218ec214349SKristof Provost ifconfig_set_description(ifconfig_handle_t *h, const char *name,
219ec214349SKristof Provost     const char *newdescription)
220ec214349SKristof Provost {
221ec214349SKristof Provost 	struct ifreq ifr;
222ec214349SKristof Provost 	int desclen;
223ec214349SKristof Provost 
2249a2ff315SKristof Provost 	memset(&ifr, 0, sizeof(ifr));
225ec214349SKristof Provost 	desclen = strlen(newdescription);
226ec214349SKristof Provost 
227ec214349SKristof Provost 	/*
228ec214349SKristof Provost 	 * Unset description if the new description is 0 characters long.
229ec214349SKristof Provost 	 * TODO: Decide whether this should be an error condition instead.
230ec214349SKristof Provost 	 */
231ec214349SKristof Provost 	if (desclen == 0) {
232ec214349SKristof Provost 		return (ifconfig_unset_description(h, name));
233ec214349SKristof Provost 	}
234ec214349SKristof Provost 
235ec214349SKristof Provost 	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
236ec214349SKristof Provost 	ifr.ifr_buffer.length = desclen + 1;
237ec214349SKristof Provost 	ifr.ifr_buffer.buffer = strdup(newdescription);
2389a2ff315SKristof Provost 
239ec214349SKristof Provost 	if (ifr.ifr_buffer.buffer == NULL) {
240ec214349SKristof Provost 		h->error.errtype = OTHER;
241ec214349SKristof Provost 		h->error.errcode = ENOMEM;
242ec214349SKristof Provost 		return (-1);
243ec214349SKristof Provost 	}
244ec214349SKristof Provost 
245b1d757bcSAlan Somers 	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFDESCR, &ifr) != 0) {
246ec214349SKristof Provost 		free(ifr.ifr_buffer.buffer);
247ec214349SKristof Provost 		return (-1);
248ec214349SKristof Provost 	}
2499a2ff315SKristof Provost 
250ec214349SKristof Provost 	free(ifr.ifr_buffer.buffer);
251ec214349SKristof Provost 	return (0);
252ec214349SKristof Provost }
253ec214349SKristof Provost 
2549a2ff315SKristof Provost int
ifconfig_unset_description(ifconfig_handle_t * h,const char * name)2559a2ff315SKristof Provost ifconfig_unset_description(ifconfig_handle_t *h, const char *name)
256ec214349SKristof Provost {
257ec214349SKristof Provost 	struct ifreq ifr;
258ec214349SKristof Provost 
2599a2ff315SKristof Provost 	memset(&ifr, 0, sizeof(ifr));
260ec214349SKristof Provost 	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
261ec214349SKristof Provost 	ifr.ifr_buffer.length = 0;
262ec214349SKristof Provost 	ifr.ifr_buffer.buffer = NULL;
263ec214349SKristof Provost 
264b1d757bcSAlan Somers 	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFDESCR, &ifr) < 0) {
265ec214349SKristof Provost 		return (-1);
266ec214349SKristof Provost 	}
267ec214349SKristof Provost 	return (0);
268ec214349SKristof Provost }
269ec214349SKristof Provost 
2709a2ff315SKristof Provost int
ifconfig_set_name(ifconfig_handle_t * h,const char * name,const char * newname)2719a2ff315SKristof Provost ifconfig_set_name(ifconfig_handle_t *h, const char *name, const char *newname)
272ec214349SKristof Provost {
273ec214349SKristof Provost 	struct ifreq ifr;
274ec214349SKristof Provost 	char *tmpname;
275ec214349SKristof Provost 
2769a2ff315SKristof Provost 	memset(&ifr, 0, sizeof(ifr));
277ec214349SKristof Provost 	tmpname = strdup(newname);
278ec214349SKristof Provost 	if (tmpname == NULL) {
279ec214349SKristof Provost 		h->error.errtype = OTHER;
280ec214349SKristof Provost 		h->error.errcode = ENOMEM;
281ec214349SKristof Provost 		return (-1);
282ec214349SKristof Provost 	}
283ec214349SKristof Provost 
284ec214349SKristof Provost 	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
285ec214349SKristof Provost 	ifr.ifr_data = tmpname;
286b1d757bcSAlan Somers 	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFNAME, &ifr) != 0) {
287ec214349SKristof Provost 		free(tmpname);
288ec214349SKristof Provost 		return (-1);
289ec214349SKristof Provost 	}
2909a2ff315SKristof Provost 
291ec214349SKristof Provost 	free(tmpname);
292ec214349SKristof Provost 	return (0);
293ec214349SKristof Provost }
294ec214349SKristof Provost 
2959a2ff315SKristof Provost int
ifconfig_get_orig_name(ifconfig_handle_t * h,const char * ifname,char ** orig_name)296c2803f1aSAndriy Voskoboinyk ifconfig_get_orig_name(ifconfig_handle_t *h, const char *ifname,
297c2803f1aSAndriy Voskoboinyk     char **orig_name)
298c2803f1aSAndriy Voskoboinyk {
299c2803f1aSAndriy Voskoboinyk 	size_t len;
300b1d757bcSAlan Somers 	unsigned int ifindex;
301c2803f1aSAndriy Voskoboinyk 	int name[6];
302b1d757bcSAlan Somers 
303b1d757bcSAlan Somers 	ifindex = if_nametoindex(ifname);
304b1d757bcSAlan Somers 	if (ifindex == 0) {
305b1d757bcSAlan Somers 		goto fail;
306b1d757bcSAlan Somers 	}
307c2803f1aSAndriy Voskoboinyk 
308c2803f1aSAndriy Voskoboinyk 	name[0] = CTL_NET;
309c2803f1aSAndriy Voskoboinyk 	name[1] = PF_LINK;
310c2803f1aSAndriy Voskoboinyk 	name[2] = NETLINK_GENERIC;
311c2803f1aSAndriy Voskoboinyk 	name[3] = IFMIB_IFDATA;
312b1d757bcSAlan Somers 	name[4] = ifindex;
313b1d757bcSAlan Somers 	name[5] = IFDATA_DRIVERNAME;
314c2803f1aSAndriy Voskoboinyk 
315c2803f1aSAndriy Voskoboinyk 	len = 0;
316b1d757bcSAlan Somers 	if (sysctl(name, 6, NULL, &len, 0, 0) < 0) {
317c2803f1aSAndriy Voskoboinyk 		goto fail;
318b1d757bcSAlan Somers 	}
319c2803f1aSAndriy Voskoboinyk 
320c2803f1aSAndriy Voskoboinyk 	*orig_name = malloc(len);
321b1d757bcSAlan Somers 	if (*orig_name == NULL) {
322c2803f1aSAndriy Voskoboinyk 		goto fail;
323b1d757bcSAlan Somers 	}
324c2803f1aSAndriy Voskoboinyk 
325c2803f1aSAndriy Voskoboinyk 	if (sysctl(name, 6, *orig_name, &len, 0, 0) < 0) {
326c2803f1aSAndriy Voskoboinyk 		free(*orig_name);
327c2803f1aSAndriy Voskoboinyk 		*orig_name = NULL;
328c2803f1aSAndriy Voskoboinyk 		goto fail;
329c2803f1aSAndriy Voskoboinyk 	}
330c2803f1aSAndriy Voskoboinyk 
331c2803f1aSAndriy Voskoboinyk 	return (0);
332c2803f1aSAndriy Voskoboinyk 
333c2803f1aSAndriy Voskoboinyk fail:
334c2803f1aSAndriy Voskoboinyk 	h->error.errtype = OTHER;
335b1d757bcSAlan Somers 	h->error.errcode = (errno != 0) ? errno : ENOENT;
336c2803f1aSAndriy Voskoboinyk 	return (-1);
337c2803f1aSAndriy Voskoboinyk }
338c2803f1aSAndriy Voskoboinyk 
339c2803f1aSAndriy Voskoboinyk int
ifconfig_get_fib(ifconfig_handle_t * h,const char * name,int * fib)340b1d757bcSAlan Somers ifconfig_get_fib(ifconfig_handle_t *h, const char *name, int *fib)
341b1d757bcSAlan Somers {
342b1d757bcSAlan Somers 	struct ifreq ifr;
343b1d757bcSAlan Somers 
344b1d757bcSAlan Somers 	memset(&ifr, 0, sizeof(ifr));
345b1d757bcSAlan Somers 	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
346b1d757bcSAlan Somers 
347b1d757bcSAlan Somers 	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFFIB, &ifr) == -1) {
348b1d757bcSAlan Somers 		return (-1);
349b1d757bcSAlan Somers 	}
350b1d757bcSAlan Somers 
351b1d757bcSAlan Somers 	*fib = ifr.ifr_fib;
352b1d757bcSAlan Somers 	return (0);
353b1d757bcSAlan Somers }
354b1d757bcSAlan Somers 
355b1d757bcSAlan Somers int
ifconfig_set_mtu(ifconfig_handle_t * h,const char * name,const int mtu)3569a2ff315SKristof Provost ifconfig_set_mtu(ifconfig_handle_t *h, const char *name, const int mtu)
357ec214349SKristof Provost {
358ec214349SKristof Provost 	struct ifreq ifr;
359ec214349SKristof Provost 
3609a2ff315SKristof Provost 	memset(&ifr, 0, sizeof(ifr));
361ec214349SKristof Provost 	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
362ec214349SKristof Provost 	ifr.ifr_mtu = mtu;
3639a2ff315SKristof Provost 
364b1d757bcSAlan Somers 	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFMTU, &ifr) < 0) {
365ec214349SKristof Provost 		return (-1);
366ec214349SKristof Provost 	}
3679a2ff315SKristof Provost 
368ec214349SKristof Provost 	return (0);
369ec214349SKristof Provost }
370ec214349SKristof Provost 
3719a2ff315SKristof Provost int
ifconfig_get_mtu(ifconfig_handle_t * h,const char * name,int * mtu)3729a2ff315SKristof Provost ifconfig_get_mtu(ifconfig_handle_t *h, const char *name, int *mtu)
373ec214349SKristof Provost {
374ec214349SKristof Provost 	struct ifreq ifr;
375ec214349SKristof Provost 
3769a2ff315SKristof Provost 	memset(&ifr, 0, sizeof(ifr));
377ec214349SKristof Provost 	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
3789a2ff315SKristof Provost 
379b1d757bcSAlan Somers 	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFMTU, &ifr) == -1) {
380ec214349SKristof Provost 		return (-1);
381ec214349SKristof Provost 	}
3829a2ff315SKristof Provost 
383ec214349SKristof Provost 	*mtu = ifr.ifr_mtu;
384ec214349SKristof Provost 	return (0);
385ec214349SKristof Provost }
386ec214349SKristof Provost 
3879a2ff315SKristof Provost int
ifconfig_get_nd6(ifconfig_handle_t * h,const char * name,struct in6_ndireq * nd)388b1d757bcSAlan Somers ifconfig_get_nd6(ifconfig_handle_t *h, const char *name,
389b1d757bcSAlan Somers     struct in6_ndireq *nd)
390b1d757bcSAlan Somers {
391b1d757bcSAlan Somers 	memset(nd, 0, sizeof(*nd));
392b1d757bcSAlan Somers 	strlcpy(nd->ifname, name, sizeof(nd->ifname));
393b1d757bcSAlan Somers 	if (ifconfig_ioctlwrap(h, AF_INET6, SIOCGIFINFO_IN6, nd) == -1) {
394b1d757bcSAlan Somers 		return (-1);
395b1d757bcSAlan Somers 	}
396b1d757bcSAlan Somers 	if (isnd6defif(h, name)) {
397b1d757bcSAlan Somers 		nd->ndi.flags |= ND6_IFF_DEFAULTIF;
398b1d757bcSAlan Somers 	} else if (h->error.errtype != OK) {
399b1d757bcSAlan Somers 		return (-1);
400b1d757bcSAlan Somers 	}
401b1d757bcSAlan Somers 
402b1d757bcSAlan Somers 	return (0);
403b1d757bcSAlan Somers }
404b1d757bcSAlan Somers 
405b1d757bcSAlan Somers int
ifconfig_set_metric(ifconfig_handle_t * h,const char * name,const int metric)406ce0d4434SAlan Somers ifconfig_set_metric(ifconfig_handle_t *h, const char *name, const int metric)
407ec214349SKristof Provost {
408ec214349SKristof Provost 	struct ifreq ifr;
409ec214349SKristof Provost 
4109a2ff315SKristof Provost 	memset(&ifr, 0, sizeof(ifr));
411ec214349SKristof Provost 	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
412ce0d4434SAlan Somers 	ifr.ifr_metric = metric;
4139a2ff315SKristof Provost 
414b1d757bcSAlan Somers 	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFMETRIC, &ifr) < 0) {
415ec214349SKristof Provost 		return (-1);
416ec214349SKristof Provost 	}
4179a2ff315SKristof Provost 
418ec214349SKristof Provost 	return (0);
419ec214349SKristof Provost }
420ec214349SKristof Provost 
4219a2ff315SKristof Provost int
ifconfig_get_metric(ifconfig_handle_t * h,const char * name,int * metric)4229a2ff315SKristof Provost ifconfig_get_metric(ifconfig_handle_t *h, const char *name, int *metric)
423ec214349SKristof Provost {
424ec214349SKristof Provost 	struct ifreq ifr;
425ec214349SKristof Provost 
4269a2ff315SKristof Provost 	memset(&ifr, 0, sizeof(ifr));
427ec214349SKristof Provost 	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
4289a2ff315SKristof Provost 
429b1d757bcSAlan Somers 	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFMETRIC, &ifr) == -1) {
430ec214349SKristof Provost 		return (-1);
431ec214349SKristof Provost 	}
4329a2ff315SKristof Provost 
433ec214349SKristof Provost 	*metric = ifr.ifr_metric;
434ec214349SKristof Provost 	return (0);
435ec214349SKristof Provost }
436ec214349SKristof Provost 
4379a2ff315SKristof Provost int
ifconfig_set_capability(ifconfig_handle_t * h,const char * name,const int capability)4389a2ff315SKristof Provost ifconfig_set_capability(ifconfig_handle_t *h, const char *name,
439ec214349SKristof Provost     const int capability)
440ec214349SKristof Provost {
441ec214349SKristof Provost 	struct ifreq ifr;
442ec214349SKristof Provost 	struct ifconfig_capabilities ifcap;
4439a2ff315SKristof Provost 	int flags, value;
444ec214349SKristof Provost 
4459a2ff315SKristof Provost 	memset(&ifr, 0, sizeof(ifr));
4469a2ff315SKristof Provost 
447b1d757bcSAlan Somers 	if (ifconfig_get_capability(h, name, &ifcap) != 0) {
448ec214349SKristof Provost 		return (-1);
449ec214349SKristof Provost 	}
450ec214349SKristof Provost 
451ec214349SKristof Provost 	value = capability;
452ec214349SKristof Provost 	flags = ifcap.curcap;
453ec214349SKristof Provost 	if (value < 0) {
454ec214349SKristof Provost 		value = -value;
455ec214349SKristof Provost 		flags &= ~value;
456ec214349SKristof Provost 	} else {
457ec214349SKristof Provost 		flags |= value;
458ec214349SKristof Provost 	}
459ec214349SKristof Provost 	flags &= ifcap.reqcap;
460ec214349SKristof Provost 
461ec214349SKristof Provost 	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
462ec214349SKristof Provost 
463ec214349SKristof Provost 	/*
464ec214349SKristof Provost 	 * TODO: Verify that it's safe to not have ifr.ifr_curcap
465ec214349SKristof Provost 	 * set for this request.
466ec214349SKristof Provost 	 */
467ec214349SKristof Provost 	ifr.ifr_reqcap = flags;
468b1d757bcSAlan Somers 	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFCAP, &ifr) < 0) {
469ec214349SKristof Provost 		return (-1);
470ec214349SKristof Provost 	}
471ec214349SKristof Provost 	return (0);
472ec214349SKristof Provost }
473ec214349SKristof Provost 
4749a2ff315SKristof Provost int
ifconfig_get_capability(ifconfig_handle_t * h,const char * name,struct ifconfig_capabilities * capability)4759a2ff315SKristof Provost ifconfig_get_capability(ifconfig_handle_t *h, const char *name,
476ec214349SKristof Provost     struct ifconfig_capabilities *capability)
477ec214349SKristof Provost {
478ec214349SKristof Provost 	struct ifreq ifr;
479ec214349SKristof Provost 
4809a2ff315SKristof Provost 	memset(&ifr, 0, sizeof(ifr));
481ec214349SKristof Provost 	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
482ec214349SKristof Provost 
483b1d757bcSAlan Somers 	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFCAP, &ifr) < 0) {
484ec214349SKristof Provost 		return (-1);
485ec214349SKristof Provost 	}
486ec214349SKristof Provost 	capability->curcap = ifr.ifr_curcap;
487ec214349SKristof Provost 	capability->reqcap = ifr.ifr_reqcap;
488ec214349SKristof Provost 	return (0);
489ec214349SKristof Provost }
490ec214349SKristof Provost 
4919a2ff315SKristof Provost int
ifconfig_get_groups(ifconfig_handle_t * h,const char * name,struct ifgroupreq * ifgr)492b1d757bcSAlan Somers ifconfig_get_groups(ifconfig_handle_t *h, const char *name,
493b1d757bcSAlan Somers     struct ifgroupreq *ifgr)
494b1d757bcSAlan Somers {
495b1d757bcSAlan Somers 	int len;
496b1d757bcSAlan Somers 
497b1d757bcSAlan Somers 	memset(ifgr, 0, sizeof(*ifgr));
498b1d757bcSAlan Somers 	strlcpy(ifgr->ifgr_name, name, IFNAMSIZ);
499b1d757bcSAlan Somers 
500b1d757bcSAlan Somers 	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFGROUP, ifgr) == -1) {
501b1d757bcSAlan Somers 		if ((h->error.errcode == EINVAL) ||
502b1d757bcSAlan Somers 		    (h->error.errcode == ENOTTY)) {
503b1d757bcSAlan Somers 			return (0);
504b1d757bcSAlan Somers 		} else {
505b1d757bcSAlan Somers 			return (-1);
506b1d757bcSAlan Somers 		}
507b1d757bcSAlan Somers 	}
508b1d757bcSAlan Somers 
509b1d757bcSAlan Somers 	len = ifgr->ifgr_len;
510b1d757bcSAlan Somers 	ifgr->ifgr_groups = (struct ifg_req *)malloc(len);
511b1d757bcSAlan Somers 	if (ifgr->ifgr_groups == NULL) {
512*1d9ba697SRyan Moeller 		h->error.errtype = OTHER;
513*1d9ba697SRyan Moeller 		h->error.errcode = ENOMEM;
514*1d9ba697SRyan Moeller 		return (-1);
515b1d757bcSAlan Somers 	}
516b1d757bcSAlan Somers 	bzero(ifgr->ifgr_groups, len);
517b1d757bcSAlan Somers 	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFGROUP, ifgr) == -1) {
518b1d757bcSAlan Somers 		return (-1);
519b1d757bcSAlan Somers 	}
520b1d757bcSAlan Somers 
521b1d757bcSAlan Somers 	return (0);
522b1d757bcSAlan Somers }
523b1d757bcSAlan Somers 
524b1d757bcSAlan Somers int
ifconfig_get_ifstatus(ifconfig_handle_t * h,const char * name,struct ifstat * ifs)525b1d757bcSAlan Somers ifconfig_get_ifstatus(ifconfig_handle_t *h, const char *name,
526b1d757bcSAlan Somers     struct ifstat *ifs)
527b1d757bcSAlan Somers {
528b1d757bcSAlan Somers 	strlcpy(ifs->ifs_name, name, sizeof(ifs->ifs_name));
529b1d757bcSAlan Somers 	return (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFSTATUS, ifs));
530b1d757bcSAlan Somers }
531b1d757bcSAlan Somers 
532b1d757bcSAlan Somers int
ifconfig_destroy_interface(ifconfig_handle_t * h,const char * name)5339a2ff315SKristof Provost ifconfig_destroy_interface(ifconfig_handle_t *h, const char *name)
534ec214349SKristof Provost {
535ec214349SKristof Provost 	struct ifreq ifr;
536ec214349SKristof Provost 
5379a2ff315SKristof Provost 	memset(&ifr, 0, sizeof(ifr));
538ec214349SKristof Provost 	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
539ec214349SKristof Provost 
540b1d757bcSAlan Somers 	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFDESTROY, &ifr) < 0) {
541ec214349SKristof Provost 		return (-1);
542ec214349SKristof Provost 	}
543ec214349SKristof Provost 	return (0);
544ec214349SKristof Provost }
545ec214349SKristof Provost 
5469a2ff315SKristof Provost int
ifconfig_create_interface(ifconfig_handle_t * h,const char * name,char ** ifname)5479a2ff315SKristof Provost ifconfig_create_interface(ifconfig_handle_t *h, const char *name, char **ifname)
548ec214349SKristof Provost {
549ec214349SKristof Provost 	struct ifreq ifr;
550ec214349SKristof Provost 
5519a2ff315SKristof Provost 	memset(&ifr, 0, sizeof(ifr));
552b1d757bcSAlan Somers 
553ec214349SKristof Provost 	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
554ec214349SKristof Provost 
555ec214349SKristof Provost 	/*
556ec214349SKristof Provost 	 * TODO:
557ec214349SKristof Provost 	 * Insert special snowflake handling here. See GitHub issue #12 for details.
558ec214349SKristof Provost 	 * In the meantime, hard-nosupport interfaces that need special handling.
559ec214349SKristof Provost 	 */
5609a2ff315SKristof Provost 	if ((strncmp(name, "wlan",
5619a2ff315SKristof Provost 	    strlen("wlan")) == 0) ||
5629a2ff315SKristof Provost 	    (strncmp(name, "vlan",
5639a2ff315SKristof Provost 	    strlen("vlan")) == 0) ||
5649a2ff315SKristof Provost 	    (strncmp(name, "vxlan",
5659a2ff315SKristof Provost 	    strlen("vxlan")) == 0)) {
566ec214349SKristof Provost 		h->error.errtype = OTHER;
567ec214349SKristof Provost 		h->error.errcode = ENOSYS;
568ec214349SKristof Provost 		return (-1);
569ec214349SKristof Provost 	}
570ec214349SKristof Provost 
571ec214349SKristof Provost 	/* No special handling for this interface type. */
572ec214349SKristof Provost 	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFCREATE2, &ifr) < 0) {
573ec214349SKristof Provost 		return (-1);
574ec214349SKristof Provost 	}
5759a2ff315SKristof Provost 
576ec214349SKristof Provost 	*ifname = strdup(ifr.ifr_name);
577b1d757bcSAlan Somers 	if (ifname == NULL) {
578b1d757bcSAlan Somers 		h->error.errtype = OTHER;
579b1d757bcSAlan Somers 		h->error.errcode = ENOMEM;
580b1d757bcSAlan Somers 		return (-1);
581b1d757bcSAlan Somers 	}
582b1d757bcSAlan Somers 
583b1d757bcSAlan Somers 	return (0);
584b1d757bcSAlan Somers }
585b1d757bcSAlan Somers 
586b1d757bcSAlan Somers int
ifconfig_create_interface_vlan(ifconfig_handle_t * h,const char * name,char ** ifname,const char * vlandev,const unsigned short vlantag)587b1d757bcSAlan Somers ifconfig_create_interface_vlan(ifconfig_handle_t *h, const char *name,
588b1d757bcSAlan Somers     char **ifname, const char *vlandev, const unsigned short vlantag)
589b1d757bcSAlan Somers {
590b1d757bcSAlan Somers 	struct ifreq ifr;
591b1d757bcSAlan Somers 	struct vlanreq params;
592b1d757bcSAlan Somers 
593b1d757bcSAlan Somers 	if ((vlantag == NOTAG) || (vlandev[0] == '\0')) {
594b1d757bcSAlan Somers 		// TODO: Add proper error tracking here
595b1d757bcSAlan Somers 		return (-1);
596b1d757bcSAlan Somers 	}
597b1d757bcSAlan Somers 
598b1d757bcSAlan Somers 	bzero(&params, sizeof(params));
599b1d757bcSAlan Somers 	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
600b1d757bcSAlan Somers 	params.vlr_tag = vlantag;
601b1d757bcSAlan Somers 	(void)strlcpy(params.vlr_parent, vlandev, sizeof(params.vlr_parent));
602b1d757bcSAlan Somers 	ifr.ifr_data = (caddr_t)&params;
603b1d757bcSAlan Somers 
604b1d757bcSAlan Somers 	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFCREATE2, &ifr) < 0) {
605b1d757bcSAlan Somers 		// TODO: Add proper error tracking here
606b1d757bcSAlan Somers 		return (-1);
607b1d757bcSAlan Somers 	}
608b1d757bcSAlan Somers 
609b1d757bcSAlan Somers 	*ifname = strdup(ifr.ifr_name);
610b1d757bcSAlan Somers 	return (0);
611b1d757bcSAlan Somers }
612b1d757bcSAlan Somers 
613b1d757bcSAlan Somers int
ifconfig_set_vlantag(ifconfig_handle_t * h,const char * name,const char * vlandev,const unsigned short vlantag)614b1d757bcSAlan Somers ifconfig_set_vlantag(ifconfig_handle_t *h, const char *name,
615b1d757bcSAlan Somers     const char *vlandev, const unsigned short vlantag)
616b1d757bcSAlan Somers {
617b1d757bcSAlan Somers 	struct ifreq ifr;
618b1d757bcSAlan Somers 	struct vlanreq params;
619b1d757bcSAlan Somers 
620b1d757bcSAlan Somers 	bzero(&params, sizeof(params));
621b1d757bcSAlan Somers 	params.vlr_tag = vlantag;
622b1d757bcSAlan Somers 	strlcpy(params.vlr_parent, vlandev, sizeof(params.vlr_parent));
623b1d757bcSAlan Somers 
624b1d757bcSAlan Somers 	ifr.ifr_data = (caddr_t)&params;
625b1d757bcSAlan Somers 	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
626b1d757bcSAlan Somers 	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSETVLAN, &ifr) == -1) {
627b1d757bcSAlan Somers 		return (-1);
628b1d757bcSAlan Somers 	}
629ec214349SKristof Provost 	return (0);
630ec214349SKristof Provost }
6310710ec8cSRyan Moeller 
6320710ec8cSRyan Moeller int
ifconfig_list_cloners(ifconfig_handle_t * h,char ** bufp,size_t * lenp)6330710ec8cSRyan Moeller ifconfig_list_cloners(ifconfig_handle_t *h, char **bufp, size_t *lenp)
6340710ec8cSRyan Moeller {
6350710ec8cSRyan Moeller 	struct if_clonereq ifcr;
6360710ec8cSRyan Moeller 	char *buf;
6370710ec8cSRyan Moeller 
6380710ec8cSRyan Moeller 	memset(&ifcr, 0, sizeof(ifcr));
6390710ec8cSRyan Moeller 	*bufp = NULL;
6400710ec8cSRyan Moeller 	*lenp = 0;
6410710ec8cSRyan Moeller 
6420710ec8cSRyan Moeller 	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFGCLONERS, &ifcr) < 0)
6430710ec8cSRyan Moeller 		return (-1);
6440710ec8cSRyan Moeller 
6450710ec8cSRyan Moeller 	buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
6460710ec8cSRyan Moeller 	if (buf == NULL) {
6470710ec8cSRyan Moeller 		h->error.errtype = OTHER;
6480710ec8cSRyan Moeller 		h->error.errcode = ENOMEM;
6490710ec8cSRyan Moeller 		return (-1);
6500710ec8cSRyan Moeller 	}
6510710ec8cSRyan Moeller 
6520710ec8cSRyan Moeller 	ifcr.ifcr_count = ifcr.ifcr_total;
6530710ec8cSRyan Moeller 	ifcr.ifcr_buffer = buf;
6540710ec8cSRyan Moeller 	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFGCLONERS, &ifcr) < 0) {
6550710ec8cSRyan Moeller 		free(buf);
6560710ec8cSRyan Moeller 		return (-1);
6570710ec8cSRyan Moeller 	}
6580710ec8cSRyan Moeller 
6590710ec8cSRyan Moeller 	*bufp = buf;
6600710ec8cSRyan Moeller 	*lenp = ifcr.ifcr_total;
6610710ec8cSRyan Moeller 	return (0);
6620710ec8cSRyan Moeller }
663