aboutsummaryrefslogtreecommitdiff
path: root/lib/libifconfig
diff options
context:
space:
mode:
authorKristof Provost <kp@FreeBSD.org>2016-09-02 18:33:08 +0000
committerKristof Provost <kp@FreeBSD.org>2016-09-02 18:33:08 +0000
commitec21434933d775bd60d0fed62c978fb07fa9ccdf (patch)
tree81f746879128bfa6684612cd981fb717af0d28c2 /lib/libifconfig
parent2279a9a428305ee43111f62f4addf6a9826eacde (diff)
Renaming libifc to libifconfig in response to feedback on initial commit of
this library. Sticking to 'libifconfig' (and 'ifconfig_' as function prefix) should reduce chances of namespace collisions, make it more clear what the library does, and be more in line with existing libraries. Submitted by: Marie Helene Kvello-Aune <marieheleneka@gmail.com> Differential Revision: https://reviews.freebsd.org/D7742 Reviewed by: cem, kp
Notes
svn path=/head/; revision=305290
Diffstat (limited to 'lib/libifconfig')
-rw-r--r--lib/libifconfig/Makefile20
-rw-r--r--lib/libifconfig/libifconfig.c397
-rw-r--r--lib/libifconfig/libifconfig.h111
-rw-r--r--lib/libifconfig/libifconfig_internal.c100
-rw-r--r--lib/libifconfig/libifconfig_internal.h87
5 files changed, 715 insertions, 0 deletions
diff --git a/lib/libifconfig/Makefile b/lib/libifconfig/Makefile
new file mode 100644
index 000000000000..924752fac9e2
--- /dev/null
+++ b/lib/libifconfig/Makefile
@@ -0,0 +1,20 @@
+# $FreeBSD$
+
+PACKAGE= lib${LIB}
+LIB= ifconfig
+# Don't build shared library, for now.
+NO_PIC=
+
+SHLIBDIR?= /lib
+SHLIB_MAJOR= 1
+SRCS= libifconfig.c libifconfig_internal.c
+
+INCSDIR= ${INCLUDEDIR}
+INCS= libifconfig.h
+
+#MAN= libifconfig.3
+
+CFLAGS+= -I${.CURDIR}
+WARNS?=6
+
+.include <bsd.lib.mk>
diff --git a/lib/libifconfig/libifconfig.c b/lib/libifconfig/libifconfig.c
new file mode 100644
index 000000000000..5acb56c845ca
--- /dev/null
+++ b/lib/libifconfig/libifconfig.c
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 2016, Marie Helene Kvello-Aune
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * thislist of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "libifconfig.h"
+#include "libifconfig_internal.h"
+
+
+ifconfig_handle_t *
+ifconfig_open(void)
+{
+ struct ifconfig_handle *h;
+
+ h = calloc(1, sizeof(struct ifconfig_handle));
+
+ for (int i = 0; i <= AF_MAX; i++) {
+ h->sockets[i] = -1;
+ }
+
+ return (h);
+}
+
+
+void
+ifconfig_close(ifconfig_handle_t *h)
+{
+ for (int i = 0; i <= AF_MAX; i++) {
+ if (h->sockets[i] != -1) {
+ (void)close(h->sockets[i]);
+ }
+ }
+ free(h);
+}
+
+
+ifconfig_errtype
+ifconfig_err_errtype(ifconfig_handle_t *h)
+{
+ return (h->error.errtype);
+}
+
+
+int
+ifconfig_err_errno(ifconfig_handle_t *h)
+{
+ return (h->error.errcode);
+}
+
+
+unsigned long
+ifconfig_err_ioctlreq(ifconfig_handle_t *h)
+{
+ return (h->error.ioctl_request);
+}
+
+
+int
+ifconfig_get_description(ifconfig_handle_t *h, const char *name, char **description)
+{
+ struct ifreq ifr;
+ char *descr = NULL;
+ size_t descrlen = 64;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ for (;;) {
+ if ((descr = reallocf(descr, descrlen)) == NULL) {
+ h->error.errtype = OTHER;
+ h->error.errcode = ENOMEM;
+ return (-1);
+ }
+
+ ifr.ifr_buffer.buffer = descr;
+ ifr.ifr_buffer.length = descrlen;
+ if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFDESCR,
+ &ifr) != 0) {
+ return (-1);
+ }
+
+ if (ifr.ifr_buffer.buffer == descr) {
+ if (strlen(descr) > 0) {
+ *description = strdup(descr);
+ free(descr);
+ return (0);
+ }
+ } else if (ifr.ifr_buffer.length > descrlen) {
+ descrlen = ifr.ifr_buffer.length;
+ continue;
+ }
+ break;
+ }
+ free(descr);
+ h->error.errtype = OTHER;
+ h->error.errcode = 0;
+ return (-1);
+}
+
+
+int
+ifconfig_set_description(ifconfig_handle_t *h, const char *name,
+ const char *newdescription)
+{
+ struct ifreq ifr;
+ int desclen;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ desclen = strlen(newdescription);
+
+ /*
+ * Unset description if the new description is 0 characters long.
+ * TODO: Decide whether this should be an error condition instead.
+ */
+ if (desclen == 0) {
+ return (ifconfig_unset_description(h, name));
+ }
+
+ (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ ifr.ifr_buffer.length = desclen + 1;
+ ifr.ifr_buffer.buffer = strdup(newdescription);
+ if (ifr.ifr_buffer.buffer == NULL) {
+ h->error.errtype = OTHER;
+ h->error.errcode = ENOMEM;
+ return (-1);
+ }
+
+ if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFDESCR, &ifr) != 0) {
+ free(ifr.ifr_buffer.buffer);
+ return (-1);
+ }
+ free(ifr.ifr_buffer.buffer);
+ return (0);
+}
+
+
+int ifconfig_unset_description(ifconfig_handle_t *h, const char *name)
+{
+ struct ifreq ifr;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_buffer.length = 0;
+ ifr.ifr_buffer.buffer = NULL;
+
+ if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFDESCR, &ifr) < 0) {
+ return (-1);
+ }
+ return (0);
+}
+
+
+int ifconfig_set_name(ifconfig_handle_t *h, const char *name, const char *newname)
+{
+ struct ifreq ifr;
+ char *tmpname;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ tmpname = strdup(newname);
+ if (tmpname == NULL) {
+ h->error.errtype = OTHER;
+ h->error.errcode = ENOMEM;
+ return (-1);
+ }
+
+ (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_data = tmpname;
+
+ if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFNAME, &ifr) != 0) {
+ free(tmpname);
+ return (-1);
+ }
+ free(tmpname);
+ return (0);
+}
+
+
+int ifconfig_set_mtu(ifconfig_handle_t *h, const char *name, const int mtu)
+{
+ struct ifreq ifr;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_mtu = mtu;
+ if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFMTU, &ifr) < 0) {
+ return (-1);
+ }
+ return (0);
+}
+
+
+int ifconfig_get_mtu(ifconfig_handle_t *h, const char *name, int *mtu)
+{
+ struct ifreq ifr;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFMTU, &ifr) == -1) {
+ return (-1);
+ }
+ *mtu = ifr.ifr_mtu;
+ return (0);
+}
+
+
+int ifconfig_set_metric(ifconfig_handle_t *h, const char *name, const int mtu)
+{
+ struct ifreq ifr;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ ifr.ifr_mtu = mtu;
+ if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFMETRIC, &ifr) < 0) {
+ return (-1);
+ }
+ return (0);
+}
+
+
+int ifconfig_get_metric(ifconfig_handle_t *h, const char *name, int *metric)
+{
+ struct ifreq ifr;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+ if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFMETRIC, &ifr) == -1) {
+ return (-1);
+ }
+ *metric = ifr.ifr_metric;
+ return (0);
+}
+
+
+int ifconfig_set_capability(ifconfig_handle_t *h, const char *name,
+ const int capability)
+{
+ struct ifreq ifr;
+ struct ifconfig_capabilities ifcap;
+ int flags;
+ int value;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ if (ifconfig_get_capability(h, name, &ifcap) != 0) {
+ return (-1);
+ }
+
+ value = capability;
+ flags = ifcap.curcap;
+ if (value < 0) {
+ value = -value;
+ flags &= ~value;
+ } else {
+ flags |= value;
+ }
+ flags &= ifcap.reqcap;
+
+ (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ /*
+ * TODO: Verify that it's safe to not have ifr.ifr_curcap
+ * set for this request.
+ */
+ ifr.ifr_reqcap = flags;
+ if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFCAP, &ifr) < 0) {
+ return (-1);
+ }
+ return (0);
+}
+
+
+int ifconfig_get_capability(ifconfig_handle_t *h, const char *name,
+ struct ifconfig_capabilities *capability)
+{
+ struct ifreq ifr;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFCAP, &ifr) < 0) {
+ return (-1);
+ }
+ capability->curcap = ifr.ifr_curcap;
+ capability->reqcap = ifr.ifr_reqcap;
+ return (0);
+}
+
+
+int ifconfig_destroy_interface(ifconfig_handle_t *h, const char *name)
+{
+ struct ifreq ifr;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFDESTROY, &ifr) < 0) {
+ return (-1);
+ }
+ return (0);
+}
+
+
+int ifconfig_create_interface(ifconfig_handle_t *h, const char *name, char **ifname)
+{
+ struct ifreq ifr;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+
+ /*
+ * TODO:
+ * Insert special snowflake handling here. See GitHub issue #12 for details.
+ * In the meantime, hard-nosupport interfaces that need special handling.
+ */
+ if ((strncmp(name, "wlan", strlen("wlan")) == 0) ||
+ (strncmp(name, "vlan", strlen("vlan")) == 0) ||
+ (strncmp(name, "vxlan", strlen("vxlan")) == 0)) {
+ h->error.errtype = OTHER;
+ h->error.errcode = ENOSYS;
+ return (-1);
+ }
+
+ /* No special handling for this interface type. */
+
+ if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFCREATE2, &ifr) < 0) {
+ return (-1);
+ }
+ *ifname = strdup(ifr.ifr_name);
+ return (0);
+}
diff --git a/lib/libifconfig/libifconfig.h b/lib/libifconfig/libifconfig.h
new file mode 100644
index 000000000000..a005aa83b33c
--- /dev/null
+++ b/lib/libifconfig/libifconfig.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2016, Marie Helene Kvello-Aune
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * thislist of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#pragma once
+
+typedef enum {
+ OTHER, IOCTL, SOCKET
+} ifconfig_errtype;
+
+/*
+ * Opaque definition so calling application can just pass a
+ * pointer to it for library use.
+ */
+struct ifconfig_handle;
+typedef struct ifconfig_handle ifconfig_handle_t;
+
+struct ifconfig_capabilities {
+ /** Current capabilities (ifconfig prints this as 'options')*/
+ int curcap;
+ /** Requested capabilities (ifconfig prints this as 'capabilities')*/
+ int reqcap;
+};
+
+
+/** Retrieves a new state object for use in other API calls.
+ * Example usage:
+ *{@code
+ * // Create state object
+ * ifconfig_handle_t *lifh = ifconfig_open();
+ *
+ * // Do stuff with it
+ *
+ * // Dispose of the state object
+ * ifconfig_close(lifh);
+ * lifh = NULL;
+ *}
+ */
+ifconfig_handle_t *ifconfig_open(void);
+
+/** Frees resources held in the provided state object.
+ * @param h The state object to close.
+ * @see #ifconfig_open(void)
+ */
+void ifconfig_close(ifconfig_handle_t *h);
+
+/** Identifies what kind of error occured. */
+ifconfig_errtype ifconfig_err_errtype(ifconfig_handle_t *h);
+
+/** Retrieves the errno associated with the error, if any. */
+int ifconfig_err_errno(ifconfig_handle_t *h);
+
+/** If error type was IOCTL, this identifies which request failed. */
+unsigned long ifconfig_err_ioctlreq(ifconfig_handle_t *h);
+
+int ifconfig_get_description(ifconfig_handle_t *h, const char *name,
+ char **description);
+int ifconfig_set_description(ifconfig_handle_t *h, const char *name,
+ const char *newdescription);
+int ifconfig_unset_description(ifconfig_handle_t *h, const char *name);
+int ifconfig_set_name(ifconfig_handle_t *h, const char *name, const char *newname);
+int ifconfig_set_mtu(ifconfig_handle_t *h, const char *name, const int mtu);
+int ifconfig_get_mtu(ifconfig_handle_t *h, const char *name, int *mtu);
+
+int ifconfig_set_metric(ifconfig_handle_t *h, const char *name, const int metric);
+int ifconfig_get_metric(ifconfig_handle_t *h, const char *name, int *metric);
+
+int ifconfig_set_capability(ifconfig_handle_t *h, const char *name,
+ const int capability);
+int ifconfig_get_capability(ifconfig_handle_t *h, const char *name,
+ struct ifconfig_capabilities *capability);
+
+/** Destroy a virtual interface
+ * @param name Interface to destroy
+ */
+int ifconfig_destroy_interface(ifconfig_handle_t *h, const char *name);
+
+/** Creates a (virtual) interface
+ * @param name Name of interface to create. Example: bridge or bridge42
+ * @param name ifname Is set to actual name of created interface
+ */
+int ifconfig_create_interface(ifconfig_handle_t *h, const char *name,
+ char **ifname);
diff --git a/lib/libifconfig/libifconfig_internal.c b/lib/libifconfig/libifconfig_internal.c
new file mode 100644
index 000000000000..304c2800e22a
--- /dev/null
+++ b/lib/libifconfig/libifconfig_internal.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016, Marie Helene Kvello-Aune
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * thislist of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+
+#include <net/if.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+
+#include "libifconfig.h" // Needed for ifconfig_errstate
+#include "libifconfig_internal.h"
+
+int
+ifconfig_ioctlwrap_ret(ifconfig_handle_t *h, unsigned long request, int rcode)
+{
+ if (rcode != 0) {
+ h->error.errtype = IOCTL;
+ h->error.ioctl_request = request;
+ h->error.errcode = errno;
+ }
+ return (rcode);
+}
+
+
+int
+ifconfig_ioctlwrap(ifconfig_handle_t *h, const int addressfamily,
+ unsigned long request, struct ifreq *ifr)
+{
+ int s;
+
+ if (ifconfig_socket(h, addressfamily, &s) != 0) {
+ return (-1);
+ }
+
+ int rcode = ioctl(s, request, ifr);
+ return (ifconfig_ioctlwrap_ret(h, request, rcode));
+}
+
+
+/*
+ * Function to get socket for the specified address family.
+ * If the socket doesn't already exist, attempt to create it.
+ */
+int ifconfig_socket(ifconfig_handle_t *h, const int addressfamily, int *s)
+{
+ if (addressfamily > AF_MAX) {
+ h->error.errtype = SOCKET;
+ h->error.errcode = EINVAL;
+ return (-1);
+ }
+
+ if (h->sockets[addressfamily] != -1) {
+ *s = h->sockets[addressfamily];
+ return (0);
+ }
+
+ /* We don't have a socket of that type available. Create one. */
+ h->sockets[addressfamily] = socket(addressfamily, SOCK_DGRAM, 0);
+ if (h->sockets[addressfamily] == -1) {
+ h->error.errtype = SOCKET;
+ h->error.errcode = errno;
+ return (-1);
+ }
+
+ *s = h->sockets[addressfamily];
+ return (0);
+}
diff --git a/lib/libifconfig/libifconfig_internal.h b/lib/libifconfig/libifconfig_internal.h
new file mode 100644
index 000000000000..2320ca7b3767
--- /dev/null
+++ b/lib/libifconfig/libifconfig_internal.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2016, Marie Helene Kvello-Aune
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * thislist of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#pragma once
+
+#include "libifconfig.h"
+
+
+struct errstate {
+ /**
+ * Type of error.
+ */
+ ifconfig_errtype errtype;
+
+ /**
+ * The error occured in this ioctl() request.
+ * Populated if errtype = IOCTL
+ */
+ unsigned long ioctl_request;
+
+ /**
+ * The value of the global errno variable when the error occured.
+ */
+ int errcode;
+};
+
+struct ifconfig_handle {
+ struct errstate error;
+ int sockets[AF_MAX + 1];
+};
+
+/**
+ * Retrieves socket for address family <paramref name="addressfamily"> from
+ * cache, or creates it if it doesn't already exist.
+ * @param addressfamily The address family of the socket to retrieve
+ * @param s The retrieved socket.
+ * @return 0 on success, -1 on failure.
+ * {@example
+ * This example shows how to retrieve a socket from the cache.
+ * {@code
+ * static void myfunc() \{
+ * int s;
+ * if (ifconfig_socket(AF_LOCAL, &s) != 0) \{
+ * // Handle error state here
+ * \}
+ * // user code here
+ * \}
+ * }
+ * }
+ */
+int ifconfig_socket(ifconfig_handle_t *h, const int addressfamily, int *s);
+
+/** Function used by other wrapper functions to populate _errstate when appropriate.*/
+int ifconfig_ioctlwrap_ret(ifconfig_handle_t *h, unsigned long request, int rcode);
+
+/** Function to wrap ioctl() and automatically populate ifconfig_errstate when appropriate.*/
+int ifconfig_ioctlwrap(ifconfig_handle_t *h, const int addressfamily,
+ unsigned long request, struct ifreq *ifr);