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

Cache object: 2b54e161f7b4f25d2d702550029602dd


[ 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.