Changed files: sys/conf/files sys/net/if_var.h sys/net/if.c sys/net/if_disc.c sys/net/if_faith.c sys/net/if_gif.c sys/net/if_gre.c sys/net/if_loop.c sys/net/if_ppp.c sys/net/if_stf.c sys/net/if_vlan.c sys/contrib/pf/net/if_pflog.c sys/contrib/pf/net/if_pfsync.c Added files: sys/net/if_clone.h sys/net/if_clone.c --- ../cleanup/sys/conf/files Tue May 11 17:37:30 2004 +++ sys/conf/files Tue May 11 17:46:52 2004 @@ -1204,6 +1204,7 @@ 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 --- ../cleanup/sys/net/if_var.h Tue May 11 17:38:57 2004 +++ sys/net/if_var.h Tue May 11 17:48:07 2004 @@ -300,9 +300,6 @@ /* 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) @@ -487,12 +484,6 @@ 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) --- ../cleanup/sys/net/if.c Tue May 11 17:38:55 2004 +++ sys/net/if.c Tue May 11 17:48:04 2004 @@ -56,6 +56,7 @@ #include #include +#include #include #include #include @@ -88,8 +89,6 @@ 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 /* @@ -104,8 +103,6 @@ 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; @@ -124,7 +121,6 @@ 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; @@ -261,6 +257,7 @@ if_grow(); /* create initial table */ ifdev_byindex(0) = make_dev(&net_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "network"); + if_clone_init(); } static void @@ -653,243 +650,6 @@ } 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) --- /dev/null Thu May 20 15:22:00 2004 +++ sys/net/if_clone.h Thu Apr 22 08:42:35 2004 @@ -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_ */ --- /dev/null Thu May 20 15:22:00 2004 +++ sys/net/if_clone.c Thu May 20 14:41:57 2004 @@ -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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#if 0 +#include +#endif +#include +#include +#include +#include + +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); +} --- ../cleanup/sys/net/if_disc.c Wed Apr 21 14:09:50 2004 +++ sys/net/if_disc.c Wed Apr 21 14:21:40 2004 @@ -45,6 +45,7 @@ #include #include +#include #include #include #include @@ -75,8 +76,8 @@ 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) --- ../cleanup/sys/net/if_faith.c Wed Apr 21 14:09:51 2004 +++ sys/net/if_faith.c Wed Apr 21 14:21:40 2004 @@ -55,6 +55,7 @@ #include #include +#include #include #include #include @@ -103,8 +104,7 @@ 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 --- ../cleanup/sys/net/if_gif.c Wed Apr 21 14:09:51 2004 +++ sys/net/if_gif.c Wed Apr 21 14:21:41 2004 @@ -51,6 +51,7 @@ #include #include +#include #include #include #include @@ -99,8 +100,7 @@ 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 *); --- ../cleanup/sys/net/if_gre.c Tue May 11 17:38:57 2004 +++ sys/net/if_gre.c Tue May 11 17:48:06 2004 @@ -62,6 +62,7 @@ #include #include +#include #include #include @@ -106,8 +107,7 @@ 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); --- ../cleanup/sys/net/if_loop.c Wed Apr 21 14:09:52 2004 +++ sys/net/if_loop.c Wed Apr 21 14:21:41 2004 @@ -54,6 +54,7 @@ #include #include +#include #include #include #include @@ -112,8 +113,7 @@ 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) --- ../cleanup/sys/net/if_ppp.c Wed Apr 21 14:09:53 2004 +++ sys/net/if_ppp.c Wed Apr 21 14:21:42 2004 @@ -97,6 +97,7 @@ #include #include +#include #include #include #include @@ -157,8 +158,7 @@ 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. --- ../cleanup/sys/net/if_stf.c Wed Apr 21 14:09:54 2004 +++ sys/net/if_stf.c Wed Apr 21 14:21:43 2004 @@ -93,6 +93,7 @@ #include #include +#include #include #include #include @@ -118,6 +119,7 @@ #include #define STFNAME "stf" +#define STFUNIT 0 #define IN6_IS_ADDR_6TO4(x) (ntohs((x)->s6_addr16[0]) == 0x2002) @@ -159,6 +161,8 @@ &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 *); @@ -172,30 +176,58 @@ 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); + +static int +stf_clone_match(struct if_clone *ifc, const char *name) +{ + int i; -/* only one clone is currently allowed */ -struct if_clone stf_cloner = - IF_CLONE_INITIALIZER(STFNAME, stf_clone_create, stf_clone_destroy, 0, 0); + 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); } @@ -225,9 +257,8 @@ 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; @@ -236,6 +267,9 @@ mtx_unlock(&stf_mtx); stf_destroy(sc); + ifc_free_unit(ifc, STFUNIT); + + return (0); } static int --- ../cleanup/sys/net/if_vlan.c Tue May 11 17:38:58 2004 +++ sys/net/if_vlan.c Tue May 11 17:48:07 2004 @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -117,8 +118,6 @@ #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_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_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; } @@ -246,18 +253,117 @@ DECLARE_MODULE(if_vlan, vlan_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); +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 . 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; @@ -277,11 +383,36 @@ 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; @@ -293,6 +424,8 @@ ether_ifdetach(ifp); free(ifv, M_VLAN); + + return (0); } static void --- ../cleanup/sys/contrib/pf/net/if_pflog.c Wed Apr 21 14:07:20 2004 +++ sys/contrib/pf/net/if_pflog.c Wed Apr 21 14:21:26 2004 @@ -62,6 +62,9 @@ #endif #include +#if defined(__FreeBSD__) +#include +#endif #include #include #include @@ -122,8 +125,7 @@ #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) --- ../cleanup/sys/contrib/pf/net/if_pfsync.c Wed Apr 21 14:07:21 2004 +++ sys/contrib/pf/net/if_pfsync.c Wed Apr 21 14:21:27 2004 @@ -57,6 +57,9 @@ #endif #include +#if defined(__FreeBSD__) +#include +#endif #include #include #include @@ -117,8 +120,7 @@ #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)