xref: /openbsd/sys/net/if_tpmr.c (revision 938ff1ae)
1 /*	$OpenBSD: if_tpmr.c,v 1.35 2023/12/23 10:52:54 bluhm 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
tpmrattach(int count)137 tpmrattach(int count)
138 {
139 	if_clone_attach(&tpmr_cloner);
140 }
141 
142 static int
tpmr_clone_create(struct if_clone * ifc,int unit)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
tpmr_clone_destroy(struct ifnet * ifp)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
tpmr_vlan_filter(const struct mbuf * m)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
tpmr_8021q_filter(const struct mbuf * m,uint64_t dst)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 *
tpmr_pf(struct ifnet * ifp0,int dir,struct mbuf * m)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 *
tpmr_input(struct ifnet * ifp0,struct mbuf * m,uint64_t dst,void * brport)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
tpmr_output(struct ifnet * ifp,struct mbuf * m,struct sockaddr * dst,struct rtentry * rt)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
tpmr_enqueue(struct ifnet * ifp,struct mbuf * m)424 tpmr_enqueue(struct ifnet *ifp, struct mbuf *m)
425 {
426 	m_freem(m);
427 	return (ENODEV);
428 }
429 
430 static void
tpmr_start(struct ifqueue * ifq)431 tpmr_start(struct ifqueue *ifq)
432 {
433 	ifq_purge(ifq);
434 }
435 
436 static int
tpmr_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data)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
tpmr_add_port(struct tpmr_softc * sc,const struct ifbreq * req)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 *
tpmr_trunkport(struct tpmr_softc * sc,const char * name)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
tpmr_del_port(struct tpmr_softc * sc,const struct ifbreq * req)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
tpmr_port_list(struct tpmr_softc * sc,struct ifbifconf * bifc)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
tpmr_p_ioctl(struct ifnet * ifp0,u_long cmd,caddr_t data)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
tpmr_p_output(struct ifnet * ifp0,struct mbuf * m,struct sockaddr * dst,struct rtentry * rt)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
tpmr_p_take(void * p)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
tpmr_p_rele(void * p)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
tpmr_p_dtor(struct tpmr_softc * sc,struct tpmr_port * p,const char * op)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
tpmr_p_detach(void * arg)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
tpmr_p_active(struct tpmr_port * p)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
tpmr_p_linkch(void * arg)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
tpmr_up(struct tpmr_softc * sc)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
tpmr_iff(struct tpmr_softc * sc)830 tpmr_iff(struct tpmr_softc *sc)
831 {
832 	return (0);
833 }
834 
835 static int
tpmr_down(struct tpmr_softc * sc)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