1c398230bSWarner Losh /*- 2f889d2efSBrooks Davis * Copyright (c) 1980, 1986, 1993 3f889d2efSBrooks Davis * The Regents of the University of California. All rights reserved. 4f889d2efSBrooks Davis * 5f889d2efSBrooks Davis * Redistribution and use in source and binary forms, with or without 6f889d2efSBrooks Davis * modification, are permitted provided that the following conditions 7f889d2efSBrooks Davis * are met: 8f889d2efSBrooks Davis * 1. Redistributions of source code must retain the above copyright 9f889d2efSBrooks Davis * notice, this list of conditions and the following disclaimer. 10f889d2efSBrooks Davis * 2. Redistributions in binary form must reproduce the above copyright 11f889d2efSBrooks Davis * notice, this list of conditions and the following disclaimer in the 12f889d2efSBrooks Davis * documentation and/or other materials provided with the distribution. 13f889d2efSBrooks Davis * 4. Neither the name of the University nor the names of its contributors 14f889d2efSBrooks Davis * may be used to endorse or promote products derived from this software 15f889d2efSBrooks Davis * without specific prior written permission. 16f889d2efSBrooks Davis * 17f889d2efSBrooks Davis * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18f889d2efSBrooks Davis * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19f889d2efSBrooks Davis * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20f889d2efSBrooks Davis * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21f889d2efSBrooks Davis * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22f889d2efSBrooks Davis * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23f889d2efSBrooks Davis * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24f889d2efSBrooks Davis * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25f889d2efSBrooks Davis * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26f889d2efSBrooks Davis * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27f889d2efSBrooks Davis * SUCH DAMAGE. 28f889d2efSBrooks Davis * 29f889d2efSBrooks Davis * @(#)if.c 8.5 (Berkeley) 1/9/95 30f889d2efSBrooks Davis * $FreeBSD$ 31f889d2efSBrooks Davis */ 32f889d2efSBrooks Davis 33f889d2efSBrooks Davis #include <sys/param.h> 34f889d2efSBrooks Davis #include <sys/malloc.h> 35f889d2efSBrooks Davis #include <sys/lock.h> 36f889d2efSBrooks Davis #include <sys/mutex.h> 37f889d2efSBrooks Davis #include <sys/kernel.h> 38f889d2efSBrooks Davis #include <sys/systm.h> 39f889d2efSBrooks Davis #include <sys/types.h> 40f889d2efSBrooks Davis #include <sys/socket.h> 41f889d2efSBrooks Davis 42f889d2efSBrooks Davis #include <net/if.h> 43f889d2efSBrooks Davis #include <net/if_clone.h> 44f889d2efSBrooks Davis #if 0 45f889d2efSBrooks Davis #include <net/if_dl.h> 46f889d2efSBrooks Davis #endif 47f889d2efSBrooks Davis #include <net/if_types.h> 48f889d2efSBrooks Davis #include <net/if_var.h> 49f889d2efSBrooks Davis #include <net/radix.h> 50f889d2efSBrooks Davis #include <net/route.h> 51f889d2efSBrooks Davis 52f889d2efSBrooks Davis static void if_clone_free(struct if_clone *ifc); 534e7e0183SAndrew Thompson static int if_clone_createif(struct if_clone *ifc, char *name, size_t len); 544e7e0183SAndrew Thompson static int if_clone_destroyif(struct if_clone *ifc, struct ifnet *ifp); 55f889d2efSBrooks Davis 56f889d2efSBrooks Davis static struct mtx if_cloners_mtx; 57f889d2efSBrooks Davis static int if_cloners_count; 58f889d2efSBrooks Davis LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners); 59f889d2efSBrooks Davis 60f889d2efSBrooks Davis #define IF_CLONERS_LOCK_INIT() \ 61f889d2efSBrooks Davis mtx_init(&if_cloners_mtx, "if_cloners lock", NULL, MTX_DEF) 62f889d2efSBrooks Davis #define IF_CLONERS_LOCK_ASSERT() mtx_assert(&if_cloners_mtx, MA_OWNED) 63f889d2efSBrooks Davis #define IF_CLONERS_LOCK() mtx_lock(&if_cloners_mtx) 64f889d2efSBrooks Davis #define IF_CLONERS_UNLOCK() mtx_unlock(&if_cloners_mtx) 65f889d2efSBrooks Davis 66f889d2efSBrooks Davis #define IF_CLONE_LOCK_INIT(ifc) \ 67f889d2efSBrooks Davis mtx_init(&(ifc)->ifc_mtx, "if_clone lock", NULL, MTX_DEF) 68f889d2efSBrooks Davis #define IF_CLONE_LOCK_DESTROY(ifc) mtx_destroy(&(ifc)->ifc_mtx) 69f889d2efSBrooks Davis #define IF_CLONE_LOCK_ASSERT(ifc) mtx_assert(&(ifc)->ifc_mtx, MA_OWNED) 70f889d2efSBrooks Davis #define IF_CLONE_LOCK(ifc) mtx_lock(&(ifc)->ifc_mtx) 71f889d2efSBrooks Davis #define IF_CLONE_UNLOCK(ifc) mtx_unlock(&(ifc)->ifc_mtx) 72f889d2efSBrooks Davis 73f889d2efSBrooks Davis #define IF_CLONE_ADDREF(ifc) \ 74f889d2efSBrooks Davis do { \ 75f889d2efSBrooks Davis IF_CLONE_LOCK(ifc); \ 76f889d2efSBrooks Davis IF_CLONE_ADDREF_LOCKED(ifc); \ 77f889d2efSBrooks Davis IF_CLONE_UNLOCK(ifc); \ 78f889d2efSBrooks Davis } while (0) 79f889d2efSBrooks Davis #define IF_CLONE_ADDREF_LOCKED(ifc) \ 80f889d2efSBrooks Davis do { \ 81f889d2efSBrooks Davis IF_CLONE_LOCK_ASSERT(ifc); \ 82f889d2efSBrooks Davis KASSERT((ifc)->ifc_refcnt >= 0, \ 83f889d2efSBrooks Davis ("negative refcnt %ld", (ifc)->ifc_refcnt)); \ 84f889d2efSBrooks Davis (ifc)->ifc_refcnt++; \ 85f889d2efSBrooks Davis } while (0) 86f889d2efSBrooks Davis #define IF_CLONE_REMREF(ifc) \ 87f889d2efSBrooks Davis do { \ 88f889d2efSBrooks Davis IF_CLONE_LOCK(ifc); \ 89f889d2efSBrooks Davis IF_CLONE_REMREF_LOCKED(ifc); \ 90f889d2efSBrooks Davis } while (0) 91f889d2efSBrooks Davis #define IF_CLONE_REMREF_LOCKED(ifc) \ 92f889d2efSBrooks Davis do { \ 93f889d2efSBrooks Davis IF_CLONE_LOCK_ASSERT(ifc); \ 94f889d2efSBrooks Davis KASSERT((ifc)->ifc_refcnt > 0, \ 95f889d2efSBrooks Davis ("bogus refcnt %ld", (ifc)->ifc_refcnt)); \ 96f889d2efSBrooks Davis if (--(ifc)->ifc_refcnt == 0) { \ 97f889d2efSBrooks Davis IF_CLONE_UNLOCK(ifc); \ 98f889d2efSBrooks Davis if_clone_free(ifc); \ 99ca64c799SMax Laier } else { \ 100f889d2efSBrooks Davis /* silently free the lock */ \ 101f889d2efSBrooks Davis IF_CLONE_UNLOCK(ifc); \ 102ca64c799SMax Laier } \ 103f889d2efSBrooks Davis } while (0) 104f889d2efSBrooks Davis 1054e7e0183SAndrew Thompson #define IFC_IFLIST_INSERT(_ifc, _ifp) \ 1064e7e0183SAndrew Thompson LIST_INSERT_HEAD(&_ifc->ifc_iflist, _ifp, if_clones) 1074e7e0183SAndrew Thompson #define IFC_IFLIST_REMOVE(_ifc, _ifp) \ 1084e7e0183SAndrew Thompson LIST_REMOVE(_ifp, if_clones) 1094e7e0183SAndrew Thompson 110c711aea6SPoul-Henning Kamp static MALLOC_DEFINE(M_CLONE, "clone", "interface cloning framework"); 111f889d2efSBrooks Davis 112f889d2efSBrooks Davis void 113f889d2efSBrooks Davis if_clone_init(void) 114f889d2efSBrooks Davis { 115f889d2efSBrooks Davis IF_CLONERS_LOCK_INIT(); 116f889d2efSBrooks Davis } 117f889d2efSBrooks Davis 118f889d2efSBrooks Davis /* 1194e7e0183SAndrew Thompson * Lookup and create a clone network interface. 120f889d2efSBrooks Davis */ 121f889d2efSBrooks Davis int 122f889d2efSBrooks Davis if_clone_create(char *name, size_t len) 123f889d2efSBrooks Davis { 124f889d2efSBrooks Davis struct if_clone *ifc; 125f889d2efSBrooks Davis 126f889d2efSBrooks Davis /* Try to find an applicable cloner for this request */ 127f889d2efSBrooks Davis IF_CLONERS_LOCK(); 128f889d2efSBrooks Davis LIST_FOREACH(ifc, &if_cloners, ifc_list) { 129f889d2efSBrooks Davis if (ifc->ifc_match(ifc, name)) { 130f889d2efSBrooks Davis break; 131f889d2efSBrooks Davis } 132f889d2efSBrooks Davis } 133f889d2efSBrooks Davis IF_CLONERS_UNLOCK(); 134f889d2efSBrooks Davis 135f889d2efSBrooks Davis if (ifc == NULL) 136f889d2efSBrooks Davis return (EINVAL); 137f889d2efSBrooks Davis 1384e7e0183SAndrew Thompson return (if_clone_createif(ifc, name, len)); 1394e7e0183SAndrew Thompson } 1404e7e0183SAndrew Thompson 1414e7e0183SAndrew Thompson /* 1424e7e0183SAndrew Thompson * Create a clone network interface. 1434e7e0183SAndrew Thompson */ 1444e7e0183SAndrew Thompson static int 1454e7e0183SAndrew Thompson if_clone_createif(struct if_clone *ifc, char *name, size_t len) 1464e7e0183SAndrew Thompson { 1474e7e0183SAndrew Thompson int err; 1484e7e0183SAndrew Thompson struct ifnet *ifp; 1494e7e0183SAndrew Thompson 1504e7e0183SAndrew Thompson if (ifunit(name) != NULL) 1514e7e0183SAndrew Thompson return (EEXIST); 1524e7e0183SAndrew Thompson 153f889d2efSBrooks Davis err = (*ifc->ifc_create)(ifc, name, len); 1544e7e0183SAndrew Thompson 1554e7e0183SAndrew Thompson if (!err) { 1564e7e0183SAndrew Thompson ifp = ifunit(name); 1574e7e0183SAndrew Thompson if (ifp == NULL) 1584e7e0183SAndrew Thompson panic("%s: lookup failed for %s", __func__, name); 1594e7e0183SAndrew Thompson 1604e7e0183SAndrew Thompson IF_CLONE_LOCK(ifc); 1614e7e0183SAndrew Thompson IFC_IFLIST_INSERT(ifc, ifp); 1624e7e0183SAndrew Thompson IF_CLONE_UNLOCK(ifc); 1634e7e0183SAndrew Thompson } 1644e7e0183SAndrew Thompson 165f889d2efSBrooks Davis return (err); 166f889d2efSBrooks Davis } 167f889d2efSBrooks Davis 168f889d2efSBrooks Davis /* 1694e7e0183SAndrew Thompson * Lookup and destroy a clone network interface. 170f889d2efSBrooks Davis */ 171f889d2efSBrooks Davis int 172f889d2efSBrooks Davis if_clone_destroy(const char *name) 173f889d2efSBrooks Davis { 174f889d2efSBrooks Davis struct if_clone *ifc; 175f889d2efSBrooks Davis struct ifnet *ifp; 176f889d2efSBrooks Davis 177f889d2efSBrooks Davis ifp = ifunit(name); 178f889d2efSBrooks Davis if (ifp == NULL) 179f889d2efSBrooks Davis return (ENXIO); 180f889d2efSBrooks Davis 181f889d2efSBrooks Davis /* Find the cloner for this interface */ 182f889d2efSBrooks Davis IF_CLONERS_LOCK(); 183f889d2efSBrooks Davis LIST_FOREACH(ifc, &if_cloners, ifc_list) { 184f889d2efSBrooks Davis if (strcmp(ifc->ifc_name, ifp->if_dname) == 0) { 185f889d2efSBrooks Davis break; 186f889d2efSBrooks Davis } 187f889d2efSBrooks Davis } 188f889d2efSBrooks Davis IF_CLONERS_UNLOCK(); 189f889d2efSBrooks Davis if (ifc == NULL) 190f889d2efSBrooks Davis return (EINVAL); 191f889d2efSBrooks Davis 1924e7e0183SAndrew Thompson return (if_clone_destroyif(ifc, ifp)); 1934e7e0183SAndrew Thompson } 1944e7e0183SAndrew Thompson 1954e7e0183SAndrew Thompson /* 1964e7e0183SAndrew Thompson * Destroy a clone network interface. 1974e7e0183SAndrew Thompson */ 1984e7e0183SAndrew Thompson static int 1994e7e0183SAndrew Thompson if_clone_destroyif(struct if_clone *ifc, struct ifnet *ifp) 2004e7e0183SAndrew Thompson { 2014e7e0183SAndrew Thompson int err; 2024e7e0183SAndrew Thompson 2034e7e0183SAndrew Thompson IF_CLONE_LOCK(ifc); 2044e7e0183SAndrew Thompson IFC_IFLIST_REMOVE(ifc, ifp); 2054e7e0183SAndrew Thompson IF_CLONE_UNLOCK(ifc); 2064e7e0183SAndrew Thompson 207f889d2efSBrooks Davis if (ifc->ifc_destroy == NULL) { 208f889d2efSBrooks Davis err = EOPNOTSUPP; 209f889d2efSBrooks Davis goto done; 210f889d2efSBrooks Davis } 211f889d2efSBrooks Davis 212f889d2efSBrooks Davis err = (*ifc->ifc_destroy)(ifc, ifp); 213f889d2efSBrooks Davis 214f889d2efSBrooks Davis done: 215f889d2efSBrooks Davis return (err); 216f889d2efSBrooks Davis } 217f889d2efSBrooks Davis 218f889d2efSBrooks Davis /* 219f889d2efSBrooks Davis * Register a network interface cloner. 220f889d2efSBrooks Davis */ 221f889d2efSBrooks Davis void 222f889d2efSBrooks Davis if_clone_attach(struct if_clone *ifc) 223f889d2efSBrooks Davis { 224f889d2efSBrooks Davis int len, maxclone; 225f889d2efSBrooks Davis 226f889d2efSBrooks Davis /* 227f889d2efSBrooks Davis * Compute bitmap size and allocate it. 228f889d2efSBrooks Davis */ 229f889d2efSBrooks Davis maxclone = ifc->ifc_maxunit + 1; 230f889d2efSBrooks Davis len = maxclone >> 3; 231f889d2efSBrooks Davis if ((len << 3) < maxclone) 232f889d2efSBrooks Davis len++; 233f889d2efSBrooks Davis ifc->ifc_units = malloc(len, M_CLONE, M_WAITOK | M_ZERO); 234f889d2efSBrooks Davis ifc->ifc_bmlen = len; 235f889d2efSBrooks Davis IF_CLONE_LOCK_INIT(ifc); 236f889d2efSBrooks Davis IF_CLONE_ADDREF(ifc); 237f889d2efSBrooks Davis 238f889d2efSBrooks Davis IF_CLONERS_LOCK(); 239f889d2efSBrooks Davis LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list); 240f889d2efSBrooks Davis if_cloners_count++; 241f889d2efSBrooks Davis IF_CLONERS_UNLOCK(); 242f889d2efSBrooks Davis 2434e7e0183SAndrew Thompson LIST_INIT(&ifc->ifc_iflist); 2444e7e0183SAndrew Thompson 245f889d2efSBrooks Davis if (ifc->ifc_attach != NULL) 246f889d2efSBrooks Davis (*ifc->ifc_attach)(ifc); 247f889d2efSBrooks Davis EVENTHANDLER_INVOKE(if_clone_event, ifc); 248f889d2efSBrooks Davis } 249f889d2efSBrooks Davis 250f889d2efSBrooks Davis /* 251f889d2efSBrooks Davis * Unregister a network interface cloner. 252f889d2efSBrooks Davis */ 253f889d2efSBrooks Davis void 254f889d2efSBrooks Davis if_clone_detach(struct if_clone *ifc) 255f889d2efSBrooks Davis { 256febd0759SAndrew Thompson struct ifc_simple_data *ifcs = ifc->ifc_data; 257f889d2efSBrooks Davis 258f889d2efSBrooks Davis IF_CLONERS_LOCK(); 259f889d2efSBrooks Davis LIST_REMOVE(ifc, ifc_list); 260f889d2efSBrooks Davis if_cloners_count--; 261f889d2efSBrooks Davis IF_CLONERS_UNLOCK(); 262f889d2efSBrooks Davis 263febd0759SAndrew Thompson /* Allow all simples to be destroyed */ 264febd0759SAndrew Thompson if (ifc->ifc_attach == ifc_simple_attach) 265febd0759SAndrew Thompson ifcs->ifcs_minifs = 0; 266febd0759SAndrew Thompson 2674e7e0183SAndrew Thompson /* destroy all interfaces for this cloner */ 2684e7e0183SAndrew Thompson while (!LIST_EMPTY(&ifc->ifc_iflist)) 2694e7e0183SAndrew Thompson if_clone_destroyif(ifc, LIST_FIRST(&ifc->ifc_iflist)); 2704e7e0183SAndrew Thompson 271f889d2efSBrooks Davis IF_CLONE_REMREF(ifc); 272f889d2efSBrooks Davis } 273f889d2efSBrooks Davis 274f889d2efSBrooks Davis static void 275f889d2efSBrooks Davis if_clone_free(struct if_clone *ifc) 276f889d2efSBrooks Davis { 277febd0759SAndrew Thompson for (int bytoff = 0; bytoff < ifc->ifc_bmlen; bytoff++) { 278febd0759SAndrew Thompson KASSERT(ifc->ifc_units[bytoff] == 0x00, 279febd0759SAndrew Thompson ("ifc_units[%d] is not empty", bytoff)); 280febd0759SAndrew Thompson } 281f889d2efSBrooks Davis 2824e7e0183SAndrew Thompson KASSERT(LIST_EMPTY(&ifc->ifc_iflist), 2834e7e0183SAndrew Thompson ("%s: ifc_iflist not empty", __func__)); 2844e7e0183SAndrew Thompson 285f889d2efSBrooks Davis IF_CLONE_LOCK_DESTROY(ifc); 286f889d2efSBrooks Davis free(ifc->ifc_units, M_CLONE); 287f889d2efSBrooks Davis } 288f889d2efSBrooks Davis 289f889d2efSBrooks Davis /* 290f889d2efSBrooks Davis * Provide list of interface cloners to userspace. 291f889d2efSBrooks Davis */ 292f889d2efSBrooks Davis int 293f889d2efSBrooks Davis if_clone_list(struct if_clonereq *ifcr) 294f889d2efSBrooks Davis { 295c859ef97SBrooks Davis char *buf, *dst, *outbuf = NULL; 296f889d2efSBrooks Davis struct if_clone *ifc; 297c859ef97SBrooks Davis int buf_count, count, err = 0; 298c859ef97SBrooks Davis 299a6d00835SMaxim Konovalov if (ifcr->ifcr_count < 0) 300a6d00835SMaxim Konovalov return (EINVAL); 301a6d00835SMaxim Konovalov 302c859ef97SBrooks Davis IF_CLONERS_LOCK(); 303c859ef97SBrooks Davis /* 304c859ef97SBrooks Davis * Set our internal output buffer size. We could end up not 305c859ef97SBrooks Davis * reporting a cloner that is added between the unlock and lock 306c859ef97SBrooks Davis * below, but that's not a major problem. Not caping our 307c859ef97SBrooks Davis * allocation to the number of cloners actually in the system 308c859ef97SBrooks Davis * could be because that would let arbitrary users cause us to 309c859ef97SBrooks Davis * allocate abritrary amounts of kernel memory. 310c859ef97SBrooks Davis */ 311c859ef97SBrooks Davis buf_count = (if_cloners_count < ifcr->ifcr_count) ? 312c859ef97SBrooks Davis if_cloners_count : ifcr->ifcr_count; 313c859ef97SBrooks Davis IF_CLONERS_UNLOCK(); 314c859ef97SBrooks Davis 315c859ef97SBrooks Davis outbuf = malloc(IFNAMSIZ*buf_count, M_CLONE, M_WAITOK | M_ZERO); 316f889d2efSBrooks Davis 317f889d2efSBrooks Davis IF_CLONERS_LOCK(); 318f889d2efSBrooks Davis 319f889d2efSBrooks Davis ifcr->ifcr_total = if_cloners_count; 320f889d2efSBrooks Davis if ((dst = ifcr->ifcr_buffer) == NULL) { 321f889d2efSBrooks Davis /* Just asking how many there are. */ 322f889d2efSBrooks Davis goto done; 323f889d2efSBrooks Davis } 324c859ef97SBrooks Davis count = (if_cloners_count < buf_count) ? 325c859ef97SBrooks Davis if_cloners_count : buf_count; 326f889d2efSBrooks Davis 327c859ef97SBrooks Davis for (ifc = LIST_FIRST(&if_cloners), buf = outbuf; 328c859ef97SBrooks Davis ifc != NULL && count != 0; 329c859ef97SBrooks Davis ifc = LIST_NEXT(ifc, ifc_list), count--, buf += IFNAMSIZ) { 330c859ef97SBrooks Davis strlcpy(buf, ifc->ifc_name, IFNAMSIZ); 331f889d2efSBrooks Davis } 332f889d2efSBrooks Davis 333f889d2efSBrooks Davis done: 334f889d2efSBrooks Davis IF_CLONERS_UNLOCK(); 335c859ef97SBrooks Davis if (err == 0) 336c859ef97SBrooks Davis err = copyout(outbuf, dst, buf_count*IFNAMSIZ); 337c859ef97SBrooks Davis if (outbuf != NULL) 338c859ef97SBrooks Davis free(outbuf, M_CLONE); 339f889d2efSBrooks Davis return (err); 340f889d2efSBrooks Davis } 341f889d2efSBrooks Davis 342f889d2efSBrooks Davis /* 343f889d2efSBrooks Davis * A utility function to extract unit numbers from interface names of 344f889d2efSBrooks Davis * the form name###. 345f889d2efSBrooks Davis * 346f889d2efSBrooks Davis * Returns 0 on success and an error on failure. 347f889d2efSBrooks Davis */ 348f889d2efSBrooks Davis int 349f889d2efSBrooks Davis ifc_name2unit(const char *name, int *unit) 350f889d2efSBrooks Davis { 351f889d2efSBrooks Davis const char *cp; 352f889d2efSBrooks Davis 353f889d2efSBrooks Davis for (cp = name; *cp != '\0' && (*cp < '0' || *cp > '9'); cp++); 354f889d2efSBrooks Davis if (*cp == '\0') { 355f889d2efSBrooks Davis *unit = -1; 356f889d2efSBrooks Davis } else { 357f889d2efSBrooks Davis for (*unit = 0; *cp != '\0'; cp++) { 358f889d2efSBrooks Davis if (*cp < '0' || *cp > '9') { 359f889d2efSBrooks Davis /* Bogus unit number. */ 360f889d2efSBrooks Davis return (EINVAL); 361f889d2efSBrooks Davis } 362f889d2efSBrooks Davis *unit = (*unit * 10) + (*cp - '0'); 363f889d2efSBrooks Davis } 364f889d2efSBrooks Davis } 365f889d2efSBrooks Davis 366f889d2efSBrooks Davis return (0); 367f889d2efSBrooks Davis } 368f889d2efSBrooks Davis 369f889d2efSBrooks Davis int 370f889d2efSBrooks Davis ifc_alloc_unit(struct if_clone *ifc, int *unit) 371f889d2efSBrooks Davis { 372f889d2efSBrooks Davis int wildcard, bytoff, bitoff; 373f889d2efSBrooks Davis int err = 0; 374f889d2efSBrooks Davis 375f889d2efSBrooks Davis IF_CLONE_LOCK(ifc); 376f889d2efSBrooks Davis 377f889d2efSBrooks Davis bytoff = bitoff = 0; 378f889d2efSBrooks Davis wildcard = (*unit < 0); 379f889d2efSBrooks Davis /* 380f889d2efSBrooks Davis * Find a free unit if none was given. 381f889d2efSBrooks Davis */ 382f889d2efSBrooks Davis if (wildcard) { 383f889d2efSBrooks Davis while ((bytoff < ifc->ifc_bmlen) 384f889d2efSBrooks Davis && (ifc->ifc_units[bytoff] == 0xff)) 385f889d2efSBrooks Davis bytoff++; 386f889d2efSBrooks Davis if (bytoff >= ifc->ifc_bmlen) { 387f889d2efSBrooks Davis err = ENOSPC; 388f889d2efSBrooks Davis goto done; 389f889d2efSBrooks Davis } 390f889d2efSBrooks Davis while ((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0) 391f889d2efSBrooks Davis bitoff++; 392f889d2efSBrooks Davis *unit = (bytoff << 3) + bitoff; 393f889d2efSBrooks Davis } 394f889d2efSBrooks Davis 395f889d2efSBrooks Davis if (*unit > ifc->ifc_maxunit) { 396f889d2efSBrooks Davis err = ENOSPC; 397f889d2efSBrooks Davis goto done; 398f889d2efSBrooks Davis } 399f889d2efSBrooks Davis 400f889d2efSBrooks Davis if (!wildcard) { 401f889d2efSBrooks Davis bytoff = *unit >> 3; 402f889d2efSBrooks Davis bitoff = *unit - (bytoff << 3); 403f889d2efSBrooks Davis } 404f889d2efSBrooks Davis 405f889d2efSBrooks Davis if((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0) { 406f889d2efSBrooks Davis err = EEXIST; 407f889d2efSBrooks Davis goto done; 408f889d2efSBrooks Davis } 409f889d2efSBrooks Davis /* 410f889d2efSBrooks Davis * Allocate the unit in the bitmap. 411f889d2efSBrooks Davis */ 412febd0759SAndrew Thompson KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) == 0, 413febd0759SAndrew Thompson ("%s: bit is already set", __func__)); 414f889d2efSBrooks Davis ifc->ifc_units[bytoff] |= (1 << bitoff); 415febd0759SAndrew Thompson IF_CLONE_ADDREF_LOCKED(ifc); 416f889d2efSBrooks Davis 417f889d2efSBrooks Davis done: 418f889d2efSBrooks Davis IF_CLONE_UNLOCK(ifc); 419f889d2efSBrooks Davis return (err); 420f889d2efSBrooks Davis } 421f889d2efSBrooks Davis 422f889d2efSBrooks Davis void 423f889d2efSBrooks Davis ifc_free_unit(struct if_clone *ifc, int unit) 424f889d2efSBrooks Davis { 425f889d2efSBrooks Davis int bytoff, bitoff; 426f889d2efSBrooks Davis 427f889d2efSBrooks Davis 428f889d2efSBrooks Davis /* 429f889d2efSBrooks Davis * Compute offset in the bitmap and deallocate the unit. 430f889d2efSBrooks Davis */ 431f889d2efSBrooks Davis bytoff = unit >> 3; 432f889d2efSBrooks Davis bitoff = unit - (bytoff << 3); 433f889d2efSBrooks Davis 434f889d2efSBrooks Davis IF_CLONE_LOCK(ifc); 435f889d2efSBrooks Davis KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0, 436f889d2efSBrooks Davis ("%s: bit is already cleared", __func__)); 437f889d2efSBrooks Davis ifc->ifc_units[bytoff] &= ~(1 << bitoff); 438febd0759SAndrew Thompson IF_CLONE_REMREF_LOCKED(ifc); /* releases lock */ 439f889d2efSBrooks Davis } 440f889d2efSBrooks Davis 441f889d2efSBrooks Davis void 442f889d2efSBrooks Davis ifc_simple_attach(struct if_clone *ifc) 443f889d2efSBrooks Davis { 444f889d2efSBrooks Davis int err; 445f889d2efSBrooks Davis int unit; 446f889d2efSBrooks Davis char name[IFNAMSIZ]; 447f889d2efSBrooks Davis struct ifc_simple_data *ifcs = ifc->ifc_data; 448f889d2efSBrooks Davis 449f889d2efSBrooks Davis KASSERT(ifcs->ifcs_minifs - 1 <= ifc->ifc_maxunit, 450f889d2efSBrooks Davis ("%s: %s requested more units then allowed (%d > %d)", 451f889d2efSBrooks Davis __func__, ifc->ifc_name, ifcs->ifcs_minifs, 452f889d2efSBrooks Davis ifc->ifc_maxunit + 1)); 453f889d2efSBrooks Davis 454f889d2efSBrooks Davis for (unit = 0; unit < ifcs->ifcs_minifs; unit++) { 455f889d2efSBrooks Davis snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, unit); 4564e7e0183SAndrew Thompson err = if_clone_createif(ifc, name, IFNAMSIZ); 457f889d2efSBrooks Davis KASSERT(err == 0, 458f889d2efSBrooks Davis ("%s: failed to create required interface %s", 459f889d2efSBrooks Davis __func__, name)); 460f889d2efSBrooks Davis } 461f889d2efSBrooks Davis } 462f889d2efSBrooks Davis 463f889d2efSBrooks Davis int 464f889d2efSBrooks Davis ifc_simple_match(struct if_clone *ifc, const char *name) 465f889d2efSBrooks Davis { 466f889d2efSBrooks Davis const char *cp; 467f889d2efSBrooks Davis int i; 468f889d2efSBrooks Davis 469f889d2efSBrooks Davis /* Match the name */ 470f889d2efSBrooks Davis for (cp = name, i = 0; i < strlen(ifc->ifc_name); i++, cp++) { 471f889d2efSBrooks Davis if (ifc->ifc_name[i] != *cp) 472f889d2efSBrooks Davis return (0); 473f889d2efSBrooks Davis } 474f889d2efSBrooks Davis 475f889d2efSBrooks Davis /* Make sure there's a unit number or nothing after the name */ 476f889d2efSBrooks Davis for (; *cp != '\0'; cp++) { 477f889d2efSBrooks Davis if (*cp < '0' || *cp > '9') 478f889d2efSBrooks Davis return (0); 479f889d2efSBrooks Davis } 480f889d2efSBrooks Davis 481f889d2efSBrooks Davis return (1); 482f889d2efSBrooks Davis } 483f889d2efSBrooks Davis 484f889d2efSBrooks Davis int 485f889d2efSBrooks Davis ifc_simple_create(struct if_clone *ifc, char *name, size_t len) 486f889d2efSBrooks Davis { 487f889d2efSBrooks Davis char *dp; 488f889d2efSBrooks Davis int wildcard; 489f889d2efSBrooks Davis int unit; 490f889d2efSBrooks Davis int err; 491f889d2efSBrooks Davis struct ifc_simple_data *ifcs = ifc->ifc_data; 492f889d2efSBrooks Davis 493f889d2efSBrooks Davis err = ifc_name2unit(name, &unit); 494f889d2efSBrooks Davis if (err != 0) 495f889d2efSBrooks Davis return (err); 496f889d2efSBrooks Davis 497f889d2efSBrooks Davis wildcard = (unit < 0); 498f889d2efSBrooks Davis 499f889d2efSBrooks Davis err = ifc_alloc_unit(ifc, &unit); 500f889d2efSBrooks Davis if (err != 0) 501f889d2efSBrooks Davis return (err); 502f889d2efSBrooks Davis 503f889d2efSBrooks Davis err = ifcs->ifcs_create(ifc, unit); 504f889d2efSBrooks Davis if (err != 0) { 505f889d2efSBrooks Davis ifc_free_unit(ifc, unit); 506f889d2efSBrooks Davis return (err); 507f889d2efSBrooks Davis } 508f889d2efSBrooks Davis 509f889d2efSBrooks Davis /* In the wildcard case, we need to update the name. */ 510f889d2efSBrooks Davis if (wildcard) { 511f889d2efSBrooks Davis for (dp = name; *dp != '\0'; dp++); 512f889d2efSBrooks Davis if (snprintf(dp, len - (dp-name), "%d", unit) > 513f889d2efSBrooks Davis len - (dp-name) - 1) { 514f889d2efSBrooks Davis /* 515f889d2efSBrooks Davis * This can only be a programmer error and 516f889d2efSBrooks Davis * there's no straightforward way to recover if 517f889d2efSBrooks Davis * it happens. 518f889d2efSBrooks Davis */ 519f889d2efSBrooks Davis panic("if_clone_create(): interface name too long"); 520f889d2efSBrooks Davis } 521f889d2efSBrooks Davis 522f889d2efSBrooks Davis } 523f889d2efSBrooks Davis 524f889d2efSBrooks Davis return (0); 525f889d2efSBrooks Davis } 526f889d2efSBrooks Davis 527f889d2efSBrooks Davis int 528f889d2efSBrooks Davis ifc_simple_destroy(struct if_clone *ifc, struct ifnet *ifp) 529f889d2efSBrooks Davis { 530f889d2efSBrooks Davis int unit; 531f889d2efSBrooks Davis struct ifc_simple_data *ifcs = ifc->ifc_data; 532f889d2efSBrooks Davis 533f889d2efSBrooks Davis unit = ifp->if_dunit; 534f889d2efSBrooks Davis 535f889d2efSBrooks Davis if (unit < ifcs->ifcs_minifs) 536f889d2efSBrooks Davis return (EINVAL); 537f889d2efSBrooks Davis 538f889d2efSBrooks Davis ifcs->ifcs_destroy(ifp); 539f889d2efSBrooks Davis 540f889d2efSBrooks Davis ifc_free_unit(ifc, unit); 541f889d2efSBrooks Davis 542f889d2efSBrooks Davis return (0); 543f889d2efSBrooks Davis } 544