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