1 /* $OpenBSD: if_tpmr.c,v 1.21 2020/12/12 00:39:07 dlg 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 static const uint8_t ether_8021_prefix[ETHER_ADDR_LEN - 1] = 66 { 0x01, 0x80, 0xc2, 0x00, 0x00 }; 67 68 #define ETHER_IS_8021_PREFIX(_m) \ 69 (memcmp((_m), ether_8021_prefix, sizeof(ether_8021_prefix)) == 0) 70 71 /* 72 * tpmr interface 73 */ 74 75 #define TPMR_NUM_PORTS 2 76 77 struct tpmr_softc; 78 79 struct tpmr_port { 80 struct ifnet *p_ifp0; 81 82 int (*p_ioctl)(struct ifnet *, u_long, caddr_t); 83 int (*p_output)(struct ifnet *, struct mbuf *, struct sockaddr *, 84 struct rtentry *); 85 86 struct task p_ltask; 87 struct task p_dtask; 88 89 struct tpmr_softc *p_tpmr; 90 unsigned int p_slot; 91 92 struct ether_brport p_brport; 93 }; 94 95 struct tpmr_softc { 96 struct ifnet sc_if; 97 unsigned int sc_dead; 98 99 struct tpmr_port *sc_ports[TPMR_NUM_PORTS]; 100 unsigned int sc_nports; 101 }; 102 103 #define DPRINTF(_sc, fmt...) do { \ 104 if (ISSET((_sc)->sc_if.if_flags, IFF_DEBUG)) \ 105 printf(fmt); \ 106 } while (0) 107 108 static int tpmr_clone_create(struct if_clone *, int); 109 static int tpmr_clone_destroy(struct ifnet *); 110 111 static int tpmr_ioctl(struct ifnet *, u_long, caddr_t); 112 static int tpmr_enqueue(struct ifnet *, struct mbuf *); 113 static int tpmr_output(struct ifnet *, struct mbuf *, struct sockaddr *, 114 struct rtentry *); 115 static void tpmr_start(struct ifqueue *); 116 117 static int tpmr_up(struct tpmr_softc *); 118 static int tpmr_down(struct tpmr_softc *); 119 static int tpmr_iff(struct tpmr_softc *); 120 121 static void tpmr_p_linkch(void *); 122 static void tpmr_p_detach(void *); 123 static int tpmr_p_ioctl(struct ifnet *, u_long, caddr_t); 124 static int tpmr_p_output(struct ifnet *, struct mbuf *, 125 struct sockaddr *, struct rtentry *); 126 127 static void tpmr_p_dtor(struct tpmr_softc *, struct tpmr_port *, 128 const char *); 129 static int tpmr_add_port(struct tpmr_softc *, 130 const struct ifbreq *); 131 static int tpmr_del_port(struct tpmr_softc *, 132 const struct ifbreq *); 133 static int tpmr_port_list(struct tpmr_softc *, struct ifbifconf *); 134 135 static struct if_clone tpmr_cloner = 136 IF_CLONE_INITIALIZER("tpmr", tpmr_clone_create, tpmr_clone_destroy); 137 138 void 139 tpmrattach(int count) 140 { 141 if_clone_attach(&tpmr_cloner); 142 } 143 144 static int 145 tpmr_clone_create(struct if_clone *ifc, int unit) 146 { 147 struct tpmr_softc *sc; 148 struct ifnet *ifp; 149 150 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO|M_CANFAIL); 151 if (sc == NULL) 152 return (ENOMEM); 153 154 ifp = &sc->sc_if; 155 156 snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d", 157 ifc->ifc_name, unit); 158 159 ifp->if_softc = sc; 160 ifp->if_type = IFT_BRIDGE; 161 ifp->if_hardmtu = ETHER_MAX_HARDMTU_LEN; 162 ifp->if_mtu = 0; 163 ifp->if_addrlen = ETHER_ADDR_LEN; 164 ifp->if_hdrlen = ETHER_HDR_LEN; 165 ifp->if_ioctl = tpmr_ioctl; 166 ifp->if_output = tpmr_output; 167 ifp->if_enqueue = tpmr_enqueue; 168 ifp->if_qstart = tpmr_start; 169 ifp->if_flags = IFF_POINTOPOINT; 170 ifp->if_xflags = IFXF_CLONED | IFXF_MPSAFE; 171 ifp->if_link_state = LINK_STATE_DOWN; 172 173 if_counters_alloc(ifp); 174 if_attach(ifp); 175 if_alloc_sadl(ifp); 176 177 #if NBPFILTER > 0 178 bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, ETHER_HDR_LEN); 179 #endif 180 181 ifp->if_llprio = IFQ_MAXPRIO; 182 183 return (0); 184 } 185 186 static int 187 tpmr_clone_destroy(struct ifnet *ifp) 188 { 189 struct tpmr_softc *sc = ifp->if_softc; 190 unsigned int i; 191 192 NET_LOCK(); 193 sc->sc_dead = 1; 194 195 if (ISSET(ifp->if_flags, IFF_RUNNING)) 196 tpmr_down(sc); 197 NET_UNLOCK(); 198 199 if_detach(ifp); 200 201 NET_LOCK(); 202 for (i = 0; i < nitems(sc->sc_ports); i++) { 203 struct tpmr_port *p = SMR_PTR_GET_LOCKED(&sc->sc_ports[i]); 204 if (p == NULL) 205 continue; 206 tpmr_p_dtor(sc, p, "destroy"); 207 } 208 NET_UNLOCK(); 209 210 free(sc, M_DEVBUF, sizeof(*sc)); 211 212 return (0); 213 } 214 215 static int 216 tpmr_vlan_filter(const struct mbuf *m) 217 { 218 const struct ether_header *eh; 219 220 eh = mtod(m, struct ether_header *); 221 switch (ntohs(eh->ether_type)) { 222 case ETHERTYPE_VLAN: 223 case ETHERTYPE_QINQ: 224 return (1); 225 default: 226 break; 227 } 228 229 return (0); 230 } 231 232 static int 233 tpmr_8021q_filter(const struct mbuf *m) 234 { 235 const struct ether_header *eh; 236 237 if (m->m_len < sizeof(*eh)) 238 return (1); 239 240 eh = mtod(m, struct ether_header *); 241 if (ETHER_IS_8021_PREFIX(eh->ether_dhost)) { 242 switch (eh->ether_dhost[5]) { 243 case 0x01: /* IEEE MAC-specific Control Protocols */ 244 case 0x02: /* IEEE 802.3 Slow Protocols */ 245 case 0x04: /* IEEE MAC-specific Control Protocols */ 246 case 0x0e: /* Individual LAN Scope, Nearest Bridge */ 247 return (1); 248 default: 249 break; 250 } 251 } 252 253 return (0); 254 } 255 256 #if NPF > 0 257 static struct mbuf * 258 tpmr_pf(struct ifnet *ifp0, int dir, struct mbuf *m) 259 { 260 struct ether_header *eh, copy; 261 sa_family_t af = AF_UNSPEC; 262 263 eh = mtod(m, struct ether_header *); 264 switch (ntohs(eh->ether_type)) { 265 case ETHERTYPE_IP: 266 af = AF_INET; 267 break; 268 case ETHERTYPE_IPV6: 269 af = AF_INET6; 270 break; 271 default: 272 return (m); 273 } 274 275 copy = *eh; 276 m_adj(m, sizeof(*eh)); 277 278 if (pf_test(af, dir, ifp0, &m) != PF_PASS) { 279 m_freem(m); 280 return (NULL); 281 } 282 if (m == NULL) 283 return (NULL); 284 285 m = m_prepend(m, sizeof(*eh), M_DONTWAIT); 286 if (m == NULL) 287 return (NULL); 288 289 /* checksum? */ 290 291 eh = mtod(m, struct ether_header *); 292 *eh = copy; 293 294 return (m); 295 } 296 #endif /* NPF > 0 */ 297 298 static struct mbuf * 299 tpmr_input(struct ifnet *ifp0, struct mbuf *m, void *brport) 300 { 301 struct tpmr_port *p = brport; 302 struct tpmr_softc *sc = p->p_tpmr; 303 struct ifnet *ifp = &sc->sc_if; 304 struct tpmr_port *pn; 305 int len; 306 #if NBPFILTER > 0 307 caddr_t if_bpf; 308 #endif 309 310 if (!ISSET(ifp->if_flags, IFF_RUNNING)) 311 goto drop; 312 313 #if NVLAN > 0 314 /* 315 * If the underlying interface removed the VLAN header itself, 316 * add it back. 317 */ 318 if (ISSET(m->m_flags, M_VLANTAG)) { 319 m = vlan_inject(m, ETHERTYPE_VLAN, m->m_pkthdr.ether_vtag); 320 if (m == NULL) { 321 counters_inc(ifp->if_counters, ifc_ierrors); 322 goto drop; 323 } 324 } 325 #endif 326 327 if (!ISSET(ifp->if_flags, IFF_LINK2) && 328 tpmr_vlan_filter(m)) 329 goto drop; 330 331 if (!ISSET(ifp->if_flags, IFF_LINK0) && 332 tpmr_8021q_filter(m)) 333 goto drop; 334 335 #if NPF > 0 336 if (!ISSET(ifp->if_flags, IFF_LINK1) && 337 (m = tpmr_pf(ifp0, PF_IN, m)) == NULL) 338 return (NULL); 339 #endif 340 341 len = m->m_pkthdr.len; 342 counters_pkt(ifp->if_counters, ifc_ipackets, ifc_ibytes, len); 343 344 #if NBPFILTER > 0 345 if_bpf = ifp->if_bpf; 346 if (if_bpf) { 347 if (bpf_mtap(if_bpf, m, 0)) 348 goto drop; 349 } 350 #endif 351 352 smr_read_enter(); 353 pn = SMR_PTR_GET(&sc->sc_ports[!p->p_slot]); 354 if (pn == NULL) 355 m_freem(m); 356 else { 357 struct ifnet *ifpn = pn->p_ifp0; 358 359 #if NPF > 0 360 if (!ISSET(ifp->if_flags, IFF_LINK1) && 361 (m = tpmr_pf(ifpn, PF_OUT, m)) == NULL) 362 ; 363 else 364 #endif 365 if (if_enqueue(ifpn, m)) 366 counters_inc(ifp->if_counters, ifc_oerrors); 367 else { 368 counters_pkt(ifp->if_counters, 369 ifc_opackets, ifc_obytes, len); 370 } 371 } 372 smr_read_leave(); 373 374 return (NULL); 375 376 drop: 377 m_freem(m); 378 return (NULL); 379 } 380 381 static int 382 tpmr_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 383 struct rtentry *rt) 384 { 385 m_freem(m); 386 return (ENODEV); 387 } 388 389 static int 390 tpmr_enqueue(struct ifnet *ifp, struct mbuf *m) 391 { 392 m_freem(m); 393 return (ENODEV); 394 } 395 396 static void 397 tpmr_start(struct ifqueue *ifq) 398 { 399 ifq_purge(ifq); 400 } 401 402 static int 403 tpmr_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 404 { 405 struct tpmr_softc *sc = ifp->if_softc; 406 int error = 0; 407 408 if (sc->sc_dead) 409 return (ENXIO); 410 411 switch (cmd) { 412 case SIOCSIFFLAGS: 413 if (ISSET(ifp->if_flags, IFF_UP)) { 414 if (!ISSET(ifp->if_flags, IFF_RUNNING)) 415 error = tpmr_up(sc); 416 } else { 417 if (ISSET(ifp->if_flags, IFF_RUNNING)) 418 error = tpmr_down(sc); 419 } 420 break; 421 422 case SIOCBRDGADD: 423 error = suser(curproc); 424 if (error != 0) 425 break; 426 427 error = tpmr_add_port(sc, (struct ifbreq *)data); 428 break; 429 case SIOCBRDGDEL: 430 error = suser(curproc); 431 if (error != 0) 432 break; 433 434 error = tpmr_del_port(sc, (struct ifbreq *)data); 435 break; 436 case SIOCBRDGIFS: 437 error = tpmr_port_list(sc, (struct ifbifconf *)data); 438 break; 439 /* stub for ifconfig(8) brconfig.c:bridge_rules() */ 440 case SIOCBRDGGRL: 441 ((struct ifbrlconf *)data)->ifbrl_len = 0; 442 break; 443 444 default: 445 error = ENOTTY; 446 break; 447 } 448 449 if (error == ENETRESET) 450 error = tpmr_iff(sc); 451 452 return (error); 453 } 454 455 static int 456 tpmr_add_port(struct tpmr_softc *sc, const struct ifbreq *req) 457 { 458 struct ifnet *ifp = &sc->sc_if; 459 struct ifnet *ifp0; 460 struct tpmr_port **pp; 461 struct tpmr_port *p; 462 int i; 463 int error; 464 465 NET_ASSERT_LOCKED(); 466 if (sc->sc_nports >= nitems(sc->sc_ports)) 467 return (ENOSPC); 468 469 ifp0 = ifunit(req->ifbr_ifsname); 470 if (ifp0 == NULL) 471 return (EINVAL); 472 473 if (ifp0->if_type != IFT_ETHER) 474 return (EPROTONOSUPPORT); 475 476 error = ether_brport_isset(ifp0); 477 if (error != 0) 478 return (error); 479 480 /* let's try */ 481 482 ifp0 = if_get(ifp0->if_index); /* get an actual reference */ 483 if (ifp0 == NULL) { 484 /* XXX this should never happen */ 485 return (EINVAL); 486 } 487 488 p = malloc(sizeof(*p), M_DEVBUF, M_WAITOK|M_ZERO|M_CANFAIL); 489 if (p == NULL) { 490 error = ENOMEM; 491 goto put; 492 } 493 494 p->p_ifp0 = ifp0; 495 p->p_tpmr = sc; 496 497 p->p_ioctl = ifp0->if_ioctl; 498 p->p_output = ifp0->if_output; 499 500 error = ifpromisc(ifp0, 1); 501 if (error != 0) 502 goto free; 503 504 /* this might have changed if we slept for malloc or ifpromisc */ 505 error = ether_brport_isset(ifp0); 506 if (error != 0) 507 goto unpromisc; 508 509 task_set(&p->p_ltask, tpmr_p_linkch, p); 510 if_linkstatehook_add(ifp0, &p->p_ltask); 511 512 task_set(&p->p_dtask, tpmr_p_detach, p); 513 if_detachhook_add(ifp0, &p->p_dtask); 514 515 p->p_brport.eb_input = tpmr_input; 516 p->p_brport.eb_port = p; 517 518 /* commit */ 519 DPRINTF(sc, "%s %s trunkport: creating port\n", 520 ifp->if_xname, ifp0->if_xname); 521 522 for (i = 0; i < nitems(sc->sc_ports); i++) { 523 pp = &sc->sc_ports[i]; 524 if (SMR_PTR_GET_LOCKED(pp) == NULL) 525 break; 526 } 527 sc->sc_nports++; 528 529 p->p_slot = i; 530 531 ether_brport_set(ifp0, &p->p_brport); 532 ifp0->if_ioctl = tpmr_p_ioctl; 533 ifp0->if_output = tpmr_p_output; 534 535 SMR_PTR_SET_LOCKED(pp, p); 536 537 tpmr_p_linkch(p); 538 539 return (0); 540 541 unpromisc: 542 ifpromisc(ifp0, 0); 543 free: 544 free(p, M_DEVBUF, sizeof(*p)); 545 put: 546 if_put(ifp0); 547 return (error); 548 } 549 550 static struct tpmr_port * 551 tpmr_trunkport(struct tpmr_softc *sc, const char *name) 552 { 553 unsigned int i; 554 555 for (i = 0; i < nitems(sc->sc_ports); i++) { 556 struct tpmr_port *p = SMR_PTR_GET_LOCKED(&sc->sc_ports[i]); 557 if (p == NULL) 558 continue; 559 560 if (strcmp(p->p_ifp0->if_xname, name) == 0) 561 return (p); 562 } 563 564 return (NULL); 565 } 566 567 static int 568 tpmr_del_port(struct tpmr_softc *sc, const struct ifbreq *req) 569 { 570 struct tpmr_port *p; 571 572 NET_ASSERT_LOCKED(); 573 p = tpmr_trunkport(sc, req->ifbr_ifsname); 574 if (p == NULL) 575 return (EINVAL); 576 577 tpmr_p_dtor(sc, p, "del"); 578 579 return (0); 580 } 581 582 583 static int 584 tpmr_port_list(struct tpmr_softc *sc, struct ifbifconf *bifc) 585 { 586 struct tpmr_port *p; 587 struct ifbreq breq; 588 int i = 0, total = nitems(sc->sc_ports), n = 0, error = 0; 589 590 NET_ASSERT_LOCKED(); 591 592 if (bifc->ifbic_len == 0) { 593 n = total; 594 goto done; 595 } 596 597 for (i = 0; i < total; i++) { 598 memset(&breq, 0, sizeof(breq)); 599 600 if (bifc->ifbic_len < sizeof(breq)) 601 break; 602 603 p = SMR_PTR_GET_LOCKED(&sc->sc_ports[i]); 604 if (p == NULL) 605 continue; 606 strlcpy(breq.ifbr_ifsname, p->p_ifp0->if_xname, IFNAMSIZ); 607 608 /* flag as span port so ifconfig(8)'s brconfig.c:bridge_list() 609 * stays quiet wrt. STP */ 610 breq.ifbr_ifsflags = IFBIF_SPAN; 611 strlcpy(breq.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ); 612 if ((error = copyout(&breq, bifc->ifbic_req + n, 613 sizeof(breq))) != 0) 614 goto done; 615 616 bifc->ifbic_len -= sizeof(breq); 617 n++; 618 } 619 620 done: 621 bifc->ifbic_len = n * sizeof(breq); 622 return (error); 623 } 624 625 static int 626 tpmr_p_ioctl(struct ifnet *ifp0, u_long cmd, caddr_t data) 627 { 628 const struct ether_brport *eb = ether_brport_get_locked(ifp0); 629 struct tpmr_port *p; 630 int error = 0; 631 632 KASSERTMSG(eb != NULL, 633 "%s: %s called without an ether_brport set", 634 ifp0->if_xname, __func__); 635 KASSERTMSG(eb->eb_input == tpmr_input, 636 "%s: %s called, but eb_input seems wrong (%p != tpmr_input())", 637 ifp0->if_xname, __func__, eb->eb_input); 638 639 p = eb->eb_port; 640 641 switch (cmd) { 642 case SIOCSIFADDR: 643 error = EBUSY; 644 break; 645 646 default: 647 error = (*p->p_ioctl)(ifp0, cmd, data); 648 break; 649 } 650 651 return (error); 652 } 653 654 static int 655 tpmr_p_output(struct ifnet *ifp0, struct mbuf *m, struct sockaddr *dst, 656 struct rtentry *rt) 657 { 658 int (*p_output)(struct ifnet *, struct mbuf *, struct sockaddr *, 659 struct rtentry *) = NULL; 660 const struct ether_brport *eb; 661 662 /* restrict transmission to bpf only */ 663 if ((m_tag_find(m, PACKET_TAG_DLT, NULL) == NULL)) { 664 m_freem(m); 665 return (EBUSY); 666 } 667 668 smr_read_enter(); 669 eb = ether_brport_get(ifp0); 670 if (eb != NULL && eb->eb_input == tpmr_input) { 671 struct tpmr_port *p = eb->eb_port; 672 p_output = p->p_output; /* code doesn't go away */ 673 } 674 smr_read_leave(); 675 676 if (p_output == NULL) { 677 m_freem(m); 678 return (ENXIO); 679 } 680 681 return ((*p_output)(ifp0, m, dst, rt)); 682 } 683 684 static void 685 tpmr_p_dtor(struct tpmr_softc *sc, struct tpmr_port *p, const char *op) 686 { 687 struct ifnet *ifp = &sc->sc_if; 688 struct ifnet *ifp0 = p->p_ifp0; 689 690 DPRINTF(sc, "%s %s: destroying port\n", 691 ifp->if_xname, ifp0->if_xname); 692 693 ifp0->if_ioctl = p->p_ioctl; 694 ifp0->if_output = p->p_output; 695 696 ether_brport_clr(ifp0); 697 698 sc->sc_nports--; 699 SMR_PTR_SET_LOCKED(&sc->sc_ports[p->p_slot], NULL); 700 701 if (ifpromisc(ifp0, 0) != 0) { 702 log(LOG_WARNING, "%s %s: unable to disable promisc\n", 703 ifp->if_xname, ifp0->if_xname); 704 } 705 706 if_detachhook_del(ifp0, &p->p_dtask); 707 if_linkstatehook_del(ifp0, &p->p_ltask); 708 709 smr_barrier(); 710 711 if_put(ifp0); 712 free(p, M_DEVBUF, sizeof(*p)); 713 714 if (ifp->if_link_state != LINK_STATE_DOWN) { 715 ifp->if_link_state = LINK_STATE_DOWN; 716 if_link_state_change(ifp); 717 } 718 } 719 720 static void 721 tpmr_p_detach(void *arg) 722 { 723 struct tpmr_port *p = arg; 724 struct tpmr_softc *sc = p->p_tpmr; 725 726 tpmr_p_dtor(sc, p, "detach"); 727 728 NET_ASSERT_LOCKED(); 729 } 730 731 static int 732 tpmr_p_active(struct tpmr_port *p) 733 { 734 struct ifnet *ifp0 = p->p_ifp0; 735 736 return (ISSET(ifp0->if_flags, IFF_RUNNING) && 737 LINK_STATE_IS_UP(ifp0->if_link_state)); 738 } 739 740 static void 741 tpmr_p_linkch(void *arg) 742 { 743 struct tpmr_port *p = arg; 744 struct tpmr_softc *sc = p->p_tpmr; 745 struct ifnet *ifp = &sc->sc_if; 746 struct tpmr_port *np; 747 u_char link_state = LINK_STATE_FULL_DUPLEX; 748 749 NET_ASSERT_LOCKED(); 750 751 if (!tpmr_p_active(p)) 752 link_state = LINK_STATE_DOWN; 753 754 np = SMR_PTR_GET_LOCKED(&sc->sc_ports[!p->p_slot]); 755 if (np == NULL || !tpmr_p_active(np)) 756 link_state = LINK_STATE_DOWN; 757 758 if (ifp->if_link_state != link_state) { 759 ifp->if_link_state = link_state; 760 if_link_state_change(ifp); 761 } 762 } 763 764 static int 765 tpmr_up(struct tpmr_softc *sc) 766 { 767 struct ifnet *ifp = &sc->sc_if; 768 769 NET_ASSERT_LOCKED(); 770 SET(ifp->if_flags, IFF_RUNNING); 771 772 return (0); 773 } 774 775 static int 776 tpmr_iff(struct tpmr_softc *sc) 777 { 778 return (0); 779 } 780 781 static int 782 tpmr_down(struct tpmr_softc *sc) 783 { 784 struct ifnet *ifp = &sc->sc_if; 785 786 NET_ASSERT_LOCKED(); 787 CLR(ifp->if_flags, IFF_RUNNING); 788 789 return (0); 790 } 791