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