1a5e10afkp/*
2a5e10afkp * Copyright (c) 1983, 1993
3a5e10afkp *  The Regents of the University of California.  All rights reserved.
40d688beasomers * Copyright (c) 2016-2017, Marie Helene Kvello-Aune.  All rights reserved.
5a5e10afkp *
6a5e10afkp * Redistribution and use in source and binary forms, with or without
7a5e10afkp * modification, are permitted provided that the following conditions
8a5e10afkp * are met:
9a5e10afkp * 1. Redistributions of source code must retain the above copyright
10a5e10afkp *    notice, this list of conditions and the following disclaimer.
11a5e10afkp * 2. Redistributions in binary form must reproduce the above copyright
12a5e10afkp *    notice, this list of conditions and the following disclaimer in the
13a5e10afkp *    documentation and/or other materials provided with the distribution.
147e6cabdimp * 3. Neither the name of the University nor the names of its contributors
15a5e10afkp *    may be used to endorse or promote products derived from this software
16a5e10afkp *    without specific prior written permission.
17a5e10afkp *
18a5e10afkp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19a5e10afkp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20a5e10afkp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21a5e10afkp * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22a5e10afkp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23a5e10afkp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24a5e10afkp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25a5e10afkp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26a5e10afkp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27a5e10afkp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28a5e10afkp * SUCH DAMAGE.
290725653kp *
300725653kp * $FreeBSD$
31a5e10afkp */
32a5e10afkp
33ef389b0avos#include <sys/types.h>
34a5e10afkp#include <sys/ioctl.h>
35ef389b0avos#include <sys/sysctl.h>
36a5e10afkp
37a5e10afkp#include <net/if.h>
38ef389b0avos#include <net/if_mib.h>
390d688beasomers#include <netinet/in.h>
400d688beasomers#include <netinet6/in6_var.h>
410d688beasomers#include <netinet6/nd6.h>
42a5e10afkp
43a5e10afkp#include <err.h>
44a5e10afkp#include <errno.h>
45a5e10afkp#include <fcntl.h>
460d688beasomers#include <ifaddrs.h>
470d688beasomers#include <stdbool.h>
48a5e10afkp#include <stdio.h>
49a5e10afkp#include <stdlib.h>
50a5e10afkp#include <string.h>
51a5e10afkp#include <unistd.h>
52a5e10afkp
530d688beasomers#include <net/if_vlan_var.h>
540d688beasomers
55e5074fakp#include "libifconfig.h"
56e5074fakp#include "libifconfig_internal.h"
57a5e10afkp
580d688beasomers#define NOTAG    ((u_short) -1)
590d688beasomers
600d688beasomersstatic bool
610d688beasomersisnd6defif(ifconfig_handle_t *h, const char *name)
620d688beasomers{
630d688beasomers	struct in6_ndifreq ndifreq;
640d688beasomers	unsigned int ifindex;
650d688beasomers
660d688beasomers	memset(&ndifreq, 0, sizeof(ndifreq));
670d688beasomers	strlcpy(ndifreq.ifname, name, sizeof(ndifreq.ifname));
680d688beasomers	ifindex = if_nametoindex(ndifreq.ifname);
690d688beasomers	if (ifconfig_ioctlwrap(h, AF_INET6, SIOCGDEFIFACE_IN6, &ndifreq) < 0) {
700d688beasomers		return (false);
710d688beasomers	}
720d688beasomers	h->error.errtype = OK;
730d688beasomers	return (ndifreq.ifindex == ifindex);
740d688beasomers}
75a5e10afkp
76e5074fakpifconfig_handle_t *
77e5074fakpifconfig_open(void)
78a5e10afkp{
790d688beasomers	ifconfig_handle_t *h;
80a5e10afkp
810725653kp	h = calloc(1, sizeof(*h));
820d688beasomers
830d688beasomers	if (h == NULL) {
840d688beasomers		return (NULL);
850d688beasomers	}
86a5e10afkp	for (int i = 0; i <= AF_MAX; i++) {
87a5e10afkp		h->sockets[i] = -1;
88a5e10afkp	}
890d688beasomers
90a5e10afkp	return (h);
91a5e10afkp}
92a5e10afkp
93a5e10afkpvoid
94e5074fakpifconfig_close(ifconfig_handle_t *h)
95a5e10afkp{
960725653kp
97a5e10afkp	for (int i = 0; i <= AF_MAX; i++) {
98a5e10afkp		if (h->sockets[i] != -1) {
99a5e10afkp			(void)close(h->sockets[i]);
100a5e10afkp		}
101a5e10afkp	}
1020d688beasomers	freeifaddrs(h->ifap);
103a5e10afkp	free(h);
104a5e10afkp}
105a5e10afkp
106e5074fakpifconfig_errtype
107e5074fakpifconfig_err_errtype(ifconfig_handle_t *h)
108a5e10afkp{
1090725653kp
110a5e10afkp	return (h->error.errtype);
111a5e10afkp}
112a5e10afkp
113a5e10afkpint
114e5074fakpifconfig_err_errno(ifconfig_handle_t *h)
115a5e10afkp{
1160725653kp
117a5e10afkp	return (h->error.errcode);
118a5e10afkp}
119a5e10afkp
120a5e10afkpunsigned long
121e5074fakpifconfig_err_ioctlreq(ifconfig_handle_t *h)
122a5e10afkp{
1230725653kp
124a5e10afkp	return (h->error.ioctl_request);
125a5e10afkp}
126a5e10afkp
127a5e10afkpint
1280d688beasomersifconfig_foreach_iface(ifconfig_handle_t *h,
1290d688beasomers    ifconfig_foreach_func_t cb, void *udata)
1300d688beasomers{
1310d688beasomers	int ret;
1320d688beasomers
1330d688beasomers	ret = ifconfig_getifaddrs(h);
1340d688beasomers	if (ret == 0) {
1350d688beasomers		struct ifaddrs *ifa;
1360d688beasomers		char *ifname = NULL;
1370d688beasomers
1380d688beasomers		for (ifa = h->ifap; ifa; ifa = ifa->ifa_next) {
1390d688beasomers			if (ifname != ifa->ifa_name) {
1400d688beasomers				ifname = ifa->ifa_name;
1410d688beasomers				cb(h, ifa, udata);
1420d688beasomers			}
1430d688beasomers		}
1440d688beasomers	}
1450d688beasomers	/* Free ifaddrs so we don't accidentally cache stale data */
1460d688beasomers	freeifaddrs(h->ifap);
1470d688beasomers	h->ifap = NULL;
1480d688beasomers
1490d688beasomers	return (ret);
1500d688beasomers}
1510d688beasomers
1520d688beasomersvoid
1530d688beasomersifconfig_foreach_ifaddr(ifconfig_handle_t *h, struct ifaddrs *ifa,
1540d688beasomers    ifconfig_foreach_func_t cb, void *udata)
1550d688beasomers{
1560d688beasomers	struct ifaddrs *ift;
1570d688beasomers
1580d688beasomers	for (ift = ifa;
1590d688beasomers	    ift != NULL &&
1600d688beasomers	    ift->ifa_addr != NULL &&
1610d688beasomers	    strcmp(ift->ifa_name, ifa->ifa_name) == 0;
1620d688beasomers	    ift = ift->ifa_next) {
1630d688beasomers		cb(h, ift, udata);
1640d688beasomers	}
1650d688beasomers}
1660d688beasomers
1670d688beasomersint
1680725653kpifconfig_get_description(ifconfig_handle_t *h, const char *name,
1690725653kp    char **description)
170a5e10afkp{
171a5e10afkp	struct ifreq ifr;
1720725653kp	char *descr;
1730725653kp	size_t descrlen;
174a5e10afkp
1750725653kp	descr = NULL;
1760725653kp	descrlen = 64;
1770725653kp	memset(&ifr, 0, sizeof(ifr));
178a5e10afkp	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
1790725653kp
180a5e10afkp	for (;;) {
181a5e10afkp		if ((descr = reallocf(descr, descrlen)) == NULL) {
182a5e10afkp			h->error.errtype = OTHER;
183a5e10afkp			h->error.errcode = ENOMEM;
184a5e10afkp			return (-1);
185a5e10afkp		}
186a5e10afkp
187a5e10afkp		ifr.ifr_buffer.buffer = descr;
188a5e10afkp		ifr.ifr_buffer.length = descrlen;
1890725653kp		if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFDESCR, &ifr) != 0) {
1900d688beasomers			free(descr);
191a5e10afkp			return (-1);
192a5e10afkp		}
193a5e10afkp
194a5e10afkp		if (ifr.ifr_buffer.buffer == descr) {
195a5e10afkp			if (strlen(descr) > 0) {
196a5e10afkp				*description = strdup(descr);
197a5e10afkp				free(descr);
1980d688beasomers
1990d688beasomers				if (description == NULL) {
2000d688beasomers					h->error.errtype = OTHER;
2010d688beasomers					h->error.errcode = ENOMEM;
2020d688beasomers					return (-1);
2030d688beasomers				}
2040d688beasomers
205a5e10afkp				return (0);
206a5e10afkp			}
207a5e10afkp		} else if (ifr.ifr_buffer.length > descrlen) {
208a5e10afkp			descrlen = ifr.ifr_buffer.length;
209a5e10afkp			continue;
210a5e10afkp		}
211a5e10afkp		break;
212a5e10afkp	}
213a5e10afkp	free(descr);
214a5e10afkp	h->error.errtype = OTHER;
215a5e10afkp	h->error.errcode = 0;
216a5e10afkp	return (-1);
217a5e10afkp}
218a5e10afkp
219a5e10afkpint
220e5074fakpifconfig_set_description(ifconfig_handle_t *h, const char *name,
221a5e10afkp    const char *newdescription)
222a5e10afkp{
223a5e10afkp	struct ifreq ifr;
224a5e10afkp	int desclen;
225a5e10afkp
2260725653kp	memset(&ifr, 0, sizeof(ifr));
227a5e10afkp	desclen = strlen(newdescription);
228a5e10afkp
229a5e10afkp	/*
230a5e10afkp	 * Unset description if the new description is 0 characters long.
231a5e10afkp	 * TODO: Decide whether this should be an error condition instead.
232a5e10afkp	 */
233a5e10afkp	if (desclen == 0) {
234e5074fakp		return (ifconfig_unset_description(h, name));
235a5e10afkp	}
236a5e10afkp
237a5e10afkp	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
238a5e10afkp	ifr.ifr_buffer.length = desclen + 1;
239a5e10afkp	ifr.ifr_buffer.buffer = strdup(newdescription);
2400725653kp
241a5e10afkp	if (ifr.ifr_buffer.buffer == NULL) {
242a5e10afkp		h->error.errtype = OTHER;
243a5e10afkp		h->error.errcode = ENOMEM;
244a5e10afkp		return (-1);
245a5e10afkp	}
246a5e10afkp
2470d688beasomers	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFDESCR, &ifr) != 0) {
248a5e10afkp		free(ifr.ifr_buffer.buffer);
249a5e10afkp		return (-1);
250a5e10afkp	}
2510725653kp
252a5e10afkp	free(ifr.ifr_buffer.buffer);
253a5e10afkp	return (0);
254a5e10afkp}
255a5e10afkp
2560725653kpint
2570725653kpifconfig_unset_description(ifconfig_handle_t *h, const char *name)
258a5e10afkp{
259a5e10afkp	struct ifreq ifr;
260a5e10afkp
2610725653kp	memset(&ifr, 0, sizeof(ifr));
262a5e10afkp	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
263a5e10afkp	ifr.ifr_buffer.length = 0;
264a5e10afkp	ifr.ifr_buffer.buffer = NULL;
265a5e10afkp
2660d688beasomers	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFDESCR, &ifr) < 0) {
267a5e10afkp		return (-1);
268a5e10afkp	}
269a5e10afkp	return (0);
270a5e10afkp}
271a5e10afkp
2720725653kpint
2730725653kpifconfig_set_name(ifconfig_handle_t *h, const char *name, const char *newname)
274a5e10afkp{
275a5e10afkp	struct ifreq ifr;
276a5e10afkp	char *tmpname;
277a5e10afkp
2780725653kp	memset(&ifr, 0, sizeof(ifr));
279a5e10afkp	tmpname = strdup(newname);
280a5e10afkp	if (tmpname == NULL) {
281a5e10afkp		h->error.errtype = OTHER;
282a5e10afkp		h->error.errcode = ENOMEM;
283a5e10afkp		return (-1);
284a5e10afkp	}
285a5e10afkp
286a5e10afkp	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
287a5e10afkp	ifr.ifr_data = tmpname;
2880d688beasomers	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFNAME, &ifr) != 0) {
289a5e10afkp		free(tmpname);
290a5e10afkp		return (-1);
291a5e10afkp	}
2920725653kp
293a5e10afkp	free(tmpname);
294a5e10afkp	return (0);
295a5e10afkp}
296a5e10afkp
2970725653kpint
298ef389b0avosifconfig_get_orig_name(ifconfig_handle_t *h, const char *ifname,
299ef389b0avos    char **orig_name)
300ef389b0avos{
301ef389b0avos	size_t len;
3020d688beasomers	unsigned int ifindex;
303ef389b0avos	int name[6];
3040d688beasomers
3050d688beasomers	ifindex = if_nametoindex(ifname);
3060d688beasomers	if (ifindex == 0) {
3070d688beasomers		goto fail;
3080d688beasomers	}
309ef389b0avos
310ef389b0avos	name[0] = CTL_NET;
311ef389b0avos	name[1] = PF_LINK;
312ef389b0avos	name[2] = NETLINK_GENERIC;
3130d688beasomers	name[3] = IFMIB_IFDATA;
3140d688beasomers	name[4] = ifindex;
3150d688beasomers	name[5] = IFDATA_DRIVERNAME;
316ef389b0avos
3170d688beasomers	len = 0;
3180d688beasomers	if (sysctl(name, 6, NULL, &len, 0, 0) < 0) {
3190d688beasomers		goto fail;
320ef389b0avos	}
321ef389b0avos
3220d688beasomers	*orig_name = malloc(len);
3230d688beasomers	if (*orig_name == NULL) {
3240d688beasomers		goto fail;
3250d688beasomers	}
326ef389b0avos
3270d688beasomers	if (sysctl(name, 6, *orig_name, &len, 0, 0) < 0) {
3280d688beasomers		free(*orig_name);
3290d688beasomers		*orig_name = NULL;
3300d688beasomers		goto fail;
3310d688beasomers	}
332ef389b0avos
3330d688beasomers	return (0);
334ef389b0avos
3350d688beasomersfail:
3360d688beasomers	h->error.errtype = OTHER;
3370d688beasomers	h->error.errcode = (errno != 0) ? errno : ENOENT;
3380d688beasomers	return (-1);
3390d688beasomers}
340ef389b0avos
3410d688beasomersint
3420d688beasomersifconfig_get_fib(ifconfig_handle_t *h, const char *name, int *fib)
3430d688beasomers{
3440d688beasomers	struct ifreq ifr;
3450d688beasomers
3460d688beasomers	memset(&ifr, 0, sizeof(ifr));
3470d688beasomers	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
348ef389b0avos
3490d688beasomers	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFFIB, &ifr) == -1) {
3500d688beasomers		return (-1);
351ef389b0avos	}
352ef389b0avos
3530d688beasomers	*fib = ifr.ifr_fib;
3540d688beasomers	return (0);
355ef389b0avos}
356ef389b0avos
357ef389b0avosint
3580725653kpifconfig_set_mtu(ifconfig_handle_t *h, const char *name, const int mtu)
359a5e10afkp{
360a5e10afkp	struct ifreq ifr;
361a5e10afkp
3620725653kp	memset(&ifr, 0, sizeof(ifr));
363a5e10afkp	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
364a5e10afkp	ifr.ifr_mtu = mtu;
3650725653kp
3660d688beasomers	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFMTU, &ifr) < 0) {
367a5e10afkp		return (-1);
368a5e10afkp	}
3690725653kp
370a5e10afkp	return (0);
371a5e10afkp}
372a5e10afkp
3730725653kpint
3740725653kpifconfig_get_mtu(ifconfig_handle_t *h, const char *name, int *mtu)
375a5e10afkp{
376a5e10afkp	struct ifreq ifr;
377a5e10afkp
3780725653kp	memset(&ifr, 0, sizeof(ifr));
379a5e10afkp	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
3800725653kp
3810d688beasomers	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFMTU, &ifr) == -1) {
382a5e10afkp		return (-1);
383a5e10afkp	}
3840725653kp
385a5e10afkp	*mtu = ifr.ifr_mtu;
386a5e10afkp	return (0);
387a5e10afkp}
388a5e10afkp
3890725653kpint
3900d688beasomersifconfig_get_nd6(ifconfig_handle_t *h, const char *name,
3910d688beasomers    struct in6_ndireq *nd)
3920d688beasomers{
3930d688beasomers	memset(nd, 0, sizeof(*nd));
3940d688beasomers	strlcpy(nd->ifname, name, sizeof(nd->ifname));
3950d688beasomers	if (ifconfig_ioctlwrap(h, AF_INET6, SIOCGIFINFO_IN6, nd) == -1) {
3960d688beasomers		return (-1);
3970d688beasomers	}
3980d688beasomers	if (isnd6defif(h, name)) {
3990d688beasomers		nd->ndi.flags |= ND6_IFF_DEFAULTIF;
4000d688beasomers	} else if (h->error.errtype != OK) {
4010d688beasomers		return (-1);
4020d688beasomers	}
4030d688beasomers
4040d688beasomers	return (0);
4050d688beasomers}
4060d688beasomers
4070d688beasomersint
408d1b7214asomersifconfig_set_metric(ifconfig_handle_t *h, const char *name, const int metric)
409a5e10afkp{
410a5e10afkp	struct ifreq ifr;
411a5e10afkp
4120725653kp	memset(&ifr, 0, sizeof(ifr));
413a5e10afkp	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
414d1b7214asomers	ifr.ifr_metric = metric;
4150725653kp
4160d688beasomers	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFMETRIC, &ifr) < 0) {
417a5e10afkp		return (-1);
418a5e10afkp	}
4190725653kp
420a5e10afkp	return (0);
421a5e10afkp}
422a5e10afkp
4230725653kpint
4240725653kpifconfig_get_metric(ifconfig_handle_t *h, const char *name, int *metric)
425a5e10afkp{
426a5e10afkp	struct ifreq ifr;
427a5e10afkp
4280725653kp	memset(&ifr, 0, sizeof(ifr));
429a5e10afkp	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
4300725653kp
4310d688beasomers	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFMETRIC, &ifr) == -1) {
432a5e10afkp		return (-1);
433a5e10afkp	}
4340725653kp
435a5e10afkp	*metric = ifr.ifr_metric;
436a5e10afkp	return (0);
437a5e10afkp}
438a5e10afkp
4390725653kpint
4400725653kpifconfig_set_capability(ifconfig_handle_t *h, const char *name,
441a5e10afkp    const int capability)
442a5e10afkp{
443a5e10afkp	struct ifreq ifr;
444e5074fakp	struct ifconfig_capabilities ifcap;
4450725653kp	int flags, value;
446a5e10afkp
4470725653kp	memset(&ifr, 0, sizeof(ifr));
4480725653kp
4490d688beasomers	if (ifconfig_get_capability(h, name, &ifcap) != 0) {
450a5e10afkp		return (-1);
451a5e10afkp	}
452a5e10afkp
453a5e10afkp	value = capability;
454a5e10afkp	flags = ifcap.curcap;
455a5e10afkp	if (value < 0) {
456a5e10afkp		value = -value;
457a5e10afkp		flags &= ~value;
458a5e10afkp	} else {
459a5e10afkp		flags |= value;
460a5e10afkp	}
461a5e10afkp	flags &= ifcap.reqcap;
462a5e10afkp
463a5e10afkp	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
464a5e10afkp
465a5e10afkp	/*
466a5e10afkp	 * TODO: Verify that it's safe to not have ifr.ifr_curcap
467a5e10afkp	 * set for this request.
468a5e10afkp	 */
469a5e10afkp	ifr.ifr_reqcap = flags;
4700d688beasomers	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFCAP, &ifr) < 0) {
471a5e10afkp		return (-1);
472a5e10afkp	}
473a5e10afkp	return (0);
474a5e10afkp}
475a5e10afkp
4760725653kpint
4770725653kpifconfig_get_capability(ifconfig_handle_t *h, const char *name,
478e5074fakp    struct ifconfig_capabilities *capability)
479a5e10afkp{
480a5e10afkp	struct ifreq ifr;
481a5e10afkp
4820725653kp	memset(&ifr, 0, sizeof(ifr));
483a5e10afkp	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
484a5e10afkp
4850d688beasomers	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFCAP, &ifr) < 0) {
486a5e10afkp		return (-1);
487a5e10afkp	}
488a5e10afkp	capability->curcap = ifr.ifr_curcap;
489a5e10afkp	capability->reqcap = ifr.ifr_reqcap;
490a5e10afkp	return (0);
491a5e10afkp}
492a5e10afkp
4930725653kpint
4940d688beasomersifconfig_get_groups(ifconfig_handle_t *h, const char *name,
4950d688beasomers    struct ifgroupreq *ifgr)
4960d688beasomers{
4970d688beasomers	int len;
4980d688beasomers
4990d688beasomers	memset(ifgr, 0, sizeof(*ifgr));
5000d688beasomers	strlcpy(ifgr->ifgr_name, name, IFNAMSIZ);
5010d688beasomers
5020d688beasomers	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFGROUP, ifgr) == -1) {
5030d688beasomers		if ((h->error.errcode == EINVAL) ||
5040d688beasomers		    (h->error.errcode == ENOTTY)) {
5050d688beasomers			return (0);
5060d688beasomers		} else {
5070d688beasomers			return (-1);
5080d688beasomers		}
5090d688beasomers	}
5100d688beasomers
5110d688beasomers	len = ifgr->ifgr_len;
5120d688beasomers	ifgr->ifgr_groups = (struct ifg_req *)malloc(len);
5130d688beasomers	if (ifgr->ifgr_groups == NULL) {
5140d688beasomers		return (1);
5150d688beasomers	}
5160d688beasomers	bzero(ifgr->ifgr_groups, len);
5170d688beasomers	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFGROUP, ifgr) == -1) {
5180d688beasomers		return (-1);
5190d688beasomers	}
5200d688beasomers
5210d688beasomers	return (0);
5220d688beasomers}
5230d688beasomers
5240d688beasomersint
5250d688beasomersifconfig_get_ifstatus(ifconfig_handle_t *h, const char *name,
5260d688beasomers    struct ifstat *ifs)
5270d688beasomers{
5280d688beasomers	strlcpy(ifs->ifs_name, name, sizeof(ifs->ifs_name));
5290d688beasomers	return (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFSTATUS, ifs));
5300d688beasomers}
5310d688beasomers
5320d688beasomersint
5330725653kpifconfig_destroy_interface(ifconfig_handle_t *h, const char *name)
534a5e10afkp{
535a5e10afkp	struct ifreq ifr;
536a5e10afkp
5370725653kp	memset(&ifr, 0, sizeof(ifr));
538a5e10afkp	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
539a5e10afkp
5400d688beasomers	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFDESTROY, &ifr) < 0) {
541a5e10afkp		return (-1);
542a5e10afkp	}
543a5e10afkp	return (0);
544a5e10afkp}
545a5e10afkp
5460725653kpint
5470725653kpifconfig_create_interface(ifconfig_handle_t *h, const char *name, char **ifname)
548a5e10afkp{
549a5e10afkp	struct ifreq ifr;
550a5e10afkp
5510725653kp	memset(&ifr, 0, sizeof(ifr));
5520d688beasomers
553a5e10afkp	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
554a5e10afkp
555a5e10afkp	/*
556a5e10afkp	 * TODO:
557a5e10afkp	 * Insert special snowflake handling here. See GitHub issue #12 for details.
558a5e10afkp	 * In the meantime, hard-nosupport interfaces that need special handling.
559a5e10afkp	 */
5600725653kp	if ((strncmp(name, "wlan",
5610725653kp	    strlen("wlan")) == 0) ||
5620725653kp	    (strncmp(name, "vlan",
5630725653kp	    strlen("vlan")) == 0) ||
5640725653kp	    (strncmp(name, "vxlan",
5650725653kp	    strlen("vxlan")) == 0)) {
566a5e10afkp		h->error.errtype = OTHER;
567a5e10afkp		h->error.errcode = ENOSYS;
568a5e10afkp		return (-1);
569a5e10afkp	}
570a5e10afkp
571a5e10afkp	/* No special handling for this interface type. */
572e5074fakp	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFCREATE2, &ifr) < 0) {
573a5e10afkp		return (-1);
574a5e10afkp	}
5750725653kp
576a5e10afkp	*ifname = strdup(ifr.ifr_name);
5770d688beasomers	if (ifname == NULL) {
5780d688beasomers		h->error.errtype = OTHER;
5790d688beasomers		h->error.errcode = ENOMEM;
5800d688beasomers		return (-1);
5810d688beasomers	}
5820d688beasomers
5830d688beasomers	return (0);
5840d688beasomers}
5850d688beasomers
5860d688beasomersint
5870d688beasomersifconfig_create_interface_vlan(ifconfig_handle_t *h, const char *name,
5880d688beasomers    char **ifname, const char *vlandev, const unsigned short vlantag)
5890d688beasomers{
5900d688beasomers	struct ifreq ifr;
5910d688beasomers	struct vlanreq params;
5920d688beasomers
5930d688beasomers	if ((vlantag == NOTAG) || (vlandev[0] == '\0')) {
5940d688beasomers		// TODO: Add proper error tracking here
5950d688beasomers		return (-1);
5960d688beasomers	}
5970d688beasomers
5980d688beasomers	bzero(&params, sizeof(params));
5990d688beasomers	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
6000d688beasomers	params.vlr_tag = vlantag;
6010d688beasomers	(void)strlcpy(params.vlr_parent, vlandev, sizeof(params.vlr_parent));
6020d688beasomers	ifr.ifr_data = (caddr_t)&params;
6030d688beasomers
6040d688beasomers	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFCREATE2, &ifr) < 0) {
6050d688beasomers		// TODO: Add proper error tracking here
6060d688beasomers		return (-1);
6070d688beasomers	}
6080d688beasomers
6090d688beasomers	*ifname = strdup(ifr.ifr_name);
6100d688beasomers	return (0);
6110d688beasomers}
6120d688beasomers
6130d688beasomersint
6140d688beasomersifconfig_set_vlantag(ifconfig_handle_t *h, const char *name,
6150d688beasomers    const char *vlandev, const unsigned short vlantag)
6160d688beasomers{
6170d688beasomers	struct ifreq ifr;
6180d688beasomers	struct vlanreq params;
6190d688beasomers
6200d688beasomers	bzero(&params, sizeof(params));
6210d688beasomers	params.vlr_tag = vlantag;
6220d688beasomers	strlcpy(params.vlr_parent, vlandev, sizeof(params.vlr_parent));
6230d688beasomers
6240d688beasomers	ifr.ifr_data = (caddr_t)&params;
6250d688beasomers	(void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
6260d688beasomers	if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSETVLAN, &ifr) == -1) {
6270d688beasomers		return (-1);
6280d688beasomers	}
629a5e10afkp	return (0);
630a5e10afkp}
631