1 /* $OpenBSD: if_bpe.c,v 1.5 2019/04/23 10:53:45 dlg 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 void * sc_lh_cookie; 106 void * sc_dh_cookie; 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 #define ether_cmp(_a, _b) memcmp((_a), (_b), ETHER_ADDR_LEN) 148 #define ether_is_eq(_a, _b) (ether_cmp((_a), (_b)) == 0) 149 #define ether_is_bcast(_a) ether_is_eq((_a), etherbroadcastaddr) 150 151 void 152 bpeattach(int count) 153 { 154 if_clone_attach(&bpe_cloner); 155 } 156 157 static int 158 bpe_clone_create(struct if_clone *ifc, int unit) 159 { 160 struct bpe_softc *sc; 161 struct ifnet *ifp; 162 163 if (bpe_entry_pool.pr_size == 0) { 164 pool_init(&bpe_entry_pool, sizeof(struct bpe_entry), 0, 165 IPL_NONE, 0, "bpepl", NULL); 166 } 167 168 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO); 169 ifp = &sc->sc_ac.ac_if; 170 171 snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", 172 ifc->ifc_name, unit); 173 174 sc->sc_key.k_if = 0; 175 sc->sc_key.k_isid = 0; 176 bpe_set_group(sc, 0); 177 178 sc->sc_txhprio = IF_HDRPRIO_PACKET; 179 sc->sc_txhprio = IF_HDRPRIO_OUTER; 180 181 rw_init(&sc->sc_bridge_lock, "bpebr"); 182 RBT_INIT(bpe_map, &sc->sc_bridge_map); 183 sc->sc_bridge_num = 0; 184 sc->sc_bridge_max = 100; /* XXX */ 185 sc->sc_bridge_tmo = 240; 186 timeout_set_proc(&sc->sc_bridge_age, bpe_bridge_age, sc); 187 188 ifp->if_softc = sc; 189 ifp->if_hardmtu = ETHER_MAX_HARDMTU_LEN; 190 ifp->if_ioctl = bpe_ioctl; 191 ifp->if_start = bpe_start; 192 ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST; 193 ifp->if_xflags = IFXF_CLONED; 194 IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 195 ether_fakeaddr(ifp); 196 197 if_counters_alloc(ifp); 198 if_attach(ifp); 199 ether_ifattach(ifp); 200 201 return (0); 202 } 203 204 static int 205 bpe_clone_destroy(struct ifnet *ifp) 206 { 207 struct bpe_softc *sc = ifp->if_softc; 208 209 NET_LOCK(); 210 if (ISSET(ifp->if_flags, IFF_RUNNING)) 211 bpe_down(sc); 212 NET_UNLOCK(); 213 214 ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY); 215 ether_ifdetach(ifp); 216 if_detach(ifp); 217 218 free(sc, M_DEVBUF, sizeof(*sc)); 219 220 return (0); 221 } 222 223 static inline int 224 bpe_entry_valid(struct bpe_softc *sc, const struct bpe_entry *be) 225 { 226 time_t diff; 227 228 if (be == NULL) 229 return (0); 230 231 if (be->be_type == BPE_ENTRY_STATIC) 232 return (1); 233 234 diff = time_uptime - be->be_age; 235 if (diff < sc->sc_bridge_tmo) 236 return (1); 237 238 return (0); 239 } 240 241 static void 242 bpe_start(struct ifnet *ifp) 243 { 244 struct bpe_softc *sc = ifp->if_softc; 245 struct ifnet *ifp0; 246 struct mbuf *m0, *m; 247 struct ether_header *ceh; 248 struct ether_header *beh; 249 uint32_t itag, *itagp; 250 int hlen = sizeof(*beh) + sizeof(*itagp); 251 #if NBPFILTER > 0 252 caddr_t if_bpf; 253 #endif 254 int txprio; 255 uint8_t prio; 256 257 ifp0 = if_get(sc->sc_key.k_if); 258 if (ifp0 == NULL || !ISSET(ifp0->if_flags, IFF_RUNNING)) { 259 ifq_purge(&ifp->if_snd); 260 goto done; 261 } 262 263 txprio = sc->sc_txhprio; 264 265 while ((m0 = ifq_dequeue(&ifp->if_snd)) != NULL) { 266 #if NBPFILTER > 0 267 if_bpf = ifp->if_bpf; 268 if (if_bpf) 269 bpf_mtap_ether(if_bpf, m0, BPF_DIRECTION_OUT); 270 #endif 271 272 ceh = mtod(m0, struct ether_header *); 273 274 /* force prepend of a whole mbuf because of alignment */ 275 m = m_get(M_DONTWAIT, m0->m_type); 276 if (m == NULL) { 277 m_freem(m0); 278 continue; 279 } 280 281 M_MOVE_PKTHDR(m, m0); 282 m->m_next = m0; 283 284 m_align(m, 0); 285 m->m_len = 0; 286 287 m = m_prepend(m, hlen, M_DONTWAIT); 288 if (m == NULL) 289 continue; 290 291 beh = mtod(m, struct ether_header *); 292 293 if (ether_is_bcast(ceh->ether_dhost)) { 294 memcpy(beh->ether_dhost, sc->sc_group, 295 sizeof(beh->ether_dhost)); 296 } else { 297 struct bpe_entry *be; 298 299 rw_enter_read(&sc->sc_bridge_lock); 300 be = RBT_FIND(bpe_map, &sc->sc_bridge_map, 301 (struct bpe_entry *)ceh->ether_dhost); 302 if (bpe_entry_valid(sc, be)) { 303 memcpy(beh->ether_dhost, &be->be_b_da, 304 sizeof(beh->ether_dhost)); 305 } else { 306 /* "flood" to unknown hosts */ 307 memcpy(beh->ether_dhost, sc->sc_group, 308 sizeof(beh->ether_dhost)); 309 } 310 rw_exit_read(&sc->sc_bridge_lock); 311 } 312 313 memcpy(beh->ether_shost, ((struct arpcom *)ifp0)->ac_enaddr, 314 sizeof(beh->ether_shost)); 315 beh->ether_type = htons(ETHERTYPE_PBB); 316 317 prio = (txprio == IF_HDRPRIO_PACKET) ? 318 m->m_pkthdr.pf.prio : txprio; 319 320 itag = sc->sc_key.k_isid; 321 itag |= prio << PBB_ITAG_PCP_SHIFT; 322 itagp = (uint32_t *)(beh + 1); 323 324 htobem32(itagp, itag); 325 326 if_enqueue(ifp0, m); 327 } 328 329 done: 330 if_put(ifp0); 331 } 332 333 static void 334 bpe_bridge_age(void *arg) 335 { 336 struct bpe_softc *sc = arg; 337 struct bpe_entry *be, *nbe; 338 time_t diff; 339 340 timeout_add_sec(&sc->sc_bridge_age, BPE_BRIDGE_AGE_TMO); 341 342 rw_enter_write(&sc->sc_bridge_lock); 343 RBT_FOREACH_SAFE(be, bpe_map, &sc->sc_bridge_map, nbe) { 344 if (be->be_type != BPE_ENTRY_DYNAMIC) 345 continue; 346 347 diff = time_uptime - be->be_age; 348 if (diff < sc->sc_bridge_tmo) 349 continue; 350 351 sc->sc_bridge_num--; 352 RBT_REMOVE(bpe_map, &sc->sc_bridge_map, be); 353 if (refcnt_rele(&be->be_refs)) 354 pool_put(&bpe_entry_pool, be); 355 } 356 rw_exit_write(&sc->sc_bridge_lock); 357 } 358 359 static int 360 bpe_rtfind(struct bpe_softc *sc, struct ifbaconf *baconf) 361 { 362 struct ifnet *ifp = &sc->sc_ac.ac_if; 363 struct bpe_entry *be; 364 struct ifbareq bareq; 365 caddr_t uaddr, end; 366 int error; 367 time_t age; 368 struct sockaddr_dl *sdl; 369 370 if (baconf->ifbac_len == 0) { 371 /* single read is atomic */ 372 baconf->ifbac_len = sc->sc_bridge_num * sizeof(bareq); 373 return (0); 374 } 375 376 uaddr = baconf->ifbac_buf; 377 end = uaddr + baconf->ifbac_len; 378 379 rw_enter_read(&sc->sc_bridge_lock); 380 RBT_FOREACH(be, bpe_map, &sc->sc_bridge_map) { 381 if (uaddr >= end) 382 break; 383 384 memcpy(bareq.ifba_name, ifp->if_xname, 385 sizeof(bareq.ifba_name)); 386 memcpy(bareq.ifba_ifsname, ifp->if_xname, 387 sizeof(bareq.ifba_ifsname)); 388 memcpy(&bareq.ifba_dst, &be->be_c_da, 389 sizeof(bareq.ifba_dst)); 390 391 memset(&bareq.ifba_dstsa, 0, sizeof(bareq.ifba_dstsa)); 392 393 bzero(&bareq.ifba_dstsa, sizeof(bareq.ifba_dstsa)); 394 sdl = (struct sockaddr_dl *)&bareq.ifba_dstsa; 395 sdl->sdl_len = sizeof(sdl); 396 sdl->sdl_family = AF_LINK; 397 sdl->sdl_index = 0; 398 sdl->sdl_type = IFT_ETHER; 399 sdl->sdl_nlen = 0; 400 sdl->sdl_alen = sizeof(be->be_b_da); 401 CTASSERT(sizeof(sdl->sdl_data) >= sizeof(be->be_b_da)); 402 memcpy(sdl->sdl_data, &be->be_b_da, sizeof(be->be_b_da)); 403 404 switch (be->be_type) { 405 case BPE_ENTRY_DYNAMIC: 406 age = time_uptime - be->be_age; 407 bareq.ifba_age = MIN(age, 0xff); 408 bareq.ifba_flags = IFBAF_DYNAMIC; 409 break; 410 case BPE_ENTRY_STATIC: 411 bareq.ifba_age = 0; 412 bareq.ifba_flags = IFBAF_STATIC; 413 break; 414 } 415 416 error = copyout(&bareq, uaddr, sizeof(bareq)); 417 if (error != 0) { 418 rw_exit_read(&sc->sc_bridge_lock); 419 return (error); 420 } 421 422 uaddr += sizeof(bareq); 423 } 424 baconf->ifbac_len = sc->sc_bridge_num * sizeof(bareq); 425 rw_exit_read(&sc->sc_bridge_lock); 426 427 return (0); 428 } 429 430 static void 431 bpe_flush_map(struct bpe_softc *sc, uint32_t flags) 432 { 433 struct bpe_entry *be, *nbe; 434 435 rw_enter_write(&sc->sc_bridge_lock); 436 RBT_FOREACH_SAFE(be, bpe_map, &sc->sc_bridge_map, nbe) { 437 if (flags == IFBF_FLUSHDYN && 438 be->be_type != BPE_ENTRY_DYNAMIC) 439 continue; 440 441 RBT_REMOVE(bpe_map, &sc->sc_bridge_map, be); 442 if (refcnt_rele(&be->be_refs)) 443 pool_put(&bpe_entry_pool, be); 444 } 445 rw_exit_write(&sc->sc_bridge_lock); 446 } 447 448 static int 449 bpe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 450 { 451 struct bpe_softc *sc = ifp->if_softc; 452 struct ifreq *ifr = (struct ifreq *)data; 453 struct ifbrparam *bparam = (struct ifbrparam *)data; 454 int error = 0; 455 456 switch (cmd) { 457 case SIOCSIFFLAGS: 458 if (ISSET(ifp->if_flags, IFF_UP)) { 459 if (!ISSET(ifp->if_flags, IFF_RUNNING)) 460 error = bpe_up(sc); 461 else 462 error = 0; 463 } else { 464 if (ISSET(ifp->if_flags, IFF_RUNNING)) 465 error = bpe_down(sc); 466 } 467 break; 468 469 case SIOCSVNETID: 470 error = bpe_set_vnetid(sc, ifr); 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 sc->sc_lh_cookie = hook_establish(ifp0->if_linkstatehooks, 1, 639 bpe_link_hook, sc); 640 641 /* Register callback if parent wants to unregister */ 642 sc->sc_dh_cookie = hook_establish(ifp0->if_detachhooks, 0, 643 bpe_detach_hook, sc); 644 645 /* we're running now */ 646 SET(ifp->if_flags, IFF_RUNNING); 647 bpe_link_state(sc, ifp0->if_link_state, ifp0->if_baudrate); 648 649 if_put(ifp0); 650 651 timeout_add_sec(&sc->sc_bridge_age, BPE_BRIDGE_AGE_TMO); 652 653 return (0); 654 655 remove: 656 rw_enter(&bpe_lock, RW_WRITE); 657 RBT_REMOVE(bpe_tree, &bpe_interfaces, (struct bpe_key *)sc); 658 rw_exit(&bpe_lock); 659 scrub: 660 CLR(ifp->if_flags, IFF_SIMPLEX); 661 ifp->if_hardmtu = 0xffff; 662 put: 663 if_put(ifp0); 664 665 return (error); 666 } 667 668 static int 669 bpe_down(struct bpe_softc *sc) 670 { 671 struct ifnet *ifp = &sc->sc_ac.ac_if; 672 struct ifnet *ifp0; 673 674 NET_ASSERT_LOCKED(); 675 676 CLR(ifp->if_flags, IFF_RUNNING); 677 678 ifp0 = if_get(sc->sc_key.k_if); 679 if (ifp0 != NULL) { 680 hook_disestablish(ifp0->if_detachhooks, sc->sc_dh_cookie); 681 hook_disestablish(ifp0->if_linkstatehooks, sc->sc_lh_cookie); 682 bpe_multi(sc, ifp0, SIOCDELMULTI); 683 } 684 if_put(ifp0); 685 686 rw_enter(&bpe_lock, RW_WRITE); 687 RBT_REMOVE(bpe_tree, &bpe_interfaces, (struct bpe_key *)sc); 688 rw_exit(&bpe_lock); 689 690 CLR(ifp->if_flags, IFF_SIMPLEX); 691 ifp->if_hardmtu = 0xffff; 692 693 return (0); 694 } 695 696 static int 697 bpe_multi(struct bpe_softc *sc, struct ifnet *ifp0, u_long cmd) 698 { 699 struct ifreq ifr; 700 struct sockaddr *sa; 701 702 /* make it convincing */ 703 CTASSERT(sizeof(ifr.ifr_name) == sizeof(ifp0->if_xname)); 704 memcpy(ifr.ifr_name, ifp0->if_xname, sizeof(ifr.ifr_name)); 705 706 sa = &ifr.ifr_addr; 707 CTASSERT(sizeof(sa->sa_data) >= sizeof(sc->sc_group)); 708 709 sa->sa_family = AF_UNSPEC; 710 memcpy(sa->sa_data, sc->sc_group, sizeof(sc->sc_group)); 711 712 return ((*ifp0->if_ioctl)(ifp0, cmd, (caddr_t)&ifr)); 713 } 714 715 static void 716 bpe_set_group(struct bpe_softc *sc, uint32_t isid) 717 { 718 uint8_t *group = sc->sc_group; 719 720 group[0] = 0x01; 721 group[1] = 0x1e; 722 group[2] = 0x83; 723 group[3] = isid >> 16; 724 group[4] = isid >> 8; 725 group[5] = isid >> 0; 726 } 727 728 static int 729 bpe_set_vnetid(struct bpe_softc *sc, const struct ifreq *ifr) 730 { 731 struct ifnet *ifp = &sc->sc_ac.ac_if; 732 uint32_t isid; 733 734 if (ifr->ifr_vnetid < PBB_ITAG_ISID_MIN || 735 ifr->ifr_vnetid > PBB_ITAG_ISID_MAX) 736 return (EINVAL); 737 738 isid = ifr->ifr_vnetid; 739 if (isid == sc->sc_key.k_isid) 740 return (0); 741 742 if (ISSET(ifp->if_flags, IFF_RUNNING)) 743 return (EBUSY); 744 745 /* commit */ 746 sc->sc_key.k_isid = isid; 747 bpe_set_group(sc, isid); 748 bpe_flush_map(sc, IFBF_FLUSHALL); 749 750 return (0); 751 } 752 753 static int 754 bpe_set_parent(struct bpe_softc *sc, const struct if_parent *p) 755 { 756 struct ifnet *ifp = &sc->sc_ac.ac_if; 757 struct ifnet *ifp0; 758 759 ifp0 = ifunit(p->ifp_parent); /* doesn't need an if_put */ 760 if (ifp0 == NULL) 761 return (ENXIO); 762 763 if (ifp0->if_type != IFT_ETHER) 764 return (ENXIO); 765 766 if (ifp0->if_index == sc->sc_key.k_if) 767 return (0); 768 769 if (ISSET(ifp->if_flags, IFF_RUNNING)) 770 return (EBUSY); 771 772 /* commit */ 773 sc->sc_key.k_if = ifp0->if_index; 774 bpe_flush_map(sc, IFBF_FLUSHALL); 775 776 return (0); 777 } 778 779 static int 780 bpe_get_parent(struct bpe_softc *sc, struct if_parent *p) 781 { 782 struct ifnet *ifp0; 783 int error = 0; 784 785 ifp0 = if_get(sc->sc_key.k_if); 786 if (ifp0 == NULL) 787 error = EADDRNOTAVAIL; 788 else 789 memcpy(p->ifp_parent, ifp0->if_xname, sizeof(p->ifp_parent)); 790 if_put(ifp0); 791 792 return (error); 793 } 794 795 static int 796 bpe_del_parent(struct bpe_softc *sc) 797 { 798 struct ifnet *ifp = &sc->sc_ac.ac_if; 799 800 if (ISSET(ifp->if_flags, IFF_RUNNING)) 801 return (EBUSY); 802 803 /* commit */ 804 sc->sc_key.k_if = 0; 805 bpe_flush_map(sc, IFBF_FLUSHALL); 806 807 return (0); 808 } 809 810 static inline struct bpe_softc * 811 bpe_find(struct ifnet *ifp0, uint32_t isid) 812 { 813 struct bpe_key k = { .k_if = ifp0->if_index, .k_isid = isid }; 814 struct bpe_softc *sc; 815 816 rw_enter_read(&bpe_lock); 817 sc = (struct bpe_softc *)RBT_FIND(bpe_tree, &bpe_interfaces, &k); 818 rw_exit_read(&bpe_lock); 819 820 return (sc); 821 } 822 823 static void 824 bpe_input_map(struct bpe_softc *sc, const uint8_t *ba, const uint8_t *ca) 825 { 826 struct bpe_entry *be; 827 int new = 0; 828 829 if (ETHER_IS_MULTICAST(ca)) 830 return; 831 832 /* remember where it came from */ 833 rw_enter_read(&sc->sc_bridge_lock); 834 be = RBT_FIND(bpe_map, &sc->sc_bridge_map, (struct bpe_entry *)ca); 835 if (be == NULL) 836 new = 1; 837 else { 838 be->be_age = time_uptime; /* only a little bit racy */ 839 840 if (be->be_type != BPE_ENTRY_DYNAMIC || 841 ether_is_eq(ba, &be->be_b_da)) 842 be = NULL; 843 else 844 refcnt_take(&be->be_refs); 845 } 846 rw_exit_read(&sc->sc_bridge_lock); 847 848 if (new) { 849 struct bpe_entry *obe; 850 unsigned int num; 851 852 be = pool_get(&bpe_entry_pool, PR_NOWAIT); 853 if (be == NULL) { 854 /* oh well */ 855 return; 856 } 857 858 memcpy(&be->be_c_da, ca, sizeof(be->be_c_da)); 859 memcpy(&be->be_b_da, ba, sizeof(be->be_b_da)); 860 be->be_type = BPE_ENTRY_DYNAMIC; 861 refcnt_init(&be->be_refs); 862 be->be_age = time_uptime; 863 864 rw_enter_write(&sc->sc_bridge_lock); 865 num = sc->sc_bridge_num; 866 if (++num > sc->sc_bridge_max) 867 obe = be; 868 else { 869 /* try and give the ref to the map */ 870 obe = RBT_INSERT(bpe_map, &sc->sc_bridge_map, be); 871 if (obe == NULL) { 872 /* count the insert */ 873 sc->sc_bridge_num = num; 874 } 875 } 876 rw_exit_write(&sc->sc_bridge_lock); 877 878 if (obe != NULL) 879 pool_put(&bpe_entry_pool, obe); 880 } else if (be != NULL) { 881 rw_enter_write(&sc->sc_bridge_lock); 882 memcpy(&be->be_b_da, ba, sizeof(be->be_b_da)); 883 rw_exit_write(&sc->sc_bridge_lock); 884 885 if (refcnt_rele(&be->be_refs)) { 886 /* ioctl may have deleted the entry */ 887 pool_put(&bpe_entry_pool, be); 888 } 889 } 890 } 891 892 void 893 bpe_input(struct ifnet *ifp0, struct mbuf *m) 894 { 895 struct bpe_softc *sc; 896 struct ifnet *ifp; 897 struct ether_header *beh, *ceh; 898 uint32_t *itagp, itag; 899 unsigned int hlen = sizeof(*beh) + sizeof(*itagp) + sizeof(*ceh); 900 struct mbuf *n; 901 int off; 902 int prio; 903 904 if (m->m_len < hlen) { 905 m = m_pullup(m, hlen); 906 if (m == NULL) { 907 /* pbb short ++ */ 908 return; 909 } 910 } 911 912 beh = mtod(m, struct ether_header *); 913 itagp = (uint32_t *)(beh + 1); 914 itag = bemtoh32(itagp); 915 916 if (itag & PBB_ITAG_RES2) { 917 /* dropped by res2 ++ */ 918 goto drop; 919 } 920 921 sc = bpe_find(ifp0, itag & PBB_ITAG_ISID); 922 if (sc == NULL) { 923 /* no interface found */ 924 goto drop; 925 } 926 927 ceh = (struct ether_header *)(itagp + 1); 928 929 bpe_input_map(sc, beh->ether_shost, ceh->ether_shost); 930 931 m_adj(m, sizeof(*beh) + sizeof(*itagp)); 932 933 n = m_getptr(m, sizeof(*ceh), &off); 934 if (n == NULL) { 935 /* no data ++ */ 936 goto drop; 937 } 938 939 if (!ALIGNED_POINTER(mtod(n, caddr_t) + off, uint32_t)) { 940 /* unaligned ++ */ 941 n = m_dup_pkt(m, ETHER_ALIGN, M_NOWAIT); 942 m_freem(m); 943 if (n == NULL) 944 return; 945 946 m = n; 947 } 948 949 ifp = &sc->sc_ac.ac_if; 950 951 prio = sc->sc_rxhprio; 952 switch (prio) { 953 case IF_HDRPRIO_PACKET: 954 break; 955 case IF_HDRPRIO_OUTER: 956 m->m_pkthdr.pf.prio = (itag & PBB_ITAG_PCP_MASK) >> 957 PBB_ITAG_PCP_SHIFT; 958 break; 959 default: 960 m->m_pkthdr.pf.prio = prio; 961 break; 962 } 963 964 m->m_flags &= ~(M_BCAST|M_MCAST); 965 m->m_pkthdr.ph_ifidx = ifp->if_index; 966 m->m_pkthdr.ph_rtableid = ifp->if_rdomain; 967 968 #if NPF > 0 969 pf_pkt_addr_changed(m); 970 #endif 971 972 if_vinput(ifp, m); 973 return; 974 975 drop: 976 m_freem(m); 977 } 978 979 void 980 bpe_detach_hook(void *arg) 981 { 982 struct bpe_softc *sc = arg; 983 struct ifnet *ifp = &sc->sc_ac.ac_if; 984 985 if (ISSET(ifp->if_flags, IFF_RUNNING)) { 986 bpe_down(sc); 987 CLR(ifp->if_flags, IFF_UP); 988 } 989 990 sc->sc_key.k_if = 0; 991 } 992 993 static void 994 bpe_link_hook(void *arg) 995 { 996 struct bpe_softc *sc = arg; 997 struct ifnet *ifp0; 998 u_char link = LINK_STATE_DOWN; 999 uint64_t baud = 0; 1000 1001 ifp0 = if_get(sc->sc_key.k_if); 1002 if (ifp0 != NULL) { 1003 link = ifp0->if_link_state; 1004 baud = ifp0->if_baudrate; 1005 } 1006 if_put(ifp0); 1007 1008 bpe_link_state(sc, link, baud); 1009 } 1010 1011 void 1012 bpe_link_state(struct bpe_softc *sc, u_char link, uint64_t baud) 1013 { 1014 struct ifnet *ifp = &sc->sc_ac.ac_if; 1015 1016 if (ifp->if_link_state == link) 1017 return; 1018 1019 ifp->if_link_state = link; 1020 ifp->if_baudrate = baud; 1021 1022 if_link_state_change(ifp); 1023 } 1024 1025 static inline int 1026 bpe_cmp(const struct bpe_key *a, const struct bpe_key *b) 1027 { 1028 if (a->k_if > b->k_if) 1029 return (1); 1030 if (a->k_if < b->k_if) 1031 return (-1); 1032 if (a->k_isid > b->k_isid) 1033 return (1); 1034 if (a->k_isid < b->k_isid) 1035 return (-1); 1036 1037 return (0); 1038 } 1039 1040 static inline int 1041 bpe_entry_cmp(const struct bpe_entry *a, const struct bpe_entry *b) 1042 { 1043 return memcmp(&a->be_c_da, &b->be_c_da, sizeof(a->be_c_da)); 1044 } 1045