1 /* $OpenBSD: if_tpmr.c,v 1.33 2023/05/16 14:32:54 jan Exp $ */ 2 3 /* 4 * Copyright (c) 2019 The University of Queensland 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * This code was written by David Gwynne <dlg@uq.edu.au> as part 21 * of the Information Technology Infrastructure Group (ITIG) in the 22 * Faculty of Engineering, Architecture and Information Technology 23 * (EAIT). 24 */ 25 26 #include "bpfilter.h" 27 #include "pf.h" 28 #include "vlan.h" 29 30 #include <sys/param.h> 31 #include <sys/kernel.h> 32 #include <sys/malloc.h> 33 #include <sys/mbuf.h> 34 #include <sys/queue.h> 35 #include <sys/socket.h> 36 #include <sys/sockio.h> 37 #include <sys/systm.h> 38 #include <sys/syslog.h> 39 #include <sys/rwlock.h> 40 #include <sys/percpu.h> 41 #include <sys/smr.h> 42 #include <sys/task.h> 43 44 #include <net/if.h> 45 #include <net/if_dl.h> 46 #include <net/if_types.h> 47 48 #include <netinet/in.h> 49 #include <netinet/if_ether.h> 50 51 #include <net/if_bridge.h> 52 53 #if NBPFILTER > 0 54 #include <net/bpf.h> 55 #endif 56 57 #if NPF > 0 58 #include <net/pfvar.h> 59 #endif 60 61 #if NVLAN > 0 62 #include <net/if_vlan_var.h> 63 #endif 64 65 /* 66 * tpmr interface 67 */ 68 69 #define TPMR_NUM_PORTS 2 70 71 struct tpmr_softc; 72 73 struct tpmr_port { 74 struct ifnet *p_ifp0; 75 76 int (*p_ioctl)(struct ifnet *, u_long, caddr_t); 77 int (*p_output)(struct ifnet *, struct mbuf *, struct sockaddr *, 78 struct rtentry *); 79 80 struct task p_ltask; 81 struct task p_dtask; 82 83 struct tpmr_softc *p_tpmr; 84 unsigned int p_slot; 85 86 int p_refcnt; 87 88 struct ether_brport p_brport; 89 }; 90 91 struct tpmr_softc { 92 struct ifnet sc_if; 93 unsigned int sc_dead; 94 95 struct tpmr_port *sc_ports[TPMR_NUM_PORTS]; 96 unsigned int sc_nports; 97 }; 98 99 #define DPRINTF(_sc, fmt...) do { \ 100 if (ISSET((_sc)->sc_if.if_flags, IFF_DEBUG)) \ 101 printf(fmt); \ 102 } while (0) 103 104 static int tpmr_clone_create(struct if_clone *, int); 105 static int tpmr_clone_destroy(struct ifnet *); 106 107 static int tpmr_ioctl(struct ifnet *, u_long, caddr_t); 108 static int tpmr_enqueue(struct ifnet *, struct mbuf *); 109 static int tpmr_output(struct ifnet *, struct mbuf *, struct sockaddr *, 110 struct rtentry *); 111 static void tpmr_start(struct ifqueue *); 112 113 static int tpmr_up(struct tpmr_softc *); 114 static int tpmr_down(struct tpmr_softc *); 115 static int tpmr_iff(struct tpmr_softc *); 116 117 static void tpmr_p_linkch(void *); 118 static void tpmr_p_detach(void *); 119 static int tpmr_p_ioctl(struct ifnet *, u_long, caddr_t); 120 static int tpmr_p_output(struct ifnet *, struct mbuf *, 121 struct sockaddr *, struct rtentry *); 122 123 static void tpmr_p_dtor(struct tpmr_softc *, struct tpmr_port *, 124 const char *); 125 static int tpmr_add_port(struct tpmr_softc *, 126 const struct ifbreq *); 127 static int tpmr_del_port(struct tpmr_softc *, 128 const struct ifbreq *); 129 static int tpmr_port_list(struct tpmr_softc *, struct ifbifconf *); 130 static void tpmr_p_take(void *); 131 static void tpmr_p_rele(void *); 132 133 static struct if_clone tpmr_cloner = 134 IF_CLONE_INITIALIZER("tpmr", tpmr_clone_create, tpmr_clone_destroy); 135 136 void 137 tpmrattach(int count) 138 { 139 if_clone_attach(&tpmr_cloner); 140 } 141 142 static int 143 tpmr_clone_create(struct if_clone *ifc, int unit) 144 { 145 struct tpmr_softc *sc; 146 struct ifnet *ifp; 147 148 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO|M_CANFAIL); 149 if (sc == NULL) 150 return (ENOMEM); 151 152 ifp = &sc->sc_if; 153 154 snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", 155 ifc->ifc_name, unit); 156 157 ifp->if_softc = sc; 158 ifp->if_type = IFT_BRIDGE; 159 ifp->if_hardmtu = ETHER_MAX_HARDMTU_LEN; 160 ifp->if_mtu = 0; 161 ifp->if_addrlen = ETHER_ADDR_LEN; 162 ifp->if_hdrlen = ETHER_HDR_LEN; 163 ifp->if_ioctl = tpmr_ioctl; 164 ifp->if_output = tpmr_output; 165 ifp->if_enqueue = tpmr_enqueue; 166 ifp->if_qstart = tpmr_start; 167 ifp->if_flags = IFF_POINTOPOINT; 168 ifp->if_xflags = IFXF_CLONED | IFXF_MPSAFE; 169 ifp->if_link_state = LINK_STATE_DOWN; 170 171 if_counters_alloc(ifp); 172 if_attach(ifp); 173 if_alloc_sadl(ifp); 174 175 #if NBPFILTER > 0 176 bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, ETHER_HDR_LEN); 177 #endif 178 179 ifp->if_llprio = IFQ_MAXPRIO; 180 181 return (0); 182 } 183 184 static int 185 tpmr_clone_destroy(struct ifnet *ifp) 186 { 187 struct tpmr_softc *sc = ifp->if_softc; 188 unsigned int i; 189 190 NET_LOCK(); 191 sc->sc_dead = 1; 192 193 if (ISSET(ifp->if_flags, IFF_RUNNING)) 194 tpmr_down(sc); 195 NET_UNLOCK(); 196 197 if_detach(ifp); 198 199 NET_LOCK(); 200 for (i = 0; i < nitems(sc->sc_ports); i++) { 201 struct tpmr_port *p = SMR_PTR_GET_LOCKED(&sc->sc_ports[i]); 202 if (p == NULL) 203 continue; 204 tpmr_p_dtor(sc, p, "destroy"); 205 } 206 NET_UNLOCK(); 207 208 free(sc, M_DEVBUF, sizeof(*sc)); 209 210 return (0); 211 } 212 213 static int 214 tpmr_vlan_filter(const struct mbuf *m) 215 { 216 const struct ether_header *eh; 217 218 eh = mtod(m, struct ether_header *); 219 switch (ntohs(eh->ether_type)) { 220 case ETHERTYPE_VLAN: 221 case ETHERTYPE_QINQ: 222 return (1); 223 default: 224 break; 225 } 226 227 return (0); 228 } 229 230 static int 231 tpmr_8021q_filter(const struct mbuf *m, uint64_t dst) 232 { 233 if (ETH64_IS_8021_RSVD(dst)) { 234 switch (dst & 0xf) { 235 case 0x01: /* IEEE MAC-specific Control Protocols */ 236 case 0x02: /* IEEE 802.3 Slow Protocols */ 237 case 0x04: /* IEEE MAC-specific Control Protocols */ 238 case 0x0e: /* Individual LAN Scope, Nearest Bridge */ 239 return (1); 240 default: 241 break; 242 } 243 } 244 245 return (0); 246 } 247 248 #if NPF > 0 249 struct tpmr_pf_ip_family { 250 sa_family_t af; 251 struct mbuf *(*ip_check)(struct ifnet *, struct mbuf *); 252 void (*ip_input)(struct ifnet *, struct mbuf *); 253 }; 254 255 static const struct tpmr_pf_ip_family tpmr_pf_ipv4 = { 256 .af = AF_INET, 257 .ip_check = ipv4_check, 258 .ip_input = ipv4_input, 259 }; 260 261 #ifdef INET6 262 static const struct tpmr_pf_ip_family tpmr_pf_ipv6 = { 263 .af = AF_INET6, 264 .ip_check = ipv6_check, 265 .ip_input = ipv6_input, 266 }; 267 #endif 268 269 static struct mbuf * 270 tpmr_pf(struct ifnet *ifp0, int dir, struct mbuf *m) 271 { 272 struct ether_header *eh, copy; 273 const struct tpmr_pf_ip_family *fam; 274 275 eh = mtod(m, struct ether_header *); 276 switch (ntohs(eh->ether_type)) { 277 case ETHERTYPE_IP: 278 fam = &tpmr_pf_ipv4; 279 break; 280 #ifdef INET6 281 case ETHERTYPE_IPV6: 282 fam = &tpmr_pf_ipv6; 283 break; 284 #endif 285 default: 286 return (m); 287 } 288 289 copy = *eh; 290 m_adj(m, sizeof(*eh)); 291 292 if (dir == PF_IN) { 293 m = (*fam->ip_check)(ifp0, m); 294 if (m == NULL) 295 return (NULL); 296 } 297 298 if (pf_test(fam->af, dir, ifp0, &m) != PF_PASS) { 299 m_freem(m); 300 return (NULL); 301 } 302 if (m == NULL) 303 return (NULL); 304 305 if (dir == PF_IN && ISSET(m->m_pkthdr.pf.flags, PF_TAG_DIVERTED)) { 306 pf_mbuf_unlink_state_key(m); 307 pf_mbuf_unlink_inpcb(m); 308 (*fam->ip_input)(ifp0, m); 309 return (NULL); 310 } 311 312 m = m_prepend(m, sizeof(*eh), M_DONTWAIT); 313 if (m == NULL) 314 return (NULL); 315 316 /* checksum? */ 317 318 eh = mtod(m, struct ether_header *); 319 *eh = copy; 320 321 return (m); 322 } 323 #endif /* NPF > 0 */ 324 325 static struct mbuf * 326 tpmr_input(struct ifnet *ifp0, struct mbuf *m, uint64_t dst, void *brport) 327 { 328 struct tpmr_port *p = brport; 329 struct tpmr_softc *sc = p->p_tpmr; 330 struct ifnet *ifp = &sc->sc_if; 331 struct ifnet *ifpn; 332 unsigned int iff; 333 struct tpmr_port *pn; 334 int len; 335 #if NBPFILTER > 0 336 caddr_t if_bpf; 337 #endif 338 339 iff = READ_ONCE(ifp->if_flags); 340 if (!ISSET(iff, IFF_RUNNING)) 341 goto drop; 342 343 #if NVLAN > 0 344 /* 345 * If the underlying interface removed the VLAN header itself, 346 * add it back. 347 */ 348 if (ISSET(m->m_flags, M_VLANTAG)) { 349 m = vlan_inject(m, ETHERTYPE_VLAN, m->m_pkthdr.ether_vtag); 350 if (m == NULL) { 351 counters_inc(ifp->if_counters, ifc_ierrors); 352 goto drop; 353 } 354 } 355 #endif 356 357 if (!ISSET(iff, IFF_LINK2) && 358 tpmr_vlan_filter(m)) 359 goto drop; 360 361 if (!ISSET(iff, IFF_LINK0) && 362 tpmr_8021q_filter(m, dst)) 363 goto drop; 364 365 #if NPF > 0 366 if (!ISSET(iff, IFF_LINK1) && 367 (m = tpmr_pf(ifp0, PF_IN, m)) == NULL) 368 return (NULL); 369 #endif 370 371 len = m->m_pkthdr.len; 372 counters_pkt(ifp->if_counters, ifc_ipackets, ifc_ibytes, len); 373 374 #if NBPFILTER > 0 375 if_bpf = READ_ONCE(ifp->if_bpf); 376 if (if_bpf) { 377 if (bpf_mtap(if_bpf, m, 0)) 378 goto drop; 379 } 380 #endif 381 382 smr_read_enter(); 383 pn = SMR_PTR_GET(&sc->sc_ports[!p->p_slot]); 384 if (pn != NULL) 385 tpmr_p_take(pn); 386 smr_read_leave(); 387 if (pn == NULL) 388 goto drop; 389 390 ifpn = pn->p_ifp0; 391 #if NPF > 0 392 if (!ISSET(iff, IFF_LINK1) && 393 (m = tpmr_pf(ifpn, PF_OUT, m)) == NULL) { 394 tpmr_p_rele(pn); 395 return (NULL); 396 } 397 #endif 398 399 if (if_enqueue(ifpn, m)) 400 counters_inc(ifp->if_counters, ifc_oerrors); 401 else { 402 counters_pkt(ifp->if_counters, 403 ifc_opackets, ifc_obytes, len); 404 } 405 406 tpmr_p_rele(pn); 407 408 return (NULL); 409 410 drop: 411 m_freem(m); 412 return (NULL); 413 } 414 415 static int 416 tpmr_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 417 struct rtentry *rt) 418 { 419 m_freem(m); 420 return (ENODEV); 421 } 422 423 static int 424 tpmr_enqueue(struct ifnet *ifp, struct mbuf *m) 425 { 426 m_freem(m); 427 return (ENODEV); 428 } 429 430 static void 431 tpmr_start(struct ifqueue *ifq) 432 { 433 ifq_purge(ifq); 434 } 435 436 static int 437 tpmr_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 438 { 439 struct tpmr_softc *sc = ifp->if_softc; 440 int error = 0; 441 442 if (sc->sc_dead) 443 return (ENXIO); 444 445 switch (cmd) { 446 case SIOCSIFFLAGS: 447 if (ISSET(ifp->if_flags, IFF_UP)) { 448 if (!ISSET(ifp->if_flags, IFF_RUNNING)) 449 error = tpmr_up(sc); 450 } else { 451 if (ISSET(ifp->if_flags, IFF_RUNNING)) 452 error = tpmr_down(sc); 453 } 454 break; 455 456 case SIOCBRDGADD: 457 error = suser(curproc); 458 if (error != 0) 459 break; 460 461 error = tpmr_add_port(sc, (struct ifbreq *)data); 462 break; 463 case SIOCBRDGDEL: 464 error = suser(curproc); 465 if (error != 0) 466 break; 467 468 error = tpmr_del_port(sc, (struct ifbreq *)data); 469 break; 470 case SIOCBRDGIFS: 471 error = tpmr_port_list(sc, (struct ifbifconf *)data); 472 break; 473 /* stub for ifconfig(8) brconfig.c:bridge_rules() */ 474 case SIOCBRDGGRL: 475 ((struct ifbrlconf *)data)->ifbrl_len = 0; 476 break; 477 478 default: 479 error = ENOTTY; 480 break; 481 } 482 483 if (error == ENETRESET) 484 error = tpmr_iff(sc); 485 486 return (error); 487 } 488 489 static int 490 tpmr_add_port(struct tpmr_softc *sc, const struct ifbreq *req) 491 { 492 struct ifnet *ifp = &sc->sc_if; 493 struct ifnet *ifp0; 494 struct tpmr_port **pp; 495 struct tpmr_port *p; 496 int i; 497 int error; 498 499 NET_ASSERT_LOCKED(); 500 if (sc->sc_nports >= nitems(sc->sc_ports)) 501 return (ENOSPC); 502 503 ifp0 = if_unit(req->ifbr_ifsname); 504 if (ifp0 == NULL) 505 return (EINVAL); 506 507 if (ifp0->if_type != IFT_ETHER) { 508 error = EPROTONOSUPPORT; 509 goto put; 510 } 511 512 error = ether_brport_isset(ifp0); 513 if (error != 0) 514 goto put; 515 516 /* let's try */ 517 518 p = malloc(sizeof(*p), M_DEVBUF, M_WAITOK|M_ZERO|M_CANFAIL); 519 if (p == NULL) { 520 error = ENOMEM; 521 goto put; 522 } 523 524 ifsetlro(ifp0, 0); 525 526 p->p_ifp0 = ifp0; 527 p->p_tpmr = sc; 528 529 p->p_ioctl = ifp0->if_ioctl; 530 p->p_output = ifp0->if_output; 531 532 error = ifpromisc(ifp0, 1); 533 if (error != 0) 534 goto free; 535 536 /* this might have changed if we slept for malloc or ifpromisc */ 537 error = ether_brport_isset(ifp0); 538 if (error != 0) 539 goto unpromisc; 540 541 task_set(&p->p_ltask, tpmr_p_linkch, p); 542 if_linkstatehook_add(ifp0, &p->p_ltask); 543 544 task_set(&p->p_dtask, tpmr_p_detach, p); 545 if_detachhook_add(ifp0, &p->p_dtask); 546 547 p->p_brport.eb_input = tpmr_input; 548 p->p_brport.eb_port_take = tpmr_p_take; 549 p->p_brport.eb_port_rele = tpmr_p_rele; 550 p->p_brport.eb_port = p; 551 552 /* commit */ 553 DPRINTF(sc, "%s %s trunkport: creating port\n", 554 ifp->if_xname, ifp0->if_xname); 555 556 for (i = 0; i < nitems(sc->sc_ports); i++) { 557 pp = &sc->sc_ports[i]; 558 if (SMR_PTR_GET_LOCKED(pp) == NULL) 559 break; 560 } 561 sc->sc_nports++; 562 563 p->p_slot = i; 564 565 tpmr_p_take(p); 566 ether_brport_set(ifp0, &p->p_brport); 567 ifp0->if_ioctl = tpmr_p_ioctl; 568 ifp0->if_output = tpmr_p_output; 569 570 SMR_PTR_SET_LOCKED(pp, p); 571 572 tpmr_p_linkch(p); 573 574 return (0); 575 576 unpromisc: 577 ifpromisc(ifp0, 0); 578 free: 579 free(p, M_DEVBUF, sizeof(*p)); 580 put: 581 if_put(ifp0); 582 return (error); 583 } 584 585 static struct tpmr_port * 586 tpmr_trunkport(struct tpmr_softc *sc, const char *name) 587 { 588 unsigned int i; 589 590 for (i = 0; i < nitems(sc->sc_ports); i++) { 591 struct tpmr_port *p = SMR_PTR_GET_LOCKED(&sc->sc_ports[i]); 592 if (p == NULL) 593 continue; 594 595 if (strcmp(p->p_ifp0->if_xname, name) == 0) 596 return (p); 597 } 598 599 return (NULL); 600 } 601 602 static int 603 tpmr_del_port(struct tpmr_softc *sc, const struct ifbreq *req) 604 { 605 struct tpmr_port *p; 606 607 NET_ASSERT_LOCKED(); 608 p = tpmr_trunkport(sc, req->ifbr_ifsname); 609 if (p == NULL) 610 return (EINVAL); 611 612 tpmr_p_dtor(sc, p, "del"); 613 614 return (0); 615 } 616 617 618 static int 619 tpmr_port_list(struct tpmr_softc *sc, struct ifbifconf *bifc) 620 { 621 struct tpmr_port *p; 622 struct ifbreq breq; 623 int i = 0, total = nitems(sc->sc_ports), n = 0, error = 0; 624 625 NET_ASSERT_LOCKED(); 626 627 if (bifc->ifbic_len == 0) { 628 n = total; 629 goto done; 630 } 631 632 for (i = 0; i < total; i++) { 633 memset(&breq, 0, sizeof(breq)); 634 635 if (bifc->ifbic_len < sizeof(breq)) 636 break; 637 638 p = SMR_PTR_GET_LOCKED(&sc->sc_ports[i]); 639 if (p == NULL) 640 continue; 641 strlcpy(breq.ifbr_ifsname, p->p_ifp0->if_xname, IFNAMSIZ); 642 643 /* flag as span port so ifconfig(8)'s brconfig.c:bridge_list() 644 * stays quiet wrt. STP */ 645 breq.ifbr_ifsflags = IFBIF_SPAN; 646 strlcpy(breq.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ); 647 if ((error = copyout(&breq, bifc->ifbic_req + n, 648 sizeof(breq))) != 0) 649 goto done; 650 651 bifc->ifbic_len -= sizeof(breq); 652 n++; 653 } 654 655 done: 656 bifc->ifbic_len = n * sizeof(breq); 657 return (error); 658 } 659 660 static int 661 tpmr_p_ioctl(struct ifnet *ifp0, u_long cmd, caddr_t data) 662 { 663 const struct ether_brport *eb = ether_brport_get_locked(ifp0); 664 struct tpmr_port *p; 665 int error = 0; 666 667 KASSERTMSG(eb != NULL, 668 "%s: %s called without an ether_brport set", 669 ifp0->if_xname, __func__); 670 KASSERTMSG(eb->eb_input == tpmr_input, 671 "%s: %s called, but eb_input seems wrong (%p != tpmr_input())", 672 ifp0->if_xname, __func__, eb->eb_input); 673 674 p = eb->eb_port; 675 676 switch (cmd) { 677 case SIOCSIFADDR: 678 error = EBUSY; 679 break; 680 681 default: 682 error = (*p->p_ioctl)(ifp0, cmd, data); 683 break; 684 } 685 686 return (error); 687 } 688 689 static int 690 tpmr_p_output(struct ifnet *ifp0, struct mbuf *m, struct sockaddr *dst, 691 struct rtentry *rt) 692 { 693 int (*p_output)(struct ifnet *, struct mbuf *, struct sockaddr *, 694 struct rtentry *) = NULL; 695 const struct ether_brport *eb; 696 697 /* restrict transmission to bpf only */ 698 if ((m_tag_find(m, PACKET_TAG_DLT, NULL) == NULL)) { 699 m_freem(m); 700 return (EBUSY); 701 } 702 703 smr_read_enter(); 704 eb = ether_brport_get(ifp0); 705 if (eb != NULL && eb->eb_input == tpmr_input) { 706 struct tpmr_port *p = eb->eb_port; 707 p_output = p->p_output; /* code doesn't go away */ 708 } 709 smr_read_leave(); 710 711 if (p_output == NULL) { 712 m_freem(m); 713 return (ENXIO); 714 } 715 716 return ((*p_output)(ifp0, m, dst, rt)); 717 } 718 719 static void 720 tpmr_p_take(void *p) 721 { 722 struct tpmr_port *port = p; 723 724 atomic_inc_int(&port->p_refcnt); 725 } 726 727 static void 728 tpmr_p_rele(void *p) 729 { 730 struct tpmr_port *port = p; 731 struct ifnet *ifp0 = port->p_ifp0; 732 733 if (atomic_dec_int_nv(&port->p_refcnt) == 0) { 734 if_put(ifp0); 735 free(port, M_DEVBUF, sizeof(*port)); 736 } 737 } 738 739 static void 740 tpmr_p_dtor(struct tpmr_softc *sc, struct tpmr_port *p, const char *op) 741 { 742 struct ifnet *ifp = &sc->sc_if; 743 struct ifnet *ifp0 = p->p_ifp0; 744 745 DPRINTF(sc, "%s %s: destroying port\n", 746 ifp->if_xname, ifp0->if_xname); 747 748 ifp0->if_ioctl = p->p_ioctl; 749 ifp0->if_output = p->p_output; 750 751 ether_brport_clr(ifp0); 752 753 sc->sc_nports--; 754 SMR_PTR_SET_LOCKED(&sc->sc_ports[p->p_slot], NULL); 755 756 if (ifpromisc(ifp0, 0) != 0) { 757 log(LOG_WARNING, "%s %s: unable to disable promisc\n", 758 ifp->if_xname, ifp0->if_xname); 759 } 760 761 if_detachhook_del(ifp0, &p->p_dtask); 762 if_linkstatehook_del(ifp0, &p->p_ltask); 763 764 tpmr_p_rele(p); 765 766 smr_barrier(); 767 768 if (ifp->if_link_state != LINK_STATE_DOWN) { 769 ifp->if_link_state = LINK_STATE_DOWN; 770 if_link_state_change(ifp); 771 } 772 } 773 774 static void 775 tpmr_p_detach(void *arg) 776 { 777 struct tpmr_port *p = arg; 778 struct tpmr_softc *sc = p->p_tpmr; 779 780 tpmr_p_dtor(sc, p, "detach"); 781 782 NET_ASSERT_LOCKED(); 783 } 784 785 static int 786 tpmr_p_active(struct tpmr_port *p) 787 { 788 struct ifnet *ifp0 = p->p_ifp0; 789 790 return (ISSET(ifp0->if_flags, IFF_RUNNING) && 791 LINK_STATE_IS_UP(ifp0->if_link_state)); 792 } 793 794 static void 795 tpmr_p_linkch(void *arg) 796 { 797 struct tpmr_port *p = arg; 798 struct tpmr_softc *sc = p->p_tpmr; 799 struct ifnet *ifp = &sc->sc_if; 800 struct tpmr_port *np; 801 u_char link_state = LINK_STATE_FULL_DUPLEX; 802 803 NET_ASSERT_LOCKED(); 804 805 if (!tpmr_p_active(p)) 806 link_state = LINK_STATE_DOWN; 807 808 np = SMR_PTR_GET_LOCKED(&sc->sc_ports[!p->p_slot]); 809 if (np == NULL || !tpmr_p_active(np)) 810 link_state = LINK_STATE_DOWN; 811 812 if (ifp->if_link_state != link_state) { 813 ifp->if_link_state = link_state; 814 if_link_state_change(ifp); 815 } 816 } 817 818 static int 819 tpmr_up(struct tpmr_softc *sc) 820 { 821 struct ifnet *ifp = &sc->sc_if; 822 823 NET_ASSERT_LOCKED(); 824 SET(ifp->if_flags, IFF_RUNNING); 825 826 return (0); 827 } 828 829 static int 830 tpmr_iff(struct tpmr_softc *sc) 831 { 832 return (0); 833 } 834 835 static int 836 tpmr_down(struct tpmr_softc *sc) 837 { 838 struct ifnet *ifp = &sc->sc_if; 839 840 NET_ASSERT_LOCKED(); 841 CLR(ifp->if_flags, IFF_RUNNING); 842 843 return (0); 844 } 845