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