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 < '0' || *cp > '9'); cp++) 586 ; 587 if (*cp == '\0') { 588 *unit = -1; 589 } else if (cp[0] == '0' && cp[1] != '\0') { 590 /* Disallow leading zeroes. */ 591 return (EINVAL); 592 } else { 593 for (*unit = 0; *cp != '\0'; cp++) { 594 if (*cp < '0' || *cp > '9') { 595 /* Bogus unit number. */ 596 return (EINVAL); 597 } 598 if (*unit > cutoff || 599 (*unit == cutoff && *cp - '0' > cutlim)) 600 return (EINVAL); 601 *unit = (*unit * 10) + (*cp - '0'); 602 } 603 } 604 605 return (0); 606 } 607 608 static int 609 ifc_alloc_unit_specific(struct if_clone *ifc, int *unit) 610 { 611 char name[IFNAMSIZ]; 612 613 if (*unit > ifc->ifc_maxunit) 614 return (ENOSPC); 615 616 if (alloc_unr_specific(ifc->ifc_unrhdr, *unit) == -1) 617 return (EEXIST); 618 619 snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, *unit); 620 if (ifunit(name) != NULL) { 621 free_unr(ifc->ifc_unrhdr, *unit); 622 return (EEXIST); 623 } 624 625 IF_CLONE_ADDREF(ifc); 626 627 return (0); 628 } 629 630 static int 631 ifc_alloc_unit_next(struct if_clone *ifc, int *unit) 632 { 633 int error; 634 635 *unit = alloc_unr(ifc->ifc_unrhdr); 636 if (*unit == -1) 637 return (ENOSPC); 638 639 free_unr(ifc->ifc_unrhdr, *unit); 640 for (;;) { 641 error = ifc_alloc_unit_specific(ifc, unit); 642 if (error != EEXIST) 643 break; 644 645 (*unit)++; 646 } 647 648 return (error); 649 } 650 651 int 652 ifc_alloc_unit(struct if_clone *ifc, int *unit) 653 { 654 if (*unit < 0) 655 return (ifc_alloc_unit_next(ifc, unit)); 656 else 657 return (ifc_alloc_unit_specific(ifc, unit)); 658 } 659 660 void 661 ifc_free_unit(struct if_clone *ifc, int unit) 662 { 663 664 free_unr(ifc->ifc_unrhdr, unit); 665 IF_CLONE_REMREF(ifc); 666 } 667 668 static int 669 ifc_simple_match(struct if_clone *ifc, const char *name) 670 { 671 const char *cp; 672 int i; 673 674 /* Match the name */ 675 for (cp = name, i = 0; i < strlen(ifc->ifc_name); i++, cp++) { 676 if (ifc->ifc_name[i] != *cp) 677 return (0); 678 } 679 680 /* Make sure there's a unit number or nothing after the name */ 681 for (; *cp != '\0'; cp++) { 682 if (*cp < '0' || *cp > '9') 683 return (0); 684 } 685 686 return (1); 687 } 688 689 static int 690 ifc_simple_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) 691 { 692 char *dp; 693 int wildcard; 694 int unit; 695 int err; 696 697 err = ifc_name2unit(name, &unit); 698 if (err != 0) 699 return (err); 700 701 wildcard = (unit < 0); 702 703 err = ifc_alloc_unit(ifc, &unit); 704 if (err != 0) 705 return (err); 706 707 err = ifc->ifcs_create(ifc, unit, params); 708 if (err != 0) { 709 ifc_free_unit(ifc, unit); 710 return (err); 711 } 712 713 /* In the wildcard case, we need to update the name. */ 714 if (wildcard) { 715 for (dp = name; *dp != '\0'; dp++); 716 if (snprintf(dp, len - (dp-name), "%d", unit) > 717 len - (dp-name) - 1) { 718 /* 719 * This can only be a programmer error and 720 * there's no straightforward way to recover if 721 * it happens. 722 */ 723 panic("if_clone_create(): interface name too long"); 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 } 764