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_private.h> 50 #include <net/if_clone.h> 51 #include <net/radix.h> 52 #include <net/route.h> 53 #include <net/vnet.h> 54 55 /* Current IF_MAXUNIT expands maximum to 5 characters. */ 56 #define IFCLOSIZ (IFNAMSIZ - 5) 57 58 /* 59 * Structure describing a `cloning' interface. 60 * 61 * List of locks 62 * (c) const until freeing 63 * (d) driver specific data, may need external protection. 64 * (e) locked by if_cloners_mtx 65 * (i) locked by ifc_mtx mtx 66 */ 67 struct if_clone { 68 char ifc_name[IFCLOSIZ]; /* (c) Name of device, e.g. `gif' */ 69 struct unrhdr *ifc_unrhdr; /* (c) alloc_unr(9) header */ 70 int ifc_maxunit; /* (c) maximum unit number */ 71 int ifc_flags; 72 long ifc_refcnt; /* (i) Reference count. */ 73 LIST_HEAD(, ifnet) ifc_iflist; /* (i) List of cloned interfaces */ 74 struct mtx ifc_mtx; /* Mutex to protect members. */ 75 76 ifc_match_f *ifc_match; /* (c) Matcher function */ 77 ifc_create_f *ifc_create; /* (c) Creates new interface */ 78 ifc_destroy_f *ifc_destroy; /* (c) Destroys cloned interface */ 79 80 #ifdef CLONE_COMPAT_13 81 /* (c) Driver specific cloning functions. Called with no locks held. */ 82 union { 83 struct { /* advanced cloner */ 84 ifc_create_t *_ifc_create; 85 ifc_destroy_t *_ifc_destroy; 86 } A; 87 struct { /* simple cloner */ 88 ifcs_create_t *_ifcs_create; 89 ifcs_destroy_t *_ifcs_destroy; 90 int _ifcs_minifs; /* minimum ifs */ 91 92 } S; 93 } U; 94 #define ifca_create U.A._ifc_create 95 #define ifca_destroy U.A._ifc_destroy 96 #define ifcs_create U.S._ifcs_create 97 #define ifcs_destroy U.S._ifcs_destroy 98 #define ifcs_minifs U.S._ifcs_minifs 99 #endif 100 101 LIST_ENTRY(if_clone) ifc_list; /* (e) On list of cloners */ 102 }; 103 104 105 106 static void if_clone_free(struct if_clone *ifc); 107 static int if_clone_createif(struct if_clone *ifc, char *name, size_t len, 108 struct ifc_data *ifd, struct ifnet **ifpp); 109 110 static int ifc_simple_match(struct if_clone *ifc, const char *name); 111 static int ifc_handle_unit(struct if_clone *ifc, char *name, size_t len, int *punit); 112 static struct if_clone *ifc_find_cloner(const char *name); 113 static struct if_clone *ifc_find_cloner_match(const char *name); 114 115 #ifdef CLONE_COMPAT_13 116 static int ifc_simple_create_wrapper(struct if_clone *ifc, char *name, size_t maxlen, 117 struct ifc_data *ifc_data, struct ifnet **ifpp); 118 static int ifc_advanced_create_wrapper(struct if_clone *ifc, char *name, size_t maxlen, 119 struct ifc_data *ifc_data, struct ifnet **ifpp); 120 #endif 121 122 static struct mtx if_cloners_mtx; 123 MTX_SYSINIT(if_cloners_lock, &if_cloners_mtx, "if_cloners lock", MTX_DEF); 124 VNET_DEFINE_STATIC(int, if_cloners_count); 125 VNET_DEFINE(LIST_HEAD(, if_clone), if_cloners); 126 127 #define V_if_cloners_count VNET(if_cloners_count) 128 #define V_if_cloners VNET(if_cloners) 129 130 #define IF_CLONERS_LOCK_ASSERT() mtx_assert(&if_cloners_mtx, MA_OWNED) 131 #define IF_CLONERS_LOCK() mtx_lock(&if_cloners_mtx) 132 #define IF_CLONERS_UNLOCK() mtx_unlock(&if_cloners_mtx) 133 134 #define IF_CLONE_LOCK_INIT(ifc) \ 135 mtx_init(&(ifc)->ifc_mtx, "if_clone lock", NULL, MTX_DEF) 136 #define IF_CLONE_LOCK_DESTROY(ifc) mtx_destroy(&(ifc)->ifc_mtx) 137 #define IF_CLONE_LOCK_ASSERT(ifc) mtx_assert(&(ifc)->ifc_mtx, MA_OWNED) 138 #define IF_CLONE_LOCK(ifc) mtx_lock(&(ifc)->ifc_mtx) 139 #define IF_CLONE_UNLOCK(ifc) mtx_unlock(&(ifc)->ifc_mtx) 140 141 #define IF_CLONE_ADDREF(ifc) \ 142 do { \ 143 IF_CLONE_LOCK(ifc); \ 144 IF_CLONE_ADDREF_LOCKED(ifc); \ 145 IF_CLONE_UNLOCK(ifc); \ 146 } while (0) 147 #define IF_CLONE_ADDREF_LOCKED(ifc) \ 148 do { \ 149 IF_CLONE_LOCK_ASSERT(ifc); \ 150 KASSERT((ifc)->ifc_refcnt >= 0, \ 151 ("negative refcnt %ld", (ifc)->ifc_refcnt)); \ 152 (ifc)->ifc_refcnt++; \ 153 } while (0) 154 #define IF_CLONE_REMREF(ifc) \ 155 do { \ 156 IF_CLONE_LOCK(ifc); \ 157 IF_CLONE_REMREF_LOCKED(ifc); \ 158 } while (0) 159 #define IF_CLONE_REMREF_LOCKED(ifc) \ 160 do { \ 161 IF_CLONE_LOCK_ASSERT(ifc); \ 162 KASSERT((ifc)->ifc_refcnt > 0, \ 163 ("bogus refcnt %ld", (ifc)->ifc_refcnt)); \ 164 if (--(ifc)->ifc_refcnt == 0) { \ 165 IF_CLONE_UNLOCK(ifc); \ 166 if_clone_free(ifc); \ 167 } else { \ 168 /* silently free the lock */ \ 169 IF_CLONE_UNLOCK(ifc); \ 170 } \ 171 } while (0) 172 173 #define IFC_IFLIST_INSERT(_ifc, _ifp) \ 174 LIST_INSERT_HEAD(&_ifc->ifc_iflist, _ifp, if_clones) 175 #define IFC_IFLIST_REMOVE(_ifc, _ifp) \ 176 LIST_REMOVE(_ifp, if_clones) 177 178 static MALLOC_DEFINE(M_CLONE, "clone", "interface cloning framework"); 179 180 void 181 vnet_if_clone_init(void) 182 { 183 184 LIST_INIT(&V_if_cloners); 185 } 186 187 /* 188 * Lookup and create a clone network interface. 189 */ 190 int 191 ifc_create_ifp(const char *name, struct ifc_data *ifd, 192 struct ifnet **ifpp) 193 { 194 struct if_clone *ifc; 195 char ifname[IFNAMSIZ]; 196 struct ifnet *ifp = NULL; 197 int error; 198 199 /* Try to find an applicable cloner for this request */ 200 ifc = ifc_find_cloner_match(name); 201 if (ifc == NULL) 202 return (EINVAL); 203 204 strlcpy(ifname, name, IFNAMSIZ); 205 error = if_clone_createif(ifc, ifname, IFNAMSIZ, ifd, &ifp); 206 if (ifpp != NULL) 207 *ifpp = ifp; 208 209 return (error); 210 } 211 212 int 213 if_clone_create(char *name, size_t len, caddr_t params) 214 { 215 struct ifc_data ifd = { .params = params }; 216 struct ifnet *ifp; 217 218 int error = ifc_create_ifp(name, &ifd, &ifp); 219 220 if (error == 0) 221 strlcpy(name, if_name(ifp), len); 222 223 return (error); 224 } 225 226 void 227 ifc_link_ifp(struct if_clone *ifc, struct ifnet *ifp) 228 { 229 230 if ((ifc->ifc_flags & IFC_NOGROUP) == 0) 231 if_addgroup(ifp, ifc->ifc_name); 232 233 IF_CLONE_LOCK(ifc); 234 IFC_IFLIST_INSERT(ifc, ifp); 235 IF_CLONE_UNLOCK(ifc); 236 } 237 238 void 239 if_clone_addif(struct if_clone *ifc, struct ifnet *ifp) 240 { 241 ifc_link_ifp(ifc, ifp); 242 } 243 244 bool 245 ifc_unlink_ifp(struct if_clone *ifc, struct ifnet *ifp) 246 { 247 struct ifnet *ifcifp; 248 249 IF_CLONE_LOCK(ifc); 250 LIST_FOREACH(ifcifp, &ifc->ifc_iflist, if_clones) { 251 if (ifcifp == ifp) { 252 IFC_IFLIST_REMOVE(ifc, ifp); 253 break; 254 } 255 } 256 IF_CLONE_UNLOCK(ifc); 257 258 if (ifcifp != NULL && (ifc->ifc_flags & IFC_F_NOGROUP) == 0) 259 if_delgroup(ifp, ifc->ifc_name); 260 261 return (ifcifp != NULL); 262 } 263 264 static struct if_clone * 265 ifc_find_cloner_match(const char *name) 266 { 267 struct if_clone *ifc; 268 269 IF_CLONERS_LOCK(); 270 LIST_FOREACH(ifc, &V_if_cloners, ifc_list) { 271 if (ifc->ifc_match(ifc, name)) 272 break; 273 } 274 IF_CLONERS_UNLOCK(); 275 276 return (ifc); 277 } 278 279 static struct if_clone * 280 ifc_find_cloner(const char *name) 281 { 282 struct if_clone *ifc; 283 284 IF_CLONERS_LOCK(); 285 LIST_FOREACH(ifc, &V_if_cloners, ifc_list) { 286 if (strcmp(ifc->ifc_name, name) == 0) { 287 break; 288 } 289 } 290 IF_CLONERS_UNLOCK(); 291 292 return (ifc); 293 } 294 295 static struct if_clone * 296 ifc_find_cloner_in_vnet(const char *name, struct vnet *vnet) 297 { 298 CURVNET_SET_QUIET(vnet); 299 struct if_clone *ifc = ifc_find_cloner(name); 300 CURVNET_RESTORE(); 301 302 return (ifc); 303 } 304 305 /* 306 * Create a clone network interface. 307 */ 308 static int 309 if_clone_createif(struct if_clone *ifc, char *name, size_t len, 310 struct ifc_data *ifd, struct ifnet **ifpp) 311 { 312 int err, unit = 0; 313 314 if (ifunit(name) != NULL) 315 return (EEXIST); 316 317 if (ifc->ifc_flags & IFC_F_AUTOUNIT) { 318 if ((err = ifc_handle_unit(ifc, name, len, &unit)) != 0) 319 return (err); 320 ifd->unit = unit; 321 } 322 *ifpp = NULL; 323 err = (*ifc->ifc_create)(ifc, name, len, ifd, ifpp); 324 325 if (err == 0) { 326 MPASS(*ifpp != NULL); 327 if_clone_addif(ifc, *ifpp); 328 } else if (ifc->ifc_flags & IFC_F_AUTOUNIT) 329 ifc_free_unit(ifc, unit); 330 331 return (err); 332 } 333 334 /* 335 * Lookup and destroy a clone network interface. 336 */ 337 int 338 if_clone_destroy(const char *name) 339 { 340 int err; 341 struct if_clone *ifc; 342 struct ifnet *ifp; 343 344 ifp = ifunit_ref(name); 345 if (ifp == NULL) 346 return (ENXIO); 347 348 ifc = ifc_find_cloner_in_vnet(ifp->if_dname, ifp->if_home_vnet); 349 if (ifc == NULL) { 350 if_rele(ifp); 351 return (EINVAL); 352 } 353 354 err = if_clone_destroyif(ifc, ifp); 355 if_rele(ifp); 356 return err; 357 } 358 359 /* 360 * Destroy a clone network interface. 361 */ 362 static int 363 if_clone_destroyif_flags(struct if_clone *ifc, struct ifnet *ifp, uint32_t flags) 364 { 365 int err; 366 367 /* 368 * Given that the cloned ifnet might be attached to a different 369 * vnet from where its cloner was registered, we have to 370 * switch to the vnet context of the target vnet. 371 */ 372 CURVNET_SET_QUIET(ifp->if_vnet); 373 374 if (!ifc_unlink_ifp(ifc, ifp)) { 375 CURVNET_RESTORE(); 376 return (ENXIO); /* ifp is not on the list. */ 377 } 378 379 int unit = ifp->if_dunit; 380 err = (*ifc->ifc_destroy)(ifc, ifp, flags); 381 382 if (err != 0) 383 ifc_link_ifp(ifc, ifp); 384 else if (ifc->ifc_flags & IFC_F_AUTOUNIT) 385 ifc_free_unit(ifc, unit); 386 CURVNET_RESTORE(); 387 return (err); 388 } 389 390 int 391 if_clone_destroyif(struct if_clone *ifc, struct ifnet *ifp) 392 { 393 return (if_clone_destroyif_flags(ifc, ifp, 0)); 394 } 395 396 static struct if_clone * 397 if_clone_alloc(const char *name, int maxunit) 398 { 399 struct if_clone *ifc; 400 401 KASSERT(name != NULL, ("%s: no name\n", __func__)); 402 403 ifc = malloc(sizeof(struct if_clone), M_CLONE, M_WAITOK | M_ZERO); 404 strncpy(ifc->ifc_name, name, IFCLOSIZ-1); 405 IF_CLONE_LOCK_INIT(ifc); 406 IF_CLONE_ADDREF(ifc); 407 ifc->ifc_maxunit = maxunit ? maxunit : IF_MAXUNIT; 408 ifc->ifc_unrhdr = new_unrhdr(0, ifc->ifc_maxunit, &ifc->ifc_mtx); 409 LIST_INIT(&ifc->ifc_iflist); 410 411 return (ifc); 412 } 413 414 static int 415 if_clone_attach(struct if_clone *ifc) 416 { 417 struct if_clone *ifc1; 418 419 IF_CLONERS_LOCK(); 420 LIST_FOREACH(ifc1, &V_if_cloners, ifc_list) 421 if (strcmp(ifc->ifc_name, ifc1->ifc_name) == 0) { 422 IF_CLONERS_UNLOCK(); 423 IF_CLONE_REMREF(ifc); 424 return (EEXIST); 425 } 426 LIST_INSERT_HEAD(&V_if_cloners, ifc, ifc_list); 427 V_if_cloners_count++; 428 IF_CLONERS_UNLOCK(); 429 430 return (0); 431 } 432 433 struct if_clone * 434 ifc_attach_cloner(const char *name, struct if_clone_addreq *req) 435 { 436 if (req->create_f == NULL || req->destroy_f == NULL) 437 return (NULL); 438 if (strnlen(name, IFCLOSIZ) >= (IFCLOSIZ - 1)) 439 return (NULL); 440 441 struct if_clone *ifc = if_clone_alloc(name, req->maxunit); 442 ifc->ifc_match = req->match_f != NULL ? req->match_f : ifc_simple_match; 443 ifc->ifc_create = req->create_f; 444 ifc->ifc_destroy = req->destroy_f; 445 ifc->ifc_flags = (req->flags & (IFC_F_AUTOUNIT | IFC_F_NOGROUP)); 446 447 if (if_clone_attach(ifc) != 0) 448 return (NULL); 449 450 EVENTHANDLER_INVOKE(if_clone_event, ifc); 451 452 return (ifc); 453 } 454 455 void 456 ifc_detach_cloner(struct if_clone *ifc) 457 { 458 if_clone_detach(ifc); 459 } 460 461 462 #ifdef CLONE_COMPAT_13 463 464 static int 465 ifc_advanced_create_wrapper(struct if_clone *ifc, char *name, size_t maxlen, 466 struct ifc_data *ifc_data, struct ifnet **ifpp) 467 { 468 int error = ifc->ifca_create(ifc, name, maxlen, ifc_data->params); 469 470 if (error == 0) 471 *ifpp = ifunit(name); 472 return (error); 473 } 474 475 static int 476 ifc_advanced_destroy_wrapper(struct if_clone *ifc, struct ifnet *ifp, uint32_t flags) 477 { 478 if (ifc->ifca_destroy == NULL) 479 return (ENOTSUP); 480 return (ifc->ifca_destroy(ifc, ifp)); 481 } 482 483 struct if_clone * 484 if_clone_advanced(const char *name, u_int maxunit, ifc_match_t match, 485 ifc_create_t create, ifc_destroy_t destroy) 486 { 487 struct if_clone *ifc; 488 489 ifc = if_clone_alloc(name, maxunit); 490 ifc->ifc_match = match; 491 ifc->ifc_create = ifc_advanced_create_wrapper; 492 ifc->ifc_destroy = ifc_advanced_destroy_wrapper; 493 ifc->ifca_destroy = destroy; 494 ifc->ifca_create = create; 495 496 if (if_clone_attach(ifc) != 0) 497 return (NULL); 498 499 EVENTHANDLER_INVOKE(if_clone_event, ifc); 500 501 return (ifc); 502 } 503 504 static int 505 ifc_simple_create_wrapper(struct if_clone *ifc, char *name, size_t maxlen, 506 struct ifc_data *ifc_data, struct ifnet **ifpp) 507 { 508 int unit = 0; 509 510 ifc_name2unit(name, &unit); 511 int error = ifc->ifcs_create(ifc, unit, ifc_data->params); 512 if (error == 0) 513 *ifpp = ifunit(name); 514 return (error); 515 } 516 517 static int 518 ifc_simple_destroy_wrapper(struct if_clone *ifc, struct ifnet *ifp, uint32_t flags) 519 { 520 if (ifp->if_dunit < ifc->ifcs_minifs && (flags & IFC_F_FORCE) == 0) 521 return (EINVAL); 522 523 ifc->ifcs_destroy(ifp); 524 return (0); 525 } 526 527 struct if_clone * 528 if_clone_simple(const char *name, ifcs_create_t create, ifcs_destroy_t destroy, 529 u_int minifs) 530 { 531 struct if_clone *ifc; 532 u_int unit; 533 534 ifc = if_clone_alloc(name, 0); 535 ifc->ifc_match = ifc_simple_match; 536 ifc->ifc_create = ifc_simple_create_wrapper; 537 ifc->ifc_destroy = ifc_simple_destroy_wrapper; 538 ifc->ifcs_create = create; 539 ifc->ifcs_destroy = destroy; 540 ifc->ifcs_minifs = minifs; 541 ifc->ifc_flags = IFC_F_AUTOUNIT; 542 543 if (if_clone_attach(ifc) != 0) 544 return (NULL); 545 546 for (unit = 0; unit < minifs; unit++) { 547 char name[IFNAMSIZ]; 548 int error __unused; 549 struct ifc_data ifd = {}; 550 struct ifnet *ifp; 551 552 snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, unit); 553 error = if_clone_createif(ifc, name, IFNAMSIZ, &ifd, &ifp); 554 KASSERT(error == 0, 555 ("%s: failed to create required interface %s", 556 __func__, name)); 557 } 558 559 EVENTHANDLER_INVOKE(if_clone_event, ifc); 560 561 return (ifc); 562 } 563 #endif 564 565 /* 566 * Unregister a network interface cloner. 567 */ 568 void 569 if_clone_detach(struct if_clone *ifc) 570 { 571 572 IF_CLONERS_LOCK(); 573 LIST_REMOVE(ifc, ifc_list); 574 V_if_cloners_count--; 575 IF_CLONERS_UNLOCK(); 576 577 /* destroy all interfaces for this cloner */ 578 while (!LIST_EMPTY(&ifc->ifc_iflist)) 579 if_clone_destroyif_flags(ifc, LIST_FIRST(&ifc->ifc_iflist), IFC_F_FORCE); 580 581 IF_CLONE_REMREF(ifc); 582 } 583 584 static void 585 if_clone_free(struct if_clone *ifc) 586 { 587 588 KASSERT(LIST_EMPTY(&ifc->ifc_iflist), 589 ("%s: ifc_iflist not empty", __func__)); 590 591 IF_CLONE_LOCK_DESTROY(ifc); 592 delete_unrhdr(ifc->ifc_unrhdr); 593 free(ifc, M_CLONE); 594 } 595 596 /* 597 * Provide list of interface cloners to userspace. 598 */ 599 int 600 if_clone_list(struct if_clonereq *ifcr) 601 { 602 char *buf, *dst, *outbuf = NULL; 603 struct if_clone *ifc; 604 int buf_count, count, err = 0; 605 606 if (ifcr->ifcr_count < 0) 607 return (EINVAL); 608 609 IF_CLONERS_LOCK(); 610 /* 611 * Set our internal output buffer size. We could end up not 612 * reporting a cloner that is added between the unlock and lock 613 * below, but that's not a major problem. Not caping our 614 * allocation to the number of cloners actually in the system 615 * could be because that would let arbitrary users cause us to 616 * allocate arbitrary amounts of kernel memory. 617 */ 618 buf_count = (V_if_cloners_count < ifcr->ifcr_count) ? 619 V_if_cloners_count : ifcr->ifcr_count; 620 IF_CLONERS_UNLOCK(); 621 622 outbuf = malloc(IFNAMSIZ*buf_count, M_CLONE, M_WAITOK | M_ZERO); 623 624 IF_CLONERS_LOCK(); 625 626 ifcr->ifcr_total = V_if_cloners_count; 627 if ((dst = ifcr->ifcr_buffer) == NULL) { 628 /* Just asking how many there are. */ 629 goto done; 630 } 631 count = (V_if_cloners_count < buf_count) ? 632 V_if_cloners_count : buf_count; 633 634 for (ifc = LIST_FIRST(&V_if_cloners), buf = outbuf; 635 ifc != NULL && count != 0; 636 ifc = LIST_NEXT(ifc, ifc_list), count--, buf += IFNAMSIZ) { 637 strlcpy(buf, ifc->ifc_name, IFNAMSIZ); 638 } 639 640 done: 641 IF_CLONERS_UNLOCK(); 642 if (err == 0 && dst != NULL) 643 err = copyout(outbuf, dst, buf_count*IFNAMSIZ); 644 if (outbuf != NULL) 645 free(outbuf, M_CLONE); 646 return (err); 647 } 648 649 #ifdef VIMAGE 650 /* 651 * if_clone_restoregroup() is used in context of if_vmove(). 652 * 653 * Since if_detach_internal() has removed the interface from ALL groups, we 654 * need to "restore" interface membership in the cloner's group. Note that 655 * interface belongs to cloner in its home vnet, so we first find the original 656 * cloner, and then we confirm that cloner with the same name exists in the 657 * current vnet. 658 */ 659 void 660 if_clone_restoregroup(struct ifnet *ifp) 661 { 662 struct if_clone *ifc; 663 struct ifnet *ifcifp; 664 char ifc_name[IFCLOSIZ] = { [0] = '\0' }; 665 666 CURVNET_SET_QUIET(ifp->if_home_vnet); 667 IF_CLONERS_LOCK(); 668 LIST_FOREACH(ifc, &V_if_cloners, ifc_list) { 669 IF_CLONE_LOCK(ifc); 670 LIST_FOREACH(ifcifp, &ifc->ifc_iflist, if_clones) { 671 if (ifp == ifcifp) { 672 strncpy(ifc_name, ifc->ifc_name, IFCLOSIZ-1); 673 break; 674 } 675 } 676 IF_CLONE_UNLOCK(ifc); 677 if (ifc_name[0] != '\0') 678 break; 679 } 680 CURVNET_RESTORE(); 681 LIST_FOREACH(ifc, &V_if_cloners, ifc_list) 682 if (strcmp(ifc->ifc_name, ifc_name) == 0 && 683 ((ifc->ifc_flags & IFC_NOGROUP) == 0)) 684 break; 685 IF_CLONERS_UNLOCK(); 686 687 if (ifc != NULL) 688 if_addgroup(ifp, ifc_name); 689 } 690 #endif 691 692 /* 693 * A utility function to extract unit numbers from interface names of 694 * the form name###. 695 * 696 * Returns 0 on success and an error on failure. 697 */ 698 int 699 ifc_name2unit(const char *name, int *unit) 700 { 701 const char *cp; 702 int cutoff = INT_MAX / 10; 703 int cutlim = INT_MAX % 10; 704 705 for (cp = name; *cp != '\0' && (*cp < '0' || *cp > '9'); cp++) 706 ; 707 if (*cp == '\0') { 708 *unit = -1; 709 } else if (cp[0] == '0' && cp[1] != '\0') { 710 /* Disallow leading zeroes. */ 711 return (EINVAL); 712 } else { 713 for (*unit = 0; *cp != '\0'; cp++) { 714 if (*cp < '0' || *cp > '9') { 715 /* Bogus unit number. */ 716 return (EINVAL); 717 } 718 if (*unit > cutoff || 719 (*unit == cutoff && *cp - '0' > cutlim)) 720 return (EINVAL); 721 *unit = (*unit * 10) + (*cp - '0'); 722 } 723 } 724 725 return (0); 726 } 727 728 static int 729 ifc_alloc_unit_specific(struct if_clone *ifc, int *unit) 730 { 731 char name[IFNAMSIZ]; 732 733 if (*unit > ifc->ifc_maxunit) 734 return (ENOSPC); 735 736 if (alloc_unr_specific(ifc->ifc_unrhdr, *unit) == -1) 737 return (EEXIST); 738 739 snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, *unit); 740 if (ifunit(name) != NULL) { 741 free_unr(ifc->ifc_unrhdr, *unit); 742 return (EEXIST); 743 } 744 745 IF_CLONE_ADDREF(ifc); 746 747 return (0); 748 } 749 750 static int 751 ifc_alloc_unit_next(struct if_clone *ifc, int *unit) 752 { 753 int error; 754 755 *unit = alloc_unr(ifc->ifc_unrhdr); 756 if (*unit == -1) 757 return (ENOSPC); 758 759 free_unr(ifc->ifc_unrhdr, *unit); 760 for (;;) { 761 error = ifc_alloc_unit_specific(ifc, unit); 762 if (error != EEXIST) 763 break; 764 765 (*unit)++; 766 } 767 768 return (error); 769 } 770 771 int 772 ifc_alloc_unit(struct if_clone *ifc, int *unit) 773 { 774 if (*unit < 0) 775 return (ifc_alloc_unit_next(ifc, unit)); 776 else 777 return (ifc_alloc_unit_specific(ifc, unit)); 778 } 779 780 void 781 ifc_free_unit(struct if_clone *ifc, int unit) 782 { 783 784 free_unr(ifc->ifc_unrhdr, unit); 785 IF_CLONE_REMREF(ifc); 786 } 787 788 static int 789 ifc_simple_match(struct if_clone *ifc, const char *name) 790 { 791 const char *cp; 792 int i; 793 794 /* Match the name */ 795 for (cp = name, i = 0; i < strlen(ifc->ifc_name); i++, cp++) { 796 if (ifc->ifc_name[i] != *cp) 797 return (0); 798 } 799 800 /* Make sure there's a unit number or nothing after the name */ 801 for (; *cp != '\0'; cp++) { 802 if (*cp < '0' || *cp > '9') 803 return (0); 804 } 805 806 return (1); 807 } 808 809 static int 810 ifc_handle_unit(struct if_clone *ifc, char *name, size_t len, int *punit) 811 { 812 char *dp; 813 int wildcard; 814 int unit; 815 int err; 816 817 err = ifc_name2unit(name, &unit); 818 if (err != 0) 819 return (err); 820 821 wildcard = (unit < 0); 822 823 err = ifc_alloc_unit(ifc, &unit); 824 if (err != 0) 825 return (err); 826 827 /* In the wildcard case, we need to update the name. */ 828 if (wildcard) { 829 for (dp = name; *dp != '\0'; dp++); 830 if (snprintf(dp, len - (dp-name), "%d", unit) > 831 len - (dp-name) - 1) { 832 /* 833 * This can only be a programmer error and 834 * there's no straightforward way to recover if 835 * it happens. 836 */ 837 panic("if_clone_create(): interface name too long"); 838 } 839 } 840 *punit = unit; 841 842 return (0); 843 } 844 845 int 846 ifc_copyin(const struct ifc_data *ifd, void *target, size_t len) 847 { 848 if (ifd->params == NULL) 849 return (EINVAL); 850 851 if (ifd->flags & IFC_F_SYSSPACE) { 852 memcpy(target, ifd->params, len); 853 return (0); 854 } else 855 return (copyin(ifd->params, target, len)); 856 } 857 858 const char * 859 ifc_name(struct if_clone *ifc) 860 { 861 return (ifc->ifc_name); 862 } 863 864 void 865 ifc_flags_set(struct if_clone *ifc, int flags) 866 { 867 ifc->ifc_flags = flags; 868 } 869 870 int 871 ifc_flags_get(struct if_clone *ifc) 872 { 873 return (ifc->ifc_flags); 874 } 875