The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net/if_clone.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-3-Clause
    3  *
    4  * Copyright (c) 2012 Gleb Smirnoff <glebius@FreeBSD.org>
    5  * Copyright (c) 1980, 1986, 1993
    6  *      The Regents of the University of California.  All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. Neither the name of the University nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  *      @(#)if.c        8.5 (Berkeley) 1/9/95
   33  * $FreeBSD$
   34  */
   35 
   36 #include <sys/param.h>
   37 #include <sys/eventhandler.h>
   38 #include <sys/malloc.h>
   39 #include <sys/limits.h>
   40 #include <sys/lock.h>
   41 #include <sys/mutex.h>
   42 #include <sys/kernel.h>
   43 #include <sys/systm.h>
   44 #include <sys/types.h>
   45 #include <sys/socket.h>
   46 
   47 #include <net/if.h>
   48 #include <net/if_var.h>
   49 #include <net/if_clone.h>
   50 #include <net/radix.h>
   51 #include <net/route.h>
   52 #include <net/vnet.h>
   53 
   54 /* Current IF_MAXUNIT expands maximum to 5 characters. */
   55 #define IFCLOSIZ        (IFNAMSIZ - 5)
   56 
   57 /*
   58  * Structure describing a `cloning' interface.
   59  *
   60  * List of locks
   61  * (c)          const until freeing
   62  * (d)          driver specific data, may need external protection.
   63  * (e)          locked by if_cloners_mtx
   64  * (i)          locked by ifc_mtx mtx
   65  */
   66 struct if_clone {
   67         char ifc_name[IFCLOSIZ];        /* (c) Name of device, e.g. `gif' */
   68         struct unrhdr *ifc_unrhdr;      /* (c) alloc_unr(9) header */
   69         int ifc_maxunit;                /* (c) maximum unit number */
   70         int ifc_flags;
   71         long ifc_refcnt;                /* (i) Reference count. */
   72         LIST_HEAD(, ifnet) ifc_iflist;  /* (i) List of cloned interfaces */
   73         struct mtx ifc_mtx;             /* Mutex to protect members. */
   74 
   75         enum { SIMPLE, ADVANCED } ifc_type; /* (c) */
   76 
   77         /* (c) Driver specific cloning functions.  Called with no locks held. */
   78         union {
   79                 struct {        /* advanced cloner */
   80                         ifc_match_t     *_ifc_match;
   81                         ifc_create_t    *_ifc_create;
   82                         ifc_destroy_t   *_ifc_destroy;
   83                 } A;
   84                 struct {        /* simple cloner */
   85                         ifcs_create_t   *_ifcs_create;
   86                         ifcs_destroy_t  *_ifcs_destroy;
   87                         int             _ifcs_minifs;   /* minimum ifs */
   88 
   89                 } S;
   90         } U;
   91 #define ifc_match       U.A._ifc_match
   92 #define ifc_create      U.A._ifc_create
   93 #define ifc_destroy     U.A._ifc_destroy
   94 #define ifcs_create     U.S._ifcs_create
   95 #define ifcs_destroy    U.S._ifcs_destroy
   96 #define ifcs_minifs     U.S._ifcs_minifs
   97 
   98         LIST_ENTRY(if_clone) ifc_list;  /* (e) On list of cloners */
   99 };
  100 
  101 static void     if_clone_free(struct if_clone *ifc);
  102 static int      if_clone_createif(struct if_clone *ifc, char *name, size_t len,
  103                     caddr_t params);
  104 
  105 static int     ifc_simple_match(struct if_clone *, const char *);
  106 static int     ifc_simple_create(struct if_clone *, char *, size_t, caddr_t);
  107 static int     ifc_simple_destroy(struct if_clone *, struct ifnet *);
  108 
  109 static struct mtx if_cloners_mtx;
  110 MTX_SYSINIT(if_cloners_lock, &if_cloners_mtx, "if_cloners lock", MTX_DEF);
  111 VNET_DEFINE_STATIC(int, if_cloners_count);
  112 VNET_DEFINE(LIST_HEAD(, if_clone), if_cloners);
  113 
  114 #define V_if_cloners_count      VNET(if_cloners_count)
  115 #define V_if_cloners            VNET(if_cloners)
  116 
  117 #define IF_CLONERS_LOCK_ASSERT()        mtx_assert(&if_cloners_mtx, MA_OWNED)
  118 #define IF_CLONERS_LOCK()               mtx_lock(&if_cloners_mtx)
  119 #define IF_CLONERS_UNLOCK()             mtx_unlock(&if_cloners_mtx)
  120 
  121 #define IF_CLONE_LOCK_INIT(ifc)         \
  122     mtx_init(&(ifc)->ifc_mtx, "if_clone lock", NULL, MTX_DEF)
  123 #define IF_CLONE_LOCK_DESTROY(ifc)      mtx_destroy(&(ifc)->ifc_mtx)
  124 #define IF_CLONE_LOCK_ASSERT(ifc)       mtx_assert(&(ifc)->ifc_mtx, MA_OWNED)
  125 #define IF_CLONE_LOCK(ifc)              mtx_lock(&(ifc)->ifc_mtx)
  126 #define IF_CLONE_UNLOCK(ifc)            mtx_unlock(&(ifc)->ifc_mtx)
  127 
  128 #define IF_CLONE_ADDREF(ifc)                                            \
  129         do {                                                            \
  130                 IF_CLONE_LOCK(ifc);                                     \
  131                 IF_CLONE_ADDREF_LOCKED(ifc);                            \
  132                 IF_CLONE_UNLOCK(ifc);                                   \
  133         } while (0)
  134 #define IF_CLONE_ADDREF_LOCKED(ifc)                                     \
  135         do {                                                            \
  136                 IF_CLONE_LOCK_ASSERT(ifc);                              \
  137                 KASSERT((ifc)->ifc_refcnt >= 0,                         \
  138                     ("negative refcnt %ld", (ifc)->ifc_refcnt));        \
  139                 (ifc)->ifc_refcnt++;                                    \
  140         } while (0)
  141 #define IF_CLONE_REMREF(ifc)                                            \
  142         do {                                                            \
  143                 IF_CLONE_LOCK(ifc);                                     \
  144                 IF_CLONE_REMREF_LOCKED(ifc);                            \
  145         } while (0)
  146 #define IF_CLONE_REMREF_LOCKED(ifc)                                     \
  147         do {                                                            \
  148                 IF_CLONE_LOCK_ASSERT(ifc);                              \
  149                 KASSERT((ifc)->ifc_refcnt > 0,                          \
  150                     ("bogus refcnt %ld", (ifc)->ifc_refcnt));           \
  151                 if (--(ifc)->ifc_refcnt == 0) {                         \
  152                         IF_CLONE_UNLOCK(ifc);                           \
  153                         if_clone_free(ifc);                             \
  154                 } else {                                                \
  155                         /* silently free the lock */                    \
  156                         IF_CLONE_UNLOCK(ifc);                           \
  157                 }                                                       \
  158         } while (0)
  159 
  160 #define IFC_IFLIST_INSERT(_ifc, _ifp)                                   \
  161         LIST_INSERT_HEAD(&_ifc->ifc_iflist, _ifp, if_clones)
  162 #define IFC_IFLIST_REMOVE(_ifc, _ifp)                                   \
  163         LIST_REMOVE(_ifp, if_clones)
  164 
  165 static MALLOC_DEFINE(M_CLONE, "clone", "interface cloning framework");
  166 
  167 void
  168 vnet_if_clone_init(void)
  169 {
  170 
  171         LIST_INIT(&V_if_cloners);
  172 }
  173 
  174 /*
  175  * Lookup and create a clone network interface.
  176  */
  177 int
  178 if_clone_create(char *name, size_t len, caddr_t params)
  179 {
  180         struct if_clone *ifc;
  181 
  182         /* Try to find an applicable cloner for this request */
  183         IF_CLONERS_LOCK();
  184         LIST_FOREACH(ifc, &V_if_cloners, ifc_list)
  185                 if (ifc->ifc_type == SIMPLE) {
  186                         if (ifc_simple_match(ifc, name))
  187                                 break;
  188                 } else {
  189                         if (ifc->ifc_match(ifc, name))
  190                                 break;
  191                 }
  192 #ifdef VIMAGE
  193         if (ifc == NULL && !IS_DEFAULT_VNET(curvnet)) {
  194                 CURVNET_SET_QUIET(vnet0);
  195                 LIST_FOREACH(ifc, &V_if_cloners, ifc_list)
  196                         if (ifc->ifc_type == SIMPLE) {
  197                                 if (ifc_simple_match(ifc, name))
  198                                         break;
  199                         } else {
  200                                 if (ifc->ifc_match(ifc, name))
  201                                         break;
  202                         }
  203                 CURVNET_RESTORE();
  204         }
  205 #endif
  206         IF_CLONERS_UNLOCK();
  207 
  208         if (ifc == NULL)
  209                 return (EINVAL);
  210 
  211         return (if_clone_createif(ifc, name, len, params));
  212 }
  213 
  214 void
  215 if_clone_addif(struct if_clone *ifc, struct ifnet *ifp)
  216 {
  217 
  218         if ((ifc->ifc_flags & IFC_NOGROUP) == 0)
  219                 if_addgroup(ifp, ifc->ifc_name);
  220 
  221         IF_CLONE_LOCK(ifc);
  222         IFC_IFLIST_INSERT(ifc, ifp);
  223         IF_CLONE_UNLOCK(ifc);
  224 }
  225 
  226 /*
  227  * Create a clone network interface.
  228  */
  229 static int
  230 if_clone_createif(struct if_clone *ifc, char *name, size_t len, caddr_t params)
  231 {
  232         int err;
  233         struct ifnet *ifp;
  234 
  235         if (ifunit(name) != NULL)
  236                 return (EEXIST);
  237 
  238         if (ifc->ifc_type == SIMPLE)
  239                 err = ifc_simple_create(ifc, name, len, params);
  240         else
  241                 err = (*ifc->ifc_create)(ifc, name, len, params);
  242         
  243         if (!err) {
  244                 ifp = ifunit(name);
  245                 if (ifp == NULL)
  246                         panic("%s: lookup failed for %s", __func__, name);
  247 
  248                 if_clone_addif(ifc, ifp);
  249         }
  250 
  251         return (err);
  252 }
  253 
  254 /*
  255  * Lookup and destroy a clone network interface.
  256  */
  257 int
  258 if_clone_destroy(const char *name)
  259 {
  260         int err;
  261         struct if_clone *ifc;
  262         struct ifnet *ifp;
  263 
  264         ifp = ifunit_ref(name);
  265         if (ifp == NULL)
  266                 return (ENXIO);
  267 
  268         /* Find the cloner for this interface */
  269         IF_CLONERS_LOCK();
  270         LIST_FOREACH(ifc, &V_if_cloners, ifc_list) {
  271                 if (strcmp(ifc->ifc_name, ifp->if_dname) == 0) {
  272                         break;
  273                 }
  274         }
  275 #ifdef VIMAGE
  276         if (ifc == NULL && !IS_DEFAULT_VNET(curvnet)) {
  277                 CURVNET_SET_QUIET(vnet0);
  278                 LIST_FOREACH(ifc, &V_if_cloners, ifc_list)
  279                         if (ifc->ifc_type == SIMPLE) {
  280                                 if (ifc_simple_match(ifc, name))
  281                                         break;
  282                         } else {
  283                                 if (ifc->ifc_match(ifc, name))
  284                                         break;
  285                         }
  286                 CURVNET_RESTORE();
  287         }
  288 #endif
  289         IF_CLONERS_UNLOCK();
  290         if (ifc == NULL) {
  291                 if_rele(ifp);
  292                 return (EINVAL);
  293         }
  294 
  295         err = if_clone_destroyif(ifc, ifp);
  296         if_rele(ifp);
  297         return err;
  298 }
  299 
  300 /*
  301  * Destroy a clone network interface.
  302  */
  303 int
  304 if_clone_destroyif(struct if_clone *ifc, struct ifnet *ifp)
  305 {
  306         int err;
  307         struct ifnet *ifcifp;
  308 
  309         if (ifc->ifc_type == ADVANCED && ifc->ifc_destroy == NULL)
  310                 return(EOPNOTSUPP);
  311 
  312         /*
  313          * Given that the cloned ifnet might be attached to a different
  314          * vnet from where its cloner was registered, we have to
  315          * switch to the vnet context of the target vnet.
  316          */
  317         CURVNET_SET_QUIET(ifp->if_vnet);
  318 
  319         IF_CLONE_LOCK(ifc);
  320         LIST_FOREACH(ifcifp, &ifc->ifc_iflist, if_clones) {
  321                 if (ifcifp == ifp) {
  322                         IFC_IFLIST_REMOVE(ifc, ifp);
  323                         break;
  324                 }
  325         }
  326         IF_CLONE_UNLOCK(ifc);
  327         if (ifcifp == NULL) {
  328                 CURVNET_RESTORE();
  329                 return (ENXIO);         /* ifp is not on the list. */
  330         }
  331         if ((ifc->ifc_flags & IFC_NOGROUP) == 0)
  332                 if_delgroup(ifp, ifc->ifc_name);
  333 
  334         if (ifc->ifc_type == SIMPLE)
  335                 err = ifc_simple_destroy(ifc, ifp);
  336         else
  337                 err = (*ifc->ifc_destroy)(ifc, ifp);
  338 
  339         if (err != 0) {
  340                 if ((ifc->ifc_flags & IFC_NOGROUP) == 0)
  341                         if_addgroup(ifp, ifc->ifc_name);
  342 
  343                 IF_CLONE_LOCK(ifc);
  344                 IFC_IFLIST_INSERT(ifc, ifp);
  345                 IF_CLONE_UNLOCK(ifc);
  346         }
  347         CURVNET_RESTORE();
  348         return (err);
  349 }
  350 
  351 static struct if_clone *
  352 if_clone_alloc(const char *name, int maxunit)
  353 {
  354         struct if_clone *ifc;
  355 
  356         KASSERT(name != NULL, ("%s: no name\n", __func__));
  357 
  358         ifc = malloc(sizeof(struct if_clone), M_CLONE, M_WAITOK | M_ZERO);
  359         strncpy(ifc->ifc_name, name, IFCLOSIZ-1);
  360         IF_CLONE_LOCK_INIT(ifc);
  361         IF_CLONE_ADDREF(ifc);
  362         ifc->ifc_maxunit = maxunit ? maxunit : IF_MAXUNIT;
  363         ifc->ifc_unrhdr = new_unrhdr(0, ifc->ifc_maxunit, &ifc->ifc_mtx);
  364         LIST_INIT(&ifc->ifc_iflist);
  365 
  366         return (ifc);
  367 }
  368 
  369 static int
  370 if_clone_attach(struct if_clone *ifc)
  371 {
  372         struct if_clone *ifc1;
  373 
  374         IF_CLONERS_LOCK();
  375         LIST_FOREACH(ifc1, &V_if_cloners, ifc_list)
  376                 if (strcmp(ifc->ifc_name, ifc1->ifc_name) == 0) {
  377                         IF_CLONERS_UNLOCK();
  378                         IF_CLONE_REMREF(ifc);
  379                         return (EEXIST);
  380                 }
  381         LIST_INSERT_HEAD(&V_if_cloners, ifc, ifc_list);
  382         V_if_cloners_count++;
  383         IF_CLONERS_UNLOCK();
  384 
  385         return (0);
  386 }
  387 
  388 struct if_clone *
  389 if_clone_advanced(const char *name, u_int maxunit, ifc_match_t match,
  390         ifc_create_t create, ifc_destroy_t destroy)
  391 {
  392         struct if_clone *ifc;
  393 
  394         ifc = if_clone_alloc(name, maxunit);
  395         ifc->ifc_type = ADVANCED;
  396         ifc->ifc_match = match;
  397         ifc->ifc_create = create;
  398         ifc->ifc_destroy = destroy;
  399 
  400         if (if_clone_attach(ifc) != 0)
  401                 return (NULL);
  402 
  403         EVENTHANDLER_INVOKE(if_clone_event, ifc);
  404 
  405         return (ifc);
  406 }
  407 
  408 struct if_clone *
  409 if_clone_simple(const char *name, ifcs_create_t create, ifcs_destroy_t destroy,
  410         u_int minifs)
  411 {
  412         struct if_clone *ifc;
  413         u_int unit;
  414 
  415         ifc = if_clone_alloc(name, 0);
  416         ifc->ifc_type = SIMPLE;
  417         ifc->ifcs_create = create;
  418         ifc->ifcs_destroy = destroy;
  419         ifc->ifcs_minifs = minifs;
  420 
  421         if (if_clone_attach(ifc) != 0)
  422                 return (NULL);
  423 
  424         for (unit = 0; unit < minifs; unit++) {
  425                 char name[IFNAMSIZ];
  426                 int error __unused;
  427 
  428                 snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, unit);
  429                 error = if_clone_createif(ifc, name, IFNAMSIZ, NULL);
  430                 KASSERT(error == 0,
  431                     ("%s: failed to create required interface %s",
  432                     __func__, name));
  433         }
  434 
  435         EVENTHANDLER_INVOKE(if_clone_event, ifc);
  436 
  437         return (ifc);
  438 }
  439 
  440 /*
  441  * Unregister a network interface cloner.
  442  */
  443 void
  444 if_clone_detach(struct if_clone *ifc)
  445 {
  446 
  447         IF_CLONERS_LOCK();
  448         LIST_REMOVE(ifc, ifc_list);
  449         V_if_cloners_count--;
  450         IF_CLONERS_UNLOCK();
  451 
  452         /* Allow all simples to be destroyed */
  453         if (ifc->ifc_type == SIMPLE)
  454                 ifc->ifcs_minifs = 0;
  455 
  456         /* destroy all interfaces for this cloner */
  457         while (!LIST_EMPTY(&ifc->ifc_iflist))
  458                 if_clone_destroyif(ifc, LIST_FIRST(&ifc->ifc_iflist));
  459 
  460         IF_CLONE_REMREF(ifc);
  461 }
  462 
  463 static void
  464 if_clone_free(struct if_clone *ifc)
  465 {
  466 
  467         KASSERT(LIST_EMPTY(&ifc->ifc_iflist),
  468             ("%s: ifc_iflist not empty", __func__));
  469 
  470         IF_CLONE_LOCK_DESTROY(ifc);
  471         delete_unrhdr(ifc->ifc_unrhdr);
  472         free(ifc, M_CLONE);
  473 }
  474 
  475 /*
  476  * Provide list of interface cloners to userspace.
  477  */
  478 int
  479 if_clone_list(struct if_clonereq *ifcr)
  480 {
  481         char *buf, *dst, *outbuf = NULL;
  482         struct if_clone *ifc;
  483         int buf_count, count, err = 0;
  484 
  485         if (ifcr->ifcr_count < 0)
  486                 return (EINVAL);
  487 
  488         IF_CLONERS_LOCK();
  489         /*
  490          * Set our internal output buffer size.  We could end up not
  491          * reporting a cloner that is added between the unlock and lock
  492          * below, but that's not a major problem.  Not caping our
  493          * allocation to the number of cloners actually in the system
  494          * could be because that would let arbitrary users cause us to
  495          * allocate arbitrary amounts of kernel memory.
  496          */
  497         buf_count = (V_if_cloners_count < ifcr->ifcr_count) ?
  498             V_if_cloners_count : ifcr->ifcr_count;
  499         IF_CLONERS_UNLOCK();
  500 
  501         outbuf = malloc(IFNAMSIZ*buf_count, M_CLONE, M_WAITOK | M_ZERO);
  502 
  503         IF_CLONERS_LOCK();
  504 
  505         ifcr->ifcr_total = V_if_cloners_count;
  506         if ((dst = ifcr->ifcr_buffer) == NULL) {
  507                 /* Just asking how many there are. */
  508                 goto done;
  509         }
  510         count = (V_if_cloners_count < buf_count) ?
  511             V_if_cloners_count : buf_count;
  512 
  513         for (ifc = LIST_FIRST(&V_if_cloners), buf = outbuf;
  514             ifc != NULL && count != 0;
  515             ifc = LIST_NEXT(ifc, ifc_list), count--, buf += IFNAMSIZ) {
  516                 strlcpy(buf, ifc->ifc_name, IFNAMSIZ);
  517         }
  518 
  519 done:
  520         IF_CLONERS_UNLOCK();
  521         if (err == 0 && dst != NULL)
  522                 err = copyout(outbuf, dst, buf_count*IFNAMSIZ);
  523         if (outbuf != NULL)
  524                 free(outbuf, M_CLONE);
  525         return (err);
  526 }
  527 
  528 /*
  529  * if_clone_findifc() looks up ifnet from the current
  530  * cloner list, and returns ifc if found.  Note that ifc_refcnt
  531  * is incremented.
  532  */
  533 struct if_clone *
  534 if_clone_findifc(struct ifnet *ifp)
  535 {
  536         struct if_clone *ifc, *ifc0;
  537         struct ifnet *ifcifp;
  538 
  539         ifc0 = NULL;
  540         IF_CLONERS_LOCK();
  541         LIST_FOREACH(ifc, &V_if_cloners, ifc_list) {
  542                 IF_CLONE_LOCK(ifc);
  543                 LIST_FOREACH(ifcifp, &ifc->ifc_iflist, if_clones) {
  544                         if (ifp == ifcifp) {
  545                                 ifc0 = ifc;
  546                                 IF_CLONE_ADDREF_LOCKED(ifc);
  547                                 break;
  548                         }
  549                 }
  550                 IF_CLONE_UNLOCK(ifc);
  551                 if (ifc0 != NULL)
  552                         break;
  553         }
  554         IF_CLONERS_UNLOCK();
  555 
  556         return (ifc0);
  557 }
  558 
  559 /*
  560  * if_clone_addgroup() decrements ifc_refcnt because it is called after
  561  * if_clone_findifc().
  562  */
  563 void
  564 if_clone_addgroup(struct ifnet *ifp, struct if_clone *ifc)
  565 {
  566         if ((ifc->ifc_flags & IFC_NOGROUP) == 0) {
  567                 if_addgroup(ifp, ifc->ifc_name);
  568                 IF_CLONE_REMREF(ifc);
  569         }
  570 }
  571 
  572 /*
  573  * A utility function to extract unit numbers from interface names of
  574  * the form name###.
  575  *
  576  * Returns 0 on success and an error on failure.
  577  */
  578 int
  579 ifc_name2unit(const char *name, int *unit)
  580 {
  581         const char      *cp;
  582         int             cutoff = INT_MAX / 10;
  583         int             cutlim = INT_MAX % 10;
  584 
  585         for (cp = name; *cp != '\0' && (*cp < '' || *cp > '9'); cp++);
  586         if (*cp == '\0') {
  587                 *unit = -1;
  588         } else if (cp[0] == '' && cp[1] != '\0') {
  589                 /* Disallow leading zeroes. */
  590                 return (EINVAL);
  591         } else {
  592                 for (*unit = 0; *cp != '\0'; cp++) {
  593                         if (*cp < '' || *cp > '9') {
  594                                 /* Bogus unit number. */
  595                                 return (EINVAL);
  596                         }
  597                         if (*unit > cutoff ||
  598                             (*unit == cutoff && *cp - '' > cutlim))
  599                                 return (EINVAL);
  600                         *unit = (*unit * 10) + (*cp - '');
  601                 }
  602         }
  603 
  604         return (0);
  605 }
  606 
  607 static int
  608 ifc_alloc_unit_specific(struct if_clone *ifc, int *unit)
  609 {
  610         char name[IFNAMSIZ];
  611 
  612         if (*unit > ifc->ifc_maxunit)
  613                 return (ENOSPC);
  614 
  615         if (alloc_unr_specific(ifc->ifc_unrhdr, *unit) == -1)
  616                 return (EEXIST);
  617 
  618         snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, *unit);
  619         if (ifunit(name) != NULL) {
  620                 free_unr(ifc->ifc_unrhdr, *unit);
  621                 return (EEXIST);
  622         }
  623 
  624         IF_CLONE_ADDREF(ifc);
  625 
  626         return (0);
  627 }
  628 
  629 static int
  630 ifc_alloc_unit_next(struct if_clone *ifc, int *unit)
  631 {
  632         int error;
  633 
  634         *unit = alloc_unr(ifc->ifc_unrhdr);
  635         if (*unit == -1)
  636                 return (ENOSPC);
  637 
  638         free_unr(ifc->ifc_unrhdr, *unit);
  639         for (;;) {
  640                 error = ifc_alloc_unit_specific(ifc, unit);
  641                 if (error != EEXIST)
  642                         break;
  643 
  644                 (*unit)++;
  645         }
  646 
  647         return (error);
  648 }
  649 
  650 int
  651 ifc_alloc_unit(struct if_clone *ifc, int *unit)
  652 {
  653         if (*unit < 0)
  654                 return (ifc_alloc_unit_next(ifc, unit));
  655         else
  656                 return (ifc_alloc_unit_specific(ifc, unit));
  657 }
  658 
  659 void
  660 ifc_free_unit(struct if_clone *ifc, int unit)
  661 {
  662 
  663         free_unr(ifc->ifc_unrhdr, unit);
  664         IF_CLONE_REMREF(ifc);
  665 }
  666 
  667 static int
  668 ifc_simple_match(struct if_clone *ifc, const char *name)
  669 {
  670         const char *cp;
  671         int i;
  672         
  673         /* Match the name */
  674         for (cp = name, i = 0; i < strlen(ifc->ifc_name); i++, cp++) {
  675                 if (ifc->ifc_name[i] != *cp)
  676                         return (0);
  677         }
  678 
  679         /* Make sure there's a unit number or nothing after the name */
  680         for (; *cp != '\0'; cp++) {
  681                 if (*cp < '' || *cp > '9')
  682                         return (0);
  683         }
  684 
  685         return (1);
  686 }
  687 
  688 static int
  689 ifc_simple_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
  690 {
  691         char *dp;
  692         int wildcard;
  693         int unit;
  694         int err;
  695 
  696         err = ifc_name2unit(name, &unit);
  697         if (err != 0)
  698                 return (err);
  699 
  700         wildcard = (unit < 0);
  701 
  702         err = ifc_alloc_unit(ifc, &unit);
  703         if (err != 0)
  704                 return (err);
  705 
  706         err = ifc->ifcs_create(ifc, unit, params);
  707         if (err != 0) {
  708                 ifc_free_unit(ifc, unit);
  709                 return (err);
  710         }
  711 
  712         /* In the wildcard case, we need to update the name. */
  713         if (wildcard) {
  714                 for (dp = name; *dp != '\0'; dp++);
  715                 if (snprintf(dp, len - (dp-name), "%d", unit) >
  716                     len - (dp-name) - 1) {
  717                         /*
  718                          * This can only be a programmer error and
  719                          * there's no straightforward way to recover if
  720                          * it happens.
  721                          */
  722                         panic("if_clone_create(): interface name too long");
  723                 }
  724 
  725         }
  726 
  727         return (0);
  728 }
  729 
  730 static int
  731 ifc_simple_destroy(struct if_clone *ifc, struct ifnet *ifp)
  732 {
  733         int unit;
  734 
  735         unit = ifp->if_dunit;
  736 
  737         if (unit < ifc->ifcs_minifs) 
  738                 return (EINVAL);
  739 
  740         ifc->ifcs_destroy(ifp);
  741 
  742         ifc_free_unit(ifc, unit);
  743 
  744         return (0);
  745 }
  746 
  747 const char *
  748 ifc_name(struct if_clone *ifc)
  749 {
  750         return (ifc->ifc_name);
  751 }
  752 
  753 void
  754 ifc_flags_set(struct if_clone *ifc, int flags)
  755 {
  756         ifc->ifc_flags = flags;
  757 }
  758 
  759 int
  760 ifc_flags_get(struct if_clone *ifc)
  761 {
  762         return (ifc->ifc_flags);
  763 }

Cache object: a6df1cd9c9f4b4fed7ad04fdb40d98f2


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.