summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/conf/files1
-rw-r--r--sys/contrib/pf/net/if_pflog.c6
-rw-r--r--sys/contrib/pf/net/if_pfsync.c6
-rw-r--r--sys/contrib/pf/net/pfvar.h1
-rw-r--r--sys/net/if.c244
-rw-r--r--sys/net/if.h22
-rw-r--r--sys/net/if_clone.c468
-rw-r--r--sys/net/if_clone.h113
-rw-r--r--sys/net/if_disc.c5
-rw-r--r--sys/net/if_faith.c4
-rw-r--r--sys/net/if_gif.c4
-rw-r--r--sys/net/if_gre.c4
-rw-r--r--sys/net/if_loop.c4
-rw-r--r--sys/net/if_ppp.c4
-rw-r--r--sys/net/if_stf.c58
-rw-r--r--sys/net/if_var.h9
-rw-r--r--sys/net/if_vlan.c151
17 files changed, 794 insertions, 310 deletions
diff --git a/sys/conf/files b/sys/conf/files
index bf3631f..0febe87 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1222,6 +1222,7 @@ net/bsd_comp.c optional ppp_bsdcomp
net/if.c standard
net/if_arcsubr.c optional arcnet
net/if_atmsubr.c optional atm
+net/if_clone.c standard
net/if_disc.c optional disc
net/if_ef.c optional ef
net/if_ethersubr.c optional ether
diff --git a/sys/contrib/pf/net/if_pflog.c b/sys/contrib/pf/net/if_pflog.c
index 960f709..ee0ec79 100644
--- a/sys/contrib/pf/net/if_pflog.c
+++ b/sys/contrib/pf/net/if_pflog.c
@@ -63,6 +63,9 @@
#endif
#include <net/if.h>
+#if defined(__FreeBSD__)
+#include <net/if_clone.h>
+#endif
#include <net/if_types.h>
#include <net/route.h>
#include <net/bpf.h>
@@ -123,8 +126,7 @@ extern int ifqmaxlen;
#ifdef __FreeBSD__
static MALLOC_DEFINE(M_PFLOG, PFLOGNAME, "Packet Filter Logging Interface");
static LIST_HEAD(pflog_list, pflog_softc) pflog_list;
-struct if_clone pflog_cloner = IF_CLONE_INITIALIZER(PFLOGNAME,
- pflog_clone_create, pflog_clone_destroy, 1, IF_MAXUNIT);
+IFC_SIMPLE_DECLARE(pflog, 1);
static void
pflog_clone_destroy(struct ifnet *ifp)
diff --git a/sys/contrib/pf/net/if_pfsync.c b/sys/contrib/pf/net/if_pfsync.c
index 936479d..1fa2a1f 100644
--- a/sys/contrib/pf/net/if_pfsync.c
+++ b/sys/contrib/pf/net/if_pfsync.c
@@ -62,6 +62,9 @@
#endif
#include <net/if.h>
+#if defined(__FreeBSD__)
+#include <net/if_clone.h>
+#endif
#include <net/if_types.h>
#include <net/route.h>
#include <net/bpf.h>
@@ -148,8 +151,7 @@ extern int hz;
#ifdef __FreeBSD__
static MALLOC_DEFINE(M_PFSYNC, PFSYNCNAME, "Packet Filter State Sync. Interface");
static LIST_HEAD(pfsync_list, pfsync_softc) pfsync_list;
-struct if_clone pfsync_cloner = IF_CLONE_INITIALIZER(PFSYNCNAME,
- pfsync_clone_create, pfsync_clone_destroy, 1, IF_MAXUNIT);
+IFC_SIMPLE_DECLARE(pfsync, 1);
static void
pfsync_clone_destroy(struct ifnet *ifp)
diff --git a/sys/contrib/pf/net/pfvar.h b/sys/contrib/pf/net/pfvar.h
index a6c739a..af32857 100644
--- a/sys/contrib/pf/net/pfvar.h
+++ b/sys/contrib/pf/net/pfvar.h
@@ -40,6 +40,7 @@
#include <net/radix.h>
#ifdef __FreeBSD__
+#include <net/if_clone.h>
#include <vm/uma.h>
#else
#include <netinet/ip_ipsp.h>
diff --git a/sys/net/if.c b/sys/net/if.c
index 2b3805e..50f496b 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -56,6 +56,7 @@
#include <net/if.h>
#include <net/if_arp.h>
+#include <net/if_clone.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/if_var.h>
@@ -90,8 +91,6 @@ static void if_slowtimo(void *);
static void if_unroute(struct ifnet *, int flag, int fam);
static void link_rtrequest(int, struct rtentry *, struct rt_addrinfo *);
static int if_rtdel(struct radix_node *, void *);
-static struct if_clone *if_clone_lookup(const char *, int *);
-static int if_clone_list(struct if_clonereq *);
static int ifhwioctl(u_long, struct ifnet *, caddr_t, struct thread *);
#ifdef INET6
/*
@@ -106,8 +105,6 @@ struct ifindex_entry *ifindex_table = NULL;
int ifqmaxlen = IFQ_MAXLEN;
struct ifnethead ifnet; /* depend on static init XXX */
struct mtx ifnet_lock;
-static int if_cloners_count;
-LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners);
static int if_indexlim = 8;
static struct klist ifklist;
@@ -126,7 +123,6 @@ SYSINIT(interface_check, SI_SUB_PROTO_IF, SI_ORDER_FIRST, if_check, NULL)
MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address");
MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address");
-MALLOC_DEFINE(M_CLONE, "clone", "interface cloning framework");
static d_open_t netopen;
static d_close_t netclose;
@@ -263,6 +259,7 @@ if_init(void *dummy __unused)
if_grow(); /* create initial table */
ifdev_byindex(0) = make_dev(&net_cdevsw, 0,
UID_ROOT, GID_WHEEL, 0600, "network");
+ if_clone_init();
}
static void
@@ -668,243 +665,6 @@ if_rtdel(struct radix_node *rn, void *arg)
return (0);
}
-/*
- * Create a clone network interface.
- */
-int
-if_clone_create(char *name, int len)
-{
- struct if_clone *ifc;
- char *dp;
- int wildcard, bytoff, bitoff;
- int unit;
- int err;
-
- ifc = if_clone_lookup(name, &unit);
- if (ifc == NULL)
- return (EINVAL);
-
- if (ifunit(name) != NULL)
- return (EEXIST);
-
- bytoff = bitoff = 0;
- wildcard = (unit < 0);
- /*
- * Find a free unit if none was given.
- */
- if (wildcard) {
- while ((bytoff < ifc->ifc_bmlen)
- && (ifc->ifc_units[bytoff] == 0xff))
- bytoff++;
- if (bytoff >= ifc->ifc_bmlen)
- return (ENOSPC);
- while ((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0)
- bitoff++;
- unit = (bytoff << 3) + bitoff;
- }
-
- if (unit > ifc->ifc_maxunit)
- return (ENXIO);
-
- err = (*ifc->ifc_create)(ifc, unit);
- if (err != 0)
- return (err);
-
- if (!wildcard) {
- bytoff = unit >> 3;
- bitoff = unit - (bytoff << 3);
- }
-
- /*
- * Allocate the unit in the bitmap.
- */
- KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) == 0,
- ("%s: bit is already set", __func__));
- ifc->ifc_units[bytoff] |= (1 << bitoff);
-
- /* In the wildcard case, we need to update the name. */
- if (wildcard) {
- for (dp = name; *dp != '\0'; dp++);
- if (snprintf(dp, len - (dp-name), "%d", unit) >
- len - (dp-name) - 1) {
- /*
- * This can only be a programmer error and
- * there's no straightforward way to recover if
- * it happens.
- */
- panic("if_clone_create(): interface name too long");
- }
-
- }
-
- return (0);
-}
-
-/*
- * Destroy a clone network interface.
- */
-int
-if_clone_destroy(const char *name)
-{
- struct if_clone *ifc;
- struct ifnet *ifp;
- int bytoff, bitoff;
- int unit;
-
- ifp = ifunit(name);
- if (ifp == NULL)
- return (ENXIO);
-
- unit = ifp->if_dunit;
-
- ifc = if_clone_lookup(ifp->if_dname, NULL);
- if (ifc == NULL)
- return (EINVAL);
-
- if (ifc->ifc_destroy == NULL)
- return (EOPNOTSUPP);
-
- (*ifc->ifc_destroy)(ifp);
-
- /*
- * Compute offset in the bitmap and deallocate the unit.
- */
- bytoff = unit >> 3;
- bitoff = unit - (bytoff << 3);
- KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0,
- ("%s: bit is already cleared", __func__));
- ifc->ifc_units[bytoff] &= ~(1 << bitoff);
- return (0);
-}
-
-/*
- * Look up a network interface cloner.
- */
-static struct if_clone *
-if_clone_lookup(const char *name, int *unitp)
-{
- struct if_clone *ifc;
- const char *cp;
- int i;
-
- for (ifc = LIST_FIRST(&if_cloners); ifc != NULL;) {
- for (cp = name, i = 0; i < ifc->ifc_namelen; i++, cp++) {
- if (ifc->ifc_name[i] != *cp)
- goto next_ifc;
- }
- goto found_name;
- next_ifc:
- ifc = LIST_NEXT(ifc, ifc_list);
- }
-
- /* No match. */
- return ((struct if_clone *)NULL);
-
- found_name:
- if (*cp == '\0') {
- i = -1;
- } else {
- for (i = 0; *cp != '\0'; cp++) {
- if (*cp < '0' || *cp > '9') {
- /* Bogus unit number. */
- return (NULL);
- }
- i = (i * 10) + (*cp - '0');
- }
- }
-
- if (unitp != NULL)
- *unitp = i;
- return (ifc);
-}
-
-/*
- * Register a network interface cloner.
- */
-void
-if_clone_attach(struct if_clone *ifc)
-{
- int bytoff, bitoff;
- int err;
- int len, maxclone;
- int unit;
-
- KASSERT(ifc->ifc_minifs - 1 <= ifc->ifc_maxunit,
- ("%s: %s requested more units then allowed (%d > %d)",
- __func__, ifc->ifc_name, ifc->ifc_minifs,
- ifc->ifc_maxunit + 1));
- /*
- * Compute bitmap size and allocate it.
- */
- maxclone = ifc->ifc_maxunit + 1;
- len = maxclone >> 3;
- if ((len << 3) < maxclone)
- len++;
- ifc->ifc_units = malloc(len, M_CLONE, M_WAITOK | M_ZERO);
- ifc->ifc_bmlen = len;
-
- LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list);
- if_cloners_count++;
-
- for (unit = 0; unit < ifc->ifc_minifs; unit++) {
- err = (*ifc->ifc_create)(ifc, unit);
- KASSERT(err == 0,
- ("%s: failed to create required interface %s%d",
- __func__, ifc->ifc_name, unit));
-
- /* Allocate the unit in the bitmap. */
- bytoff = unit >> 3;
- bitoff = unit - (bytoff << 3);
- ifc->ifc_units[bytoff] |= (1 << bitoff);
- }
- EVENTHANDLER_INVOKE(if_clone_event, ifc);
-}
-
-/*
- * Unregister a network interface cloner.
- */
-void
-if_clone_detach(struct if_clone *ifc)
-{
-
- LIST_REMOVE(ifc, ifc_list);
- free(ifc->ifc_units, M_CLONE);
- if_cloners_count--;
-}
-
-/*
- * Provide list of interface cloners to userspace.
- */
-static int
-if_clone_list(struct if_clonereq *ifcr)
-{
- char outbuf[IFNAMSIZ], *dst;
- struct if_clone *ifc;
- int count, error = 0;
-
- ifcr->ifcr_total = if_cloners_count;
- if ((dst = ifcr->ifcr_buffer) == NULL) {
- /* Just asking how many there are. */
- return (0);
- }
-
- if (ifcr->ifcr_count < 0)
- return (EINVAL);
-
- count = (if_cloners_count < ifcr->ifcr_count) ?
- if_cloners_count : ifcr->ifcr_count;
-
- for (ifc = LIST_FIRST(&if_cloners); ifc != NULL && count != 0;
- ifc = LIST_NEXT(ifc, ifc_list), count--, dst += IFNAMSIZ) {
- strlcpy(outbuf, ifc->ifc_name, IFNAMSIZ);
- error = copyout(outbuf, dst, IFNAMSIZ);
- if (error)
- break;
- }
-
- return (error);
-}
-
#define equal(a1, a2) (bcmp((a1), (a2), ((a1))->sa_len) == 0)
/*
diff --git a/sys/net/if.h b/sys/net/if.h
index 2266fee..1dab8c0 100644
--- a/sys/net/if.h
+++ b/sys/net/if.h
@@ -60,28 +60,6 @@ struct ifnet;
#define IFNAMSIZ IF_NAMESIZE
#define IF_MAXUNIT 0x7fff /* historical value */
#endif
-
-#ifdef _KERNEL
-/*
- * Structure describing a `cloning' interface.
- */
-struct if_clone {
- LIST_ENTRY(if_clone) ifc_list; /* on list of cloners */
- const char *ifc_name; /* name of device, e.g. `gif' */
- size_t ifc_namelen; /* length of name */
- int ifc_minifs; /* minimum number of interfaces */
- int ifc_maxunit; /* maximum unit number */
- unsigned char *ifc_units; /* bitmap to handle units */
- int ifc_bmlen; /* bitmap length */
-
- int (*ifc_create)(struct if_clone *, int);
- void (*ifc_destroy)(struct ifnet *);
-};
-
-#define IF_CLONE_INITIALIZER(name, create, destroy, minifs, maxunit) \
- { { 0 }, name, sizeof(name) - 1, minifs, maxunit, NULL, 0, create, destroy }
-#endif
-
#if __BSD_VISIBLE
/*
diff --git a/sys/net/if_clone.c b/sys/net/if_clone.c
new file mode 100644
index 0000000..37184b2
--- /dev/null
+++ b/sys/net/if_clone.c
@@ -0,0 +1,468 @@
+/*
+ * Copyright (c) 1980, 1986, 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.
+ *
+ * @(#)if.c 8.5 (Berkeley) 1/9/95
+ * $FreeBSD$
+ */
+
+#include <sys/param.h>
+#include <sys/malloc.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_clone.h>
+#if 0
+#include <net/if_dl.h>
+#endif
+#include <net/if_types.h>
+#include <net/if_var.h>
+#include <net/radix.h>
+#include <net/route.h>
+
+static void if_clone_free(struct if_clone *ifc);
+
+static struct mtx if_cloners_mtx;
+static int if_cloners_count;
+LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners);
+
+#define IF_CLONERS_LOCK_INIT() \
+ mtx_init(&if_cloners_mtx, "if_cloners lock", NULL, MTX_DEF)
+#define IF_CLONERS_LOCK_ASSERT() mtx_assert(&if_cloners_mtx, MA_OWNED)
+#define IF_CLONERS_LOCK() mtx_lock(&if_cloners_mtx)
+#define IF_CLONERS_UNLOCK() mtx_unlock(&if_cloners_mtx)
+
+#define IF_CLONE_LOCK_INIT(ifc) \
+ mtx_init(&(ifc)->ifc_mtx, "if_clone lock", NULL, MTX_DEF)
+#define IF_CLONE_LOCK_DESTROY(ifc) mtx_destroy(&(ifc)->ifc_mtx)
+#define IF_CLONE_LOCK_ASSERT(ifc) mtx_assert(&(ifc)->ifc_mtx, MA_OWNED)
+#define IF_CLONE_LOCK(ifc) mtx_lock(&(ifc)->ifc_mtx)
+#define IF_CLONE_UNLOCK(ifc) mtx_unlock(&(ifc)->ifc_mtx)
+
+#define IF_CLONE_ADDREF(ifc) \
+ do { \
+ IF_CLONE_LOCK(ifc); \
+ IF_CLONE_ADDREF_LOCKED(ifc); \
+ IF_CLONE_UNLOCK(ifc); \
+ } while (0)
+#define IF_CLONE_ADDREF_LOCKED(ifc) \
+ do { \
+ IF_CLONE_LOCK_ASSERT(ifc); \
+ KASSERT((ifc)->ifc_refcnt >= 0, \
+ ("negative refcnt %ld", (ifc)->ifc_refcnt)); \
+ (ifc)->ifc_refcnt++; \
+ } while (0)
+#define IF_CLONE_REMREF(ifc) \
+ do { \
+ IF_CLONE_LOCK(ifc); \
+ IF_CLONE_REMREF_LOCKED(ifc); \
+ } while (0)
+#define IF_CLONE_REMREF_LOCKED(ifc) \
+ do { \
+ IF_CLONE_LOCK_ASSERT(ifc); \
+ KASSERT((ifc)->ifc_refcnt > 0, \
+ ("bogus refcnt %ld", (ifc)->ifc_refcnt)); \
+ if (--(ifc)->ifc_refcnt == 0) { \
+ IF_CLONE_UNLOCK(ifc); \
+ if_clone_free(ifc); \
+ } \
+ /* silently free the lock */ \
+ IF_CLONE_UNLOCK(ifc); \
+ } while (0)
+
+MALLOC_DEFINE(M_CLONE, "clone", "interface cloning framework");
+
+void
+if_clone_init(void)
+{
+ IF_CLONERS_LOCK_INIT();
+}
+
+/*
+ * Create a clone network interface.
+ */
+int
+if_clone_create(char *name, size_t len)
+{
+ int err;
+ struct if_clone *ifc;
+
+ if (ifunit(name) != NULL)
+ return (EEXIST);
+
+ /* Try to find an applicable cloner for this request */
+ IF_CLONERS_LOCK();
+ LIST_FOREACH(ifc, &if_cloners, ifc_list) {
+ if (ifc->ifc_match(ifc, name)) {
+ IF_CLONE_ADDREF(ifc);
+ break;
+ }
+ }
+ IF_CLONERS_UNLOCK();
+
+ if (ifc == NULL)
+ return (EINVAL);
+
+ err = (*ifc->ifc_create)(ifc, name, len);
+ IF_CLONE_REMREF(ifc);
+ return (err);
+}
+
+/*
+ * Destroy a clone network interface.
+ */
+int
+if_clone_destroy(const char *name)
+{
+ int err;
+ struct if_clone *ifc;
+ struct ifnet *ifp;
+
+ ifp = ifunit(name);
+ if (ifp == NULL)
+ return (ENXIO);
+
+ /* Find the cloner for this interface */
+ IF_CLONERS_LOCK();
+ LIST_FOREACH(ifc, &if_cloners, ifc_list) {
+ if (strcmp(ifc->ifc_name, ifp->if_dname) == 0) {
+ IF_CLONE_ADDREF(ifc);
+ break;
+ }
+ }
+ IF_CLONERS_UNLOCK();
+ if (ifc == NULL)
+ return (EINVAL);
+
+ if (ifc->ifc_destroy == NULL) {
+ err = EOPNOTSUPP;
+ goto done;
+ }
+
+ err = (*ifc->ifc_destroy)(ifc, ifp);
+
+done:
+ IF_CLONE_REMREF(ifc);
+ return (err);
+}
+
+/*
+ * Register a network interface cloner.
+ */
+void
+if_clone_attach(struct if_clone *ifc)
+{
+ int len, maxclone;
+
+ /*
+ * Compute bitmap size and allocate it.
+ */
+ maxclone = ifc->ifc_maxunit + 1;
+ len = maxclone >> 3;
+ if ((len << 3) < maxclone)
+ len++;
+ ifc->ifc_units = malloc(len, M_CLONE, M_WAITOK | M_ZERO);
+ ifc->ifc_bmlen = len;
+ IF_CLONE_LOCK_INIT(ifc);
+ IF_CLONE_ADDREF(ifc);
+
+ IF_CLONERS_LOCK();
+ LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list);
+ if_cloners_count++;
+ IF_CLONERS_UNLOCK();
+
+ if (ifc->ifc_attach != NULL)
+ (*ifc->ifc_attach)(ifc);
+ EVENTHANDLER_INVOKE(if_clone_event, ifc);
+}
+
+/*
+ * Unregister a network interface cloner.
+ */
+void
+if_clone_detach(struct if_clone *ifc)
+{
+
+ IF_CLONERS_LOCK();
+ LIST_REMOVE(ifc, ifc_list);
+ if_cloners_count--;
+ IF_CLONERS_UNLOCK();
+
+ IF_CLONE_REMREF(ifc);
+}
+
+static void
+if_clone_free(struct if_clone *ifc)
+{
+
+ IF_CLONE_LOCK_DESTROY(ifc);
+ free(ifc->ifc_units, M_CLONE);
+}
+
+/*
+ * Provide list of interface cloners to userspace.
+ */
+int
+if_clone_list(struct if_clonereq *ifcr)
+{
+ char outbuf[IFNAMSIZ], *dst;
+ struct if_clone *ifc;
+ int count, err = 0;
+
+ IF_CLONERS_LOCK();
+
+ ifcr->ifcr_total = if_cloners_count;
+ if ((dst = ifcr->ifcr_buffer) == NULL) {
+ /* Just asking how many there are. */
+ goto done;
+ }
+
+ if (ifcr->ifcr_count < 0) {
+ err = EINVAL;
+ goto done;
+ }
+
+ count = (if_cloners_count < ifcr->ifcr_count) ?
+ if_cloners_count : ifcr->ifcr_count;
+
+ for (ifc = LIST_FIRST(&if_cloners); ifc != NULL && count != 0;
+ ifc = LIST_NEXT(ifc, ifc_list), count--, dst += IFNAMSIZ) {
+ strlcpy(outbuf, ifc->ifc_name, IFNAMSIZ);
+ err = copyout(outbuf, dst, IFNAMSIZ);
+ if (err)
+ break;
+ }
+
+done:
+ IF_CLONERS_UNLOCK();
+ return (err);
+}
+
+/*
+ * A utility function to extract unit numbers from interface names of
+ * the form name###.
+ *
+ * Returns 0 on success and an error on failure.
+ */
+int
+ifc_name2unit(const char *name, int *unit)
+{
+ const char *cp;
+
+ for (cp = name; *cp != '\0' && (*cp < '0' || *cp > '9'); cp++);
+ if (*cp == '\0') {
+ *unit = -1;
+ } else {
+ for (*unit = 0; *cp != '\0'; cp++) {
+ if (*cp < '0' || *cp > '9') {
+ /* Bogus unit number. */
+ return (EINVAL);
+ }
+ *unit = (*unit * 10) + (*cp - '0');
+ }
+ }
+
+ return (0);
+}
+
+int
+ifc_alloc_unit(struct if_clone *ifc, int *unit)
+{
+ int wildcard, bytoff, bitoff;
+ int err = 0;
+
+ IF_CLONE_LOCK(ifc);
+
+ bytoff = bitoff = 0;
+ wildcard = (*unit < 0);
+ /*
+ * Find a free unit if none was given.
+ */
+ if (wildcard) {
+ while ((bytoff < ifc->ifc_bmlen)
+ && (ifc->ifc_units[bytoff] == 0xff))
+ bytoff++;
+ if (bytoff >= ifc->ifc_bmlen) {
+ err = ENOSPC;
+ goto done;
+ }
+ while ((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0)
+ bitoff++;
+ *unit = (bytoff << 3) + bitoff;
+ }
+
+ if (*unit > ifc->ifc_maxunit) {
+ err = ENOSPC;
+ goto done;
+ }
+
+ if (!wildcard) {
+ bytoff = *unit >> 3;
+ bitoff = *unit - (bytoff << 3);
+ }
+
+ if((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0) {
+ err = EEXIST;
+ goto done;
+ }
+ /*
+ * Allocate the unit in the bitmap.
+ */
+ ifc->ifc_units[bytoff] |= (1 << bitoff);
+
+done:
+ IF_CLONE_UNLOCK(ifc);
+ return (err);
+}
+
+void
+ifc_free_unit(struct if_clone *ifc, int unit)
+{
+ int bytoff, bitoff;
+
+
+ /*
+ * Compute offset in the bitmap and deallocate the unit.
+ */
+ bytoff = unit >> 3;
+ bitoff = unit - (bytoff << 3);
+
+ IF_CLONE_LOCK(ifc);
+ KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0,
+ ("%s: bit is already cleared", __func__));
+ ifc->ifc_units[bytoff] &= ~(1 << bitoff);
+ IF_CLONE_UNLOCK(ifc);
+}
+
+void
+ifc_simple_attach(struct if_clone *ifc)
+{
+ int err;
+ int unit;
+ char name[IFNAMSIZ];
+ struct ifc_simple_data *ifcs = ifc->ifc_data;
+
+ KASSERT(ifcs->ifcs_minifs - 1 <= ifc->ifc_maxunit,
+ ("%s: %s requested more units then allowed (%d > %d)",
+ __func__, ifc->ifc_name, ifcs->ifcs_minifs,
+ ifc->ifc_maxunit + 1));
+
+ for (unit = 0; unit < ifcs->ifcs_minifs; unit++) {
+ snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, unit);
+ err = (*ifc->ifc_create)(ifc, name, IFNAMSIZ);
+ KASSERT(err == 0,
+ ("%s: failed to create required interface %s",
+ __func__, name));
+ }
+}
+
+int
+ifc_simple_match(struct if_clone *ifc, const char *name)
+{
+ const char *cp;
+ int i;
+
+ /* Match the name */
+ for (cp = name, i = 0; i < strlen(ifc->ifc_name); i++, cp++) {
+ if (ifc->ifc_name[i] != *cp)
+ return (0);
+ }
+
+ /* Make sure there's a unit number or nothing after the name */
+ for (; *cp != '\0'; cp++) {
+ if (*cp < '0' || *cp > '9')
+ return (0);
+ }
+
+ return (1);
+}
+
+int
+ifc_simple_create(struct if_clone *ifc, char *name, size_t len)
+{
+ char *dp;
+ int wildcard;
+ int unit;
+ int err;
+ struct ifc_simple_data *ifcs = ifc->ifc_data;
+
+ err = ifc_name2unit(name, &unit);
+ if (err != 0)
+ return (err);
+
+ wildcard = (unit < 0);
+
+ err = ifc_alloc_unit(ifc, &unit);
+ if (err != 0)
+ return (err);
+
+ err = ifcs->ifcs_create(ifc, unit);
+ if (err != 0) {
+ ifc_free_unit(ifc, unit);
+ return (err);
+ }
+
+ /* In the wildcard case, we need to update the name. */
+ if (wildcard) {
+ for (dp = name; *dp != '\0'; dp++);
+ if (snprintf(dp, len - (dp-name), "%d", unit) >
+ len - (dp-name) - 1) {
+ /*
+ * This can only be a programmer error and
+ * there's no straightforward way to recover if
+ * it happens.
+ */
+ panic("if_clone_create(): interface name too long");
+ }
+
+ }
+
+ return (0);
+}
+
+int
+ifc_simple_destroy(struct if_clone *ifc, struct ifnet *ifp)
+{
+ int unit;
+ struct ifc_simple_data *ifcs = ifc->ifc_data;
+
+ unit = ifp->if_dunit;
+
+ if (unit < ifcs->ifcs_minifs)
+ return (EINVAL);
+
+ ifcs->ifcs_destroy(ifp);
+
+ ifc_free_unit(ifc, unit);
+
+ return (0);
+}
diff --git a/sys/net/if_clone.h b/sys/net/if_clone.h
new file mode 100644
index 0000000..61f1f1f
--- /dev/null
+++ b/sys/net/if_clone.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 1982, 1986, 1989, 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.
+ *
+ * From: @(#)if.h 8.1 (Berkeley) 6/10/93
+ * $FreeBSD$
+ */
+
+#ifndef _NET_IF_CLONE_H_
+#define _NET_IF_CLONE_H_
+
+#ifdef _KERNEL
+
+#define IFC_CLONE_INITIALIZER(name, data, maxunit, \
+ attach, match, create, destroy) \
+ { { 0 }, name, maxunit, NULL, 0, data, attach, match, create, destroy }
+
+/*
+ * Structure describing a `cloning' interface.
+ *
+ * List of locks
+ * (c) const until freeing
+ * (d) driver specific data, may need external protection.
+ * (e) locked by if_cloners_mtx
+ * (i) locked by ifc_mtx mtx
+ */
+struct if_clone {
+ LIST_ENTRY(if_clone) ifc_list; /* (e) On list of cloners */
+ const char *ifc_name; /* (c) Name of device, e.g. `gif' */
+ int ifc_maxunit; /* (c) Maximum unit number */
+ unsigned char *ifc_units; /* (i) Bitmap to handle units. */
+ /* Considered private, access */
+ /* via ifc_(alloc|free)_unit(). */
+ int ifc_bmlen; /* (c) Bitmap length. */
+ void *ifc_data; /* (*) Data for ifc_* functions. */
+
+ /* (c) Driver specific cloning functions. Called with no locks held. */
+ void (*ifc_attach)(struct if_clone *);
+ int (*ifc_match)(struct if_clone *, const char *);
+ int (*ifc_create)(struct if_clone *, char *, size_t);
+ int (*ifc_destroy)(struct if_clone *, struct ifnet *);
+
+ long ifc_refcnt; /* (i) Refrence count. */
+ struct mtx ifc_mtx; /* Muted to protect members. */
+};
+
+void if_clone_init(void);
+void if_clone_attach(struct if_clone *);
+void if_clone_detach(struct if_clone *);
+
+int if_clone_create(char *, size_t);
+int if_clone_destroy(const char *);
+int if_clone_list(struct if_clonereq *);
+
+int ifc_name2unit(const char *name, int *unit);
+int ifc_alloc_unit(struct if_clone *, int *);
+void ifc_free_unit(struct if_clone *, int);
+
+/*
+ * The ifc_simple functions, structures, and macros implement basic
+ * cloning as in 5.[012].
+ */
+
+struct ifc_simple_data {
+ int ifcs_minifs; /* minimum number of interfaces */
+
+ int (*ifcs_create)(struct if_clone *, int);
+ void (*ifcs_destroy)(struct ifnet *);
+};
+
+/* interface clone event */
+typedef void (*if_clone_event_handler_t)(void *, struct if_clone *);
+EVENTHANDLER_DECLARE(if_clone_event, if_clone_event_handler_t);
+
+#define IFC_SIMPLE_DECLARE(name, minifs) \
+struct ifc_simple_data name##_cloner_data = \
+ {minifs, name##_clone_create, name##_clone_destroy}; \
+struct if_clone name##_cloner = \
+ IFC_CLONE_INITIALIZER(#name, &name##_cloner_data, IF_MAXUNIT, \
+ ifc_simple_attach, ifc_simple_match, ifc_simple_create, ifc_simple_destroy)
+
+void ifc_simple_attach(struct if_clone *);
+int ifc_simple_match(struct if_clone *, const char *);
+int ifc_simple_create(struct if_clone *, char *, size_t);
+int ifc_simple_destroy(struct if_clone *, struct ifnet *);
+
+#endif /* _KERNEL */
+
+#endif /* !_NET_IF_CLONE_H_ */
diff --git a/sys/net/if_disc.c b/sys/net/if_disc.c
index 1302c39..f8296dc 100644
--- a/sys/net/if_disc.c
+++ b/sys/net/if_disc.c
@@ -45,6 +45,7 @@
#include <sys/sockio.h>
#include <net/if.h>
+#include <net/if_clone.h>
#include <net/if_types.h>
#include <net/route.h>
#include <net/bpf.h>
@@ -75,8 +76,8 @@ static void disc_clone_destroy(struct ifnet *);
static struct mtx disc_mtx;
static MALLOC_DEFINE(M_DISC, DISCNAME, "Discard interface");
static LIST_HEAD(, disc_softc) disc_softc_list;
-static struct if_clone disc_cloner = IF_CLONE_INITIALIZER(DISCNAME,
- disc_clone_create, disc_clone_destroy, 0, IF_MAXUNIT);
+
+IFC_SIMPLE_DECLARE(disc, 0);
static int
disc_clone_create(struct if_clone *ifc, int unit)
diff --git a/sys/net/if_faith.c b/sys/net/if_faith.c
index e6ab287..76d7546 100644
--- a/sys/net/if_faith.c
+++ b/sys/net/if_faith.c
@@ -56,6 +56,7 @@
#include <sys/malloc.h>
#include <net/if.h>
+#include <net/if_clone.h>
#include <net/if_types.h>
#include <net/netisr.h>
#include <net/route.h>
@@ -104,8 +105,7 @@ static int faith_clone_create(struct if_clone *, int);
static void faith_clone_destroy(struct ifnet *);
static void faith_destroy(struct faith_softc *);
-struct if_clone faith_cloner = IF_CLONE_INITIALIZER(FAITHNAME,
- faith_clone_create, faith_clone_destroy, 0, IF_MAXUNIT);
+IFC_SIMPLE_DECLARE(faith, 0);
#define FAITHMTU 1500
diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c
index cc644ea..41be175 100644
--- a/sys/net/if_gif.c
+++ b/sys/net/if_gif.c
@@ -52,6 +52,7 @@
#include <machine/cpu.h>
#include <net/if.h>
+#include <net/if_clone.h>
#include <net/if_types.h>
#include <net/netisr.h>
#include <net/route.h>
@@ -100,8 +101,7 @@ void (*ng_gif_detach_p)(struct ifnet *ifp);
static int gif_clone_create(struct if_clone *, int);
static void gif_clone_destroy(struct ifnet *);
-struct if_clone gif_cloner = IF_CLONE_INITIALIZER("gif",
- gif_clone_create, gif_clone_destroy, 0, IF_MAXUNIT);
+IFC_SIMPLE_DECLARE(gif, 0);
static int gifmodevent(module_t, int, void *);
diff --git a/sys/net/if_gre.c b/sys/net/if_gre.c
index b088ec6..f8ea058 100644
--- a/sys/net/if_gre.c
+++ b/sys/net/if_gre.c
@@ -63,6 +63,7 @@
#include <net/ethernet.h>
#include <net/if.h>
+#include <net/if_clone.h>
#include <net/if_types.h>
#include <net/route.h>
@@ -107,8 +108,7 @@ static int gre_ioctl(struct ifnet *, u_long, caddr_t);
static int gre_output(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *rt);
-static struct if_clone gre_cloner =
- IF_CLONE_INITIALIZER("gre", gre_clone_create, gre_clone_destroy, 0, IF_MAXUNIT);
+IFC_SIMPLE_DECLARE(gre, 0);
static int gre_compute_route(struct gre_softc *sc);
diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c
index adfad22..ba7508e 100644
--- a/sys/net/if_loop.c
+++ b/sys/net/if_loop.c
@@ -54,6 +54,7 @@
#include <sys/sysctl.h>
#include <net/if.h>
+#include <net/if_clone.h>
#include <net/if_types.h>
#include <net/netisr.h>
#include <net/route.h>
@@ -112,8 +113,7 @@ static MALLOC_DEFINE(M_LO, LONAME, "Loopback Interface");
static struct mtx lo_mtx;
static LIST_HEAD(lo_list, lo_softc) lo_list;
-struct if_clone lo_cloner = IF_CLONE_INITIALIZER(LONAME,
- lo_clone_create, lo_clone_destroy, 1, IF_MAXUNIT);
+IFC_SIMPLE_DECLARE(lo, 1);
static void
lo_clone_destroy(ifp)
diff --git a/sys/net/if_ppp.c b/sys/net/if_ppp.c
index d0db17e..2e808da 100644
--- a/sys/net/if_ppp.c
+++ b/sys/net/if_ppp.c
@@ -97,6 +97,7 @@
#include <sys/module.h>
#include <net/if.h>
+#include <net/if_clone.h>
#include <net/if_types.h>
#include <net/netisr.h>
#include <net/bpf.h>
@@ -157,8 +158,7 @@ static void pppdumpm(struct mbuf *m0);
static int ppp_clone_create(struct if_clone *, int);
static void ppp_clone_destroy(struct ifnet *);
-static struct if_clone ppp_cloner = IF_CLONE_INITIALIZER(PPPNAME,
- ppp_clone_create, ppp_clone_destroy, 0, IF_MAXUNIT);
+IFC_SIMPLE_DECLARE(ppp, 0);
/*
* Some useful mbuf macros not in mbuf.h.
diff --git a/sys/net/if_stf.c b/sys/net/if_stf.c
index 0844550..2f9eb02 100644
--- a/sys/net/if_stf.c
+++ b/sys/net/if_stf.c
@@ -94,6 +94,7 @@
#include <sys/malloc.h>
#include <net/if.h>
+#include <net/if_clone.h>
#include <net/route.h>
#include <net/netisr.h>
#include <net/if_types.h>
@@ -119,6 +120,7 @@
#include <net/bpf.h>
#define STFNAME "stf"
+#define STFUNIT 0
#define IN6_IS_ADDR_6TO4(x) (ntohs((x)->s6_addr16[0]) == 0x2002)
@@ -160,6 +162,8 @@ struct protosw in_stf_protosw =
&rip_usrreqs
};
+static char *stfnames[] = {"stf0", "stf", "6to4", NULL};
+
static int stfmodevent(module_t, int, void *);
static int stf_encapcheck(const struct mbuf *, int, int, void *);
static struct in6_ifaddr *stf_getsrcifa6(struct ifnet *);
@@ -173,30 +177,58 @@ static int stf_checkaddr6(struct stf_softc *, struct in6_addr *,
static void stf_rtrequest(int, struct rtentry *, struct rt_addrinfo *);
static int stf_ioctl(struct ifnet *, u_long, caddr_t);
-static int stf_clone_create(struct if_clone *, int);
-static void stf_clone_destroy(struct ifnet *);
+static int stf_clone_match(struct if_clone *, const char *);
+static int stf_clone_create(struct if_clone *, char *, size_t);
+static int stf_clone_destroy(struct if_clone *, struct ifnet *);
+struct if_clone stf_cloner = IFC_CLONE_INITIALIZER(STFNAME, NULL, 0,
+ NULL, stf_clone_match, stf_clone_create, stf_clone_destroy);
-/* only one clone is currently allowed */
-struct if_clone stf_cloner =
- IF_CLONE_INITIALIZER(STFNAME, stf_clone_create, stf_clone_destroy, 0, 0);
+static int
+stf_clone_match(struct if_clone *ifc, const char *name)
+{
+ int i;
+
+ for(i = 0; stfnames[i] != NULL; i++) {
+ if (strcmp(stfnames[i], name) == 0)
+ return (1);
+ }
+
+ return (0);
+}
static int
-stf_clone_create(ifc, unit)
- struct if_clone *ifc;
- int unit;
+stf_clone_create(struct if_clone *ifc, char *name, size_t len)
{
+ int err, unit;
struct stf_softc *sc;
struct ifnet *ifp;
+ /*
+ * We can only have one unit, but since unit allocation is
+ * already locked, we use it to keep from allocating extra
+ * interfaces.
+ */
+ unit = STFUNIT;
+ err = ifc_alloc_unit(ifc, &unit);
+ if (err != 0)
+ return (err);
+
sc = malloc(sizeof(struct stf_softc), M_STF, M_WAITOK | M_ZERO);
ifp = &sc->sc_if;
- if_initname(ifp, ifc->ifc_name, unit);
+ /*
+ * Set the name manually rather then using if_initname because
+ * we don't conform to the default naming convention for interfaces.
+ */
+ strlcpy(ifp->if_xname, name, IFNAMSIZ);
+ ifp->if_dname = ifc->ifc_name;
+ ifp->if_dunit = IF_DUNIT_NONE;
sc->encap_cookie = encap_attach_func(AF_INET, IPPROTO_IPV6,
stf_encapcheck, &in_stf_protosw, sc);
if (sc->encap_cookie == NULL) {
if_printf(ifp, "attach failed\n");
free(sc, M_STF);
+ ifc_free_unit(ifc, unit);
return (ENOMEM);
}
@@ -226,9 +258,8 @@ stf_destroy(struct stf_softc *sc)
free(sc, M_STF);
}
-static void
-stf_clone_destroy(ifp)
- struct ifnet *ifp;
+static int
+stf_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
{
struct stf_softc *sc = (void *) ifp;
@@ -237,6 +268,9 @@ stf_clone_destroy(ifp)
mtx_unlock(&stf_mtx);
stf_destroy(sc);
+ ifc_free_unit(ifc, STFUNIT);
+
+ return (0);
}
static int
diff --git a/sys/net/if_var.h b/sys/net/if_var.h
index 9fd82c7..50ec732 100644
--- a/sys/net/if_var.h
+++ b/sys/net/if_var.h
@@ -316,9 +316,6 @@ EVENTHANDLER_DECLARE(ifnet_arrival_event, ifnet_arrival_event_handler_t);
/* interface departure event */
typedef void (*ifnet_departure_event_handler_t)(void *, struct ifnet *);
EVENTHANDLER_DECLARE(ifnet_departure_event, ifnet_departure_event_handler_t);
-/* interface clone event */
-typedef void (*if_clone_event_handler_t)(void *, struct if_clone *);
-EVENTHANDLER_DECLARE(if_clone_event, if_clone_event_handler_t);
#define IF_AFDATA_LOCK_INIT(ifp) \
mtx_init(&(ifp)->if_afdata_mtx, "if_afdata", NULL, MTX_DEF)
@@ -685,12 +682,6 @@ struct ifaddr *ifaof_ifpforaddr(struct sockaddr *, struct ifnet *);
struct ifmultiaddr *ifmaof_ifpforaddr(struct sockaddr *, struct ifnet *);
int if_simloop(struct ifnet *ifp, struct mbuf *m, int af, int hlen);
-void if_clone_attach(struct if_clone *);
-void if_clone_detach(struct if_clone *);
-
-int if_clone_create(char *, int);
-int if_clone_destroy(const char *);
-
#define IF_LLADDR(ifp) \
LLADDR((struct sockaddr_dl *) ifaddr_byindex((ifp)->if_index)->ifa_addr)
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c
index f9c22d2..9449dec 100644
--- a/sys/net/if_vlan.c
+++ b/sys/net/if_vlan.c
@@ -57,6 +57,7 @@
#include <net/bpf.h>
#include <net/ethernet.h>
#include <net/if.h>
+#include <net/if_clone.h>
#include <net/if_arp.h>
#include <net/if_dl.h>
#include <net/if_types.h>
@@ -117,8 +118,6 @@ static struct mtx ifv_mtx;
#define VLAN_LOCK() mtx_lock(&ifv_mtx)
#define VLAN_UNLOCK() mtx_unlock(&ifv_mtx)
-static int vlan_clone_create(struct if_clone *, int);
-static void vlan_clone_destroy(struct ifnet *);
static void vlan_start(struct ifnet *ifp);
static void vlan_ifinit(void *foo);
static void vlan_input(struct ifnet *ifp, struct mbuf *m);
@@ -127,9 +126,16 @@ static int vlan_setmulti(struct ifnet *ifp);
static int vlan_unconfig(struct ifnet *ifp);
static int vlan_config(struct ifvlan *ifv, struct ifnet *p);
static void vlan_link_state(struct ifnet *ifp, int link);
+static int vlan_set_promisc(struct ifnet *ifp);
-struct if_clone vlan_cloner = IF_CLONE_INITIALIZER(VLANNAME,
- vlan_clone_create, vlan_clone_destroy, 0, IF_MAXUNIT);
+static struct ifnet *vlan_clone_match_ethertag(struct if_clone *,
+ const char *, int *);
+static int vlan_clone_match(struct if_clone *, const char *);
+static int vlan_clone_create(struct if_clone *, char *, size_t);
+static int vlan_clone_destroy(struct if_clone *, struct ifnet *);
+
+struct if_clone vlan_cloner = IFC_CLONE_INITIALIZER(VLANNAME, NULL, IF_MAXUNIT,
+ NULL, vlan_clone_match, vlan_clone_create, vlan_clone_destroy);
/*
* Program our multicast filter. What we're actually doing is
@@ -231,7 +237,8 @@ vlan_modevent(module_t mod, int type, void *data)
vlan_input_p = NULL;
vlan_link_state_p = NULL;
while (!LIST_EMPTY(&ifv_list))
- vlan_clone_destroy(&LIST_FIRST(&ifv_list)->ifv_if);
+ vlan_clone_destroy(&vlan_cloner,
+ &LIST_FIRST(&ifv_list)->ifv_if);
VLAN_LOCK_DESTROY();
break;
}
@@ -247,18 +254,117 @@ static moduledata_t vlan_mod = {
DECLARE_MODULE(if_vlan, vlan_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
MODULE_DEPEND(if_vlan, miibus, 1, 1, 1);
+static struct ifnet *
+vlan_clone_match_ethertag(struct if_clone *ifc, const char *name, int *tag)
+{
+ int t;
+ const char *cp;
+ struct ifnet *ifp;
+
+ t = 0;
+
+ /* Check for <etherif>.<vlan> style interface names. */
+ IFNET_RLOCK();
+ TAILQ_FOREACH(ifp, &ifnet, if_link) {
+ if (ifp->if_type != IFT_ETHER)
+ continue;
+ if (strncmp(ifp->if_xname, name, strlen(ifp->if_xname)) != 0)
+ continue;
+ cp = name + strlen(ifp->if_xname);
+ if (*cp != '.')
+ continue;
+ for(; *cp != '\0'; cp++) {
+ if (*cp < '0' || *cp > '9')
+ continue;
+ t = (t * 10) + (*cp - '0');
+ }
+ if (tag != NULL)
+ *tag = t;
+ break;
+ }
+ IFNET_RUNLOCK();
+
+ return ifp;
+}
+
+static int
+vlan_clone_match(struct if_clone *ifc, const char *name)
+{
+ const char *cp;
+
+ if (vlan_clone_match_ethertag(ifc, name, NULL) != NULL)
+ return (1);
+
+ if (strncmp(VLANNAME, name, strlen(VLANNAME)) != 0)
+ return (0);
+ for (cp = name + 4; *cp != '\0'; cp++) {
+ if (*cp < '0' || *cp > '9')
+ return (0);
+ }
+
+ return (1);
+}
+
static int
-vlan_clone_create(struct if_clone *ifc, int unit)
+vlan_clone_create(struct if_clone *ifc, char *name, size_t len)
{
+ char *dp;
+ int wildcard;
+ int unit;
+ int error;
+ int tag;
+ int ethertag;
struct ifvlan *ifv;
struct ifnet *ifp;
+ struct ifnet *p;
+
+ if ((p = vlan_clone_match_ethertag(ifc, name, &tag)) != NULL) {
+ ethertag = 1;
+ unit = -1;
+ wildcard = 0;
+
+ /*
+ * Don't let the caller set up a VLAN tag with
+ * anything except VLID bits.
+ */
+ if (tag & ~EVL_VLID_MASK) {
+ return (EINVAL);
+ }
+ } else {
+ ethertag = 0;
+
+ error = ifc_name2unit(name, &unit);
+ if (error != 0)
+ return (error);
+
+ wildcard = (unit < 0);
+ }
+
+ error = ifc_alloc_unit(ifc, &unit);
+ if (error != 0)
+ return (error);
+
+ /* In the wildcard case, we need to update the name. */
+ if (wildcard) {
+ for (dp = name; *dp != '\0'; dp++);
+ if (snprintf(dp, len - (dp-name), "%d", unit) >
+ len - (dp-name) - 1) {
+ panic("%s: interface name too long", __func__);
+ }
+ }
ifv = malloc(sizeof(struct ifvlan), M_VLAN, M_WAITOK | M_ZERO);
ifp = &ifv->ifv_if;
SLIST_INIT(&ifv->vlan_mc_listhead);
ifp->if_softc = ifv;
- if_initname(ifp, ifc->ifc_name, unit);
+ /*
+ * Set the name manually rather then using if_initname because
+ * we don't conform to the default naming convention for interfaces.
+ */
+ strlcpy(ifp->if_xname, name, IFNAMSIZ);
+ ifp->if_dname = ifc->ifc_name;
+ ifp->if_dunit = unit;
/* NB: flags are not set here */
ifp->if_linkmib = &ifv->ifv_mib;
ifp->if_linkmiblen = sizeof ifv->ifv_mib;
@@ -278,11 +384,36 @@ vlan_clone_create(struct if_clone *ifc, int unit)
LIST_INSERT_HEAD(&ifv_list, ifv, ifv_list);
VLAN_UNLOCK();
+ if (ethertag) {
+ VLAN_LOCK();
+ error = vlan_config(ifv, p);
+ if (error != 0) {
+ /*
+ * Since we've partialy failed, we need to back
+ * out all the way, otherwise userland could get
+ * confused. Thus, we destroy the interface.
+ */
+ LIST_REMOVE(ifv, ifv_list);
+ vlan_unconfig(ifp);
+ VLAN_UNLOCK();
+ ether_ifdetach(ifp);
+ free(ifv, M_VLAN);
+
+ return (error);
+ }
+ ifv->ifv_tag = tag;
+ ifp->if_flags |= IFF_RUNNING;
+ VLAN_UNLOCK();
+
+ /* Update promiscuous mode, if necessary. */
+ vlan_set_promisc(ifp);
+ }
+
return (0);
}
-static void
-vlan_clone_destroy(struct ifnet *ifp)
+static int
+vlan_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
{
struct ifvlan *ifv = ifp->if_softc;
@@ -294,6 +425,8 @@ vlan_clone_destroy(struct ifnet *ifp)
ether_ifdetach(ifp);
free(ifv, M_VLAN);
+
+ return (0);
}
static void
OpenPOWER on IntegriCloud