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 return (NULL); 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 return (NULL); 413 414 for (unit = 0; unit < minifs; unit++) { 415 char name[IFNAMSIZ]; 416 int error; 417 418 snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, unit); 419 error = if_clone_createif(ifc, name, IFNAMSIZ, NULL); 420 KASSERT(error == 0, 421 ("%s: failed to create required interface %s", 422 __func__, name)); 423 } 424 425 EVENTHANDLER_INVOKE(if_clone_event, ifc); 426 427 return (ifc); 428 } 429 430 /* 431 * Unregister a network interface cloner. 432 */ 433 void 434 if_clone_detach(struct if_clone *ifc) 435 { 436 437 IF_CLONERS_LOCK(); 438 LIST_REMOVE(ifc, ifc_list); 439 V_if_cloners_count--; 440 IF_CLONERS_UNLOCK(); 441 442 /* Allow all simples to be destroyed */ 443 if (ifc->ifc_type == SIMPLE) 444 ifc->ifcs_minifs = 0; 445 446 /* destroy all interfaces for this cloner */ 447 while (!LIST_EMPTY(&ifc->ifc_iflist)) 448 if_clone_destroyif(ifc, LIST_FIRST(&ifc->ifc_iflist)); 449 450 IF_CLONE_REMREF(ifc); 451 } 452 453 static void 454 if_clone_free(struct if_clone *ifc) 455 { 456 457 KASSERT(LIST_EMPTY(&ifc->ifc_iflist), 458 ("%s: ifc_iflist not empty", __func__)); 459 460 IF_CLONE_LOCK_DESTROY(ifc); 461 delete_unrhdr(ifc->ifc_unrhdr); 462 free(ifc, M_CLONE); 463 } 464 465 /* 466 * Provide list of interface cloners to userspace. 467 */ 468 int 469 if_clone_list(struct if_clonereq *ifcr) 470 { 471 char *buf, *dst, *outbuf = NULL; 472 struct if_clone *ifc; 473 int buf_count, count, err = 0; 474 475 if (ifcr->ifcr_count < 0) 476 return (EINVAL); 477 478 IF_CLONERS_LOCK(); 479 /* 480 * Set our internal output buffer size. We could end up not 481 * reporting a cloner that is added between the unlock and lock 482 * below, but that's not a major problem. Not caping our 483 * allocation to the number of cloners actually in the system 484 * could be because that would let arbitrary users cause us to 485 * allocate arbitrary amounts of kernel memory. 486 */ 487 buf_count = (V_if_cloners_count < ifcr->ifcr_count) ? 488 V_if_cloners_count : ifcr->ifcr_count; 489 IF_CLONERS_UNLOCK(); 490 491 outbuf = malloc(IFNAMSIZ*buf_count, M_CLONE, M_WAITOK | M_ZERO); 492 493 IF_CLONERS_LOCK(); 494 495 ifcr->ifcr_total = V_if_cloners_count; 496 if ((dst = ifcr->ifcr_buffer) == NULL) { 497 /* Just asking how many there are. */ 498 goto done; 499 } 500 count = (V_if_cloners_count < buf_count) ? 501 V_if_cloners_count : buf_count; 502 503 for (ifc = LIST_FIRST(&V_if_cloners), buf = outbuf; 504 ifc != NULL && count != 0; 505 ifc = LIST_NEXT(ifc, ifc_list), count--, buf += IFNAMSIZ) { 506 strlcpy(buf, ifc->ifc_name, IFNAMSIZ); 507 } 508 509 done: 510 IF_CLONERS_UNLOCK(); 511 if (err == 0 && dst != NULL) 512 err = copyout(outbuf, dst, buf_count*IFNAMSIZ); 513 if (outbuf != NULL) 514 free(outbuf, M_CLONE); 515 return (err); 516 } 517 518 /* 519 * if_clone_findifc() looks up ifnet from the current 520 * cloner list, and returns ifc if found. Note that ifc_refcnt 521 * is incremented. 522 */ 523 struct if_clone * 524 if_clone_findifc(struct ifnet *ifp) 525 { 526 struct if_clone *ifc, *ifc0; 527 struct ifnet *ifcifp; 528 529 ifc0 = NULL; 530 IF_CLONERS_LOCK(); 531 LIST_FOREACH(ifc, &V_if_cloners, ifc_list) { 532 IF_CLONE_LOCK(ifc); 533 LIST_FOREACH(ifcifp, &ifc->ifc_iflist, if_clones) { 534 if (ifp == ifcifp) { 535 ifc0 = ifc; 536 IF_CLONE_ADDREF_LOCKED(ifc); 537 break; 538 } 539 } 540 IF_CLONE_UNLOCK(ifc); 541 if (ifc0 != NULL) 542 break; 543 } 544 IF_CLONERS_UNLOCK(); 545 546 return (ifc0); 547 } 548 549 /* 550 * if_clone_addgroup() decrements ifc_refcnt because it is called after 551 * if_clone_findifc(). 552 */ 553 void 554 if_clone_addgroup(struct ifnet *ifp, struct if_clone *ifc) 555 { 556 557 if_addgroup(ifp, ifc->ifc_name); 558 IF_CLONE_REMREF(ifc); 559 } 560 561 /* 562 * A utility function to extract unit numbers from interface names of 563 * the form name###. 564 * 565 * Returns 0 on success and an error on failure. 566 */ 567 int 568 ifc_name2unit(const char *name, int *unit) 569 { 570 const char *cp; 571 int cutoff = INT_MAX / 10; 572 int cutlim = INT_MAX % 10; 573 574 for (cp = name; *cp != '\0' && (*cp < '0' || *cp > '9'); cp++); 575 if (*cp == '\0') { 576 *unit = -1; 577 } else if (cp[0] == '0' && cp[1] != '\0') { 578 /* Disallow leading zeroes. */ 579 return (EINVAL); 580 } else { 581 for (*unit = 0; *cp != '\0'; cp++) { 582 if (*cp < '0' || *cp > '9') { 583 /* Bogus unit number. */ 584 return (EINVAL); 585 } 586 if (*unit > cutoff || 587 (*unit == cutoff && *cp - '0' > cutlim)) 588 return (EINVAL); 589 *unit = (*unit * 10) + (*cp - '0'); 590 } 591 } 592 593 return (0); 594 } 595 596 static int 597 ifc_alloc_unit_specific(struct if_clone *ifc, int *unit) 598 { 599 char name[IFNAMSIZ]; 600 601 if (*unit > ifc->ifc_maxunit) 602 return (ENOSPC); 603 604 if (alloc_unr_specific(ifc->ifc_unrhdr, *unit) == -1) 605 return (EEXIST); 606 607 snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, *unit); 608 if (ifunit(name) != NULL) { 609 free_unr(ifc->ifc_unrhdr, *unit); 610 return (EEXIST); 611 } 612 613 IF_CLONE_ADDREF(ifc); 614 615 return (0); 616 } 617 618 static int 619 ifc_alloc_unit_next(struct if_clone *ifc, int *unit) 620 { 621 int error; 622 623 *unit = alloc_unr(ifc->ifc_unrhdr); 624 if (*unit == -1) 625 return (ENOSPC); 626 627 free_unr(ifc->ifc_unrhdr, *unit); 628 for (;;) { 629 error = ifc_alloc_unit_specific(ifc, unit); 630 if (error != EEXIST) 631 break; 632 633 (*unit)++; 634 } 635 636 return (error); 637 } 638 639 int 640 ifc_alloc_unit(struct if_clone *ifc, int *unit) 641 { 642 if (*unit < 0) 643 return (ifc_alloc_unit_next(ifc, unit)); 644 else 645 return (ifc_alloc_unit_specific(ifc, unit)); 646 } 647 648 void 649 ifc_free_unit(struct if_clone *ifc, int unit) 650 { 651 652 free_unr(ifc->ifc_unrhdr, unit); 653 IF_CLONE_REMREF(ifc); 654 } 655 656 static int 657 ifc_simple_match(struct if_clone *ifc, const char *name) 658 { 659 const char *cp; 660 int i; 661 662 /* Match the name */ 663 for (cp = name, i = 0; i < strlen(ifc->ifc_name); i++, cp++) { 664 if (ifc->ifc_name[i] != *cp) 665 return (0); 666 } 667 668 /* Make sure there's a unit number or nothing after the name */ 669 for (; *cp != '\0'; cp++) { 670 if (*cp < '0' || *cp > '9') 671 return (0); 672 } 673 674 return (1); 675 } 676 677 static int 678 ifc_simple_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) 679 { 680 char *dp; 681 int wildcard; 682 int unit; 683 int err; 684 685 err = ifc_name2unit(name, &unit); 686 if (err != 0) 687 return (err); 688 689 wildcard = (unit < 0); 690 691 err = ifc_alloc_unit(ifc, &unit); 692 if (err != 0) 693 return (err); 694 695 err = ifc->ifcs_create(ifc, unit, params); 696 if (err != 0) { 697 ifc_free_unit(ifc, unit); 698 return (err); 699 } 700 701 /* In the wildcard case, we need to update the name. */ 702 if (wildcard) { 703 for (dp = name; *dp != '\0'; dp++); 704 if (snprintf(dp, len - (dp-name), "%d", unit) > 705 len - (dp-name) - 1) { 706 /* 707 * This can only be a programmer error and 708 * there's no straightforward way to recover if 709 * it happens. 710 */ 711 panic("if_clone_create(): interface name too long"); 712 } 713 714 } 715 716 return (0); 717 } 718 719 static int 720 ifc_simple_destroy(struct if_clone *ifc, struct ifnet *ifp) 721 { 722 int unit; 723 724 unit = ifp->if_dunit; 725 726 if (unit < ifc->ifcs_minifs) 727 return (EINVAL); 728 729 ifc->ifcs_destroy(ifp); 730 731 ifc_free_unit(ifc, unit); 732 733 return (0); 734 } 735