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