xref: /openbsd/sys/net/if_bpe.c (revision 55cc5ba3)
1 /*	$OpenBSD: if_bpe.c,v 1.15 2021/01/19 07:30:19 mvs Exp $ */
2 /*
3  * Copyright (c) 2018 David Gwynne <dlg@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include "bpfilter.h"
19 #include "pf.h"
20 
21 #include <sys/param.h>
22 #include <sys/systm.h>
23 #include <sys/kernel.h>
24 #include <sys/mbuf.h>
25 #include <sys/socket.h>
26 #include <sys/ioctl.h>
27 #include <sys/timeout.h>
28 #include <sys/pool.h>
29 #include <sys/tree.h>
30 
31 #include <net/if.h>
32 #include <net/if_var.h>
33 #include <net/if_dl.h>
34 #include <net/if_media.h>
35 #include <net/if_types.h>
36 #include <net/rtable.h>
37 
38 #include <netinet/in.h>
39 #include <netinet/if_ether.h>
40 
41 /* for bridge stuff */
42 #include <net/if_bridge.h>
43 
44 
45 #if NBPFILTER > 0
46 #include <net/bpf.h>
47 #endif
48 
49 #include <net/if_bpe.h>
50 
51 #define PBB_ITAG_ISID		0x00ffffff
52 #define PBB_ITAG_ISID_MIN	0x00000000
53 #define PBB_ITAG_ISID_MAX	0x00ffffff
54 #define PBB_ITAG_RES2		0x03000000	/* must be zero on input */
55 #define PBB_ITAG_RES1		0x04000000	/* ignore on input */
56 #define PBB_ITAG_UCA		0x08000000
57 #define PBB_ITAG_DEI		0x10000000
58 #define PBB_ITAG_PCP_SHIFT	29
59 #define PBB_ITAG_PCP_MASK	(0x7U << PBB_ITAG_PCP_SHIFT)
60 
61 #define BPE_BRIDGE_AGE_TMO	100 /* seconds */
62 
63 struct bpe_key {
64 	int			k_if;
65 	uint32_t		k_isid;
66 
67 	RBT_ENTRY(bpe_tunnel)	k_entry;
68 };
69 
70 RBT_HEAD(bpe_tree, bpe_key);
71 
72 static inline int bpe_cmp(const struct bpe_key *, const struct bpe_key *);
73 
74 RBT_PROTOTYPE(bpe_tree, bpe_key, k_entry, bpe_cmp);
75 RBT_GENERATE(bpe_tree, bpe_key, k_entry, bpe_cmp);
76 
77 struct bpe_entry {
78 	struct ether_addr	be_c_da; /* customer address - must be first */
79 	struct ether_addr	be_b_da; /* bridge address */
80 	unsigned int		be_type;
81 #define BPE_ENTRY_DYNAMIC		0
82 #define BPE_ENTRY_STATIC		1
83 	struct refcnt		be_refs;
84 	time_t			be_age;
85 
86 	RBT_ENTRY(bpe_entry)	be_entry;
87 };
88 
89 RBT_HEAD(bpe_map, bpe_entry);
90 
91 static inline int bpe_entry_cmp(const struct bpe_entry *,
92     const struct bpe_entry *);
93 
94 RBT_PROTOTYPE(bpe_map, bpe_entry, be_entry, bpe_entry_cmp);
95 RBT_GENERATE(bpe_map, bpe_entry, be_entry, bpe_entry_cmp);
96 
97 struct bpe_softc {
98 	struct bpe_key		sc_key; /* must be first */
99 	struct arpcom		sc_ac;
100 	int			sc_txhprio;
101 	int			sc_rxhprio;
102 	uint8_t			sc_group[ETHER_ADDR_LEN];
103 
104 	struct task		sc_ltask;
105 	struct task		sc_dtask;
106 
107 	struct bpe_map		sc_bridge_map;
108 	struct rwlock		sc_bridge_lock;
109 	unsigned int		sc_bridge_num;
110 	unsigned int		sc_bridge_max;
111 	int			sc_bridge_tmo; /* seconds */
112 	struct timeout		sc_bridge_age;
113 };
114 
115 void		bpeattach(int);
116 
117 static int	bpe_clone_create(struct if_clone *, int);
118 static int	bpe_clone_destroy(struct ifnet *);
119 
120 static void	bpe_start(struct ifnet *);
121 static int	bpe_ioctl(struct ifnet *, u_long, caddr_t);
122 static int	bpe_media_get(struct bpe_softc *, struct ifreq *);
123 static int	bpe_up(struct bpe_softc *);
124 static int	bpe_down(struct bpe_softc *);
125 static int	bpe_multi(struct bpe_softc *, struct ifnet *, u_long);
126 static int	bpe_set_vnetid(struct bpe_softc *, const struct ifreq *);
127 static void	bpe_set_group(struct bpe_softc *, uint32_t);
128 static int	bpe_set_parent(struct bpe_softc *, const struct if_parent *);
129 static int	bpe_get_parent(struct bpe_softc *, struct if_parent *);
130 static int	bpe_del_parent(struct bpe_softc *);
131 static void	bpe_link_hook(void *);
132 static void	bpe_link_state(struct bpe_softc *, u_char, uint64_t);
133 static void	bpe_detach_hook(void *);
134 
135 static void	bpe_input_map(struct bpe_softc *,
136 		    const uint8_t *, const uint8_t *);
137 static void	bpe_bridge_age(void *);
138 
139 static struct if_clone bpe_cloner =
140     IF_CLONE_INITIALIZER("bpe", bpe_clone_create, bpe_clone_destroy);
141 
142 static struct bpe_tree bpe_interfaces = RBT_INITIALIZER();
143 static struct rwlock bpe_lock = RWLOCK_INITIALIZER("bpeifs");
144 static struct pool bpe_entry_pool;
145 
146 void
147 bpeattach(int count)
148 {
149 	if_clone_attach(&bpe_cloner);
150 }
151 
152 static int
153 bpe_clone_create(struct if_clone *ifc, int unit)
154 {
155 	struct bpe_softc *sc;
156 	struct ifnet *ifp;
157 
158 	if (bpe_entry_pool.pr_size == 0) {
159 		pool_init(&bpe_entry_pool, sizeof(struct bpe_entry), 0,
160 		    IPL_NONE, 0, "bpepl", NULL);
161 	}
162 
163 	sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
164 	ifp = &sc->sc_ac.ac_if;
165 
166 	snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d",
167 	    ifc->ifc_name, unit);
168 
169 	sc->sc_key.k_if = 0;
170 	sc->sc_key.k_isid = 0;
171 	bpe_set_group(sc, 0);
172 
173 	sc->sc_txhprio = IF_HDRPRIO_PACKET;
174 	sc->sc_rxhprio = IF_HDRPRIO_OUTER;
175 
176 	task_set(&sc->sc_ltask, bpe_link_hook, sc);
177 	task_set(&sc->sc_dtask, bpe_detach_hook, sc);
178 
179 	rw_init(&sc->sc_bridge_lock, "bpebr");
180 	RBT_INIT(bpe_map, &sc->sc_bridge_map);
181 	sc->sc_bridge_num = 0;
182 	sc->sc_bridge_max = 100; /* XXX */
183 	sc->sc_bridge_tmo = 240;
184 	timeout_set_proc(&sc->sc_bridge_age, bpe_bridge_age, sc);
185 
186 	ifp->if_softc = sc;
187 	ifp->if_hardmtu = ETHER_MAX_HARDMTU_LEN;
188 	ifp->if_ioctl = bpe_ioctl;
189 	ifp->if_start = bpe_start;
190 	ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST;
191 	ifp->if_xflags = IFXF_CLONED;
192 	ether_fakeaddr(ifp);
193 
194 	if_counters_alloc(ifp);
195 	if_attach(ifp);
196 	ether_ifattach(ifp);
197 
198 	return (0);
199 }
200 
201 static int
202 bpe_clone_destroy(struct ifnet *ifp)
203 {
204 	struct bpe_softc *sc = ifp->if_softc;
205 
206 	NET_LOCK();
207 	if (ISSET(ifp->if_flags, IFF_RUNNING))
208 		bpe_down(sc);
209 	NET_UNLOCK();
210 
211 	ether_ifdetach(ifp);
212 	if_detach(ifp);
213 
214 	free(sc, M_DEVBUF, sizeof(*sc));
215 
216 	return (0);
217 }
218 
219 static inline int
220 bpe_entry_valid(struct bpe_softc *sc, const struct bpe_entry *be)
221 {
222 	time_t diff;
223 
224 	if (be == NULL)
225 		return (0);
226 
227 	if (be->be_type == BPE_ENTRY_STATIC)
228 		return (1);
229 
230 	diff = getuptime() - be->be_age;
231 	if (diff < sc->sc_bridge_tmo)
232 		return (1);
233 
234 	return (0);
235 }
236 
237 static void
238 bpe_start(struct ifnet *ifp)
239 {
240 	struct bpe_softc *sc = ifp->if_softc;
241 	struct ifnet *ifp0;
242 	struct mbuf *m0, *m;
243 	struct ether_header *ceh;
244 	struct ether_header *beh;
245 	uint32_t itag, *itagp;
246 	int hlen = sizeof(*beh) + sizeof(*itagp);
247 #if NBPFILTER > 0
248 	caddr_t if_bpf;
249 #endif
250 	int txprio;
251 	uint8_t prio;
252 
253 	ifp0 = if_get(sc->sc_key.k_if);
254 	if (ifp0 == NULL || !ISSET(ifp0->if_flags, IFF_RUNNING)) {
255 		ifq_purge(&ifp->if_snd);
256 		goto done;
257 	}
258 
259 	txprio = sc->sc_txhprio;
260 
261 	while ((m0 = ifq_dequeue(&ifp->if_snd)) != NULL) {
262 #if NBPFILTER > 0
263 		if_bpf = ifp->if_bpf;
264 		if (if_bpf)
265 			bpf_mtap_ether(if_bpf, m0, BPF_DIRECTION_OUT);
266 #endif
267 
268 		ceh = mtod(m0, struct ether_header *);
269 
270 		/* force prepend of a whole mbuf because of alignment */
271 		m = m_get(M_DONTWAIT, m0->m_type);
272 		if (m == NULL) {
273 			m_freem(m0);
274 			continue;
275 		}
276 
277 		M_MOVE_PKTHDR(m, m0);
278 		m->m_next = m0;
279 
280 		m_align(m, 0);
281 		m->m_len = 0;
282 
283 		m = m_prepend(m, hlen, M_DONTWAIT);
284 		if (m == NULL)
285 			continue;
286 
287 		beh = mtod(m, struct ether_header *);
288 
289 		if (ETHER_IS_BROADCAST(ceh->ether_dhost)) {
290 			memcpy(beh->ether_dhost, sc->sc_group,
291 			    sizeof(beh->ether_dhost));
292 		} else {
293 			struct bpe_entry *be;
294 
295 			rw_enter_read(&sc->sc_bridge_lock);
296 			be = RBT_FIND(bpe_map, &sc->sc_bridge_map,
297 			    (struct bpe_entry *)ceh->ether_dhost);
298 			if (bpe_entry_valid(sc, be)) {
299 				memcpy(beh->ether_dhost, &be->be_b_da,
300 				    sizeof(beh->ether_dhost));
301 			} else {
302 				/* "flood" to unknown hosts */
303 				memcpy(beh->ether_dhost, sc->sc_group,
304 				    sizeof(beh->ether_dhost));
305 			}
306 			rw_exit_read(&sc->sc_bridge_lock);
307 		}
308 
309 		memcpy(beh->ether_shost, ((struct arpcom *)ifp0)->ac_enaddr,
310 		    sizeof(beh->ether_shost));
311 		beh->ether_type = htons(ETHERTYPE_PBB);
312 
313 		prio = (txprio == IF_HDRPRIO_PACKET) ?
314 		    m->m_pkthdr.pf.prio : txprio;
315 
316 		itag = sc->sc_key.k_isid;
317 		itag |= prio << PBB_ITAG_PCP_SHIFT;
318 		itagp = (uint32_t *)(beh + 1);
319 
320 		htobem32(itagp, itag);
321 
322 		if_enqueue(ifp0, m);
323 	}
324 
325 done:
326 	if_put(ifp0);
327 }
328 
329 static void
330 bpe_bridge_age(void *arg)
331 {
332 	struct bpe_softc *sc = arg;
333 	struct bpe_entry *be, *nbe;
334 	time_t diff;
335 
336 	timeout_add_sec(&sc->sc_bridge_age, BPE_BRIDGE_AGE_TMO);
337 
338 	rw_enter_write(&sc->sc_bridge_lock);
339 	RBT_FOREACH_SAFE(be, bpe_map, &sc->sc_bridge_map, nbe) {
340 		if (be->be_type != BPE_ENTRY_DYNAMIC)
341 			continue;
342 
343 		diff = getuptime() - be->be_age;
344 		if (diff < sc->sc_bridge_tmo)
345 			continue;
346 
347 		sc->sc_bridge_num--;
348 		RBT_REMOVE(bpe_map, &sc->sc_bridge_map, be);
349 		if (refcnt_rele(&be->be_refs))
350 			pool_put(&bpe_entry_pool, be);
351 	}
352 	rw_exit_write(&sc->sc_bridge_lock);
353 }
354 
355 static int
356 bpe_rtfind(struct bpe_softc *sc, struct ifbaconf *baconf)
357 {
358 	struct ifnet *ifp = &sc->sc_ac.ac_if;
359 	struct bpe_entry *be;
360 	struct ifbareq bareq;
361 	caddr_t uaddr, end;
362 	int error;
363 	time_t age;
364 	struct sockaddr_dl *sdl;
365 
366 	if (baconf->ifbac_len == 0) {
367 		/* single read is atomic */
368 		baconf->ifbac_len = sc->sc_bridge_num * sizeof(bareq);
369 		return (0);
370 	}
371 
372 	uaddr = baconf->ifbac_buf;
373 	end = uaddr + baconf->ifbac_len;
374 
375 	rw_enter_read(&sc->sc_bridge_lock);
376 	RBT_FOREACH(be, bpe_map, &sc->sc_bridge_map) {
377 		if (uaddr >= end)
378 			break;
379 
380 		memcpy(bareq.ifba_name, ifp->if_xname,
381 		    sizeof(bareq.ifba_name));
382 		memcpy(bareq.ifba_ifsname, ifp->if_xname,
383 		    sizeof(bareq.ifba_ifsname));
384 		memcpy(&bareq.ifba_dst, &be->be_c_da,
385 		    sizeof(bareq.ifba_dst));
386 
387 		memset(&bareq.ifba_dstsa, 0, sizeof(bareq.ifba_dstsa));
388 
389 		bzero(&bareq.ifba_dstsa, sizeof(bareq.ifba_dstsa));
390 		sdl = (struct sockaddr_dl *)&bareq.ifba_dstsa;
391 		sdl->sdl_len = sizeof(sdl);
392 		sdl->sdl_family = AF_LINK;
393 		sdl->sdl_index = 0;
394 		sdl->sdl_type = IFT_ETHER;
395 		sdl->sdl_nlen = 0;
396 		sdl->sdl_alen = sizeof(be->be_b_da);
397 		CTASSERT(sizeof(sdl->sdl_data) >= sizeof(be->be_b_da));
398 		memcpy(sdl->sdl_data, &be->be_b_da, sizeof(be->be_b_da));
399 
400 		switch (be->be_type) {
401 		case BPE_ENTRY_DYNAMIC:
402 			age = getuptime() - be->be_age;
403 			bareq.ifba_age = MIN(age, 0xff);
404 			bareq.ifba_flags = IFBAF_DYNAMIC;
405 			break;
406 		case BPE_ENTRY_STATIC:
407 			bareq.ifba_age = 0;
408 			bareq.ifba_flags = IFBAF_STATIC;
409 			break;
410 		}
411 
412 		error = copyout(&bareq, uaddr, sizeof(bareq));
413 		if (error != 0) {
414 			rw_exit_read(&sc->sc_bridge_lock);
415 			return (error);
416 		}
417 
418 		uaddr += sizeof(bareq);
419 	}
420 	baconf->ifbac_len = sc->sc_bridge_num * sizeof(bareq);
421 	rw_exit_read(&sc->sc_bridge_lock);
422 
423 	return (0);
424 }
425 
426 static void
427 bpe_flush_map(struct bpe_softc *sc, uint32_t flags)
428 {
429 	struct bpe_entry *be, *nbe;
430 
431 	rw_enter_write(&sc->sc_bridge_lock);
432 	RBT_FOREACH_SAFE(be, bpe_map, &sc->sc_bridge_map, nbe) {
433 		if (flags == IFBF_FLUSHDYN &&
434 		    be->be_type != BPE_ENTRY_DYNAMIC)
435 			continue;
436 
437 		RBT_REMOVE(bpe_map, &sc->sc_bridge_map, be);
438 		if (refcnt_rele(&be->be_refs))
439 			pool_put(&bpe_entry_pool, be);
440 	}
441 	rw_exit_write(&sc->sc_bridge_lock);
442 }
443 
444 static int
445 bpe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
446 {
447 	struct bpe_softc *sc = ifp->if_softc;
448 	struct ifreq *ifr = (struct ifreq *)data;
449 	struct ifbrparam *bparam = (struct ifbrparam *)data;
450 	int error = 0;
451 
452 	switch (cmd) {
453 	case SIOCSIFFLAGS:
454 		if (ISSET(ifp->if_flags, IFF_UP)) {
455 			if (!ISSET(ifp->if_flags, IFF_RUNNING))
456 				error = bpe_up(sc);
457 			else
458 				error = 0;
459 		} else {
460 			if (ISSET(ifp->if_flags, IFF_RUNNING))
461 				error = bpe_down(sc);
462 		}
463 		break;
464 
465 	case SIOCSVNETID:
466 		error = bpe_set_vnetid(sc, ifr);
467 		break;
468 	case SIOCGVNETID:
469 		ifr->ifr_vnetid = sc->sc_key.k_isid;
470 		break;
471 
472 	case SIOCSIFPARENT:
473 		error = bpe_set_parent(sc, (struct if_parent *)data);
474 		break;
475 	case SIOCGIFPARENT:
476 		error = bpe_get_parent(sc, (struct if_parent *)data);
477 		break;
478 	case SIOCDIFPARENT:
479 		error = bpe_del_parent(sc);
480 		break;
481 
482 	case SIOCSTXHPRIO:
483 		error = if_txhprio_l2_check(ifr->ifr_hdrprio);
484 		if (error != 0)
485 			break;
486 
487 		sc->sc_txhprio = ifr->ifr_hdrprio;
488 		break;
489 	case SIOCGTXHPRIO:
490 		ifr->ifr_hdrprio = sc->sc_txhprio;
491 		break;
492 
493 	case SIOCSRXHPRIO:
494 		error = if_rxhprio_l2_check(ifr->ifr_hdrprio);
495 		if (error != 0)
496 			break;
497 
498 		sc->sc_rxhprio = ifr->ifr_hdrprio;
499 		break;
500 	case SIOCGRXHPRIO:
501 		ifr->ifr_hdrprio = sc->sc_rxhprio;
502 		break;
503 
504 	case SIOCGIFMEDIA:
505 		error = bpe_media_get(sc, ifr);
506 		break;
507 
508 	case SIOCBRDGSCACHE:
509 		error = suser(curproc);
510 		if (error != 0)
511 			break;
512 
513 		if (bparam->ifbrp_csize < 1) {
514 			error = EINVAL;
515 			break;
516 		}
517 
518 		/* commit */
519 		sc->sc_bridge_max = bparam->ifbrp_csize;
520 		break;
521 	case SIOCBRDGGCACHE:
522 		bparam->ifbrp_csize = sc->sc_bridge_max;
523 		break;
524 
525 	case SIOCBRDGSTO:
526 		error = suser(curproc);
527 		if (error != 0)
528 			break;
529 
530 		if (bparam->ifbrp_ctime < 8 ||
531 		    bparam->ifbrp_ctime > 3600) {
532 			error = EINVAL;
533 			break;
534 		}
535 		sc->sc_bridge_tmo = bparam->ifbrp_ctime;
536 		break;
537 	case SIOCBRDGGTO:
538 		bparam->ifbrp_ctime = sc->sc_bridge_tmo;
539 		break;
540 
541 	case SIOCBRDGRTS:
542 		error = bpe_rtfind(sc, (struct ifbaconf *)data);
543 		break;
544 	case SIOCBRDGFLUSH:
545 		error = suser(curproc);
546 		if (error != 0)
547 			break;
548 
549 		bpe_flush_map(sc,
550 		    ((struct ifbreq *)data)->ifbr_ifsflags);
551 		break;
552 
553 	default:
554 		error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
555 		break;
556 	}
557 
558 	return (error);
559 }
560 
561 static int
562 bpe_media_get(struct bpe_softc *sc, struct ifreq *ifr)
563 {
564 	struct ifnet *ifp0;
565 	int error;
566 
567 	ifp0 = if_get(sc->sc_key.k_if);
568 	if (ifp0 != NULL)
569 		error = (*ifp0->if_ioctl)(ifp0, SIOCGIFMEDIA, (caddr_t)ifr);
570 	else
571 		error = ENOTTY;
572 	if_put(ifp0);
573 
574 	return (error);
575 }
576 
577 static int
578 bpe_up(struct bpe_softc *sc)
579 {
580 	struct ifnet *ifp = &sc->sc_ac.ac_if;
581 	struct ifnet *ifp0;
582 	struct bpe_softc *osc;
583 	int error = 0;
584 	u_int hardmtu;
585 	u_int hlen = sizeof(struct ether_header) + sizeof(uint32_t);
586 
587 	KASSERT(!ISSET(ifp->if_flags, IFF_RUNNING));
588 	NET_ASSERT_LOCKED();
589 
590 	ifp0 = if_get(sc->sc_key.k_if);
591 	if (ifp0 == NULL)
592 		return (ENXIO);
593 
594 	/* check again if bpe will work on top of the parent */
595 	if (ifp0->if_type != IFT_ETHER) {
596 		error = EPROTONOSUPPORT;
597 		goto put;
598 	}
599 
600 	hardmtu = ifp0->if_hardmtu;
601 	if (hardmtu < hlen) {
602 		error = ENOBUFS;
603 		goto put;
604 	}
605 	hardmtu -= hlen;
606 	if (ifp->if_mtu > hardmtu) {
607 		error = ENOBUFS;
608 		goto put;
609 	}
610 
611 	/* parent is fine, let's prepare the bpe to handle packets */
612 	ifp->if_hardmtu = hardmtu;
613 	SET(ifp->if_flags, ifp0->if_flags & IFF_SIMPLEX);
614 
615 	/* commit the interface */
616 	error = rw_enter(&bpe_lock, RW_WRITE | RW_INTR);
617 	if (error != 0)
618 		goto scrub;
619 
620 	osc = (struct bpe_softc *)RBT_INSERT(bpe_tree, &bpe_interfaces,
621 	    (struct bpe_key *)sc);
622 	rw_exit(&bpe_lock);
623 
624 	if (osc != NULL) {
625 		error = EADDRINUSE;
626 		goto scrub;
627 	}
628 
629 	if (bpe_multi(sc, ifp0, SIOCADDMULTI) != 0) {
630 		error = ENOTCONN;
631 		goto remove;
632 	}
633 
634 	/* Register callback for physical link state changes */
635 	if_linkstatehook_add(ifp0, &sc->sc_ltask);
636 
637 	/* Register callback if parent wants to unregister */
638 	if_detachhook_add(ifp0, &sc->sc_dtask);
639 
640 	/* we're running now */
641 	SET(ifp->if_flags, IFF_RUNNING);
642 	bpe_link_state(sc, ifp0->if_link_state, ifp0->if_baudrate);
643 
644 	if_put(ifp0);
645 
646 	timeout_add_sec(&sc->sc_bridge_age, BPE_BRIDGE_AGE_TMO);
647 
648 	return (0);
649 
650 remove:
651 	rw_enter(&bpe_lock, RW_WRITE);
652 	RBT_REMOVE(bpe_tree, &bpe_interfaces, (struct bpe_key *)sc);
653 	rw_exit(&bpe_lock);
654 scrub:
655 	CLR(ifp->if_flags, IFF_SIMPLEX);
656 	ifp->if_hardmtu = 0xffff;
657 put:
658 	if_put(ifp0);
659 
660 	return (error);
661 }
662 
663 static int
664 bpe_down(struct bpe_softc *sc)
665 {
666 	struct ifnet *ifp = &sc->sc_ac.ac_if;
667 	struct ifnet *ifp0;
668 
669 	NET_ASSERT_LOCKED();
670 
671 	CLR(ifp->if_flags, IFF_RUNNING);
672 
673 	ifp0 = if_get(sc->sc_key.k_if);
674 	if (ifp0 != NULL) {
675 		if_detachhook_del(ifp0, &sc->sc_dtask);
676 		if_linkstatehook_del(ifp0, &sc->sc_ltask);
677 		bpe_multi(sc, ifp0, SIOCDELMULTI);
678 	}
679 	if_put(ifp0);
680 
681 	rw_enter(&bpe_lock, RW_WRITE);
682 	RBT_REMOVE(bpe_tree, &bpe_interfaces, (struct bpe_key *)sc);
683 	rw_exit(&bpe_lock);
684 
685 	CLR(ifp->if_flags, IFF_SIMPLEX);
686 	ifp->if_hardmtu = 0xffff;
687 
688 	return (0);
689 }
690 
691 static int
692 bpe_multi(struct bpe_softc *sc, struct ifnet *ifp0, u_long cmd)
693 {
694 	struct ifreq ifr;
695 	struct sockaddr *sa;
696 
697 	/* make it convincing */
698 	CTASSERT(sizeof(ifr.ifr_name) == sizeof(ifp0->if_xname));
699 	memcpy(ifr.ifr_name, ifp0->if_xname, sizeof(ifr.ifr_name));
700 
701 	sa = &ifr.ifr_addr;
702 	CTASSERT(sizeof(sa->sa_data) >= sizeof(sc->sc_group));
703 
704 	sa->sa_family = AF_UNSPEC;
705 	memcpy(sa->sa_data, sc->sc_group, sizeof(sc->sc_group));
706 
707 	return ((*ifp0->if_ioctl)(ifp0, cmd, (caddr_t)&ifr));
708 }
709 
710 static void
711 bpe_set_group(struct bpe_softc *sc, uint32_t isid)
712 {
713 	uint8_t *group = sc->sc_group;
714 
715 	group[0] = 0x01;
716 	group[1] = 0x1e;
717 	group[2] = 0x83;
718 	group[3] = isid >> 16;
719 	group[4] = isid >> 8;
720 	group[5] = isid >> 0;
721 }
722 
723 static int
724 bpe_set_vnetid(struct bpe_softc *sc, const struct ifreq *ifr)
725 {
726 	struct ifnet *ifp = &sc->sc_ac.ac_if;
727 	uint32_t isid;
728 
729 	if (ifr->ifr_vnetid < PBB_ITAG_ISID_MIN ||
730 	    ifr->ifr_vnetid > PBB_ITAG_ISID_MAX)
731 		return (EINVAL);
732 
733 	isid = ifr->ifr_vnetid;
734 	if (isid == sc->sc_key.k_isid)
735 		return (0);
736 
737 	if (ISSET(ifp->if_flags, IFF_RUNNING))
738 		return (EBUSY);
739 
740 	/* commit */
741 	sc->sc_key.k_isid = isid;
742 	bpe_set_group(sc, isid);
743 	bpe_flush_map(sc, IFBF_FLUSHALL);
744 
745 	return (0);
746 }
747 
748 static int
749 bpe_set_parent(struct bpe_softc *sc, const struct if_parent *p)
750 {
751 	struct ifnet *ifp = &sc->sc_ac.ac_if;
752 	struct ifnet *ifp0;
753 	int error = 0;
754 
755 	ifp0 = if_unit(p->ifp_parent);
756 	if (ifp0 == NULL)
757 		return (ENXIO);
758 
759 	if (ifp0->if_type != IFT_ETHER) {
760 		error = ENXIO;
761 		goto put;
762 	}
763 
764 	if (ifp0->if_index == sc->sc_key.k_if)
765 		goto put;
766 
767 	if (ISSET(ifp->if_flags, IFF_RUNNING)) {
768 		error = EBUSY;
769 		goto put;
770 	}
771 
772 	/* commit */
773 	sc->sc_key.k_if = ifp0->if_index;
774 	bpe_flush_map(sc, IFBF_FLUSHALL);
775 
776 put:
777 	if_put(ifp0);
778 	return (error);
779 }
780 
781 static int
782 bpe_get_parent(struct bpe_softc *sc, struct if_parent *p)
783 {
784 	struct ifnet *ifp0;
785 	int error = 0;
786 
787 	ifp0 = if_get(sc->sc_key.k_if);
788 	if (ifp0 == NULL)
789 		error = EADDRNOTAVAIL;
790 	else
791 		memcpy(p->ifp_parent, ifp0->if_xname, sizeof(p->ifp_parent));
792 	if_put(ifp0);
793 
794 	return (error);
795 }
796 
797 static int
798 bpe_del_parent(struct bpe_softc *sc)
799 {
800 	struct ifnet *ifp = &sc->sc_ac.ac_if;
801 
802 	if (ISSET(ifp->if_flags, IFF_RUNNING))
803 		return (EBUSY);
804 
805 	/* commit */
806 	sc->sc_key.k_if = 0;
807 	bpe_flush_map(sc, IFBF_FLUSHALL);
808 
809 	return (0);
810 }
811 
812 static inline struct bpe_softc *
813 bpe_find(struct ifnet *ifp0, uint32_t isid)
814 {
815 	struct bpe_key k = { .k_if = ifp0->if_index, .k_isid = isid };
816 	struct bpe_softc *sc;
817 
818 	rw_enter_read(&bpe_lock);
819 	sc = (struct bpe_softc *)RBT_FIND(bpe_tree, &bpe_interfaces, &k);
820 	rw_exit_read(&bpe_lock);
821 
822 	return (sc);
823 }
824 
825 static void
826 bpe_input_map(struct bpe_softc *sc, const uint8_t *ba, const uint8_t *ca)
827 {
828 	struct bpe_entry *be;
829 	int new = 0;
830 
831 	if (ETHER_IS_MULTICAST(ca))
832 		return;
833 
834 	/* remember where it came from */
835 	rw_enter_read(&sc->sc_bridge_lock);
836 	be = RBT_FIND(bpe_map, &sc->sc_bridge_map, (struct bpe_entry *)ca);
837 	if (be == NULL)
838 		new = 1;
839 	else {
840 		be->be_age = getuptime(); /* only a little bit racy */
841 
842 		if (be->be_type != BPE_ENTRY_DYNAMIC ||
843 		    ETHER_IS_EQ(ba, &be->be_b_da))
844 			be = NULL;
845 		else
846 			refcnt_take(&be->be_refs);
847 	}
848 	rw_exit_read(&sc->sc_bridge_lock);
849 
850 	if (new) {
851 		struct bpe_entry *obe;
852 		unsigned int num;
853 
854 		be = pool_get(&bpe_entry_pool, PR_NOWAIT);
855 		if (be == NULL) {
856 			/* oh well */
857 			return;
858 		}
859 
860 		memcpy(&be->be_c_da, ca, sizeof(be->be_c_da));
861 		memcpy(&be->be_b_da, ba, sizeof(be->be_b_da));
862 		be->be_type = BPE_ENTRY_DYNAMIC;
863 		refcnt_init(&be->be_refs);
864 		be->be_age = getuptime();
865 
866 		rw_enter_write(&sc->sc_bridge_lock);
867 		num = sc->sc_bridge_num;
868 		if (++num > sc->sc_bridge_max)
869 			obe = be;
870 		else {
871 			/* try and give the ref to the map */
872 			obe = RBT_INSERT(bpe_map, &sc->sc_bridge_map, be);
873 			if (obe == NULL) {
874 				/* count the insert */
875 				sc->sc_bridge_num = num;
876 			}
877 		}
878 		rw_exit_write(&sc->sc_bridge_lock);
879 
880 		if (obe != NULL)
881 			pool_put(&bpe_entry_pool, obe);
882 	} else if (be != NULL) {
883 		rw_enter_write(&sc->sc_bridge_lock);
884 		memcpy(&be->be_b_da, ba, sizeof(be->be_b_da));
885 		rw_exit_write(&sc->sc_bridge_lock);
886 
887 		if (refcnt_rele(&be->be_refs)) {
888 			/* ioctl may have deleted the entry */
889 			pool_put(&bpe_entry_pool, be);
890 		}
891 	}
892 }
893 
894 void
895 bpe_input(struct ifnet *ifp0, struct mbuf *m)
896 {
897 	struct bpe_softc *sc;
898 	struct ifnet *ifp;
899 	struct ether_header *beh, *ceh;
900 	uint32_t *itagp, itag;
901 	unsigned int hlen = sizeof(*beh) + sizeof(*itagp) + sizeof(*ceh);
902 	struct mbuf *n;
903 	int off;
904 	int prio;
905 
906 	if (m->m_len < hlen) {
907 		m = m_pullup(m, hlen);
908 		if (m == NULL) {
909 			/* pbb short ++ */
910 			return;
911 		}
912 	}
913 
914 	beh = mtod(m, struct ether_header *);
915 	itagp = (uint32_t *)(beh + 1);
916 	itag = bemtoh32(itagp);
917 
918 	if (itag & PBB_ITAG_RES2) {
919 		/* dropped by res2 ++ */
920 		goto drop;
921 	}
922 
923 	sc = bpe_find(ifp0, itag & PBB_ITAG_ISID);
924 	if (sc == NULL) {
925 		/* no interface found */
926 		goto drop;
927 	}
928 
929 	ceh = (struct ether_header *)(itagp + 1);
930 
931 	bpe_input_map(sc, beh->ether_shost, ceh->ether_shost);
932 
933 	m_adj(m, sizeof(*beh) + sizeof(*itagp));
934 
935 	n = m_getptr(m, sizeof(*ceh), &off);
936 	if (n == NULL) {
937 		/* no data ++ */
938 		goto drop;
939 	}
940 
941 	if (!ALIGNED_POINTER(mtod(n, caddr_t) + off, uint32_t)) {
942 		/* unaligned ++ */
943 		n = m_dup_pkt(m, ETHER_ALIGN, M_NOWAIT);
944 		m_freem(m);
945 		if (n == NULL)
946 			return;
947 
948 		m = n;
949 	}
950 
951 	ifp = &sc->sc_ac.ac_if;
952 
953 	prio = sc->sc_rxhprio;
954 	switch (prio) {
955 	case IF_HDRPRIO_PACKET:
956 		break;
957 	case IF_HDRPRIO_OUTER:
958 		m->m_pkthdr.pf.prio = (itag & PBB_ITAG_PCP_MASK) >>
959 		    PBB_ITAG_PCP_SHIFT;
960 		break;
961 	default:
962 		m->m_pkthdr.pf.prio = prio;
963 		break;
964 	}
965 
966 	m->m_flags &= ~(M_BCAST|M_MCAST);
967 	m->m_pkthdr.ph_ifidx = ifp->if_index;
968 	m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
969 
970 #if NPF > 0
971 	pf_pkt_addr_changed(m);
972 #endif
973 
974 	if_vinput(ifp, m);
975 	return;
976 
977 drop:
978 	m_freem(m);
979 }
980 
981 void
982 bpe_detach_hook(void *arg)
983 {
984 	struct bpe_softc *sc = arg;
985 	struct ifnet *ifp = &sc->sc_ac.ac_if;
986 
987 	if (ISSET(ifp->if_flags, IFF_RUNNING)) {
988 		bpe_down(sc);
989 		CLR(ifp->if_flags, IFF_UP);
990 	}
991 
992 	sc->sc_key.k_if = 0;
993 }
994 
995 static void
996 bpe_link_hook(void *arg)
997 {
998 	struct bpe_softc *sc = arg;
999 	struct ifnet *ifp0;
1000 	u_char link = LINK_STATE_DOWN;
1001 	uint64_t baud = 0;
1002 
1003 	ifp0 = if_get(sc->sc_key.k_if);
1004 	if (ifp0 != NULL) {
1005 		link = ifp0->if_link_state;
1006 		baud = ifp0->if_baudrate;
1007 	}
1008 	if_put(ifp0);
1009 
1010 	bpe_link_state(sc, link, baud);
1011 }
1012 
1013 void
1014 bpe_link_state(struct bpe_softc *sc, u_char link, uint64_t baud)
1015 {
1016 	struct ifnet *ifp = &sc->sc_ac.ac_if;
1017 
1018 	if (ifp->if_link_state == link)
1019 		return;
1020 
1021 	ifp->if_link_state = link;
1022 	ifp->if_baudrate = baud;
1023 
1024 	if_link_state_change(ifp);
1025 }
1026 
1027 static inline int
1028 bpe_cmp(const struct bpe_key *a, const struct bpe_key *b)
1029 {
1030 	if (a->k_if > b->k_if)
1031 		return (1);
1032 	if (a->k_if < b->k_if)
1033 		return (-1);
1034 	if (a->k_isid > b->k_isid)
1035 		return (1);
1036 	if (a->k_isid < b->k_isid)
1037 		return (-1);
1038 
1039 	return (0);
1040 }
1041 
1042 static inline int
1043 bpe_entry_cmp(const struct bpe_entry *a, const struct bpe_entry *b)
1044 {
1045 	return memcmp(&a->be_c_da, &b->be_c_da, sizeof(a->be_c_da));
1046 }
1047