xref: /openbsd-src/sys/net/if_tpmr.c (revision 58fbf5d6aa35e3d66f2c32c61d2f38824a990e85)
1 /*	$OpenBSD: if_tpmr.c,v 1.22 2021/01/19 07:31:05 mvs 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 = if_unit(req->ifbr_ifsname);
470 	if (ifp0 == NULL)
471 		return (EINVAL);
472 
473 	if (ifp0->if_type != IFT_ETHER) {
474 		error = EPROTONOSUPPORT;
475 		goto put;
476 	}
477 
478 	error = ether_brport_isset(ifp0);
479 	if (error != 0)
480 		goto put;
481 
482 	/* let's try */
483 
484 	p = malloc(sizeof(*p), M_DEVBUF, M_WAITOK|M_ZERO|M_CANFAIL);
485 	if (p == NULL) {
486 		error = ENOMEM;
487 		goto put;
488 	}
489 
490 	p->p_ifp0 = ifp0;
491 	p->p_tpmr = sc;
492 
493 	p->p_ioctl = ifp0->if_ioctl;
494 	p->p_output = ifp0->if_output;
495 
496 	error = ifpromisc(ifp0, 1);
497 	if (error != 0)
498 		goto free;
499 
500 	/* this might have changed if we slept for malloc or ifpromisc */
501 	error = ether_brport_isset(ifp0);
502 	if (error != 0)
503 		goto unpromisc;
504 
505 	task_set(&p->p_ltask, tpmr_p_linkch, p);
506 	if_linkstatehook_add(ifp0, &p->p_ltask);
507 
508 	task_set(&p->p_dtask, tpmr_p_detach, p);
509 	if_detachhook_add(ifp0, &p->p_dtask);
510 
511 	p->p_brport.eb_input = tpmr_input;
512 	p->p_brport.eb_port = p;
513 
514 	/* commit */
515 	DPRINTF(sc, "%s %s trunkport: creating port\n",
516 	    ifp->if_xname, ifp0->if_xname);
517 
518 	for (i = 0; i < nitems(sc->sc_ports); i++) {
519 		pp = &sc->sc_ports[i];
520 		if (SMR_PTR_GET_LOCKED(pp) == NULL)
521 			break;
522 	}
523 	sc->sc_nports++;
524 
525 	p->p_slot = i;
526 
527 	ether_brport_set(ifp0, &p->p_brport);
528 	ifp0->if_ioctl = tpmr_p_ioctl;
529 	ifp0->if_output = tpmr_p_output;
530 
531 	SMR_PTR_SET_LOCKED(pp, p);
532 
533 	tpmr_p_linkch(p);
534 
535 	return (0);
536 
537 unpromisc:
538 	ifpromisc(ifp0, 0);
539 free:
540 	free(p, M_DEVBUF, sizeof(*p));
541 put:
542 	if_put(ifp0);
543 	return (error);
544 }
545 
546 static struct tpmr_port *
547 tpmr_trunkport(struct tpmr_softc *sc, const char *name)
548 {
549 	unsigned int i;
550 
551 	for (i = 0; i < nitems(sc->sc_ports); i++) {
552 		struct tpmr_port *p = SMR_PTR_GET_LOCKED(&sc->sc_ports[i]);
553 		if (p == NULL)
554 			continue;
555 
556 		if (strcmp(p->p_ifp0->if_xname, name) == 0)
557 			return (p);
558 	}
559 
560 	return (NULL);
561 }
562 
563 static int
564 tpmr_del_port(struct tpmr_softc *sc, const struct ifbreq *req)
565 {
566 	struct tpmr_port *p;
567 
568 	NET_ASSERT_LOCKED();
569 	p = tpmr_trunkport(sc, req->ifbr_ifsname);
570 	if (p == NULL)
571 		return (EINVAL);
572 
573 	tpmr_p_dtor(sc, p, "del");
574 
575 	return (0);
576 }
577 
578 
579 static int
580 tpmr_port_list(struct tpmr_softc *sc, struct ifbifconf *bifc)
581 {
582 	struct tpmr_port *p;
583 	struct ifbreq breq;
584 	int i = 0, total = nitems(sc->sc_ports), n = 0, error = 0;
585 
586 	NET_ASSERT_LOCKED();
587 
588 	if (bifc->ifbic_len == 0) {
589 		n = total;
590 		goto done;
591 	}
592 
593 	for (i = 0; i < total; i++) {
594 		memset(&breq, 0, sizeof(breq));
595 
596 		if (bifc->ifbic_len < sizeof(breq))
597 			break;
598 
599 		p = SMR_PTR_GET_LOCKED(&sc->sc_ports[i]);
600 		if (p == NULL)
601 			continue;
602 		strlcpy(breq.ifbr_ifsname, p->p_ifp0->if_xname, IFNAMSIZ);
603 
604 		/* flag as span port so ifconfig(8)'s brconfig.c:bridge_list()
605 		 * stays quiet wrt. STP */
606 		breq.ifbr_ifsflags = IFBIF_SPAN;
607 		strlcpy(breq.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
608 		if ((error = copyout(&breq, bifc->ifbic_req + n,
609 		    sizeof(breq))) != 0)
610 			goto done;
611 
612 		bifc->ifbic_len -= sizeof(breq);
613 		n++;
614 	}
615 
616 done:
617 	bifc->ifbic_len = n * sizeof(breq);
618 	return (error);
619 }
620 
621 static int
622 tpmr_p_ioctl(struct ifnet *ifp0, u_long cmd, caddr_t data)
623 {
624 	const struct ether_brport *eb = ether_brport_get_locked(ifp0);
625 	struct tpmr_port *p;
626 	int error = 0;
627 
628 	KASSERTMSG(eb != NULL,
629 	    "%s: %s called without an ether_brport set",
630 	    ifp0->if_xname, __func__);
631 	KASSERTMSG(eb->eb_input == tpmr_input,
632 	    "%s: %s called, but eb_input seems wrong (%p != tpmr_input())",
633 	    ifp0->if_xname, __func__, eb->eb_input);
634 
635 	p = eb->eb_port;
636 
637 	switch (cmd) {
638 	case SIOCSIFADDR:
639 		error = EBUSY;
640 		break;
641 
642 	default:
643 		error = (*p->p_ioctl)(ifp0, cmd, data);
644 		break;
645 	}
646 
647 	return (error);
648 }
649 
650 static int
651 tpmr_p_output(struct ifnet *ifp0, struct mbuf *m, struct sockaddr *dst,
652     struct rtentry *rt)
653 {
654 	int (*p_output)(struct ifnet *, struct mbuf *, struct sockaddr *,
655 	    struct rtentry *) = NULL;
656 	const struct ether_brport *eb;
657 
658 	/* restrict transmission to bpf only */
659 	if ((m_tag_find(m, PACKET_TAG_DLT, NULL) == NULL)) {
660 		m_freem(m);
661 		return (EBUSY);
662 	}
663 
664 	smr_read_enter();
665 	eb = ether_brport_get(ifp0);
666 	if (eb != NULL && eb->eb_input == tpmr_input) {
667 		struct tpmr_port *p = eb->eb_port;
668 		p_output = p->p_output; /* code doesn't go away */
669 	}
670 	smr_read_leave();
671 
672 	if (p_output == NULL) {
673 		m_freem(m);
674 		return (ENXIO);
675 	}
676 
677 	return ((*p_output)(ifp0, m, dst, rt));
678 }
679 
680 static void
681 tpmr_p_dtor(struct tpmr_softc *sc, struct tpmr_port *p, const char *op)
682 {
683 	struct ifnet *ifp = &sc->sc_if;
684 	struct ifnet *ifp0 = p->p_ifp0;
685 
686 	DPRINTF(sc, "%s %s: destroying port\n",
687 	    ifp->if_xname, ifp0->if_xname);
688 
689 	ifp0->if_ioctl = p->p_ioctl;
690 	ifp0->if_output = p->p_output;
691 
692 	ether_brport_clr(ifp0);
693 
694 	sc->sc_nports--;
695 	SMR_PTR_SET_LOCKED(&sc->sc_ports[p->p_slot], NULL);
696 
697 	if (ifpromisc(ifp0, 0) != 0) {
698 		log(LOG_WARNING, "%s %s: unable to disable promisc\n",
699 		    ifp->if_xname, ifp0->if_xname);
700 	}
701 
702 	if_detachhook_del(ifp0, &p->p_dtask);
703 	if_linkstatehook_del(ifp0, &p->p_ltask);
704 
705 	smr_barrier();
706 
707 	if_put(ifp0);
708 	free(p, M_DEVBUF, sizeof(*p));
709 
710 	if (ifp->if_link_state != LINK_STATE_DOWN) {
711 		ifp->if_link_state = LINK_STATE_DOWN;
712 		if_link_state_change(ifp);
713 	}
714 }
715 
716 static void
717 tpmr_p_detach(void *arg)
718 {
719 	struct tpmr_port *p = arg;
720 	struct tpmr_softc *sc = p->p_tpmr;
721 
722 	tpmr_p_dtor(sc, p, "detach");
723 
724 	NET_ASSERT_LOCKED();
725 }
726 
727 static int
728 tpmr_p_active(struct tpmr_port *p)
729 {
730 	struct ifnet *ifp0 = p->p_ifp0;
731 
732 	return (ISSET(ifp0->if_flags, IFF_RUNNING) &&
733 	    LINK_STATE_IS_UP(ifp0->if_link_state));
734 }
735 
736 static void
737 tpmr_p_linkch(void *arg)
738 {
739 	struct tpmr_port *p = arg;
740 	struct tpmr_softc *sc = p->p_tpmr;
741 	struct ifnet *ifp = &sc->sc_if;
742 	struct tpmr_port *np;
743 	u_char link_state = LINK_STATE_FULL_DUPLEX;
744 
745 	NET_ASSERT_LOCKED();
746 
747 	if (!tpmr_p_active(p))
748 		link_state = LINK_STATE_DOWN;
749 
750 	np = SMR_PTR_GET_LOCKED(&sc->sc_ports[!p->p_slot]);
751 	if (np == NULL || !tpmr_p_active(np))
752 		link_state = LINK_STATE_DOWN;
753 
754 	if (ifp->if_link_state != link_state) {
755 		ifp->if_link_state = link_state;
756 		if_link_state_change(ifp);
757 	}
758 }
759 
760 static int
761 tpmr_up(struct tpmr_softc *sc)
762 {
763 	struct ifnet *ifp = &sc->sc_if;
764 
765 	NET_ASSERT_LOCKED();
766 	SET(ifp->if_flags, IFF_RUNNING);
767 
768 	return (0);
769 }
770 
771 static int
772 tpmr_iff(struct tpmr_softc *sc)
773 {
774 	return (0);
775 }
776 
777 static int
778 tpmr_down(struct tpmr_softc *sc)
779 {
780 	struct ifnet *ifp = &sc->sc_if;
781 
782 	NET_ASSERT_LOCKED();
783 	CLR(ifp->if_flags, IFF_RUNNING);
784 
785 	return (0);
786 }
787