1 /* $OpenBSD: if_bpe.c,v 1.7 2019/05/21 10:11:10 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_rxhprio = 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 break; 472 case SIOCGVNETID: 473 ifr->ifr_vnetid = sc->sc_key.k_isid; 474 break; 475 476 case SIOCSIFPARENT: 477 error = bpe_set_parent(sc, (struct if_parent *)data); 478 break; 479 case SIOCGIFPARENT: 480 error = bpe_get_parent(sc, (struct if_parent *)data); 481 break; 482 case SIOCDIFPARENT: 483 error = bpe_del_parent(sc); 484 break; 485 486 case SIOCSTXHPRIO: 487 error = if_txhprio_l2_check(ifr->ifr_hdrprio); 488 if (error != 0) 489 break; 490 491 sc->sc_txhprio = ifr->ifr_hdrprio; 492 break; 493 case SIOCGTXHPRIO: 494 ifr->ifr_hdrprio = sc->sc_txhprio; 495 break; 496 497 case SIOCSRXHPRIO: 498 error = if_rxhprio_l2_check(ifr->ifr_hdrprio); 499 if (error != 0) 500 break; 501 502 sc->sc_rxhprio = ifr->ifr_hdrprio; 503 break; 504 case SIOCGRXHPRIO: 505 ifr->ifr_hdrprio = sc->sc_rxhprio; 506 break; 507 508 case SIOCGIFMEDIA: 509 error = bpe_media_get(sc, ifr); 510 break; 511 512 case SIOCBRDGSCACHE: 513 error = suser(curproc); 514 if (error != 0) 515 break; 516 517 if (bparam->ifbrp_csize < 1) { 518 error = EINVAL; 519 break; 520 } 521 522 /* commit */ 523 sc->sc_bridge_max = bparam->ifbrp_csize; 524 break; 525 case SIOCBRDGGCACHE: 526 bparam->ifbrp_csize = sc->sc_bridge_max; 527 break; 528 529 case SIOCBRDGSTO: 530 error = suser(curproc); 531 if (error != 0) 532 break; 533 534 if (bparam->ifbrp_ctime < 8 || 535 bparam->ifbrp_ctime > 3600) { 536 error = EINVAL; 537 break; 538 } 539 sc->sc_bridge_tmo = bparam->ifbrp_ctime; 540 break; 541 case SIOCBRDGGTO: 542 bparam->ifbrp_ctime = sc->sc_bridge_tmo; 543 break; 544 545 case SIOCBRDGRTS: 546 error = bpe_rtfind(sc, (struct ifbaconf *)data); 547 break; 548 case SIOCBRDGFLUSH: 549 error = suser(curproc); 550 if (error != 0) 551 break; 552 553 bpe_flush_map(sc, 554 ((struct ifbreq *)data)->ifbr_ifsflags); 555 break; 556 557 default: 558 error = ether_ioctl(ifp, &sc->sc_ac, cmd, data); 559 break; 560 } 561 562 return (error); 563 } 564 565 static int 566 bpe_media_get(struct bpe_softc *sc, struct ifreq *ifr) 567 { 568 struct ifnet *ifp0; 569 int error; 570 571 ifp0 = if_get(sc->sc_key.k_if); 572 if (ifp0 != NULL) 573 error = (*ifp0->if_ioctl)(ifp0, SIOCGIFMEDIA, (caddr_t)ifr); 574 else 575 error = ENOTTY; 576 if_put(ifp0); 577 578 return (error); 579 } 580 581 static int 582 bpe_up(struct bpe_softc *sc) 583 { 584 struct ifnet *ifp = &sc->sc_ac.ac_if; 585 struct ifnet *ifp0; 586 struct bpe_softc *osc; 587 int error = 0; 588 u_int hardmtu; 589 u_int hlen = sizeof(struct ether_header) + sizeof(uint32_t); 590 591 KASSERT(!ISSET(ifp->if_flags, IFF_RUNNING)); 592 NET_ASSERT_LOCKED(); 593 594 ifp0 = if_get(sc->sc_key.k_if); 595 if (ifp0 == NULL) 596 return (ENXIO); 597 598 /* check again if bpe will work on top of the parent */ 599 if (ifp0->if_type != IFT_ETHER) { 600 error = EPROTONOSUPPORT; 601 goto put; 602 } 603 604 hardmtu = ifp0->if_hardmtu; 605 if (hardmtu < hlen) { 606 error = ENOBUFS; 607 goto put; 608 } 609 hardmtu -= hlen; 610 if (ifp->if_mtu > hardmtu) { 611 error = ENOBUFS; 612 goto put; 613 } 614 615 /* parent is fine, let's prepare the bpe to handle packets */ 616 ifp->if_hardmtu = hardmtu; 617 SET(ifp->if_flags, ifp0->if_flags & IFF_SIMPLEX); 618 619 /* commit the interface */ 620 error = rw_enter(&bpe_lock, RW_WRITE | RW_INTR); 621 if (error != 0) 622 goto scrub; 623 624 osc = (struct bpe_softc *)RBT_INSERT(bpe_tree, &bpe_interfaces, 625 (struct bpe_key *)sc); 626 rw_exit(&bpe_lock); 627 628 if (osc != NULL) { 629 error = EADDRINUSE; 630 goto scrub; 631 } 632 633 if (bpe_multi(sc, ifp0, SIOCADDMULTI) != 0) { 634 error = ENOTCONN; 635 goto remove; 636 } 637 638 /* Register callback for physical link state changes */ 639 sc->sc_lh_cookie = hook_establish(ifp0->if_linkstatehooks, 1, 640 bpe_link_hook, sc); 641 642 /* Register callback if parent wants to unregister */ 643 sc->sc_dh_cookie = hook_establish(ifp0->if_detachhooks, 0, 644 bpe_detach_hook, sc); 645 646 /* we're running now */ 647 SET(ifp->if_flags, IFF_RUNNING); 648 bpe_link_state(sc, ifp0->if_link_state, ifp0->if_baudrate); 649 650 if_put(ifp0); 651 652 timeout_add_sec(&sc->sc_bridge_age, BPE_BRIDGE_AGE_TMO); 653 654 return (0); 655 656 remove: 657 rw_enter(&bpe_lock, RW_WRITE); 658 RBT_REMOVE(bpe_tree, &bpe_interfaces, (struct bpe_key *)sc); 659 rw_exit(&bpe_lock); 660 scrub: 661 CLR(ifp->if_flags, IFF_SIMPLEX); 662 ifp->if_hardmtu = 0xffff; 663 put: 664 if_put(ifp0); 665 666 return (error); 667 } 668 669 static int 670 bpe_down(struct bpe_softc *sc) 671 { 672 struct ifnet *ifp = &sc->sc_ac.ac_if; 673 struct ifnet *ifp0; 674 675 NET_ASSERT_LOCKED(); 676 677 CLR(ifp->if_flags, IFF_RUNNING); 678 679 ifp0 = if_get(sc->sc_key.k_if); 680 if (ifp0 != NULL) { 681 hook_disestablish(ifp0->if_detachhooks, sc->sc_dh_cookie); 682 hook_disestablish(ifp0->if_linkstatehooks, sc->sc_lh_cookie); 683 bpe_multi(sc, ifp0, SIOCDELMULTI); 684 } 685 if_put(ifp0); 686 687 rw_enter(&bpe_lock, RW_WRITE); 688 RBT_REMOVE(bpe_tree, &bpe_interfaces, (struct bpe_key *)sc); 689 rw_exit(&bpe_lock); 690 691 CLR(ifp->if_flags, IFF_SIMPLEX); 692 ifp->if_hardmtu = 0xffff; 693 694 return (0); 695 } 696 697 static int 698 bpe_multi(struct bpe_softc *sc, struct ifnet *ifp0, u_long cmd) 699 { 700 struct ifreq ifr; 701 struct sockaddr *sa; 702 703 /* make it convincing */ 704 CTASSERT(sizeof(ifr.ifr_name) == sizeof(ifp0->if_xname)); 705 memcpy(ifr.ifr_name, ifp0->if_xname, sizeof(ifr.ifr_name)); 706 707 sa = &ifr.ifr_addr; 708 CTASSERT(sizeof(sa->sa_data) >= sizeof(sc->sc_group)); 709 710 sa->sa_family = AF_UNSPEC; 711 memcpy(sa->sa_data, sc->sc_group, sizeof(sc->sc_group)); 712 713 return ((*ifp0->if_ioctl)(ifp0, cmd, (caddr_t)&ifr)); 714 } 715 716 static void 717 bpe_set_group(struct bpe_softc *sc, uint32_t isid) 718 { 719 uint8_t *group = sc->sc_group; 720 721 group[0] = 0x01; 722 group[1] = 0x1e; 723 group[2] = 0x83; 724 group[3] = isid >> 16; 725 group[4] = isid >> 8; 726 group[5] = isid >> 0; 727 } 728 729 static int 730 bpe_set_vnetid(struct bpe_softc *sc, const struct ifreq *ifr) 731 { 732 struct ifnet *ifp = &sc->sc_ac.ac_if; 733 uint32_t isid; 734 735 if (ifr->ifr_vnetid < PBB_ITAG_ISID_MIN || 736 ifr->ifr_vnetid > PBB_ITAG_ISID_MAX) 737 return (EINVAL); 738 739 isid = ifr->ifr_vnetid; 740 if (isid == sc->sc_key.k_isid) 741 return (0); 742 743 if (ISSET(ifp->if_flags, IFF_RUNNING)) 744 return (EBUSY); 745 746 /* commit */ 747 sc->sc_key.k_isid = isid; 748 bpe_set_group(sc, isid); 749 bpe_flush_map(sc, IFBF_FLUSHALL); 750 751 return (0); 752 } 753 754 static int 755 bpe_set_parent(struct bpe_softc *sc, const struct if_parent *p) 756 { 757 struct ifnet *ifp = &sc->sc_ac.ac_if; 758 struct ifnet *ifp0; 759 760 ifp0 = ifunit(p->ifp_parent); /* doesn't need an if_put */ 761 if (ifp0 == NULL) 762 return (ENXIO); 763 764 if (ifp0->if_type != IFT_ETHER) 765 return (ENXIO); 766 767 if (ifp0->if_index == sc->sc_key.k_if) 768 return (0); 769 770 if (ISSET(ifp->if_flags, IFF_RUNNING)) 771 return (EBUSY); 772 773 /* commit */ 774 sc->sc_key.k_if = ifp0->if_index; 775 bpe_flush_map(sc, IFBF_FLUSHALL); 776 777 return (0); 778 } 779 780 static int 781 bpe_get_parent(struct bpe_softc *sc, struct if_parent *p) 782 { 783 struct ifnet *ifp0; 784 int error = 0; 785 786 ifp0 = if_get(sc->sc_key.k_if); 787 if (ifp0 == NULL) 788 error = EADDRNOTAVAIL; 789 else 790 memcpy(p->ifp_parent, ifp0->if_xname, sizeof(p->ifp_parent)); 791 if_put(ifp0); 792 793 return (error); 794 } 795 796 static int 797 bpe_del_parent(struct bpe_softc *sc) 798 { 799 struct ifnet *ifp = &sc->sc_ac.ac_if; 800 801 if (ISSET(ifp->if_flags, IFF_RUNNING)) 802 return (EBUSY); 803 804 /* commit */ 805 sc->sc_key.k_if = 0; 806 bpe_flush_map(sc, IFBF_FLUSHALL); 807 808 return (0); 809 } 810 811 static inline struct bpe_softc * 812 bpe_find(struct ifnet *ifp0, uint32_t isid) 813 { 814 struct bpe_key k = { .k_if = ifp0->if_index, .k_isid = isid }; 815 struct bpe_softc *sc; 816 817 rw_enter_read(&bpe_lock); 818 sc = (struct bpe_softc *)RBT_FIND(bpe_tree, &bpe_interfaces, &k); 819 rw_exit_read(&bpe_lock); 820 821 return (sc); 822 } 823 824 static void 825 bpe_input_map(struct bpe_softc *sc, const uint8_t *ba, const uint8_t *ca) 826 { 827 struct bpe_entry *be; 828 int new = 0; 829 830 if (ETHER_IS_MULTICAST(ca)) 831 return; 832 833 /* remember where it came from */ 834 rw_enter_read(&sc->sc_bridge_lock); 835 be = RBT_FIND(bpe_map, &sc->sc_bridge_map, (struct bpe_entry *)ca); 836 if (be == NULL) 837 new = 1; 838 else { 839 be->be_age = time_uptime; /* only a little bit racy */ 840 841 if (be->be_type != BPE_ENTRY_DYNAMIC || 842 ether_is_eq(ba, &be->be_b_da)) 843 be = NULL; 844 else 845 refcnt_take(&be->be_refs); 846 } 847 rw_exit_read(&sc->sc_bridge_lock); 848 849 if (new) { 850 struct bpe_entry *obe; 851 unsigned int num; 852 853 be = pool_get(&bpe_entry_pool, PR_NOWAIT); 854 if (be == NULL) { 855 /* oh well */ 856 return; 857 } 858 859 memcpy(&be->be_c_da, ca, sizeof(be->be_c_da)); 860 memcpy(&be->be_b_da, ba, sizeof(be->be_b_da)); 861 be->be_type = BPE_ENTRY_DYNAMIC; 862 refcnt_init(&be->be_refs); 863 be->be_age = time_uptime; 864 865 rw_enter_write(&sc->sc_bridge_lock); 866 num = sc->sc_bridge_num; 867 if (++num > sc->sc_bridge_max) 868 obe = be; 869 else { 870 /* try and give the ref to the map */ 871 obe = RBT_INSERT(bpe_map, &sc->sc_bridge_map, be); 872 if (obe == NULL) { 873 /* count the insert */ 874 sc->sc_bridge_num = num; 875 } 876 } 877 rw_exit_write(&sc->sc_bridge_lock); 878 879 if (obe != NULL) 880 pool_put(&bpe_entry_pool, obe); 881 } else if (be != NULL) { 882 rw_enter_write(&sc->sc_bridge_lock); 883 memcpy(&be->be_b_da, ba, sizeof(be->be_b_da)); 884 rw_exit_write(&sc->sc_bridge_lock); 885 886 if (refcnt_rele(&be->be_refs)) { 887 /* ioctl may have deleted the entry */ 888 pool_put(&bpe_entry_pool, be); 889 } 890 } 891 } 892 893 void 894 bpe_input(struct ifnet *ifp0, struct mbuf *m) 895 { 896 struct bpe_softc *sc; 897 struct ifnet *ifp; 898 struct ether_header *beh, *ceh; 899 uint32_t *itagp, itag; 900 unsigned int hlen = sizeof(*beh) + sizeof(*itagp) + sizeof(*ceh); 901 struct mbuf *n; 902 int off; 903 int prio; 904 905 if (m->m_len < hlen) { 906 m = m_pullup(m, hlen); 907 if (m == NULL) { 908 /* pbb short ++ */ 909 return; 910 } 911 } 912 913 beh = mtod(m, struct ether_header *); 914 itagp = (uint32_t *)(beh + 1); 915 itag = bemtoh32(itagp); 916 917 if (itag & PBB_ITAG_RES2) { 918 /* dropped by res2 ++ */ 919 goto drop; 920 } 921 922 sc = bpe_find(ifp0, itag & PBB_ITAG_ISID); 923 if (sc == NULL) { 924 /* no interface found */ 925 goto drop; 926 } 927 928 ceh = (struct ether_header *)(itagp + 1); 929 930 bpe_input_map(sc, beh->ether_shost, ceh->ether_shost); 931 932 m_adj(m, sizeof(*beh) + sizeof(*itagp)); 933 934 n = m_getptr(m, sizeof(*ceh), &off); 935 if (n == NULL) { 936 /* no data ++ */ 937 goto drop; 938 } 939 940 if (!ALIGNED_POINTER(mtod(n, caddr_t) + off, uint32_t)) { 941 /* unaligned ++ */ 942 n = m_dup_pkt(m, ETHER_ALIGN, M_NOWAIT); 943 m_freem(m); 944 if (n == NULL) 945 return; 946 947 m = n; 948 } 949 950 ifp = &sc->sc_ac.ac_if; 951 952 prio = sc->sc_rxhprio; 953 switch (prio) { 954 case IF_HDRPRIO_PACKET: 955 break; 956 case IF_HDRPRIO_OUTER: 957 m->m_pkthdr.pf.prio = (itag & PBB_ITAG_PCP_MASK) >> 958 PBB_ITAG_PCP_SHIFT; 959 break; 960 default: 961 m->m_pkthdr.pf.prio = prio; 962 break; 963 } 964 965 m->m_flags &= ~(M_BCAST|M_MCAST); 966 m->m_pkthdr.ph_ifidx = ifp->if_index; 967 m->m_pkthdr.ph_rtableid = ifp->if_rdomain; 968 969 #if NPF > 0 970 pf_pkt_addr_changed(m); 971 #endif 972 973 if_vinput(ifp, m); 974 return; 975 976 drop: 977 m_freem(m); 978 } 979 980 void 981 bpe_detach_hook(void *arg) 982 { 983 struct bpe_softc *sc = arg; 984 struct ifnet *ifp = &sc->sc_ac.ac_if; 985 986 if (ISSET(ifp->if_flags, IFF_RUNNING)) { 987 bpe_down(sc); 988 CLR(ifp->if_flags, IFF_UP); 989 } 990 991 sc->sc_key.k_if = 0; 992 } 993 994 static void 995 bpe_link_hook(void *arg) 996 { 997 struct bpe_softc *sc = arg; 998 struct ifnet *ifp0; 999 u_char link = LINK_STATE_DOWN; 1000 uint64_t baud = 0; 1001 1002 ifp0 = if_get(sc->sc_key.k_if); 1003 if (ifp0 != NULL) { 1004 link = ifp0->if_link_state; 1005 baud = ifp0->if_baudrate; 1006 } 1007 if_put(ifp0); 1008 1009 bpe_link_state(sc, link, baud); 1010 } 1011 1012 void 1013 bpe_link_state(struct bpe_softc *sc, u_char link, uint64_t baud) 1014 { 1015 struct ifnet *ifp = &sc->sc_ac.ac_if; 1016 1017 if (ifp->if_link_state == link) 1018 return; 1019 1020 ifp->if_link_state = link; 1021 ifp->if_baudrate = baud; 1022 1023 if_link_state_change(ifp); 1024 } 1025 1026 static inline int 1027 bpe_cmp(const struct bpe_key *a, const struct bpe_key *b) 1028 { 1029 if (a->k_if > b->k_if) 1030 return (1); 1031 if (a->k_if < b->k_if) 1032 return (-1); 1033 if (a->k_isid > b->k_isid) 1034 return (1); 1035 if (a->k_isid < b->k_isid) 1036 return (-1); 1037 1038 return (0); 1039 } 1040 1041 static inline int 1042 bpe_entry_cmp(const struct bpe_entry *a, const struct bpe_entry *b) 1043 { 1044 return memcmp(&a->be_c_da, &b->be_c_da, sizeof(a->be_c_da)); 1045 } 1046