xref: /openbsd-src/sys/net/if_tpmr.c (revision 46035553bfdd96e63c94e32da0210227ec2e3cf1)
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