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