1 /* $OpenBSD: if_bpe.c,v 1.12 2020/07/10 13:26:41 patrick Exp $ */ 2 /* 3 * Copyright (c) 2018 David Gwynne <dlg@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include "bpfilter.h" 19 #include "pf.h" 20 21 #include <sys/param.h> 22 #include <sys/systm.h> 23 #include <sys/kernel.h> 24 #include <sys/mbuf.h> 25 #include <sys/socket.h> 26 #include <sys/ioctl.h> 27 #include <sys/timeout.h> 28 #include <sys/pool.h> 29 #include <sys/tree.h> 30 31 #include <net/if.h> 32 #include <net/if_var.h> 33 #include <net/if_dl.h> 34 #include <net/if_media.h> 35 #include <net/if_types.h> 36 #include <net/rtable.h> 37 38 #include <netinet/in.h> 39 #include <netinet/if_ether.h> 40 41 /* for bridge stuff */ 42 #include <net/if_bridge.h> 43 44 45 #if NBPFILTER > 0 46 #include <net/bpf.h> 47 #endif 48 49 #include <net/if_bpe.h> 50 51 #define PBB_ITAG_ISID 0x00ffffff 52 #define PBB_ITAG_ISID_MIN 0x00000000 53 #define PBB_ITAG_ISID_MAX 0x00ffffff 54 #define PBB_ITAG_RES2 0x03000000 /* must be zero on input */ 55 #define PBB_ITAG_RES1 0x04000000 /* ignore on input */ 56 #define PBB_ITAG_UCA 0x08000000 57 #define PBB_ITAG_DEI 0x10000000 58 #define PBB_ITAG_PCP_SHIFT 29 59 #define PBB_ITAG_PCP_MASK (0x7U << PBB_ITAG_PCP_SHIFT) 60 61 #define BPE_BRIDGE_AGE_TMO 100 /* seconds */ 62 63 struct bpe_key { 64 int k_if; 65 uint32_t k_isid; 66 67 RBT_ENTRY(bpe_tunnel) k_entry; 68 }; 69 70 RBT_HEAD(bpe_tree, bpe_key); 71 72 static inline int bpe_cmp(const struct bpe_key *, const struct bpe_key *); 73 74 RBT_PROTOTYPE(bpe_tree, bpe_key, k_entry, bpe_cmp); 75 RBT_GENERATE(bpe_tree, bpe_key, k_entry, bpe_cmp); 76 77 struct bpe_entry { 78 struct ether_addr be_c_da; /* customer address - must be first */ 79 struct ether_addr be_b_da; /* bridge address */ 80 unsigned int be_type; 81 #define BPE_ENTRY_DYNAMIC 0 82 #define BPE_ENTRY_STATIC 1 83 struct refcnt be_refs; 84 time_t be_age; 85 86 RBT_ENTRY(bpe_entry) be_entry; 87 }; 88 89 RBT_HEAD(bpe_map, bpe_entry); 90 91 static inline int bpe_entry_cmp(const struct bpe_entry *, 92 const struct bpe_entry *); 93 94 RBT_PROTOTYPE(bpe_map, bpe_entry, be_entry, bpe_entry_cmp); 95 RBT_GENERATE(bpe_map, bpe_entry, be_entry, bpe_entry_cmp); 96 97 struct bpe_softc { 98 struct bpe_key sc_key; /* must be first */ 99 struct arpcom sc_ac; 100 struct ifmedia sc_media; 101 int sc_txhprio; 102 int sc_rxhprio; 103 uint8_t sc_group[ETHER_ADDR_LEN]; 104 105 struct task sc_ltask; 106 struct task sc_dtask; 107 108 struct bpe_map sc_bridge_map; 109 struct rwlock sc_bridge_lock; 110 unsigned int sc_bridge_num; 111 unsigned int sc_bridge_max; 112 int sc_bridge_tmo; /* seconds */ 113 struct timeout sc_bridge_age; 114 }; 115 116 void bpeattach(int); 117 118 static int bpe_clone_create(struct if_clone *, int); 119 static int bpe_clone_destroy(struct ifnet *); 120 121 static void bpe_start(struct ifnet *); 122 static int bpe_ioctl(struct ifnet *, u_long, caddr_t); 123 static int bpe_media_get(struct bpe_softc *, struct ifreq *); 124 static int bpe_up(struct bpe_softc *); 125 static int bpe_down(struct bpe_softc *); 126 static int bpe_multi(struct bpe_softc *, struct ifnet *, u_long); 127 static int bpe_set_vnetid(struct bpe_softc *, const struct ifreq *); 128 static void bpe_set_group(struct bpe_softc *, uint32_t); 129 static int bpe_set_parent(struct bpe_softc *, const struct if_parent *); 130 static int bpe_get_parent(struct bpe_softc *, struct if_parent *); 131 static int bpe_del_parent(struct bpe_softc *); 132 static void bpe_link_hook(void *); 133 static void bpe_link_state(struct bpe_softc *, u_char, uint64_t); 134 static void bpe_detach_hook(void *); 135 136 static void bpe_input_map(struct bpe_softc *, 137 const uint8_t *, const uint8_t *); 138 static void bpe_bridge_age(void *); 139 140 static struct if_clone bpe_cloner = 141 IF_CLONE_INITIALIZER("bpe", bpe_clone_create, bpe_clone_destroy); 142 143 static struct bpe_tree bpe_interfaces = RBT_INITIALIZER(); 144 static struct rwlock bpe_lock = RWLOCK_INITIALIZER("bpeifs"); 145 static struct pool bpe_entry_pool; 146 147 void 148 bpeattach(int count) 149 { 150 if_clone_attach(&bpe_cloner); 151 } 152 153 static int 154 bpe_clone_create(struct if_clone *ifc, int unit) 155 { 156 struct bpe_softc *sc; 157 struct ifnet *ifp; 158 159 if (bpe_entry_pool.pr_size == 0) { 160 pool_init(&bpe_entry_pool, sizeof(struct bpe_entry), 0, 161 IPL_NONE, 0, "bpepl", NULL); 162 } 163 164 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); 165 ifp = &sc->sc_ac.ac_if; 166 167 snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", 168 ifc->ifc_name, unit); 169 170 sc->sc_key.k_if = 0; 171 sc->sc_key.k_isid = 0; 172 bpe_set_group(sc, 0); 173 174 sc->sc_txhprio = IF_HDRPRIO_PACKET; 175 sc->sc_rxhprio = IF_HDRPRIO_OUTER; 176 177 task_set(&sc->sc_ltask, bpe_link_hook, sc); 178 task_set(&sc->sc_dtask, bpe_detach_hook, sc); 179 180 rw_init(&sc->sc_bridge_lock, "bpebr"); 181 RBT_INIT(bpe_map, &sc->sc_bridge_map); 182 sc->sc_bridge_num = 0; 183 sc->sc_bridge_max = 100; /* XXX */ 184 sc->sc_bridge_tmo = 240; 185 timeout_set_proc(&sc->sc_bridge_age, bpe_bridge_age, sc); 186 187 ifp->if_softc = sc; 188 ifp->if_hardmtu = ETHER_MAX_HARDMTU_LEN; 189 ifp->if_ioctl = bpe_ioctl; 190 ifp->if_start = bpe_start; 191 ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST; 192 ifp->if_xflags = IFXF_CLONED; 193 ifq_set_maxlen(&ifp->if_snd, IFQ_MAXLEN); 194 ether_fakeaddr(ifp); 195 196 if_counters_alloc(ifp); 197 if_attach(ifp); 198 ether_ifattach(ifp); 199 200 return (0); 201 } 202 203 static int 204 bpe_clone_destroy(struct ifnet *ifp) 205 { 206 struct bpe_softc *sc = ifp->if_softc; 207 208 NET_LOCK(); 209 if (ISSET(ifp->if_flags, IFF_RUNNING)) 210 bpe_down(sc); 211 NET_UNLOCK(); 212 213 ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY); 214 ether_ifdetach(ifp); 215 if_detach(ifp); 216 217 free(sc, M_DEVBUF, sizeof(*sc)); 218 219 return (0); 220 } 221 222 static inline int 223 bpe_entry_valid(struct bpe_softc *sc, const struct bpe_entry *be) 224 { 225 time_t diff; 226 227 if (be == NULL) 228 return (0); 229 230 if (be->be_type == BPE_ENTRY_STATIC) 231 return (1); 232 233 diff = getuptime() - be->be_age; 234 if (diff < sc->sc_bridge_tmo) 235 return (1); 236 237 return (0); 238 } 239 240 static void 241 bpe_start(struct ifnet *ifp) 242 { 243 struct bpe_softc *sc = ifp->if_softc; 244 struct ifnet *ifp0; 245 struct mbuf *m0, *m; 246 struct ether_header *ceh; 247 struct ether_header *beh; 248 uint32_t itag, *itagp; 249 int hlen = sizeof(*beh) + sizeof(*itagp); 250 #if NBPFILTER > 0 251 caddr_t if_bpf; 252 #endif 253 int txprio; 254 uint8_t prio; 255 256 ifp0 = if_get(sc->sc_key.k_if); 257 if (ifp0 == NULL || !ISSET(ifp0->if_flags, IFF_RUNNING)) { 258 ifq_purge(&ifp->if_snd); 259 goto done; 260 } 261 262 txprio = sc->sc_txhprio; 263 264 while ((m0 = ifq_dequeue(&ifp->if_snd)) != NULL) { 265 #if NBPFILTER > 0 266 if_bpf = ifp->if_bpf; 267 if (if_bpf) 268 bpf_mtap_ether(if_bpf, m0, BPF_DIRECTION_OUT); 269 #endif 270 271 ceh = mtod(m0, struct ether_header *); 272 273 /* force prepend of a whole mbuf because of alignment */ 274 m = m_get(M_DONTWAIT, m0->m_type); 275 if (m == NULL) { 276 m_freem(m0); 277 continue; 278 } 279 280 M_MOVE_PKTHDR(m, m0); 281 m->m_next = m0; 282 283 m_align(m, 0); 284 m->m_len = 0; 285 286 m = m_prepend(m, hlen, M_DONTWAIT); 287 if (m == NULL) 288 continue; 289 290 beh = mtod(m, struct ether_header *); 291 292 if (ETHER_IS_BROADCAST(ceh->ether_dhost)) { 293 memcpy(beh->ether_dhost, sc->sc_group, 294 sizeof(beh->ether_dhost)); 295 } else { 296 struct bpe_entry *be; 297 298 rw_enter_read(&sc->sc_bridge_lock); 299 be = RBT_FIND(bpe_map, &sc->sc_bridge_map, 300 (struct bpe_entry *)ceh->ether_dhost); 301 if (bpe_entry_valid(sc, be)) { 302 memcpy(beh->ether_dhost, &be->be_b_da, 303 sizeof(beh->ether_dhost)); 304 } else { 305 /* "flood" to unknown hosts */ 306 memcpy(beh->ether_dhost, sc->sc_group, 307 sizeof(beh->ether_dhost)); 308 } 309 rw_exit_read(&sc->sc_bridge_lock); 310 } 311 312 memcpy(beh->ether_shost, ((struct arpcom *)ifp0)->ac_enaddr, 313 sizeof(beh->ether_shost)); 314 beh->ether_type = htons(ETHERTYPE_PBB); 315 316 prio = (txprio == IF_HDRPRIO_PACKET) ? 317 m->m_pkthdr.pf.prio : txprio; 318 319 itag = sc->sc_key.k_isid; 320 itag |= prio << PBB_ITAG_PCP_SHIFT; 321 itagp = (uint32_t *)(beh + 1); 322 323 htobem32(itagp, itag); 324 325 if_enqueue(ifp0, m); 326 } 327 328 done: 329 if_put(ifp0); 330 } 331 332 static void 333 bpe_bridge_age(void *arg) 334 { 335 struct bpe_softc *sc = arg; 336 struct bpe_entry *be, *nbe; 337 time_t diff; 338 339 timeout_add_sec(&sc->sc_bridge_age, BPE_BRIDGE_AGE_TMO); 340 341 rw_enter_write(&sc->sc_bridge_lock); 342 RBT_FOREACH_SAFE(be, bpe_map, &sc->sc_bridge_map, nbe) { 343 if (be->be_type != BPE_ENTRY_DYNAMIC) 344 continue; 345 346 diff = getuptime() - be->be_age; 347 if (diff < sc->sc_bridge_tmo) 348 continue; 349 350 sc->sc_bridge_num--; 351 RBT_REMOVE(bpe_map, &sc->sc_bridge_map, be); 352 if (refcnt_rele(&be->be_refs)) 353 pool_put(&bpe_entry_pool, be); 354 } 355 rw_exit_write(&sc->sc_bridge_lock); 356 } 357 358 static int 359 bpe_rtfind(struct bpe_softc *sc, struct ifbaconf *baconf) 360 { 361 struct ifnet *ifp = &sc->sc_ac.ac_if; 362 struct bpe_entry *be; 363 struct ifbareq bareq; 364 caddr_t uaddr, end; 365 int error; 366 time_t age; 367 struct sockaddr_dl *sdl; 368 369 if (baconf->ifbac_len == 0) { 370 /* single read is atomic */ 371 baconf->ifbac_len = sc->sc_bridge_num * sizeof(bareq); 372 return (0); 373 } 374 375 uaddr = baconf->ifbac_buf; 376 end = uaddr + baconf->ifbac_len; 377 378 rw_enter_read(&sc->sc_bridge_lock); 379 RBT_FOREACH(be, bpe_map, &sc->sc_bridge_map) { 380 if (uaddr >= end) 381 break; 382 383 memcpy(bareq.ifba_name, ifp->if_xname, 384 sizeof(bareq.ifba_name)); 385 memcpy(bareq.ifba_ifsname, ifp->if_xname, 386 sizeof(bareq.ifba_ifsname)); 387 memcpy(&bareq.ifba_dst, &be->be_c_da, 388 sizeof(bareq.ifba_dst)); 389 390 memset(&bareq.ifba_dstsa, 0, sizeof(bareq.ifba_dstsa)); 391 392 bzero(&bareq.ifba_dstsa, sizeof(bareq.ifba_dstsa)); 393 sdl = (struct sockaddr_dl *)&bareq.ifba_dstsa; 394 sdl->sdl_len = sizeof(sdl); 395 sdl->sdl_family = AF_LINK; 396 sdl->sdl_index = 0; 397 sdl->sdl_type = IFT_ETHER; 398 sdl->sdl_nlen = 0; 399 sdl->sdl_alen = sizeof(be->be_b_da); 400 CTASSERT(sizeof(sdl->sdl_data) >= sizeof(be->be_b_da)); 401 memcpy(sdl->sdl_data, &be->be_b_da, sizeof(be->be_b_da)); 402 403 switch (be->be_type) { 404 case BPE_ENTRY_DYNAMIC: 405 age = getuptime() - be->be_age; 406 bareq.ifba_age = MIN(age, 0xff); 407 bareq.ifba_flags = IFBAF_DYNAMIC; 408 break; 409 case BPE_ENTRY_STATIC: 410 bareq.ifba_age = 0; 411 bareq.ifba_flags = IFBAF_STATIC; 412 break; 413 } 414 415 error = copyout(&bareq, uaddr, sizeof(bareq)); 416 if (error != 0) { 417 rw_exit_read(&sc->sc_bridge_lock); 418 return (error); 419 } 420 421 uaddr += sizeof(bareq); 422 } 423 baconf->ifbac_len = sc->sc_bridge_num * sizeof(bareq); 424 rw_exit_read(&sc->sc_bridge_lock); 425 426 return (0); 427 } 428 429 static void 430 bpe_flush_map(struct bpe_softc *sc, uint32_t flags) 431 { 432 struct bpe_entry *be, *nbe; 433 434 rw_enter_write(&sc->sc_bridge_lock); 435 RBT_FOREACH_SAFE(be, bpe_map, &sc->sc_bridge_map, nbe) { 436 if (flags == IFBF_FLUSHDYN && 437 be->be_type != BPE_ENTRY_DYNAMIC) 438 continue; 439 440 RBT_REMOVE(bpe_map, &sc->sc_bridge_map, be); 441 if (refcnt_rele(&be->be_refs)) 442 pool_put(&bpe_entry_pool, be); 443 } 444 rw_exit_write(&sc->sc_bridge_lock); 445 } 446 447 static int 448 bpe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 449 { 450 struct bpe_softc *sc = ifp->if_softc; 451 struct ifreq *ifr = (struct ifreq *)data; 452 struct ifbrparam *bparam = (struct ifbrparam *)data; 453 int error = 0; 454 455 switch (cmd) { 456 case SIOCSIFFLAGS: 457 if (ISSET(ifp->if_flags, IFF_UP)) { 458 if (!ISSET(ifp->if_flags, IFF_RUNNING)) 459 error = bpe_up(sc); 460 else 461 error = 0; 462 } else { 463 if (ISSET(ifp->if_flags, IFF_RUNNING)) 464 error = bpe_down(sc); 465 } 466 break; 467 468 case SIOCSVNETID: 469 error = bpe_set_vnetid(sc, ifr); 470 break; 471 case SIOCGVNETID: 472 ifr->ifr_vnetid = sc->sc_key.k_isid; 473 break; 474 475 case SIOCSIFPARENT: 476 error = bpe_set_parent(sc, (struct if_parent *)data); 477 break; 478 case SIOCGIFPARENT: 479 error = bpe_get_parent(sc, (struct if_parent *)data); 480 break; 481 case SIOCDIFPARENT: 482 error = bpe_del_parent(sc); 483 break; 484 485 case SIOCSTXHPRIO: 486 error = if_txhprio_l2_check(ifr->ifr_hdrprio); 487 if (error != 0) 488 break; 489 490 sc->sc_txhprio = ifr->ifr_hdrprio; 491 break; 492 case SIOCGTXHPRIO: 493 ifr->ifr_hdrprio = sc->sc_txhprio; 494 break; 495 496 case SIOCSRXHPRIO: 497 error = if_rxhprio_l2_check(ifr->ifr_hdrprio); 498 if (error != 0) 499 break; 500 501 sc->sc_rxhprio = ifr->ifr_hdrprio; 502 break; 503 case SIOCGRXHPRIO: 504 ifr->ifr_hdrprio = sc->sc_rxhprio; 505 break; 506 507 case SIOCGIFMEDIA: 508 error = bpe_media_get(sc, ifr); 509 break; 510 511 case SIOCBRDGSCACHE: 512 error = suser(curproc); 513 if (error != 0) 514 break; 515 516 if (bparam->ifbrp_csize < 1) { 517 error = EINVAL; 518 break; 519 } 520 521 /* commit */ 522 sc->sc_bridge_max = bparam->ifbrp_csize; 523 break; 524 case SIOCBRDGGCACHE: 525 bparam->ifbrp_csize = sc->sc_bridge_max; 526 break; 527 528 case SIOCBRDGSTO: 529 error = suser(curproc); 530 if (error != 0) 531 break; 532 533 if (bparam->ifbrp_ctime < 8 || 534 bparam->ifbrp_ctime > 3600) { 535 error = EINVAL; 536 break; 537 } 538 sc->sc_bridge_tmo = bparam->ifbrp_ctime; 539 break; 540 case SIOCBRDGGTO: 541 bparam->ifbrp_ctime = sc->sc_bridge_tmo; 542 break; 543 544 case SIOCBRDGRTS: 545 error = bpe_rtfind(sc, (struct ifbaconf *)data); 546 break; 547 case SIOCBRDGFLUSH: 548 error = suser(curproc); 549 if (error != 0) 550 break; 551 552 bpe_flush_map(sc, 553 ((struct ifbreq *)data)->ifbr_ifsflags); 554 break; 555 556 default: 557 error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); 558 break; 559 } 560 561 return (error); 562 } 563 564 static int 565 bpe_media_get(struct bpe_softc *sc, struct ifreq *ifr) 566 { 567 struct ifnet *ifp0; 568 int error; 569 570 ifp0 = if_get(sc->sc_key.k_if); 571 if (ifp0 != NULL) 572 error = (*ifp0->if_ioctl)(ifp0, SIOCGIFMEDIA, (caddr_t)ifr); 573 else 574 error = ENOTTY; 575 if_put(ifp0); 576 577 return (error); 578 } 579 580 static int 581 bpe_up(struct bpe_softc *sc) 582 { 583 struct ifnet *ifp = &sc->sc_ac.ac_if; 584 struct ifnet *ifp0; 585 struct bpe_softc *osc; 586 int error = 0; 587 u_int hardmtu; 588 u_int hlen = sizeof(struct ether_header) + sizeof(uint32_t); 589 590 KASSERT(!ISSET(ifp->if_flags, IFF_RUNNING)); 591 NET_ASSERT_LOCKED(); 592 593 ifp0 = if_get(sc->sc_key.k_if); 594 if (ifp0 == NULL) 595 return (ENXIO); 596 597 /* check again if bpe will work on top of the parent */ 598 if (ifp0->if_type != IFT_ETHER) { 599 error = EPROTONOSUPPORT; 600 goto put; 601 } 602 603 hardmtu = ifp0->if_hardmtu; 604 if (hardmtu < hlen) { 605 error = ENOBUFS; 606 goto put; 607 } 608 hardmtu -= hlen; 609 if (ifp->if_mtu > hardmtu) { 610 error = ENOBUFS; 611 goto put; 612 } 613 614 /* parent is fine, let's prepare the bpe to handle packets */ 615 ifp->if_hardmtu = hardmtu; 616 SET(ifp->if_flags, ifp0->if_flags & IFF_SIMPLEX); 617 618 /* commit the interface */ 619 error = rw_enter(&bpe_lock, RW_WRITE | RW_INTR); 620 if (error != 0) 621 goto scrub; 622 623 osc = (struct bpe_softc *)RBT_INSERT(bpe_tree, &bpe_interfaces, 624 (struct bpe_key *)sc); 625 rw_exit(&bpe_lock); 626 627 if (osc != NULL) { 628 error = EADDRINUSE; 629 goto scrub; 630 } 631 632 if (bpe_multi(sc, ifp0, SIOCADDMULTI) != 0) { 633 error = ENOTCONN; 634 goto remove; 635 } 636 637 /* Register callback for physical link state changes */ 638 if_linkstatehook_add(ifp0, &sc->sc_ltask); 639 640 /* Register callback if parent wants to unregister */ 641 if_detachhook_add(ifp0, &sc->sc_dtask); 642 643 /* we're running now */ 644 SET(ifp->if_flags, IFF_RUNNING); 645 bpe_link_state(sc, ifp0->if_link_state, ifp0->if_baudrate); 646 647 if_put(ifp0); 648 649 timeout_add_sec(&sc->sc_bridge_age, BPE_BRIDGE_AGE_TMO); 650 651 return (0); 652 653 remove: 654 rw_enter(&bpe_lock, RW_WRITE); 655 RBT_REMOVE(bpe_tree, &bpe_interfaces, (struct bpe_key *)sc); 656 rw_exit(&bpe_lock); 657 scrub: 658 CLR(ifp->if_flags, IFF_SIMPLEX); 659 ifp->if_hardmtu = 0xffff; 660 put: 661 if_put(ifp0); 662 663 return (error); 664 } 665 666 static int 667 bpe_down(struct bpe_softc *sc) 668 { 669 struct ifnet *ifp = &sc->sc_ac.ac_if; 670 struct ifnet *ifp0; 671 672 NET_ASSERT_LOCKED(); 673 674 CLR(ifp->if_flags, IFF_RUNNING); 675 676 ifp0 = if_get(sc->sc_key.k_if); 677 if (ifp0 != NULL) { 678 if_detachhook_del(ifp0, &sc->sc_dtask); 679 if_linkstatehook_del(ifp0, &sc->sc_ltask); 680 bpe_multi(sc, ifp0, SIOCDELMULTI); 681 } 682 if_put(ifp0); 683 684 rw_enter(&bpe_lock, RW_WRITE); 685 RBT_REMOVE(bpe_tree, &bpe_interfaces, (struct bpe_key *)sc); 686 rw_exit(&bpe_lock); 687 688 CLR(ifp->if_flags, IFF_SIMPLEX); 689 ifp->if_hardmtu = 0xffff; 690 691 return (0); 692 } 693 694 static int 695 bpe_multi(struct bpe_softc *sc, struct ifnet *ifp0, u_long cmd) 696 { 697 struct ifreq ifr; 698 struct sockaddr *sa; 699 700 /* make it convincing */ 701 CTASSERT(sizeof(ifr.ifr_name) == sizeof(ifp0->if_xname)); 702 memcpy(ifr.ifr_name, ifp0->if_xname, sizeof(ifr.ifr_name)); 703 704 sa = &ifr.ifr_addr; 705 CTASSERT(sizeof(sa->sa_data) >= sizeof(sc->sc_group)); 706 707 sa->sa_family = AF_UNSPEC; 708 memcpy(sa->sa_data, sc->sc_group, sizeof(sc->sc_group)); 709 710 return ((*ifp0->if_ioctl)(ifp0, cmd, (caddr_t)&ifr)); 711 } 712 713 static void 714 bpe_set_group(struct bpe_softc *sc, uint32_t isid) 715 { 716 uint8_t *group = sc->sc_group; 717 718 group[0] = 0x01; 719 group[1] = 0x1e; 720 group[2] = 0x83; 721 group[3] = isid >> 16; 722 group[4] = isid >> 8; 723 group[5] = isid >> 0; 724 } 725 726 static int 727 bpe_set_vnetid(struct bpe_softc *sc, const struct ifreq *ifr) 728 { 729 struct ifnet *ifp = &sc->sc_ac.ac_if; 730 uint32_t isid; 731 732 if (ifr->ifr_vnetid < PBB_ITAG_ISID_MIN || 733 ifr->ifr_vnetid > PBB_ITAG_ISID_MAX) 734 return (EINVAL); 735 736 isid = ifr->ifr_vnetid; 737 if (isid == sc->sc_key.k_isid) 738 return (0); 739 740 if (ISSET(ifp->if_flags, IFF_RUNNING)) 741 return (EBUSY); 742 743 /* commit */ 744 sc->sc_key.k_isid = isid; 745 bpe_set_group(sc, isid); 746 bpe_flush_map(sc, IFBF_FLUSHALL); 747 748 return (0); 749 } 750 751 static int 752 bpe_set_parent(struct bpe_softc *sc, const struct if_parent *p) 753 { 754 struct ifnet *ifp = &sc->sc_ac.ac_if; 755 struct ifnet *ifp0; 756 757 ifp0 = ifunit(p->ifp_parent); /* doesn't need an if_put */ 758 if (ifp0 == NULL) 759 return (ENXIO); 760 761 if (ifp0->if_type != IFT_ETHER) 762 return (ENXIO); 763 764 if (ifp0->if_index == sc->sc_key.k_if) 765 return (0); 766 767 if (ISSET(ifp->if_flags, IFF_RUNNING)) 768 return (EBUSY); 769 770 /* commit */ 771 sc->sc_key.k_if = ifp0->if_index; 772 bpe_flush_map(sc, IFBF_FLUSHALL); 773 774 return (0); 775 } 776 777 static int 778 bpe_get_parent(struct bpe_softc *sc, struct if_parent *p) 779 { 780 struct ifnet *ifp0; 781 int error = 0; 782 783 ifp0 = if_get(sc->sc_key.k_if); 784 if (ifp0 == NULL) 785 error = EADDRNOTAVAIL; 786 else 787 memcpy(p->ifp_parent, ifp0->if_xname, sizeof(p->ifp_parent)); 788 if_put(ifp0); 789 790 return (error); 791 } 792 793 static int 794 bpe_del_parent(struct bpe_softc *sc) 795 { 796 struct ifnet *ifp = &sc->sc_ac.ac_if; 797 798 if (ISSET(ifp->if_flags, IFF_RUNNING)) 799 return (EBUSY); 800 801 /* commit */ 802 sc->sc_key.k_if = 0; 803 bpe_flush_map(sc, IFBF_FLUSHALL); 804 805 return (0); 806 } 807 808 static inline struct bpe_softc * 809 bpe_find(struct ifnet *ifp0, uint32_t isid) 810 { 811 struct bpe_key k = { .k_if = ifp0->if_index, .k_isid = isid }; 812 struct bpe_softc *sc; 813 814 rw_enter_read(&bpe_lock); 815 sc = (struct bpe_softc *)RBT_FIND(bpe_tree, &bpe_interfaces, &k); 816 rw_exit_read(&bpe_lock); 817 818 return (sc); 819 } 820 821 static void 822 bpe_input_map(struct bpe_softc *sc, const uint8_t *ba, const uint8_t *ca) 823 { 824 struct bpe_entry *be; 825 int new = 0; 826 827 if (ETHER_IS_MULTICAST(ca)) 828 return; 829 830 /* remember where it came from */ 831 rw_enter_read(&sc->sc_bridge_lock); 832 be = RBT_FIND(bpe_map, &sc->sc_bridge_map, (struct bpe_entry *)ca); 833 if (be == NULL) 834 new = 1; 835 else { 836 be->be_age = getuptime(); /* only a little bit racy */ 837 838 if (be->be_type != BPE_ENTRY_DYNAMIC || 839 ETHER_IS_EQ(ba, &be->be_b_da)) 840 be = NULL; 841 else 842 refcnt_take(&be->be_refs); 843 } 844 rw_exit_read(&sc->sc_bridge_lock); 845 846 if (new) { 847 struct bpe_entry *obe; 848 unsigned int num; 849 850 be = pool_get(&bpe_entry_pool, PR_NOWAIT); 851 if (be == NULL) { 852 /* oh well */ 853 return; 854 } 855 856 memcpy(&be->be_c_da, ca, sizeof(be->be_c_da)); 857 memcpy(&be->be_b_da, ba, sizeof(be->be_b_da)); 858 be->be_type = BPE_ENTRY_DYNAMIC; 859 refcnt_init(&be->be_refs); 860 be->be_age = getuptime(); 861 862 rw_enter_write(&sc->sc_bridge_lock); 863 num = sc->sc_bridge_num; 864 if (++num > sc->sc_bridge_max) 865 obe = be; 866 else { 867 /* try and give the ref to the map */ 868 obe = RBT_INSERT(bpe_map, &sc->sc_bridge_map, be); 869 if (obe == NULL) { 870 /* count the insert */ 871 sc->sc_bridge_num = num; 872 } 873 } 874 rw_exit_write(&sc->sc_bridge_lock); 875 876 if (obe != NULL) 877 pool_put(&bpe_entry_pool, obe); 878 } else if (be != NULL) { 879 rw_enter_write(&sc->sc_bridge_lock); 880 memcpy(&be->be_b_da, ba, sizeof(be->be_b_da)); 881 rw_exit_write(&sc->sc_bridge_lock); 882 883 if (refcnt_rele(&be->be_refs)) { 884 /* ioctl may have deleted the entry */ 885 pool_put(&bpe_entry_pool, be); 886 } 887 } 888 } 889 890 void 891 bpe_input(struct ifnet *ifp0, struct mbuf *m) 892 { 893 struct bpe_softc *sc; 894 struct ifnet *ifp; 895 struct ether_header *beh, *ceh; 896 uint32_t *itagp, itag; 897 unsigned int hlen = sizeof(*beh) + sizeof(*itagp) + sizeof(*ceh); 898 struct mbuf *n; 899 int off; 900 int prio; 901 902 if (m->m_len < hlen) { 903 m = m_pullup(m, hlen); 904 if (m == NULL) { 905 /* pbb short ++ */ 906 return; 907 } 908 } 909 910 beh = mtod(m, struct ether_header *); 911 itagp = (uint32_t *)(beh + 1); 912 itag = bemtoh32(itagp); 913 914 if (itag & PBB_ITAG_RES2) { 915 /* dropped by res2 ++ */ 916 goto drop; 917 } 918 919 sc = bpe_find(ifp0, itag & PBB_ITAG_ISID); 920 if (sc == NULL) { 921 /* no interface found */ 922 goto drop; 923 } 924 925 ceh = (struct ether_header *)(itagp + 1); 926 927 bpe_input_map(sc, beh->ether_shost, ceh->ether_shost); 928 929 m_adj(m, sizeof(*beh) + sizeof(*itagp)); 930 931 n = m_getptr(m, sizeof(*ceh), &off); 932 if (n == NULL) { 933 /* no data ++ */ 934 goto drop; 935 } 936 937 if (!ALIGNED_POINTER(mtod(n, caddr_t) + off, uint32_t)) { 938 /* unaligned ++ */ 939 n = m_dup_pkt(m, ETHER_ALIGN, M_NOWAIT); 940 m_freem(m); 941 if (n == NULL) 942 return; 943 944 m = n; 945 } 946 947 ifp = &sc->sc_ac.ac_if; 948 949 prio = sc->sc_rxhprio; 950 switch (prio) { 951 case IF_HDRPRIO_PACKET: 952 break; 953 case IF_HDRPRIO_OUTER: 954 m->m_pkthdr.pf.prio = (itag & PBB_ITAG_PCP_MASK) >> 955 PBB_ITAG_PCP_SHIFT; 956 break; 957 default: 958 m->m_pkthdr.pf.prio = prio; 959 break; 960 } 961 962 m->m_flags &= ~(M_BCAST|M_MCAST); 963 m->m_pkthdr.ph_ifidx = ifp->if_index; 964 m->m_pkthdr.ph_rtableid = ifp->if_rdomain; 965 966 #if NPF > 0 967 pf_pkt_addr_changed(m); 968 #endif 969 970 if_vinput(ifp, m); 971 return; 972 973 drop: 974 m_freem(m); 975 } 976 977 void 978 bpe_detach_hook(void *arg) 979 { 980 struct bpe_softc *sc = arg; 981 struct ifnet *ifp = &sc->sc_ac.ac_if; 982 983 if (ISSET(ifp->if_flags, IFF_RUNNING)) { 984 bpe_down(sc); 985 CLR(ifp->if_flags, IFF_UP); 986 } 987 988 sc->sc_key.k_if = 0; 989 } 990 991 static void 992 bpe_link_hook(void *arg) 993 { 994 struct bpe_softc *sc = arg; 995 struct ifnet *ifp0; 996 u_char link = LINK_STATE_DOWN; 997 uint64_t baud = 0; 998 999 ifp0 = if_get(sc->sc_key.k_if); 1000 if (ifp0 != NULL) { 1001 link = ifp0->if_link_state; 1002 baud = ifp0->if_baudrate; 1003 } 1004 if_put(ifp0); 1005 1006 bpe_link_state(sc, link, baud); 1007 } 1008 1009 void 1010 bpe_link_state(struct bpe_softc *sc, u_char link, uint64_t baud) 1011 { 1012 struct ifnet *ifp = &sc->sc_ac.ac_if; 1013 1014 if (ifp->if_link_state == link) 1015 return; 1016 1017 ifp->if_link_state = link; 1018 ifp->if_baudrate = baud; 1019 1020 if_link_state_change(ifp); 1021 } 1022 1023 static inline int 1024 bpe_cmp(const struct bpe_key *a, const struct bpe_key *b) 1025 { 1026 if (a->k_if > b->k_if) 1027 return (1); 1028 if (a->k_if < b->k_if) 1029 return (-1); 1030 if (a->k_isid > b->k_isid) 1031 return (1); 1032 if (a->k_isid < b->k_isid) 1033 return (-1); 1034 1035 return (0); 1036 } 1037 1038 static inline int 1039 bpe_entry_cmp(const struct bpe_entry *a, const struct bpe_entry *b) 1040 { 1041 return memcmp(&a->be_c_da, &b->be_c_da, sizeof(a->be_c_da)); 1042 } 1043