1 /*- 2 * Copyright (c) 1980, 1986, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 4. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * @(#)if.c 8.5 (Berkeley) 1/9/95 30 * $FreeBSD$ 31 */ 32 33 #include <sys/param.h> 34 #include <sys/malloc.h> 35 #include <sys/limits.h> 36 #include <sys/lock.h> 37 #include <sys/mutex.h> 38 #include <sys/kernel.h> 39 #include <sys/systm.h> 40 #include <sys/types.h> 41 #include <sys/socket.h> 42 43 #include <net/if.h> 44 #include <net/if_clone.h> 45 #if 0 46 #include <net/if_dl.h> 47 #endif 48 #include <net/if_types.h> 49 #include <net/if_var.h> 50 #include <net/radix.h> 51 #include <net/route.h> 52 53 static void if_clone_free(struct if_clone *ifc); 54 static int if_clone_createif(struct if_clone *ifc, char *name, size_t len, 55 caddr_t params); 56 57 static struct mtx if_cloners_mtx; 58 static int if_cloners_count; 59 LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners); 60 61 #define IF_CLONERS_LOCK_INIT() \ 62 mtx_init(&if_cloners_mtx, "if_cloners lock", NULL, MTX_DEF) 63 #define IF_CLONERS_LOCK_ASSERT() mtx_assert(&if_cloners_mtx, MA_OWNED) 64 #define IF_CLONERS_LOCK() mtx_lock(&if_cloners_mtx) 65 #define IF_CLONERS_UNLOCK() mtx_unlock(&if_cloners_mtx) 66 67 #define IF_CLONE_LOCK_INIT(ifc) \ 68 mtx_init(&(ifc)->ifc_mtx, "if_clone lock", NULL, MTX_DEF) 69 #define IF_CLONE_LOCK_DESTROY(ifc) mtx_destroy(&(ifc)->ifc_mtx) 70 #define IF_CLONE_LOCK_ASSERT(ifc) mtx_assert(&(ifc)->ifc_mtx, MA_OWNED) 71 #define IF_CLONE_LOCK(ifc) mtx_lock(&(ifc)->ifc_mtx) 72 #define IF_CLONE_UNLOCK(ifc) mtx_unlock(&(ifc)->ifc_mtx) 73 74 #define IF_CLONE_ADDREF(ifc) \ 75 do { \ 76 IF_CLONE_LOCK(ifc); \ 77 IF_CLONE_ADDREF_LOCKED(ifc); \ 78 IF_CLONE_UNLOCK(ifc); \ 79 } while (0) 80 #define IF_CLONE_ADDREF_LOCKED(ifc) \ 81 do { \ 82 IF_CLONE_LOCK_ASSERT(ifc); \ 83 KASSERT((ifc)->ifc_refcnt >= 0, \ 84 ("negative refcnt %ld", (ifc)->ifc_refcnt)); \ 85 (ifc)->ifc_refcnt++; \ 86 } while (0) 87 #define IF_CLONE_REMREF(ifc) \ 88 do { \ 89 IF_CLONE_LOCK(ifc); \ 90 IF_CLONE_REMREF_LOCKED(ifc); \ 91 } while (0) 92 #define IF_CLONE_REMREF_LOCKED(ifc) \ 93 do { \ 94 IF_CLONE_LOCK_ASSERT(ifc); \ 95 KASSERT((ifc)->ifc_refcnt > 0, \ 96 ("bogus refcnt %ld", (ifc)->ifc_refcnt)); \ 97 if (--(ifc)->ifc_refcnt == 0) { \ 98 IF_CLONE_UNLOCK(ifc); \ 99 if_clone_free(ifc); \ 100 } else { \ 101 /* silently free the lock */ \ 102 IF_CLONE_UNLOCK(ifc); \ 103 } \ 104 } while (0) 105 106 #define IFC_IFLIST_INSERT(_ifc, _ifp) \ 107 LIST_INSERT_HEAD(&_ifc->ifc_iflist, _ifp, if_clones) 108 #define IFC_IFLIST_REMOVE(_ifc, _ifp) \ 109 LIST_REMOVE(_ifp, if_clones) 110 111 static MALLOC_DEFINE(M_CLONE, "clone", "interface cloning framework"); 112 113 void 114 if_clone_init(void) 115 { 116 IF_CLONERS_LOCK_INIT(); 117 } 118 119 /* 120 * Lookup and create a clone network interface. 121 */ 122 int 123 if_clone_create(char *name, size_t len, caddr_t params) 124 { 125 struct if_clone *ifc; 126 127 /* Try to find an applicable cloner for this request */ 128 IF_CLONERS_LOCK(); 129 LIST_FOREACH(ifc, &if_cloners, ifc_list) { 130 if (ifc->ifc_match(ifc, name)) { 131 break; 132 } 133 } 134 IF_CLONERS_UNLOCK(); 135 136 if (ifc == NULL) 137 return (EINVAL); 138 139 return (if_clone_createif(ifc, name, len, params)); 140 } 141 142 /* 143 * Create a clone network interface. 144 */ 145 static int 146 if_clone_createif(struct if_clone *ifc, char *name, size_t len, caddr_t params) 147 { 148 int err; 149 struct ifnet *ifp; 150 151 if (ifunit(name) != NULL) 152 return (EEXIST); 153 154 err = (*ifc->ifc_create)(ifc, name, len, params); 155 156 if (!err) { 157 ifp = ifunit(name); 158 if (ifp == NULL) 159 panic("%s: lookup failed for %s", __func__, name); 160 161 if_addgroup(ifp, ifc->ifc_name); 162 163 IF_CLONE_LOCK(ifc); 164 IFC_IFLIST_INSERT(ifc, ifp); 165 IF_CLONE_UNLOCK(ifc); 166 } 167 168 return (err); 169 } 170 171 /* 172 * Lookup and destroy a clone network interface. 173 */ 174 int 175 if_clone_destroy(const char *name) 176 { 177 struct if_clone *ifc; 178 struct ifnet *ifp; 179 180 ifp = ifunit(name); 181 if (ifp == NULL) 182 return (ENXIO); 183 184 /* Find the cloner for this interface */ 185 IF_CLONERS_LOCK(); 186 LIST_FOREACH(ifc, &if_cloners, ifc_list) { 187 if (strcmp(ifc->ifc_name, ifp->if_dname) == 0) { 188 break; 189 } 190 } 191 IF_CLONERS_UNLOCK(); 192 if (ifc == NULL) 193 return (EINVAL); 194 195 return (if_clone_destroyif(ifc, ifp)); 196 } 197 198 /* 199 * Destroy a clone network interface. 200 */ 201 int 202 if_clone_destroyif(struct if_clone *ifc, struct ifnet *ifp) 203 { 204 int err; 205 206 if (ifc->ifc_destroy == NULL) { 207 err = EOPNOTSUPP; 208 goto done; 209 } 210 211 IF_CLONE_LOCK(ifc); 212 IFC_IFLIST_REMOVE(ifc, ifp); 213 IF_CLONE_UNLOCK(ifc); 214 215 if_delgroup(ifp, ifc->ifc_name); 216 217 err = (*ifc->ifc_destroy)(ifc, ifp); 218 219 if (err != 0) { 220 if_addgroup(ifp, ifc->ifc_name); 221 222 IF_CLONE_LOCK(ifc); 223 IFC_IFLIST_INSERT(ifc, ifp); 224 IF_CLONE_UNLOCK(ifc); 225 } 226 227 done: 228 return (err); 229 } 230 231 /* 232 * Register a network interface cloner. 233 */ 234 void 235 if_clone_attach(struct if_clone *ifc) 236 { 237 int len, maxclone; 238 239 /* 240 * Compute bitmap size and allocate it. 241 */ 242 maxclone = ifc->ifc_maxunit + 1; 243 len = maxclone >> 3; 244 if ((len << 3) < maxclone) 245 len++; 246 ifc->ifc_units = malloc(len, M_CLONE, M_WAITOK | M_ZERO); 247 ifc->ifc_bmlen = len; 248 IF_CLONE_LOCK_INIT(ifc); 249 IF_CLONE_ADDREF(ifc); 250 251 IF_CLONERS_LOCK(); 252 LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list); 253 if_cloners_count++; 254 IF_CLONERS_UNLOCK(); 255 256 LIST_INIT(&ifc->ifc_iflist); 257 258 if (ifc->ifc_attach != NULL) 259 (*ifc->ifc_attach)(ifc); 260 EVENTHANDLER_INVOKE(if_clone_event, ifc); 261 } 262 263 /* 264 * Unregister a network interface cloner. 265 */ 266 void 267 if_clone_detach(struct if_clone *ifc) 268 { 269 struct ifc_simple_data *ifcs = ifc->ifc_data; 270 271 IF_CLONERS_LOCK(); 272 LIST_REMOVE(ifc, ifc_list); 273 if_cloners_count--; 274 IF_CLONERS_UNLOCK(); 275 276 /* Allow all simples to be destroyed */ 277 if (ifc->ifc_attach == ifc_simple_attach) 278 ifcs->ifcs_minifs = 0; 279 280 /* destroy all interfaces for this cloner */ 281 while (!LIST_EMPTY(&ifc->ifc_iflist)) 282 if_clone_destroyif(ifc, LIST_FIRST(&ifc->ifc_iflist)); 283 284 IF_CLONE_REMREF(ifc); 285 } 286 287 static void 288 if_clone_free(struct if_clone *ifc) 289 { 290 for (int bytoff = 0; bytoff < ifc->ifc_bmlen; bytoff++) { 291 KASSERT(ifc->ifc_units[bytoff] == 0x00, 292 ("ifc_units[%d] is not empty", bytoff)); 293 } 294 295 KASSERT(LIST_EMPTY(&ifc->ifc_iflist), 296 ("%s: ifc_iflist not empty", __func__)); 297 298 IF_CLONE_LOCK_DESTROY(ifc); 299 free(ifc->ifc_units, M_CLONE); 300 } 301 302 /* 303 * Provide list of interface cloners to userspace. 304 */ 305 int 306 if_clone_list(struct if_clonereq *ifcr) 307 { 308 char *buf, *dst, *outbuf = NULL; 309 struct if_clone *ifc; 310 int buf_count, count, err = 0; 311 312 if (ifcr->ifcr_count < 0) 313 return (EINVAL); 314 315 IF_CLONERS_LOCK(); 316 /* 317 * Set our internal output buffer size. We could end up not 318 * reporting a cloner that is added between the unlock and lock 319 * below, but that's not a major problem. Not caping our 320 * allocation to the number of cloners actually in the system 321 * could be because that would let arbitrary users cause us to 322 * allocate abritrary amounts of kernel memory. 323 */ 324 buf_count = (if_cloners_count < ifcr->ifcr_count) ? 325 if_cloners_count : ifcr->ifcr_count; 326 IF_CLONERS_UNLOCK(); 327 328 outbuf = malloc(IFNAMSIZ*buf_count, M_CLONE, M_WAITOK | M_ZERO); 329 330 IF_CLONERS_LOCK(); 331 332 ifcr->ifcr_total = if_cloners_count; 333 if ((dst = ifcr->ifcr_buffer) == NULL) { 334 /* Just asking how many there are. */ 335 goto done; 336 } 337 count = (if_cloners_count < buf_count) ? 338 if_cloners_count : buf_count; 339 340 for (ifc = LIST_FIRST(&if_cloners), buf = outbuf; 341 ifc != NULL && count != 0; 342 ifc = LIST_NEXT(ifc, ifc_list), count--, buf += IFNAMSIZ) { 343 strlcpy(buf, ifc->ifc_name, IFNAMSIZ); 344 } 345 346 done: 347 IF_CLONERS_UNLOCK(); 348 if (err == 0) 349 err = copyout(outbuf, dst, buf_count*IFNAMSIZ); 350 if (outbuf != NULL) 351 free(outbuf, M_CLONE); 352 return (err); 353 } 354 355 /* 356 * A utility function to extract unit numbers from interface names of 357 * the form name###. 358 * 359 * Returns 0 on success and an error on failure. 360 */ 361 int 362 ifc_name2unit(const char *name, int *unit) 363 { 364 const char *cp; 365 int cutoff = INT_MAX / 10; 366 int cutlim = INT_MAX % 10; 367 368 for (cp = name; *cp != '\0' && (*cp < '0' || *cp > '9'); cp++); 369 if (*cp == '\0') { 370 *unit = -1; 371 } else if (cp[0] == '0' && cp[1] != '\0') { 372 /* Disallow leading zeroes. */ 373 return (EINVAL); 374 } else { 375 for (*unit = 0; *cp != '\0'; cp++) { 376 if (*cp < '0' || *cp > '9') { 377 /* Bogus unit number. */ 378 return (EINVAL); 379 } 380 if (*unit > cutoff || 381 (*unit == cutoff && *cp - '0' > cutlim)) 382 return (EINVAL); 383 *unit = (*unit * 10) + (*cp - '0'); 384 } 385 } 386 387 return (0); 388 } 389 390 int 391 ifc_alloc_unit(struct if_clone *ifc, int *unit) 392 { 393 int wildcard, bytoff, bitoff; 394 int err = 0; 395 396 IF_CLONE_LOCK(ifc); 397 398 bytoff = bitoff = 0; 399 wildcard = (*unit < 0); 400 /* 401 * Find a free unit if none was given. 402 */ 403 if (wildcard) { 404 while ((bytoff < ifc->ifc_bmlen) 405 && (ifc->ifc_units[bytoff] == 0xff)) 406 bytoff++; 407 if (bytoff >= ifc->ifc_bmlen) { 408 err = ENOSPC; 409 goto done; 410 } 411 while ((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0) 412 bitoff++; 413 *unit = (bytoff << 3) + bitoff; 414 } 415 416 if (*unit > ifc->ifc_maxunit) { 417 err = ENOSPC; 418 goto done; 419 } 420 421 if (!wildcard) { 422 bytoff = *unit >> 3; 423 bitoff = *unit - (bytoff << 3); 424 } 425 426 if((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0) { 427 err = EEXIST; 428 goto done; 429 } 430 /* 431 * Allocate the unit in the bitmap. 432 */ 433 KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) == 0, 434 ("%s: bit is already set", __func__)); 435 ifc->ifc_units[bytoff] |= (1 << bitoff); 436 IF_CLONE_ADDREF_LOCKED(ifc); 437 438 done: 439 IF_CLONE_UNLOCK(ifc); 440 return (err); 441 } 442 443 void 444 ifc_free_unit(struct if_clone *ifc, int unit) 445 { 446 int bytoff, bitoff; 447 448 449 /* 450 * Compute offset in the bitmap and deallocate the unit. 451 */ 452 bytoff = unit >> 3; 453 bitoff = unit - (bytoff << 3); 454 455 IF_CLONE_LOCK(ifc); 456 KASSERT((ifc->ifc_units[bytoff] & (1 << bitoff)) != 0, 457 ("%s: bit is already cleared", __func__)); 458 ifc->ifc_units[bytoff] &= ~(1 << bitoff); 459 IF_CLONE_REMREF_LOCKED(ifc); /* releases lock */ 460 } 461 462 void 463 ifc_simple_attach(struct if_clone *ifc) 464 { 465 int err; 466 int unit; 467 char name[IFNAMSIZ]; 468 struct ifc_simple_data *ifcs = ifc->ifc_data; 469 470 KASSERT(ifcs->ifcs_minifs - 1 <= ifc->ifc_maxunit, 471 ("%s: %s requested more units than allowed (%d > %d)", 472 __func__, ifc->ifc_name, ifcs->ifcs_minifs, 473 ifc->ifc_maxunit + 1)); 474 475 for (unit = 0; unit < ifcs->ifcs_minifs; unit++) { 476 snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, unit); 477 err = if_clone_createif(ifc, name, IFNAMSIZ, NULL); 478 KASSERT(err == 0, 479 ("%s: failed to create required interface %s", 480 __func__, name)); 481 } 482 } 483 484 int 485 ifc_simple_match(struct if_clone *ifc, const char *name) 486 { 487 const char *cp; 488 int i; 489 490 /* Match the name */ 491 for (cp = name, i = 0; i < strlen(ifc->ifc_name); i++, cp++) { 492 if (ifc->ifc_name[i] != *cp) 493 return (0); 494 } 495 496 /* Make sure there's a unit number or nothing after the name */ 497 for (; *cp != '\0'; cp++) { 498 if (*cp < '0' || *cp > '9') 499 return (0); 500 } 501 502 return (1); 503 } 504 505 int 506 ifc_simple_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) 507 { 508 char *dp; 509 int wildcard; 510 int unit; 511 int err; 512 struct ifc_simple_data *ifcs = ifc->ifc_data; 513 514 err = ifc_name2unit(name, &unit); 515 if (err != 0) 516 return (err); 517 518 wildcard = (unit < 0); 519 520 err = ifc_alloc_unit(ifc, &unit); 521 if (err != 0) 522 return (err); 523 524 err = ifcs->ifcs_create(ifc, unit, params); 525 if (err != 0) { 526 ifc_free_unit(ifc, unit); 527 return (err); 528 } 529 530 /* In the wildcard case, we need to update the name. */ 531 if (wildcard) { 532 for (dp = name; *dp != '\0'; dp++); 533 if (snprintf(dp, len - (dp-name), "%d", unit) > 534 len - (dp-name) - 1) { 535 /* 536 * This can only be a programmer error and 537 * there's no straightforward way to recover if 538 * it happens. 539 */ 540 panic("if_clone_create(): interface name too long"); 541 } 542 543 } 544 545 return (0); 546 } 547 548 int 549 ifc_simple_destroy(struct if_clone *ifc, struct ifnet *ifp) 550 { 551 int unit; 552 struct ifc_simple_data *ifcs = ifc->ifc_data; 553 554 unit = ifp->if_dunit; 555 556 if (unit < ifcs->ifcs_minifs) 557 return (EINVAL); 558 559 ifcs->ifcs_destroy(ifp); 560 561 ifc_free_unit(ifc, unit); 562 563 return (0); 564 } 565