1 /*- 2 * Copyright 1998 Massachusetts Institute of Technology 3 * 4 * Permission to use, copy, modify, and distribute this software and 5 * its documentation for any purpose and without fee is hereby 6 * granted, provided that both the above copyright notice and this 7 * permission notice appear in all copies, that both the above 8 * copyright notice and this permission notice appear in all 9 * supporting documentation, and that the name of M.I.T. not be used 10 * in advertising or publicity pertaining to distribution of the 11 * software without specific, written prior permission. M.I.T. makes 12 * no representations about the suitability of this software for any 13 * purpose. It is provided "as is" without express or implied 14 * warranty. 15 * 16 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 17 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 20 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 23 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD$ 30 */ 31 32 /* 33 * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs. 34 * Might be extended some day to also handle IEEE 802.1p priority 35 * tagging. This is sort of sneaky in the implementation, since 36 * we need to pretend to be enough of an Ethernet implementation 37 * to make arp work. The way we do this is by telling everyone 38 * that we are an Ethernet, and then catch the packets that 39 * ether_output() left on our output queue when it calls 40 * if_start(), rewrite them for use by the real outgoing interface, 41 * and ask it to send them. 42 */ 43 44 #include "opt_inet.h" 45 #include "opt_vlan.h" 46 47 #include <sys/param.h> 48 #include <sys/kernel.h> 49 #include <sys/lock.h> 50 #include <sys/malloc.h> 51 #include <sys/mbuf.h> 52 #include <sys/module.h> 53 #include <sys/rwlock.h> 54 #include <sys/queue.h> 55 #include <sys/socket.h> 56 #include <sys/sockio.h> 57 #include <sys/sysctl.h> 58 #include <sys/systm.h> 59 60 #include <net/bpf.h> 61 #include <net/ethernet.h> 62 #include <net/if.h> 63 #include <net/if_clone.h> 64 #include <net/if_arp.h> 65 #include <net/if_dl.h> 66 #include <net/if_types.h> 67 #include <net/if_vlan_var.h> 68 69 #ifdef INET 70 #include <netinet/in.h> 71 #include <netinet/if_ether.h> 72 #endif 73 74 #define VLANNAME "vlan" 75 #define VLAN_DEF_HWIDTH 4 76 #define VLAN_IFFLAGS (IFF_BROADCAST | IFF_MULTICAST) 77 78 LIST_HEAD(ifvlanhead, ifvlan); 79 80 struct ifvlantrunk { 81 struct ifnet *parent; /* parent interface of this trunk */ 82 struct rwlock rw; 83 #ifdef VLAN_ARRAY 84 #define VLAN_ARRAY_SIZE (EVL_VLID_MASK + 1) 85 struct ifvlan *vlans[VLAN_ARRAY_SIZE]; /* static table */ 86 #else 87 struct ifvlanhead *hash; /* dynamic hash-list table */ 88 uint16_t hmask; 89 uint16_t hwidth; 90 #endif 91 int refcnt; 92 LIST_ENTRY(ifvlantrunk) trunk_entry; 93 }; 94 static LIST_HEAD(, ifvlantrunk) trunk_list; 95 96 struct vlan_mc_entry { 97 struct ether_addr mc_addr; 98 SLIST_ENTRY(vlan_mc_entry) mc_entries; 99 }; 100 101 struct ifvlan { 102 struct ifvlantrunk *ifv_trunk; 103 struct ifnet *ifv_ifp; 104 #define TRUNK(ifv) ((ifv)->ifv_trunk) 105 #define PARENT(ifv) ((ifv)->ifv_trunk->parent) 106 int ifv_pflags; /* special flags we have set on parent */ 107 struct ifv_linkmib { 108 int ifvm_encaplen; /* encapsulation length */ 109 int ifvm_mtufudge; /* MTU fudged by this much */ 110 int ifvm_mintu; /* min transmission unit */ 111 uint16_t ifvm_tag; /* tag to apply on packets leaving if */ 112 } ifv_mib; 113 SLIST_HEAD(, vlan_mc_entry) vlan_mc_listhead; 114 LIST_ENTRY(ifvlan) ifv_list; 115 }; 116 #define ifv_tag ifv_mib.ifvm_tag 117 #define ifv_encaplen ifv_mib.ifvm_encaplen 118 #define ifv_mtufudge ifv_mib.ifvm_mtufudge 119 #define ifv_mintu ifv_mib.ifvm_mintu 120 121 /* Special flags we should propagate to parent. */ 122 static struct { 123 int flag; 124 int (*func)(struct ifnet *, int); 125 } vlan_pflags[] = { 126 {IFF_PROMISC, ifpromisc}, 127 {IFF_ALLMULTI, if_allmulti}, 128 {0, NULL} 129 }; 130 131 SYSCTL_DECL(_net_link); 132 SYSCTL_NODE(_net_link, IFT_L2VLAN, vlan, CTLFLAG_RW, 0, "IEEE 802.1Q VLAN"); 133 SYSCTL_NODE(_net_link_vlan, PF_LINK, link, CTLFLAG_RW, 0, "for consistency"); 134 135 static MALLOC_DEFINE(M_VLAN, VLANNAME, "802.1Q Virtual LAN Interface"); 136 137 static eventhandler_tag ifdetach_tag; 138 139 /* 140 * We have a global mutex, that is used to serialize configuration 141 * changes and isn't used in normal packet delivery. 142 * 143 * We also have a per-trunk rwlock, that is locked shared on packet 144 * processing and exclusive when configuration is changed. 145 * 146 * The VLAN_ARRAY substitutes the dynamic hash with a static array 147 * with 4096 entries. In theory this can give a boots in processing, 148 * however on practice it does not. Probably this is because array 149 * is too big to fit into CPU cache. 150 */ 151 static struct mtx ifv_mtx; 152 #define VLAN_LOCK_INIT() mtx_init(&ifv_mtx, "vlan_global", NULL, MTX_DEF) 153 #define VLAN_LOCK_DESTROY() mtx_destroy(&ifv_mtx) 154 #define VLAN_LOCK_ASSERT() mtx_assert(&ifv_mtx, MA_OWNED) 155 #define VLAN_LOCK() mtx_lock(&ifv_mtx) 156 #define VLAN_UNLOCK() mtx_unlock(&ifv_mtx) 157 #define TRUNK_LOCK_INIT(trunk) rw_init(&(trunk)->rw, VLANNAME) 158 #define TRUNK_LOCK_DESTROY(trunk) rw_destroy(&(trunk)->rw) 159 #define TRUNK_LOCK(trunk) rw_wlock(&(trunk)->rw) 160 #define TRUNK_UNLOCK(trunk) rw_wunlock(&(trunk)->rw) 161 #define TRUNK_LOCK_ASSERT(trunk) rw_assert(&(trunk)->rw, RA_WLOCKED) 162 #define TRUNK_RLOCK(trunk) rw_rlock(&(trunk)->rw) 163 #define TRUNK_RUNLOCK(trunk) rw_runlock(&(trunk)->rw) 164 #define TRUNK_LOCK_RASSERT(trunk) rw_assert(&(trunk)->rw, RA_RLOCKED) 165 166 #ifndef VLAN_ARRAY 167 static void vlan_inithash(struct ifvlantrunk *trunk); 168 static void vlan_freehash(struct ifvlantrunk *trunk); 169 static int vlan_inshash(struct ifvlantrunk *trunk, struct ifvlan *ifv); 170 static int vlan_remhash(struct ifvlantrunk *trunk, struct ifvlan *ifv); 171 static void vlan_growhash(struct ifvlantrunk *trunk, int howmuch); 172 static __inline struct ifvlan * vlan_gethash(struct ifvlantrunk *trunk, 173 uint16_t tag); 174 #endif 175 static void trunk_destroy(struct ifvlantrunk *trunk); 176 177 static void vlan_start(struct ifnet *ifp); 178 static void vlan_init(void *foo); 179 static void vlan_input(struct ifnet *ifp, struct mbuf *m); 180 static int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr); 181 static int vlan_setflag(struct ifnet *ifp, int flag, int status, 182 int (*func)(struct ifnet *, int)); 183 static int vlan_setflags(struct ifnet *ifp, int status); 184 static int vlan_setmulti(struct ifnet *ifp); 185 static int vlan_unconfig(struct ifnet *ifp); 186 static int vlan_unconfig_locked(struct ifnet *ifp); 187 static int vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t tag); 188 static void vlan_link_state(struct ifnet *ifp, int link); 189 static void vlan_capabilities(struct ifvlan *ifv); 190 static void vlan_trunk_capabilities(struct ifnet *ifp); 191 192 static struct ifnet *vlan_clone_match_ethertag(struct if_clone *, 193 const char *, int *); 194 static int vlan_clone_match(struct if_clone *, const char *); 195 static int vlan_clone_create(struct if_clone *, char *, size_t, caddr_t); 196 static int vlan_clone_destroy(struct if_clone *, struct ifnet *); 197 198 static void vlan_ifdetach(void *arg, struct ifnet *ifp); 199 200 static struct if_clone vlan_cloner = IFC_CLONE_INITIALIZER(VLANNAME, NULL, 201 IF_MAXUNIT, NULL, vlan_clone_match, vlan_clone_create, vlan_clone_destroy); 202 203 #ifndef VLAN_ARRAY 204 #define HASH(n, m) ((((n) >> 8) ^ ((n) >> 4) ^ (n)) & (m)) 205 206 static void 207 vlan_inithash(struct ifvlantrunk *trunk) 208 { 209 int i, n; 210 211 /* 212 * The trunk must not be locked here since we call malloc(M_WAITOK). 213 * It is OK in case this function is called before the trunk struct 214 * gets hooked up and becomes visible from other threads. 215 */ 216 217 KASSERT(trunk->hwidth == 0 && trunk->hash == NULL, 218 ("%s: hash already initialized", __func__)); 219 220 trunk->hwidth = VLAN_DEF_HWIDTH; 221 n = 1 << trunk->hwidth; 222 trunk->hmask = n - 1; 223 trunk->hash = malloc(sizeof(struct ifvlanhead) * n, M_VLAN, M_WAITOK); 224 for (i = 0; i < n; i++) 225 LIST_INIT(&trunk->hash[i]); 226 } 227 228 static void 229 vlan_freehash(struct ifvlantrunk *trunk) 230 { 231 #ifdef INVARIANTS 232 int i; 233 234 KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); 235 for (i = 0; i < (1 << trunk->hwidth); i++) 236 KASSERT(LIST_EMPTY(&trunk->hash[i]), 237 ("%s: hash table not empty", __func__)); 238 #endif 239 free(trunk->hash, M_VLAN); 240 trunk->hash = NULL; 241 trunk->hwidth = trunk->hmask = 0; 242 } 243 244 static int 245 vlan_inshash(struct ifvlantrunk *trunk, struct ifvlan *ifv) 246 { 247 int i, b; 248 struct ifvlan *ifv2; 249 250 TRUNK_LOCK_ASSERT(trunk); 251 KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); 252 253 b = 1 << trunk->hwidth; 254 i = HASH(ifv->ifv_tag, trunk->hmask); 255 LIST_FOREACH(ifv2, &trunk->hash[i], ifv_list) 256 if (ifv->ifv_tag == ifv2->ifv_tag) 257 return (EEXIST); 258 259 /* 260 * Grow the hash when the number of vlans exceeds half of the number of 261 * hash buckets squared. This will make the average linked-list length 262 * buckets/2. 263 */ 264 if (trunk->refcnt > (b * b) / 2) { 265 vlan_growhash(trunk, 1); 266 i = HASH(ifv->ifv_tag, trunk->hmask); 267 } 268 LIST_INSERT_HEAD(&trunk->hash[i], ifv, ifv_list); 269 trunk->refcnt++; 270 271 return (0); 272 } 273 274 static int 275 vlan_remhash(struct ifvlantrunk *trunk, struct ifvlan *ifv) 276 { 277 int i, b; 278 struct ifvlan *ifv2; 279 280 TRUNK_LOCK_ASSERT(trunk); 281 KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); 282 283 b = 1 << trunk->hwidth; 284 i = HASH(ifv->ifv_tag, trunk->hmask); 285 LIST_FOREACH(ifv2, &trunk->hash[i], ifv_list) 286 if (ifv2 == ifv) { 287 trunk->refcnt--; 288 LIST_REMOVE(ifv2, ifv_list); 289 if (trunk->refcnt < (b * b) / 2) 290 vlan_growhash(trunk, -1); 291 return (0); 292 } 293 294 panic("%s: vlan not found\n", __func__); 295 return (ENOENT); /*NOTREACHED*/ 296 } 297 298 /* 299 * Grow the hash larger or smaller if memory permits. 300 */ 301 static void 302 vlan_growhash(struct ifvlantrunk *trunk, int howmuch) 303 { 304 305 struct ifvlan *ifv; 306 struct ifvlanhead *hash2; 307 int hwidth2, i, j, n, n2; 308 309 TRUNK_LOCK_ASSERT(trunk); 310 KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__)); 311 312 if (howmuch == 0) { 313 /* Harmless yet obvious coding error */ 314 printf("%s: howmuch is 0\n", __func__); 315 return; 316 } 317 318 hwidth2 = trunk->hwidth + howmuch; 319 n = 1 << trunk->hwidth; 320 n2 = 1 << hwidth2; 321 /* Do not shrink the table below the default */ 322 if (hwidth2 < VLAN_DEF_HWIDTH) 323 return; 324 325 /* M_NOWAIT because we're called with trunk mutex held */ 326 hash2 = malloc(sizeof(struct ifvlanhead) * n2, M_VLAN, M_NOWAIT); 327 if (hash2 == NULL) { 328 printf("%s: out of memory -- hash size not changed\n", 329 __func__); 330 return; /* We can live with the old hash table */ 331 } 332 for (j = 0; j < n2; j++) 333 LIST_INIT(&hash2[j]); 334 for (i = 0; i < n; i++) 335 while (!LIST_EMPTY(&trunk->hash[i])) { 336 ifv = LIST_FIRST(&trunk->hash[i]); 337 LIST_REMOVE(ifv, ifv_list); 338 j = HASH(ifv->ifv_tag, n2 - 1); 339 LIST_INSERT_HEAD(&hash2[j], ifv, ifv_list); 340 } 341 free(trunk->hash, M_VLAN); 342 trunk->hash = hash2; 343 trunk->hwidth = hwidth2; 344 trunk->hmask = n2 - 1; 345 } 346 347 static __inline struct ifvlan * 348 vlan_gethash(struct ifvlantrunk *trunk, uint16_t tag) 349 { 350 struct ifvlan *ifv; 351 352 TRUNK_LOCK_RASSERT(trunk); 353 354 LIST_FOREACH(ifv, &trunk->hash[HASH(tag, trunk->hmask)], ifv_list) 355 if (ifv->ifv_tag == tag) 356 return (ifv); 357 return (NULL); 358 } 359 360 #if 0 361 /* Debugging code to view the hashtables. */ 362 static void 363 vlan_dumphash(struct ifvlantrunk *trunk) 364 { 365 int i; 366 struct ifvlan *ifv; 367 368 for (i = 0; i < (1 << trunk->hwidth); i++) { 369 printf("%d: ", i); 370 LIST_FOREACH(ifv, &trunk->hash[i], ifv_list) 371 printf("%s ", ifv->ifv_ifp->if_xname); 372 printf("\n"); 373 } 374 } 375 #endif /* 0 */ 376 #endif /* !VLAN_ARRAY */ 377 378 static void 379 trunk_destroy(struct ifvlantrunk *trunk) 380 { 381 VLAN_LOCK_ASSERT(); 382 383 TRUNK_LOCK(trunk); 384 #ifndef VLAN_ARRAY 385 vlan_freehash(trunk); 386 #endif 387 trunk->parent->if_vlantrunk = NULL; 388 LIST_REMOVE(trunk, trunk_entry); 389 TRUNK_UNLOCK(trunk); 390 TRUNK_LOCK_DESTROY(trunk); 391 free(trunk, M_VLAN); 392 } 393 394 /* 395 * Program our multicast filter. What we're actually doing is 396 * programming the multicast filter of the parent. This has the 397 * side effect of causing the parent interface to receive multicast 398 * traffic that it doesn't really want, which ends up being discarded 399 * later by the upper protocol layers. Unfortunately, there's no way 400 * to avoid this: there really is only one physical interface. 401 * 402 * XXX: There is a possible race here if more than one thread is 403 * modifying the multicast state of the vlan interface at the same time. 404 */ 405 static int 406 vlan_setmulti(struct ifnet *ifp) 407 { 408 struct ifnet *ifp_p; 409 struct ifmultiaddr *ifma, *rifma = NULL; 410 struct ifvlan *sc; 411 struct vlan_mc_entry *mc = NULL; 412 struct sockaddr_dl sdl; 413 int error; 414 415 /*VLAN_LOCK_ASSERT();*/ 416 417 /* Find the parent. */ 418 sc = ifp->if_softc; 419 ifp_p = PARENT(sc); 420 421 bzero((char *)&sdl, sizeof(sdl)); 422 sdl.sdl_len = sizeof(sdl); 423 sdl.sdl_family = AF_LINK; 424 sdl.sdl_index = ifp_p->if_index; 425 sdl.sdl_type = IFT_ETHER; 426 sdl.sdl_alen = ETHER_ADDR_LEN; 427 428 /* First, remove any existing filter entries. */ 429 while (SLIST_FIRST(&sc->vlan_mc_listhead) != NULL) { 430 mc = SLIST_FIRST(&sc->vlan_mc_listhead); 431 bcopy((char *)&mc->mc_addr, LLADDR(&sdl), ETHER_ADDR_LEN); 432 error = if_delmulti(ifp_p, (struct sockaddr *)&sdl); 433 if (error) 434 return (error); 435 SLIST_REMOVE_HEAD(&sc->vlan_mc_listhead, mc_entries); 436 free(mc, M_VLAN); 437 } 438 439 /* Now program new ones. */ 440 TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 441 if (ifma->ifma_addr->sa_family != AF_LINK) 442 continue; 443 mc = malloc(sizeof(struct vlan_mc_entry), M_VLAN, M_NOWAIT); 444 if (mc == NULL) 445 return (ENOMEM); 446 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 447 (char *)&mc->mc_addr, ETHER_ADDR_LEN); 448 SLIST_INSERT_HEAD(&sc->vlan_mc_listhead, mc, mc_entries); 449 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 450 LLADDR(&sdl), ETHER_ADDR_LEN); 451 error = if_addmulti(ifp_p, (struct sockaddr *)&sdl, &rifma); 452 if (error) 453 return (error); 454 } 455 456 return (0); 457 } 458 459 /* 460 * A handler for network interface departure events. 461 * Track departure of trunks here so that we don't access invalid 462 * pointers or whatever if a trunk is ripped from under us, e.g., 463 * by ejecting its hot-plug card. 464 */ 465 static void 466 vlan_ifdetach(void *arg __unused, struct ifnet *ifp) 467 { 468 struct ifvlan *ifv; 469 int i; 470 471 /* 472 * Check if it's a trunk interface first of all 473 * to avoid needless locking. 474 */ 475 if (ifp->if_vlantrunk == NULL) 476 return; 477 478 VLAN_LOCK(); 479 /* 480 * OK, it's a trunk. Loop over and detach all vlan's on it. 481 * Check trunk pointer after each vlan_unconfig() as it will 482 * free it and set to NULL after the last vlan was detached. 483 */ 484 #ifdef VLAN_ARRAY 485 for (i = 0; i < VLAN_ARRAY_SIZE; i++) 486 if ((ifv = ifp->if_vlantrunk->vlans[i])) { 487 vlan_unconfig_locked(ifv->ifv_ifp); 488 if (ifp->if_vlantrunk == NULL) 489 break; 490 } 491 #else /* VLAN_ARRAY */ 492 restart: 493 for (i = 0; i < (1 << ifp->if_vlantrunk->hwidth); i++) 494 if ((ifv = LIST_FIRST(&ifp->if_vlantrunk->hash[i]))) { 495 vlan_unconfig_locked(ifv->ifv_ifp); 496 if (ifp->if_vlantrunk) 497 goto restart; /* trunk->hwidth can change */ 498 else 499 break; 500 } 501 #endif /* VLAN_ARRAY */ 502 /* Trunk should have been destroyed in vlan_unconfig(). */ 503 KASSERT(ifp->if_vlantrunk == NULL, ("%s: purge failed", __func__)); 504 VLAN_UNLOCK(); 505 } 506 507 /* 508 * VLAN support can be loaded as a module. The only place in the 509 * system that's intimately aware of this is ether_input. We hook 510 * into this code through vlan_input_p which is defined there and 511 * set here. Noone else in the system should be aware of this so 512 * we use an explicit reference here. 513 */ 514 extern void (*vlan_input_p)(struct ifnet *, struct mbuf *); 515 516 /* For if_link_state_change() eyes only... */ 517 extern void (*vlan_link_state_p)(struct ifnet *, int); 518 519 static int 520 vlan_modevent(module_t mod, int type, void *data) 521 { 522 523 switch (type) { 524 case MOD_LOAD: 525 ifdetach_tag = EVENTHANDLER_REGISTER(ifnet_departure_event, 526 vlan_ifdetach, NULL, EVENTHANDLER_PRI_ANY); 527 if (ifdetach_tag == NULL) 528 return (ENOMEM); 529 LIST_INIT(&trunk_list); 530 VLAN_LOCK_INIT(); 531 vlan_input_p = vlan_input; 532 vlan_link_state_p = vlan_link_state; 533 vlan_trunk_cap_p = vlan_trunk_capabilities; 534 if_clone_attach(&vlan_cloner); 535 break; 536 case MOD_UNLOAD: 537 { 538 struct ifvlantrunk *trunk, *trunk1; 539 540 if_clone_detach(&vlan_cloner); 541 EVENTHANDLER_DEREGISTER(ifnet_departure_event, ifdetach_tag); 542 vlan_input_p = NULL; 543 vlan_link_state_p = NULL; 544 vlan_trunk_cap_p = NULL; 545 VLAN_LOCK(); 546 LIST_FOREACH_SAFE(trunk, &trunk_list, trunk_entry, trunk1) 547 trunk_destroy(trunk); 548 VLAN_UNLOCK(); 549 VLAN_LOCK_DESTROY(); 550 break; 551 } 552 default: 553 return (EOPNOTSUPP); 554 } 555 return (0); 556 } 557 558 static moduledata_t vlan_mod = { 559 "if_vlan", 560 vlan_modevent, 561 0 562 }; 563 564 DECLARE_MODULE(if_vlan, vlan_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 565 MODULE_VERSION(if_vlan, 3); 566 MODULE_DEPEND(if_vlan, miibus, 1, 1, 1); 567 568 static struct ifnet * 569 vlan_clone_match_ethertag(struct if_clone *ifc, const char *name, int *tag) 570 { 571 const char *cp; 572 struct ifnet *ifp; 573 int t = 0; 574 575 /* Check for <etherif>.<vlan> style interface names. */ 576 IFNET_RLOCK(); 577 TAILQ_FOREACH(ifp, &ifnet, if_link) { 578 if (ifp->if_type != IFT_ETHER) 579 continue; 580 if (strncmp(ifp->if_xname, name, strlen(ifp->if_xname)) != 0) 581 continue; 582 cp = name + strlen(ifp->if_xname); 583 if (*cp != '.') 584 continue; 585 for(; *cp != '\0'; cp++) { 586 if (*cp < '0' || *cp > '9') 587 continue; 588 t = (t * 10) + (*cp - '0'); 589 } 590 if (tag != NULL) 591 *tag = t; 592 break; 593 } 594 IFNET_RUNLOCK(); 595 596 return (ifp); 597 } 598 599 static int 600 vlan_clone_match(struct if_clone *ifc, const char *name) 601 { 602 const char *cp; 603 604 if (vlan_clone_match_ethertag(ifc, name, NULL) != NULL) 605 return (1); 606 607 if (strncmp(VLANNAME, name, strlen(VLANNAME)) != 0) 608 return (0); 609 for (cp = name + 4; *cp != '\0'; cp++) { 610 if (*cp < '0' || *cp > '9') 611 return (0); 612 } 613 614 return (1); 615 } 616 617 static int 618 vlan_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params) 619 { 620 char *dp; 621 int wildcard; 622 int unit; 623 int error; 624 int tag; 625 int ethertag; 626 struct ifvlan *ifv; 627 struct ifnet *ifp; 628 struct ifnet *p; 629 struct vlanreq vlr; 630 static const u_char eaddr[6]; /* 00:00:00:00:00:00 */ 631 632 /* 633 * There are 3 (ugh) ways to specify the cloned device: 634 * o pass a parameter block with the clone request. 635 * o specify parameters in the text of the clone device name 636 * o specify no parameters and get an unattached device that 637 * must be configured separately. 638 * The first technique is preferred; the latter two are 639 * supported for backwards compatibilty. 640 */ 641 if (params) { 642 error = copyin(params, &vlr, sizeof(vlr)); 643 if (error) 644 return error; 645 p = ifunit(vlr.vlr_parent); 646 if (p == NULL) 647 return ENXIO; 648 /* 649 * Don't let the caller set up a VLAN tag with 650 * anything except VLID bits. 651 */ 652 if (vlr.vlr_tag & ~EVL_VLID_MASK) 653 return (EINVAL); 654 error = ifc_name2unit(name, &unit); 655 if (error != 0) 656 return (error); 657 658 ethertag = 1; 659 tag = vlr.vlr_tag; 660 wildcard = (unit < 0); 661 } else if ((p = vlan_clone_match_ethertag(ifc, name, &tag)) != NULL) { 662 ethertag = 1; 663 unit = -1; 664 wildcard = 0; 665 666 /* 667 * Don't let the caller set up a VLAN tag with 668 * anything except VLID bits. 669 */ 670 if (tag & ~EVL_VLID_MASK) 671 return (EINVAL); 672 } else { 673 ethertag = 0; 674 675 error = ifc_name2unit(name, &unit); 676 if (error != 0) 677 return (error); 678 679 wildcard = (unit < 0); 680 } 681 682 error = ifc_alloc_unit(ifc, &unit); 683 if (error != 0) 684 return (error); 685 686 /* In the wildcard case, we need to update the name. */ 687 if (wildcard) { 688 for (dp = name; *dp != '\0'; dp++); 689 if (snprintf(dp, len - (dp-name), "%d", unit) > 690 len - (dp-name) - 1) { 691 panic("%s: interface name too long", __func__); 692 } 693 } 694 695 ifv = malloc(sizeof(struct ifvlan), M_VLAN, M_WAITOK | M_ZERO); 696 ifp = ifv->ifv_ifp = if_alloc(IFT_ETHER); 697 if (ifp == NULL) { 698 ifc_free_unit(ifc, unit); 699 free(ifv, M_VLAN); 700 return (ENOSPC); 701 } 702 SLIST_INIT(&ifv->vlan_mc_listhead); 703 704 ifp->if_softc = ifv; 705 /* 706 * Set the name manually rather than using if_initname because 707 * we don't conform to the default naming convention for interfaces. 708 */ 709 strlcpy(ifp->if_xname, name, IFNAMSIZ); 710 ifp->if_dname = ifc->ifc_name; 711 ifp->if_dunit = unit; 712 /* NB: flags are not set here */ 713 ifp->if_linkmib = &ifv->ifv_mib; 714 ifp->if_linkmiblen = sizeof(ifv->ifv_mib); 715 /* NB: mtu is not set here */ 716 717 ifp->if_init = vlan_init; 718 ifp->if_start = vlan_start; 719 ifp->if_ioctl = vlan_ioctl; 720 ifp->if_snd.ifq_maxlen = ifqmaxlen; 721 ifp->if_flags = VLAN_IFFLAGS; 722 ether_ifattach(ifp, eaddr); 723 /* Now undo some of the damage... */ 724 ifp->if_baudrate = 0; 725 ifp->if_type = IFT_L2VLAN; 726 ifp->if_hdrlen = ETHER_VLAN_ENCAP_LEN; 727 728 if (ethertag) { 729 error = vlan_config(ifv, p, tag); 730 if (error != 0) { 731 /* 732 * Since we've partialy failed, we need to back 733 * out all the way, otherwise userland could get 734 * confused. Thus, we destroy the interface. 735 */ 736 ether_ifdetach(ifp); 737 vlan_unconfig(ifp); 738 if_free_type(ifp, IFT_ETHER); 739 free(ifv, M_VLAN); 740 741 return (error); 742 } 743 ifp->if_drv_flags |= IFF_DRV_RUNNING; 744 745 /* Update flags on the parent, if necessary. */ 746 vlan_setflags(ifp, 1); 747 } 748 749 return (0); 750 } 751 752 static int 753 vlan_clone_destroy(struct if_clone *ifc, struct ifnet *ifp) 754 { 755 struct ifvlan *ifv = ifp->if_softc; 756 int unit = ifp->if_dunit; 757 758 ether_ifdetach(ifp); /* first, remove it from system-wide lists */ 759 vlan_unconfig(ifp); /* now it can be unconfigured and freed */ 760 if_free_type(ifp, IFT_ETHER); 761 free(ifv, M_VLAN); 762 ifc_free_unit(ifc, unit); 763 764 return (0); 765 } 766 767 /* 768 * The ifp->if_init entry point for vlan(4) is a no-op. 769 */ 770 static void 771 vlan_init(void *foo __unused) 772 { 773 } 774 775 /* 776 * The if_start method for vlan(4) interface. It doesn't 777 * raises the IFF_DRV_OACTIVE flag, since it is called 778 * only from IFQ_HANDOFF() macro in ether_output_frame(). 779 * If the interface queue is full, and vlan_start() is 780 * not called, the queue would never get emptied and 781 * interface would stall forever. 782 */ 783 static void 784 vlan_start(struct ifnet *ifp) 785 { 786 struct ifvlan *ifv; 787 struct ifnet *p; 788 struct mbuf *m; 789 int error; 790 791 ifv = ifp->if_softc; 792 p = PARENT(ifv); 793 794 for (;;) { 795 IF_DEQUEUE(&ifp->if_snd, m); 796 if (m == 0) 797 break; 798 BPF_MTAP(ifp, m); 799 800 /* 801 * Do not run parent's if_start() if the parent is not up, 802 * or parent's driver will cause a system crash. 803 */ 804 if (!((p->if_flags & IFF_UP) && 805 (p->if_drv_flags & IFF_DRV_RUNNING))) { 806 m_freem(m); 807 ifp->if_collisions++; 808 continue; 809 } 810 811 /* 812 * If underlying interface can do VLAN tag insertion itself, 813 * just pass the packet along. However, we need some way to 814 * tell the interface where the packet came from so that it 815 * knows how to find the VLAN tag to use, so we attach a 816 * packet tag that holds it. 817 */ 818 if (p->if_capenable & IFCAP_VLAN_HWTAGGING) { 819 struct m_tag *mtag = (struct m_tag *) 820 uma_zalloc(zone_mtag_vlan, M_NOWAIT); 821 if (mtag == NULL) { 822 ifp->if_oerrors++; 823 m_freem(m); 824 continue; 825 } 826 VLAN_TAG_VALUE(mtag) = ifv->ifv_tag; 827 m_tag_prepend(m, mtag); 828 m->m_flags |= M_VLANTAG; 829 } else { 830 struct ether_vlan_header *evl; 831 832 M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT); 833 if (m == NULL) { 834 if_printf(ifp, 835 "unable to prepend VLAN header\n"); 836 ifp->if_oerrors++; 837 continue; 838 } 839 /* M_PREPEND takes care of m_len, m_pkthdr.len for us */ 840 841 if (m->m_len < sizeof(*evl)) { 842 m = m_pullup(m, sizeof(*evl)); 843 if (m == NULL) { 844 if_printf(ifp, 845 "cannot pullup VLAN header\n"); 846 ifp->if_oerrors++; 847 continue; 848 } 849 } 850 851 /* 852 * Transform the Ethernet header into an Ethernet header 853 * with 802.1Q encapsulation. 854 */ 855 bcopy(mtod(m, char *) + ifv->ifv_encaplen, 856 mtod(m, char *), ETHER_HDR_LEN); 857 evl = mtod(m, struct ether_vlan_header *); 858 evl->evl_proto = evl->evl_encap_proto; 859 evl->evl_encap_proto = htons(ETHERTYPE_VLAN); 860 evl->evl_tag = htons(ifv->ifv_tag); 861 #ifdef DEBUG 862 printf("%s: %*D\n", __func__, (int)sizeof(*evl), 863 (unsigned char *)evl, ":"); 864 #endif 865 } 866 867 /* 868 * Send it, precisely as ether_output() would have. 869 * We are already running at splimp. 870 */ 871 IFQ_HANDOFF(p, m, error); 872 if (!error) 873 ifp->if_opackets++; 874 else 875 ifp->if_oerrors++; 876 } 877 } 878 879 static void 880 vlan_input(struct ifnet *ifp, struct mbuf *m) 881 { 882 struct ifvlantrunk *trunk = ifp->if_vlantrunk; 883 struct ifvlan *ifv; 884 struct m_tag *mtag; 885 uint16_t tag; 886 887 KASSERT(trunk != NULL, ("%s: no trunk", __func__)); 888 889 if (m->m_flags & M_VLANTAG) { 890 /* 891 * Packet is tagged, but m contains a normal 892 * Ethernet frame; the tag is stored out-of-band. 893 */ 894 mtag = m_tag_locate(m, MTAG_VLAN, MTAG_VLAN_TAG, NULL); 895 KASSERT(mtag != NULL, 896 ("%s: M_VLANTAG without m_tag", __func__)); 897 tag = EVL_VLANOFTAG(VLAN_TAG_VALUE(mtag)); 898 m_tag_delete(m, mtag); 899 m->m_flags &= ~M_VLANTAG; 900 } else { 901 struct ether_vlan_header *evl; 902 903 /* 904 * Packet is tagged in-band as specified by 802.1q. 905 */ 906 mtag = NULL; 907 switch (ifp->if_type) { 908 case IFT_ETHER: 909 if (m->m_len < sizeof(*evl) && 910 (m = m_pullup(m, sizeof(*evl))) == NULL) { 911 if_printf(ifp, "cannot pullup VLAN header\n"); 912 return; 913 } 914 evl = mtod(m, struct ether_vlan_header *); 915 KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN, 916 ("%s: bad encapsulation protocol (%u)", 917 __func__, ntohs(evl->evl_encap_proto))); 918 919 tag = EVL_VLANOFTAG(ntohs(evl->evl_tag)); 920 921 /* 922 * Restore the original ethertype. We'll remove 923 * the encapsulation after we've found the vlan 924 * interface corresponding to the tag. 925 */ 926 evl->evl_encap_proto = evl->evl_proto; 927 break; 928 default: 929 #ifdef INVARIANTS 930 panic("%s: %s has unsupported if_type %u", 931 __func__, ifp->if_xname, ifp->if_type); 932 #endif 933 m_freem(m); 934 ifp->if_noproto++; 935 return; 936 } 937 } 938 939 TRUNK_RLOCK(trunk); 940 #ifdef VLAN_ARRAY 941 ifv = trunk->vlans[tag]; 942 #else 943 ifv = vlan_gethash(trunk, tag); 944 #endif 945 if (ifv == NULL || (ifv->ifv_ifp->if_flags & IFF_UP) == 0) { 946 TRUNK_RUNLOCK(trunk); 947 m_freem(m); 948 ifp->if_noproto++; 949 return; 950 } 951 TRUNK_RUNLOCK(trunk); 952 953 if (mtag == NULL) { 954 /* 955 * Packet had an in-line encapsulation header; 956 * remove it. The original header has already 957 * been fixed up above. 958 */ 959 bcopy(mtod(m, caddr_t), 960 mtod(m, caddr_t) + ETHER_VLAN_ENCAP_LEN, 961 ETHER_HDR_LEN); 962 m_adj(m, ETHER_VLAN_ENCAP_LEN); 963 } 964 965 m->m_pkthdr.rcvif = ifv->ifv_ifp; 966 ifv->ifv_ifp->if_ipackets++; 967 968 /* Pass it back through the parent's input routine. */ 969 (*ifp->if_input)(ifv->ifv_ifp, m); 970 } 971 972 static int 973 vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t tag) 974 { 975 struct ifvlantrunk *trunk; 976 struct ifnet *ifp; 977 int error = 0; 978 979 /* VID numbers 0x0 and 0xFFF are reserved */ 980 if (tag == 0 || tag == 0xFFF) 981 return (EINVAL); 982 if (p->if_type != IFT_ETHER) 983 return (EPROTONOSUPPORT); 984 if ((p->if_flags & VLAN_IFFLAGS) != VLAN_IFFLAGS) 985 return (EPROTONOSUPPORT); 986 if (ifv->ifv_trunk) 987 return (EBUSY); 988 989 if (p->if_vlantrunk == NULL) { 990 trunk = malloc(sizeof(struct ifvlantrunk), 991 M_VLAN, M_WAITOK | M_ZERO); 992 #ifndef VLAN_ARRAY 993 vlan_inithash(trunk); 994 #endif 995 VLAN_LOCK(); 996 if (p->if_vlantrunk != NULL) { 997 /* A race that that is very unlikely to be hit. */ 998 #ifndef VLAN_ARRAY 999 vlan_freehash(trunk); 1000 #endif 1001 free(trunk, M_VLAN); 1002 goto exists; 1003 } 1004 TRUNK_LOCK_INIT(trunk); 1005 LIST_INSERT_HEAD(&trunk_list, trunk, trunk_entry); 1006 TRUNK_LOCK(trunk); 1007 p->if_vlantrunk = trunk; 1008 trunk->parent = p; 1009 } else { 1010 VLAN_LOCK(); 1011 exists: 1012 trunk = p->if_vlantrunk; 1013 TRUNK_LOCK(trunk); 1014 } 1015 1016 ifv->ifv_tag = tag; /* must set this before vlan_inshash() */ 1017 #ifdef VLAN_ARRAY 1018 if (trunk->vlans[tag] != NULL) { 1019 error = EEXIST; 1020 goto done; 1021 } 1022 trunk->vlans[tag] = ifv; 1023 trunk->refcnt++; 1024 #else 1025 error = vlan_inshash(trunk, ifv); 1026 if (error) 1027 goto done; 1028 #endif 1029 ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN; 1030 ifv->ifv_mintu = ETHERMIN; 1031 ifv->ifv_pflags = 0; 1032 1033 /* 1034 * If the parent supports the VLAN_MTU capability, 1035 * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames, 1036 * use it. 1037 */ 1038 if (p->if_capenable & IFCAP_VLAN_MTU) { 1039 /* 1040 * No need to fudge the MTU since the parent can 1041 * handle extended frames. 1042 */ 1043 ifv->ifv_mtufudge = 0; 1044 } else { 1045 /* 1046 * Fudge the MTU by the encapsulation size. This 1047 * makes us incompatible with strictly compliant 1048 * 802.1Q implementations, but allows us to use 1049 * the feature with other NetBSD implementations, 1050 * which might still be useful. 1051 */ 1052 ifv->ifv_mtufudge = ifv->ifv_encaplen; 1053 } 1054 1055 ifv->ifv_trunk = trunk; 1056 ifp = ifv->ifv_ifp; 1057 ifp->if_mtu = p->if_mtu - ifv->ifv_mtufudge; 1058 ifp->if_baudrate = p->if_baudrate; 1059 /* 1060 * Copy only a selected subset of flags from the parent. 1061 * Other flags are none of our business. 1062 */ 1063 #define VLAN_COPY_FLAGS (IFF_SIMPLEX) 1064 ifp->if_flags &= ~VLAN_COPY_FLAGS; 1065 ifp->if_flags |= p->if_flags & VLAN_COPY_FLAGS; 1066 #undef VLAN_COPY_FLAGS 1067 1068 ifp->if_link_state = p->if_link_state; 1069 1070 vlan_capabilities(ifv); 1071 1072 /* 1073 * Set up our ``Ethernet address'' to reflect the underlying 1074 * physical interface's. 1075 */ 1076 bcopy(IF_LLADDR(p), IF_LLADDR(ifp), ETHER_ADDR_LEN); 1077 1078 /* 1079 * Configure multicast addresses that may already be 1080 * joined on the vlan device. 1081 */ 1082 (void)vlan_setmulti(ifp); /* XXX: VLAN lock held */ 1083 done: 1084 TRUNK_UNLOCK(trunk); 1085 VLAN_UNLOCK(); 1086 1087 return (error); 1088 } 1089 1090 static int 1091 vlan_unconfig(struct ifnet *ifp) 1092 { 1093 int ret; 1094 1095 VLAN_LOCK(); 1096 ret = vlan_unconfig_locked(ifp); 1097 VLAN_UNLOCK(); 1098 return (ret); 1099 } 1100 1101 static int 1102 vlan_unconfig_locked(struct ifnet *ifp) 1103 { 1104 struct ifvlantrunk *trunk; 1105 struct vlan_mc_entry *mc; 1106 struct ifvlan *ifv; 1107 int error; 1108 1109 VLAN_LOCK_ASSERT(); 1110 1111 ifv = ifp->if_softc; 1112 trunk = ifv->ifv_trunk; 1113 1114 if (trunk) { 1115 struct sockaddr_dl sdl; 1116 struct ifnet *p = trunk->parent; 1117 1118 TRUNK_LOCK(trunk); 1119 1120 /* 1121 * Since the interface is being unconfigured, we need to 1122 * empty the list of multicast groups that we may have joined 1123 * while we were alive from the parent's list. 1124 */ 1125 bzero((char *)&sdl, sizeof(sdl)); 1126 sdl.sdl_len = sizeof(sdl); 1127 sdl.sdl_family = AF_LINK; 1128 sdl.sdl_index = p->if_index; 1129 sdl.sdl_type = IFT_ETHER; 1130 sdl.sdl_alen = ETHER_ADDR_LEN; 1131 1132 while(SLIST_FIRST(&ifv->vlan_mc_listhead) != NULL) { 1133 mc = SLIST_FIRST(&ifv->vlan_mc_listhead); 1134 bcopy((char *)&mc->mc_addr, LLADDR(&sdl), 1135 ETHER_ADDR_LEN); 1136 error = if_delmulti(p, (struct sockaddr *)&sdl); 1137 if (error) 1138 return (error); 1139 SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries); 1140 free(mc, M_VLAN); 1141 } 1142 1143 vlan_setflags(ifp, 0); /* clear special flags on parent */ 1144 #ifdef VLAN_ARRAY 1145 trunk->vlans[ifv->ifv_tag] = NULL; 1146 trunk->refcnt--; 1147 #else 1148 vlan_remhash(trunk, ifv); 1149 #endif 1150 ifv->ifv_trunk = NULL; 1151 1152 /* 1153 * Check if we were the last. 1154 */ 1155 if (trunk->refcnt == 0) { 1156 trunk->parent->if_vlantrunk = NULL; 1157 /* 1158 * XXXGL: If some ithread has already entered 1159 * vlan_input() and is now blocked on the trunk 1160 * lock, then it should preempt us right after 1161 * unlock and finish its work. Then we will acquire 1162 * lock again in trunk_destroy(). 1163 * XXX: not true in case of VLAN_ARRAY 1164 */ 1165 TRUNK_UNLOCK(trunk); 1166 trunk_destroy(trunk); 1167 } else 1168 TRUNK_UNLOCK(trunk); 1169 } 1170 1171 /* Disconnect from parent. */ 1172 if (ifv->ifv_pflags) 1173 if_printf(ifp, "%s: ifv_pflags unclean\n", __func__); 1174 ifp->if_mtu = ETHERMTU; 1175 ifp->if_link_state = LINK_STATE_UNKNOWN; 1176 ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 1177 1178 return (0); 1179 } 1180 1181 /* Handle a reference counted flag that should be set on the parent as well */ 1182 static int 1183 vlan_setflag(struct ifnet *ifp, int flag, int status, 1184 int (*func)(struct ifnet *, int)) 1185 { 1186 struct ifvlan *ifv; 1187 int error; 1188 1189 /* XXX VLAN_LOCK_ASSERT(); */ 1190 1191 ifv = ifp->if_softc; 1192 status = status ? (ifp->if_flags & flag) : 0; 1193 /* Now "status" contains the flag value or 0 */ 1194 1195 /* 1196 * See if recorded parent's status is different from what 1197 * we want it to be. If it is, flip it. We record parent's 1198 * status in ifv_pflags so that we won't clear parent's flag 1199 * we haven't set. In fact, we don't clear or set parent's 1200 * flags directly, but get or release references to them. 1201 * That's why we can be sure that recorded flags still are 1202 * in accord with actual parent's flags. 1203 */ 1204 if (status != (ifv->ifv_pflags & flag)) { 1205 error = (*func)(PARENT(ifv), status); 1206 if (error) 1207 return (error); 1208 ifv->ifv_pflags &= ~flag; 1209 ifv->ifv_pflags |= status; 1210 } 1211 return (0); 1212 } 1213 1214 /* 1215 * Handle IFF_* flags that require certain changes on the parent: 1216 * if "status" is true, update parent's flags respective to our if_flags; 1217 * if "status" is false, forcedly clear the flags set on parent. 1218 */ 1219 static int 1220 vlan_setflags(struct ifnet *ifp, int status) 1221 { 1222 int error, i; 1223 1224 for (i = 0; vlan_pflags[i].flag; i++) { 1225 error = vlan_setflag(ifp, vlan_pflags[i].flag, 1226 status, vlan_pflags[i].func); 1227 if (error) 1228 return (error); 1229 } 1230 return (0); 1231 } 1232 1233 /* Inform all vlans that their parent has changed link state */ 1234 static void 1235 vlan_link_state(struct ifnet *ifp, int link) 1236 { 1237 struct ifvlantrunk *trunk = ifp->if_vlantrunk; 1238 struct ifvlan *ifv; 1239 int i; 1240 1241 TRUNK_LOCK(trunk); 1242 #ifdef VLAN_ARRAY 1243 for (i = 0; i < VLAN_ARRAY_SIZE; i++) 1244 if (trunk->vlans[i] != NULL) { 1245 ifv = trunk->vlans[i]; 1246 #else 1247 for (i = 0; i < (1 << trunk->hwidth); i++) { 1248 LIST_FOREACH(ifv, &trunk->hash[i], ifv_list) 1249 #endif 1250 if_link_state_change(ifv->ifv_ifp, 1251 trunk->parent->if_link_state); 1252 } 1253 TRUNK_UNLOCK(trunk); 1254 } 1255 1256 static void 1257 vlan_capabilities(struct ifvlan *ifv) 1258 { 1259 struct ifnet *p = PARENT(ifv); 1260 struct ifnet *ifp = ifv->ifv_ifp; 1261 1262 TRUNK_LOCK_ASSERT(TRUNK(ifv)); 1263 1264 /* 1265 * If the parent interface can do checksum offloading 1266 * on VLANs, then propagate its hardware-assisted 1267 * checksumming flags. Also assert that checksum 1268 * offloading requires hardware VLAN tagging. 1269 */ 1270 if (p->if_capabilities & IFCAP_VLAN_HWCSUM) 1271 ifp->if_capabilities = p->if_capabilities & IFCAP_HWCSUM; 1272 1273 if (p->if_capenable & IFCAP_VLAN_HWCSUM && 1274 p->if_capenable & IFCAP_VLAN_HWTAGGING) { 1275 ifp->if_capenable = p->if_capenable & IFCAP_HWCSUM; 1276 ifp->if_hwassist = p->if_hwassist; 1277 } else { 1278 ifp->if_capenable = 0; 1279 ifp->if_hwassist = 0; 1280 } 1281 } 1282 1283 static void 1284 vlan_trunk_capabilities(struct ifnet *ifp) 1285 { 1286 struct ifvlantrunk *trunk = ifp->if_vlantrunk; 1287 struct ifvlan *ifv; 1288 int i; 1289 1290 TRUNK_LOCK(trunk); 1291 #ifdef VLAN_ARRAY 1292 for (i = 0; i < VLAN_ARRAY_SIZE; i++) 1293 if (trunk->vlans[i] != NULL) { 1294 ifv = trunk->vlans[i]; 1295 #else 1296 for (i = 0; i < (1 << trunk->hwidth); i++) { 1297 LIST_FOREACH(ifv, &trunk->hash[i], ifv_list) 1298 #endif 1299 vlan_capabilities(ifv); 1300 } 1301 TRUNK_UNLOCK(trunk); 1302 } 1303 1304 static int 1305 vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 1306 { 1307 struct ifaddr *ifa; 1308 struct ifnet *p; 1309 struct ifreq *ifr; 1310 struct ifvlan *ifv; 1311 struct vlanreq vlr; 1312 int error = 0; 1313 1314 ifr = (struct ifreq *)data; 1315 ifa = (struct ifaddr *)data; 1316 ifv = ifp->if_softc; 1317 1318 switch (cmd) { 1319 case SIOCSIFADDR: 1320 ifp->if_flags |= IFF_UP; 1321 1322 switch (ifa->ifa_addr->sa_family) { 1323 #ifdef INET 1324 case AF_INET: 1325 arp_ifinit(ifv->ifv_ifp, ifa); 1326 break; 1327 #endif 1328 default: 1329 break; 1330 } 1331 break; 1332 1333 case SIOCGIFADDR: 1334 { 1335 struct sockaddr *sa; 1336 1337 sa = (struct sockaddr *) &ifr->ifr_data; 1338 bcopy(IF_LLADDR(ifp), (caddr_t)sa->sa_data, 1339 ETHER_ADDR_LEN); 1340 } 1341 break; 1342 1343 case SIOCGIFMEDIA: 1344 VLAN_LOCK(); 1345 if (TRUNK(ifv) != NULL) { 1346 error = (*PARENT(ifv)->if_ioctl)(PARENT(ifv), 1347 SIOCGIFMEDIA, data); 1348 VLAN_UNLOCK(); 1349 /* Limit the result to the parent's current config. */ 1350 if (error == 0) { 1351 struct ifmediareq *ifmr; 1352 1353 ifmr = (struct ifmediareq *)data; 1354 if (ifmr->ifm_count >= 1 && ifmr->ifm_ulist) { 1355 ifmr->ifm_count = 1; 1356 error = copyout(&ifmr->ifm_current, 1357 ifmr->ifm_ulist, 1358 sizeof(int)); 1359 } 1360 } 1361 } else { 1362 VLAN_UNLOCK(); 1363 error = EINVAL; 1364 } 1365 break; 1366 1367 case SIOCSIFMEDIA: 1368 error = EINVAL; 1369 break; 1370 1371 case SIOCSIFMTU: 1372 /* 1373 * Set the interface MTU. 1374 */ 1375 VLAN_LOCK(); 1376 if (TRUNK(ifv) != NULL) { 1377 if (ifr->ifr_mtu > 1378 (PARENT(ifv)->if_mtu - ifv->ifv_mtufudge) || 1379 ifr->ifr_mtu < 1380 (ifv->ifv_mintu - ifv->ifv_mtufudge)) 1381 error = EINVAL; 1382 else 1383 ifp->if_mtu = ifr->ifr_mtu; 1384 } else 1385 error = EINVAL; 1386 VLAN_UNLOCK(); 1387 break; 1388 1389 case SIOCSETVLAN: 1390 error = copyin(ifr->ifr_data, &vlr, sizeof(vlr)); 1391 if (error) 1392 break; 1393 if (vlr.vlr_parent[0] == '\0') { 1394 vlan_unconfig(ifp); 1395 break; 1396 } 1397 p = ifunit(vlr.vlr_parent); 1398 if (p == 0) { 1399 error = ENOENT; 1400 break; 1401 } 1402 /* 1403 * Don't let the caller set up a VLAN tag with 1404 * anything except VLID bits. 1405 */ 1406 if (vlr.vlr_tag & ~EVL_VLID_MASK) { 1407 error = EINVAL; 1408 break; 1409 } 1410 error = vlan_config(ifv, p, vlr.vlr_tag); 1411 if (error) 1412 break; 1413 ifp->if_drv_flags |= IFF_DRV_RUNNING; 1414 1415 /* Update flags on the parent, if necessary. */ 1416 vlan_setflags(ifp, 1); 1417 break; 1418 1419 case SIOCGETVLAN: 1420 bzero(&vlr, sizeof(vlr)); 1421 VLAN_LOCK(); 1422 if (TRUNK(ifv) != NULL) { 1423 strlcpy(vlr.vlr_parent, PARENT(ifv)->if_xname, 1424 sizeof(vlr.vlr_parent)); 1425 vlr.vlr_tag = ifv->ifv_tag; 1426 } 1427 VLAN_UNLOCK(); 1428 error = copyout(&vlr, ifr->ifr_data, sizeof(vlr)); 1429 break; 1430 1431 case SIOCSIFFLAGS: 1432 /* 1433 * We should propagate selected flags to the parent, 1434 * e.g., promiscuous mode. 1435 */ 1436 if (TRUNK(ifv) != NULL) 1437 error = vlan_setflags(ifp, 1); 1438 break; 1439 1440 case SIOCADDMULTI: 1441 case SIOCDELMULTI: 1442 /* 1443 * If we don't have a parent, just remember the membership for 1444 * when we do. 1445 */ 1446 if (TRUNK(ifv) != NULL) 1447 error = vlan_setmulti(ifp); 1448 break; 1449 1450 default: 1451 error = EINVAL; 1452 } 1453 1454 return (error); 1455 } 1456