1*938ff1aeSbluhm /* $OpenBSD: if_bpe.c,v 1.22 2023/12/23 10:52:54 bluhm Exp $ */
25fb1d1dcSdlg /*
35fb1d1dcSdlg * Copyright (c) 2018 David Gwynne <dlg@openbsd.org>
45fb1d1dcSdlg *
55fb1d1dcSdlg * Permission to use, copy, modify, and distribute this software for any
65fb1d1dcSdlg * purpose with or without fee is hereby granted, provided that the above
75fb1d1dcSdlg * copyright notice and this permission notice appear in all copies.
85fb1d1dcSdlg *
95fb1d1dcSdlg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
105fb1d1dcSdlg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
115fb1d1dcSdlg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
125fb1d1dcSdlg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
135fb1d1dcSdlg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
145fb1d1dcSdlg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
155fb1d1dcSdlg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
165fb1d1dcSdlg */
175fb1d1dcSdlg
185fb1d1dcSdlg #include "bpfilter.h"
191773e850Sjsg #include "pf.h"
205fb1d1dcSdlg
215fb1d1dcSdlg #include <sys/param.h>
225fb1d1dcSdlg #include <sys/systm.h>
235fb1d1dcSdlg #include <sys/kernel.h>
245fb1d1dcSdlg #include <sys/mbuf.h>
255fb1d1dcSdlg #include <sys/socket.h>
265fb1d1dcSdlg #include <sys/ioctl.h>
275fb1d1dcSdlg #include <sys/timeout.h>
285fb1d1dcSdlg #include <sys/pool.h>
295fb1d1dcSdlg #include <sys/tree.h>
30ea0a6b3dSdlg #include <sys/smr.h>
315fb1d1dcSdlg
325fb1d1dcSdlg #include <net/if.h>
335fb1d1dcSdlg #include <net/if_var.h>
345fb1d1dcSdlg #include <net/if_dl.h>
355fb1d1dcSdlg #include <net/if_media.h>
365fb1d1dcSdlg #include <net/if_types.h>
375fb1d1dcSdlg #include <net/rtable.h>
385fb1d1dcSdlg
395fb1d1dcSdlg #include <netinet/in.h>
405fb1d1dcSdlg #include <netinet/if_ether.h>
415fb1d1dcSdlg
425fb1d1dcSdlg /* for bridge stuff */
435fb1d1dcSdlg #include <net/if_bridge.h>
44ea0a6b3dSdlg #include <net/if_etherbridge.h>
455fb1d1dcSdlg
465fb1d1dcSdlg #if NBPFILTER > 0
475fb1d1dcSdlg #include <net/bpf.h>
485fb1d1dcSdlg #endif
495fb1d1dcSdlg
505fb1d1dcSdlg #include <net/if_bpe.h>
515fb1d1dcSdlg
525fb1d1dcSdlg #define PBB_ITAG_ISID 0x00ffffff
535fb1d1dcSdlg #define PBB_ITAG_ISID_MIN 0x00000000
545fb1d1dcSdlg #define PBB_ITAG_ISID_MAX 0x00ffffff
555fb1d1dcSdlg #define PBB_ITAG_RES2 0x03000000 /* must be zero on input */
565fb1d1dcSdlg #define PBB_ITAG_RES1 0x04000000 /* ignore on input */
575fb1d1dcSdlg #define PBB_ITAG_UCA 0x08000000
585fb1d1dcSdlg #define PBB_ITAG_DEI 0x10000000
595fb1d1dcSdlg #define PBB_ITAG_PCP_SHIFT 29
605fb1d1dcSdlg #define PBB_ITAG_PCP_MASK (0x7U << PBB_ITAG_PCP_SHIFT)
615fb1d1dcSdlg
625fb1d1dcSdlg #define BPE_BRIDGE_AGE_TMO 100 /* seconds */
635fb1d1dcSdlg
645fb1d1dcSdlg struct bpe_key {
655fb1d1dcSdlg int k_if;
665fb1d1dcSdlg uint32_t k_isid;
675fb1d1dcSdlg
685fb1d1dcSdlg RBT_ENTRY(bpe_tunnel) k_entry;
695fb1d1dcSdlg };
705fb1d1dcSdlg
715fb1d1dcSdlg RBT_HEAD(bpe_tree, bpe_key);
725fb1d1dcSdlg
735fb1d1dcSdlg static inline int bpe_cmp(const struct bpe_key *, const struct bpe_key *);
745fb1d1dcSdlg
755fb1d1dcSdlg RBT_PROTOTYPE(bpe_tree, bpe_key, k_entry, bpe_cmp);
765fb1d1dcSdlg RBT_GENERATE(bpe_tree, bpe_key, k_entry, bpe_cmp);
775fb1d1dcSdlg
785fb1d1dcSdlg struct bpe_softc {
795fb1d1dcSdlg struct bpe_key sc_key; /* must be first */
805fb1d1dcSdlg struct arpcom sc_ac;
815fb1d1dcSdlg int sc_txhprio;
828400c33fSdlg int sc_rxhprio;
83ea0a6b3dSdlg struct ether_addr sc_group;
845fb1d1dcSdlg
854f5e51a4Sdlg struct task sc_ltask;
863fe9d1bdSdlg struct task sc_dtask;
875fb1d1dcSdlg
88ea0a6b3dSdlg struct etherbridge sc_eb;
895fb1d1dcSdlg };
905fb1d1dcSdlg
915fb1d1dcSdlg void bpeattach(int);
925fb1d1dcSdlg
935fb1d1dcSdlg static int bpe_clone_create(struct if_clone *, int);
945fb1d1dcSdlg static int bpe_clone_destroy(struct ifnet *);
955fb1d1dcSdlg
965fb1d1dcSdlg static void bpe_start(struct ifnet *);
975fb1d1dcSdlg static int bpe_ioctl(struct ifnet *, u_long, caddr_t);
985fb1d1dcSdlg static int bpe_media_get(struct bpe_softc *, struct ifreq *);
995fb1d1dcSdlg static int bpe_up(struct bpe_softc *);
1005fb1d1dcSdlg static int bpe_down(struct bpe_softc *);
1015fb1d1dcSdlg static int bpe_multi(struct bpe_softc *, struct ifnet *, u_long);
1025fb1d1dcSdlg static int bpe_set_vnetid(struct bpe_softc *, const struct ifreq *);
1035fb1d1dcSdlg static void bpe_set_group(struct bpe_softc *, uint32_t);
1045fb1d1dcSdlg static int bpe_set_parent(struct bpe_softc *, const struct if_parent *);
1055fb1d1dcSdlg static int bpe_get_parent(struct bpe_softc *, struct if_parent *);
1065fb1d1dcSdlg static int bpe_del_parent(struct bpe_softc *);
107f00572e7Sdlg static int bpe_add_addr(struct bpe_softc *, const struct ifbareq *);
108f00572e7Sdlg static int bpe_del_addr(struct bpe_softc *, const struct ifbareq *);
109f00572e7Sdlg
1105fb1d1dcSdlg static void bpe_link_hook(void *);
1115fb1d1dcSdlg static void bpe_link_state(struct bpe_softc *, u_char, uint64_t);
1125fb1d1dcSdlg static void bpe_detach_hook(void *);
1135fb1d1dcSdlg
1145fb1d1dcSdlg static struct if_clone bpe_cloner =
1155fb1d1dcSdlg IF_CLONE_INITIALIZER("bpe", bpe_clone_create, bpe_clone_destroy);
1165fb1d1dcSdlg
117ea0a6b3dSdlg static int bpe_eb_port_eq(void *, void *, void *);
118ea0a6b3dSdlg static void *bpe_eb_port_take(void *, void *);
119ea0a6b3dSdlg static void bpe_eb_port_rele(void *, void *);
120ea0a6b3dSdlg static size_t bpe_eb_port_ifname(void *, char *, size_t, void *);
121ea0a6b3dSdlg static void bpe_eb_port_sa(void *, struct sockaddr_storage *, void *);
122ea0a6b3dSdlg
123ea0a6b3dSdlg static const struct etherbridge_ops bpe_etherbridge_ops = {
124ea0a6b3dSdlg bpe_eb_port_eq,
125ea0a6b3dSdlg bpe_eb_port_take,
126ea0a6b3dSdlg bpe_eb_port_rele,
127ea0a6b3dSdlg bpe_eb_port_ifname,
128ea0a6b3dSdlg bpe_eb_port_sa,
129ea0a6b3dSdlg };
130ea0a6b3dSdlg
1315fb1d1dcSdlg static struct bpe_tree bpe_interfaces = RBT_INITIALIZER();
1325fb1d1dcSdlg static struct rwlock bpe_lock = RWLOCK_INITIALIZER("bpeifs");
133ea0a6b3dSdlg static struct pool bpe_endpoint_pool;
1345fb1d1dcSdlg
1355fb1d1dcSdlg void
bpeattach(int count)1365fb1d1dcSdlg bpeattach(int count)
1375fb1d1dcSdlg {
1385fb1d1dcSdlg if_clone_attach(&bpe_cloner);
1395fb1d1dcSdlg }
1405fb1d1dcSdlg
1415fb1d1dcSdlg static int
bpe_clone_create(struct if_clone * ifc,int unit)1425fb1d1dcSdlg bpe_clone_create(struct if_clone *ifc, int unit)
1435fb1d1dcSdlg {
1445fb1d1dcSdlg struct bpe_softc *sc;
1455fb1d1dcSdlg struct ifnet *ifp;
146ea0a6b3dSdlg int error;
1475fb1d1dcSdlg
148ea0a6b3dSdlg if (bpe_endpoint_pool.pr_size == 0) {
149ea0a6b3dSdlg pool_init(&bpe_endpoint_pool, sizeof(struct ether_addr), 0,
1505fb1d1dcSdlg IPL_NONE, 0, "bpepl", NULL);
1515fb1d1dcSdlg }
1525fb1d1dcSdlg
1535fb1d1dcSdlg sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
154ea0a6b3dSdlg
1555fb1d1dcSdlg ifp = &sc->sc_ac.ac_if;
1565fb1d1dcSdlg
1575fb1d1dcSdlg snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d",
1585fb1d1dcSdlg ifc->ifc_name, unit);
1595fb1d1dcSdlg
160ea0a6b3dSdlg error = etherbridge_init(&sc->sc_eb, ifp->if_xname,
161ea0a6b3dSdlg &bpe_etherbridge_ops, sc);
162ea0a6b3dSdlg if (error == -1) {
163ea0a6b3dSdlg free(sc, M_DEVBUF, sizeof(*sc));
164ea0a6b3dSdlg return (error);
165ea0a6b3dSdlg }
166ea0a6b3dSdlg
1675fb1d1dcSdlg sc->sc_key.k_if = 0;
1685fb1d1dcSdlg sc->sc_key.k_isid = 0;
1695fb1d1dcSdlg bpe_set_group(sc, 0);
1705fb1d1dcSdlg
1715fb1d1dcSdlg sc->sc_txhprio = IF_HDRPRIO_PACKET;
1726639c057Sdlg sc->sc_rxhprio = IF_HDRPRIO_OUTER;
1735fb1d1dcSdlg
1744f5e51a4Sdlg task_set(&sc->sc_ltask, bpe_link_hook, sc);
1753fe9d1bdSdlg task_set(&sc->sc_dtask, bpe_detach_hook, sc);
1763fe9d1bdSdlg
1775fb1d1dcSdlg ifp->if_softc = sc;
1785fb1d1dcSdlg ifp->if_hardmtu = ETHER_MAX_HARDMTU_LEN;
1795fb1d1dcSdlg ifp->if_ioctl = bpe_ioctl;
1805fb1d1dcSdlg ifp->if_start = bpe_start;
1815fb1d1dcSdlg ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST;
1825fb1d1dcSdlg ifp->if_xflags = IFXF_CLONED;
1835fb1d1dcSdlg ether_fakeaddr(ifp);
1845fb1d1dcSdlg
185*938ff1aeSbluhm if_counters_alloc(ifp);
1865fb1d1dcSdlg if_attach(ifp);
1875fb1d1dcSdlg ether_ifattach(ifp);
1885fb1d1dcSdlg
1895fb1d1dcSdlg return (0);
1905fb1d1dcSdlg }
1915fb1d1dcSdlg
1925fb1d1dcSdlg static int
bpe_clone_destroy(struct ifnet * ifp)1935fb1d1dcSdlg bpe_clone_destroy(struct ifnet *ifp)
1945fb1d1dcSdlg {
1955fb1d1dcSdlg struct bpe_softc *sc = ifp->if_softc;
1965fb1d1dcSdlg
1975fb1d1dcSdlg NET_LOCK();
1985fb1d1dcSdlg if (ISSET(ifp->if_flags, IFF_RUNNING))
1995fb1d1dcSdlg bpe_down(sc);
2005fb1d1dcSdlg NET_UNLOCK();
2015fb1d1dcSdlg
2025fb1d1dcSdlg ether_ifdetach(ifp);
2035fb1d1dcSdlg if_detach(ifp);
2045fb1d1dcSdlg
205ea0a6b3dSdlg etherbridge_destroy(&sc->sc_eb);
206ea0a6b3dSdlg
2075fb1d1dcSdlg free(sc, M_DEVBUF, sizeof(*sc));
2085fb1d1dcSdlg
2095fb1d1dcSdlg return (0);
2105fb1d1dcSdlg }
2115fb1d1dcSdlg
2125fb1d1dcSdlg static void
bpe_start(struct ifnet * ifp)2135fb1d1dcSdlg bpe_start(struct ifnet *ifp)
2145fb1d1dcSdlg {
2155fb1d1dcSdlg struct bpe_softc *sc = ifp->if_softc;
2165fb1d1dcSdlg struct ifnet *ifp0;
2175fb1d1dcSdlg struct mbuf *m0, *m;
2185fb1d1dcSdlg struct ether_header *ceh;
2195fb1d1dcSdlg struct ether_header *beh;
2205fb1d1dcSdlg uint32_t itag, *itagp;
2215fb1d1dcSdlg int hlen = sizeof(*beh) + sizeof(*itagp);
2225fb1d1dcSdlg #if NBPFILTER > 0
2235fb1d1dcSdlg caddr_t if_bpf;
2245fb1d1dcSdlg #endif
2255fb1d1dcSdlg int txprio;
2265fb1d1dcSdlg uint8_t prio;
2275fb1d1dcSdlg
2285fb1d1dcSdlg ifp0 = if_get(sc->sc_key.k_if);
2295fb1d1dcSdlg if (ifp0 == NULL || !ISSET(ifp0->if_flags, IFF_RUNNING)) {
2305fb1d1dcSdlg ifq_purge(&ifp->if_snd);
2315fb1d1dcSdlg goto done;
2325fb1d1dcSdlg }
2335fb1d1dcSdlg
2345fb1d1dcSdlg txprio = sc->sc_txhprio;
2355fb1d1dcSdlg
2365fb1d1dcSdlg while ((m0 = ifq_dequeue(&ifp->if_snd)) != NULL) {
2375fb1d1dcSdlg #if NBPFILTER > 0
2385fb1d1dcSdlg if_bpf = ifp->if_bpf;
2395fb1d1dcSdlg if (if_bpf)
2405fb1d1dcSdlg bpf_mtap_ether(if_bpf, m0, BPF_DIRECTION_OUT);
2415fb1d1dcSdlg #endif
2425fb1d1dcSdlg
2435fb1d1dcSdlg ceh = mtod(m0, struct ether_header *);
2445fb1d1dcSdlg
2455fb1d1dcSdlg /* force prepend of a whole mbuf because of alignment */
2465fb1d1dcSdlg m = m_get(M_DONTWAIT, m0->m_type);
2475fb1d1dcSdlg if (m == NULL) {
2485fb1d1dcSdlg m_freem(m0);
2495fb1d1dcSdlg continue;
2505fb1d1dcSdlg }
2515fb1d1dcSdlg
2525fb1d1dcSdlg M_MOVE_PKTHDR(m, m0);
2535fb1d1dcSdlg m->m_next = m0;
2545fb1d1dcSdlg
2555fb1d1dcSdlg m_align(m, 0);
2565fb1d1dcSdlg m->m_len = 0;
2575fb1d1dcSdlg
2585fb1d1dcSdlg m = m_prepend(m, hlen, M_DONTWAIT);
2595fb1d1dcSdlg if (m == NULL)
2605fb1d1dcSdlg continue;
2615fb1d1dcSdlg
2625fb1d1dcSdlg beh = mtod(m, struct ether_header *);
2635fb1d1dcSdlg
26478cd82e3Smpi if (ETHER_IS_BROADCAST(ceh->ether_dhost)) {
265ea0a6b3dSdlg memcpy(beh->ether_dhost, &sc->sc_group,
2665fb1d1dcSdlg sizeof(beh->ether_dhost));
2675fb1d1dcSdlg } else {
268ea0a6b3dSdlg struct ether_addr *endpoint;
2695fb1d1dcSdlg
270ea0a6b3dSdlg smr_read_enter();
2719703528fSdlg endpoint = etherbridge_resolve_ea(&sc->sc_eb,
272ea0a6b3dSdlg (struct ether_addr *)ceh->ether_dhost);
273ea0a6b3dSdlg if (endpoint == NULL) {
2745fb1d1dcSdlg /* "flood" to unknown hosts */
275ea0a6b3dSdlg endpoint = &sc->sc_group;
2765fb1d1dcSdlg }
277ea0a6b3dSdlg memcpy(beh->ether_dhost, endpoint,
278ea0a6b3dSdlg sizeof(beh->ether_dhost));
279ea0a6b3dSdlg smr_read_leave();
2805fb1d1dcSdlg }
2815fb1d1dcSdlg
2825fb1d1dcSdlg memcpy(beh->ether_shost, ((struct arpcom *)ifp0)->ac_enaddr,
2835fb1d1dcSdlg sizeof(beh->ether_shost));
2845fb1d1dcSdlg beh->ether_type = htons(ETHERTYPE_PBB);
2855fb1d1dcSdlg
2865fb1d1dcSdlg prio = (txprio == IF_HDRPRIO_PACKET) ?
2875fb1d1dcSdlg m->m_pkthdr.pf.prio : txprio;
2885fb1d1dcSdlg
2895fb1d1dcSdlg itag = sc->sc_key.k_isid;
2905fb1d1dcSdlg itag |= prio << PBB_ITAG_PCP_SHIFT;
2915fb1d1dcSdlg itagp = (uint32_t *)(beh + 1);
2925fb1d1dcSdlg
2935fb1d1dcSdlg htobem32(itagp, itag);
2945fb1d1dcSdlg
2955fb1d1dcSdlg if_enqueue(ifp0, m);
2965fb1d1dcSdlg }
2975fb1d1dcSdlg
2985fb1d1dcSdlg done:
2995fb1d1dcSdlg if_put(ifp0);
3005fb1d1dcSdlg }
3015fb1d1dcSdlg
3025fb1d1dcSdlg static int
bpe_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data)3035fb1d1dcSdlg bpe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
3045fb1d1dcSdlg {
3055fb1d1dcSdlg struct bpe_softc *sc = ifp->if_softc;
3065fb1d1dcSdlg struct ifreq *ifr = (struct ifreq *)data;
3075fb1d1dcSdlg struct ifbrparam *bparam = (struct ifbrparam *)data;
3085fb1d1dcSdlg int error = 0;
3095fb1d1dcSdlg
3105fb1d1dcSdlg switch (cmd) {
3115fb1d1dcSdlg case SIOCSIFFLAGS:
3125fb1d1dcSdlg if (ISSET(ifp->if_flags, IFF_UP)) {
3135fb1d1dcSdlg if (!ISSET(ifp->if_flags, IFF_RUNNING))
3145fb1d1dcSdlg error = bpe_up(sc);
3155fb1d1dcSdlg else
3165fb1d1dcSdlg error = 0;
3175fb1d1dcSdlg } else {
3185fb1d1dcSdlg if (ISSET(ifp->if_flags, IFF_RUNNING))
3195fb1d1dcSdlg error = bpe_down(sc);
3205fb1d1dcSdlg }
3215fb1d1dcSdlg break;
3225fb1d1dcSdlg
3235fb1d1dcSdlg case SIOCSVNETID:
3245fb1d1dcSdlg error = bpe_set_vnetid(sc, ifr);
3257e627389Sdlg break;
3265fb1d1dcSdlg case SIOCGVNETID:
3275fb1d1dcSdlg ifr->ifr_vnetid = sc->sc_key.k_isid;
3285fb1d1dcSdlg break;
3295fb1d1dcSdlg
3305fb1d1dcSdlg case SIOCSIFPARENT:
3315fb1d1dcSdlg error = bpe_set_parent(sc, (struct if_parent *)data);
3325fb1d1dcSdlg break;
3335fb1d1dcSdlg case SIOCGIFPARENT:
3345fb1d1dcSdlg error = bpe_get_parent(sc, (struct if_parent *)data);
3355fb1d1dcSdlg break;
3365fb1d1dcSdlg case SIOCDIFPARENT:
3375fb1d1dcSdlg error = bpe_del_parent(sc);
3385fb1d1dcSdlg break;
3395fb1d1dcSdlg
3405fb1d1dcSdlg case SIOCSTXHPRIO:
341b9e5cef3Sdlg error = if_txhprio_l2_check(ifr->ifr_hdrprio);
342b9e5cef3Sdlg if (error != 0)
3435fb1d1dcSdlg break;
3445fb1d1dcSdlg
3455fb1d1dcSdlg sc->sc_txhprio = ifr->ifr_hdrprio;
3465fb1d1dcSdlg break;
3475fb1d1dcSdlg case SIOCGTXHPRIO:
3485fb1d1dcSdlg ifr->ifr_hdrprio = sc->sc_txhprio;
3495fb1d1dcSdlg break;
3505fb1d1dcSdlg
3518400c33fSdlg case SIOCSRXHPRIO:
352b9e5cef3Sdlg error = if_rxhprio_l2_check(ifr->ifr_hdrprio);
353b9e5cef3Sdlg if (error != 0)
3548400c33fSdlg break;
3558400c33fSdlg
3568400c33fSdlg sc->sc_rxhprio = ifr->ifr_hdrprio;
3578400c33fSdlg break;
3588400c33fSdlg case SIOCGRXHPRIO:
3598400c33fSdlg ifr->ifr_hdrprio = sc->sc_rxhprio;
3608400c33fSdlg break;
3618400c33fSdlg
3625fb1d1dcSdlg case SIOCGIFMEDIA:
3635fb1d1dcSdlg error = bpe_media_get(sc, ifr);
3645fb1d1dcSdlg break;
3655fb1d1dcSdlg
3665fb1d1dcSdlg case SIOCBRDGSCACHE:
3675fb1d1dcSdlg error = suser(curproc);
3685fb1d1dcSdlg if (error != 0)
3695fb1d1dcSdlg break;
3705fb1d1dcSdlg
371ea0a6b3dSdlg error = etherbridge_set_max(&sc->sc_eb, bparam);
3725fb1d1dcSdlg break;
3735fb1d1dcSdlg case SIOCBRDGGCACHE:
374ea0a6b3dSdlg error = etherbridge_get_max(&sc->sc_eb, bparam);
3755fb1d1dcSdlg break;
3765fb1d1dcSdlg
3775fb1d1dcSdlg case SIOCBRDGSTO:
3785fb1d1dcSdlg error = suser(curproc);
3795fb1d1dcSdlg if (error != 0)
3805fb1d1dcSdlg break;
3815fb1d1dcSdlg
382ea0a6b3dSdlg error = etherbridge_set_tmo(&sc->sc_eb, bparam);
3835fb1d1dcSdlg break;
3845fb1d1dcSdlg case SIOCBRDGGTO:
385ea0a6b3dSdlg error = etherbridge_get_tmo(&sc->sc_eb, bparam);
3865fb1d1dcSdlg break;
3875fb1d1dcSdlg
3885fb1d1dcSdlg case SIOCBRDGRTS:
389ea0a6b3dSdlg error = etherbridge_rtfind(&sc->sc_eb,
390ea0a6b3dSdlg (struct ifbaconf *)data);
3915fb1d1dcSdlg break;
3925fb1d1dcSdlg case SIOCBRDGFLUSH:
3935fb1d1dcSdlg error = suser(curproc);
3945fb1d1dcSdlg if (error != 0)
3955fb1d1dcSdlg break;
3965fb1d1dcSdlg
397ea0a6b3dSdlg etherbridge_flush(&sc->sc_eb,
3985fb1d1dcSdlg ((struct ifbreq *)data)->ifbr_ifsflags);
3995fb1d1dcSdlg break;
400f00572e7Sdlg case SIOCBRDGSADDR:
401f00572e7Sdlg error = bpe_add_addr(sc, (struct ifbareq *)data);
402f00572e7Sdlg break;
403f00572e7Sdlg case SIOCBRDGDADDR:
404f00572e7Sdlg error = bpe_del_addr(sc, (struct ifbareq *)data);
405f00572e7Sdlg break;
4065fb1d1dcSdlg
4075fb1d1dcSdlg default:
4085fb1d1dcSdlg error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
4095fb1d1dcSdlg break;
4105fb1d1dcSdlg }
4115fb1d1dcSdlg
4125fb1d1dcSdlg return (error);
4135fb1d1dcSdlg }
4145fb1d1dcSdlg
4155fb1d1dcSdlg static int
bpe_media_get(struct bpe_softc * sc,struct ifreq * ifr)4165fb1d1dcSdlg bpe_media_get(struct bpe_softc *sc, struct ifreq *ifr)
4175fb1d1dcSdlg {
4185fb1d1dcSdlg struct ifnet *ifp0;
4195fb1d1dcSdlg int error;
4205fb1d1dcSdlg
4215fb1d1dcSdlg ifp0 = if_get(sc->sc_key.k_if);
4225fb1d1dcSdlg if (ifp0 != NULL)
4235fb1d1dcSdlg error = (*ifp0->if_ioctl)(ifp0, SIOCGIFMEDIA, (caddr_t)ifr);
4245fb1d1dcSdlg else
4255fb1d1dcSdlg error = ENOTTY;
4265fb1d1dcSdlg if_put(ifp0);
4275fb1d1dcSdlg
4285fb1d1dcSdlg return (error);
4295fb1d1dcSdlg }
4305fb1d1dcSdlg
4315fb1d1dcSdlg static int
bpe_up(struct bpe_softc * sc)4325fb1d1dcSdlg bpe_up(struct bpe_softc *sc)
4335fb1d1dcSdlg {
4345fb1d1dcSdlg struct ifnet *ifp = &sc->sc_ac.ac_if;
4355fb1d1dcSdlg struct ifnet *ifp0;
4365fb1d1dcSdlg struct bpe_softc *osc;
437ea0a6b3dSdlg int error;
4385fb1d1dcSdlg u_int hardmtu;
4395fb1d1dcSdlg u_int hlen = sizeof(struct ether_header) + sizeof(uint32_t);
4405fb1d1dcSdlg
4415fb1d1dcSdlg KASSERT(!ISSET(ifp->if_flags, IFF_RUNNING));
4425fb1d1dcSdlg NET_ASSERT_LOCKED();
4435fb1d1dcSdlg
444ea0a6b3dSdlg error = etherbridge_up(&sc->sc_eb);
445ea0a6b3dSdlg if (error != 0)
446ea0a6b3dSdlg return (error);
447ea0a6b3dSdlg
4485fb1d1dcSdlg ifp0 = if_get(sc->sc_key.k_if);
449ea0a6b3dSdlg if (ifp0 == NULL) {
450ea0a6b3dSdlg error = ENXIO;
451ea0a6b3dSdlg goto down;
452ea0a6b3dSdlg }
4535fb1d1dcSdlg
4545fb1d1dcSdlg /* check again if bpe will work on top of the parent */
4555fb1d1dcSdlg if (ifp0->if_type != IFT_ETHER) {
4565fb1d1dcSdlg error = EPROTONOSUPPORT;
4575fb1d1dcSdlg goto put;
4585fb1d1dcSdlg }
4595fb1d1dcSdlg
4605fb1d1dcSdlg hardmtu = ifp0->if_hardmtu;
4615fb1d1dcSdlg if (hardmtu < hlen) {
4625fb1d1dcSdlg error = ENOBUFS;
4635fb1d1dcSdlg goto put;
4645fb1d1dcSdlg }
4655fb1d1dcSdlg hardmtu -= hlen;
4665fb1d1dcSdlg if (ifp->if_mtu > hardmtu) {
4675fb1d1dcSdlg error = ENOBUFS;
4685fb1d1dcSdlg goto put;
4695fb1d1dcSdlg }
4705fb1d1dcSdlg
4715fb1d1dcSdlg /* parent is fine, let's prepare the bpe to handle packets */
4725fb1d1dcSdlg ifp->if_hardmtu = hardmtu;
4735fb1d1dcSdlg SET(ifp->if_flags, ifp0->if_flags & IFF_SIMPLEX);
4745fb1d1dcSdlg
4755fb1d1dcSdlg /* commit the interface */
4765fb1d1dcSdlg error = rw_enter(&bpe_lock, RW_WRITE | RW_INTR);
4775fb1d1dcSdlg if (error != 0)
4785fb1d1dcSdlg goto scrub;
4795fb1d1dcSdlg
4805fb1d1dcSdlg osc = (struct bpe_softc *)RBT_INSERT(bpe_tree, &bpe_interfaces,
4815fb1d1dcSdlg (struct bpe_key *)sc);
4825fb1d1dcSdlg rw_exit(&bpe_lock);
4835fb1d1dcSdlg
4845fb1d1dcSdlg if (osc != NULL) {
4855fb1d1dcSdlg error = EADDRINUSE;
4865fb1d1dcSdlg goto scrub;
4875fb1d1dcSdlg }
4885fb1d1dcSdlg
4895fb1d1dcSdlg if (bpe_multi(sc, ifp0, SIOCADDMULTI) != 0) {
4905fb1d1dcSdlg error = ENOTCONN;
4915fb1d1dcSdlg goto remove;
4925fb1d1dcSdlg }
4935fb1d1dcSdlg
4945fb1d1dcSdlg /* Register callback for physical link state changes */
4954f5e51a4Sdlg if_linkstatehook_add(ifp0, &sc->sc_ltask);
4965fb1d1dcSdlg
4975fb1d1dcSdlg /* Register callback if parent wants to unregister */
4983fe9d1bdSdlg if_detachhook_add(ifp0, &sc->sc_dtask);
4995fb1d1dcSdlg
5005fb1d1dcSdlg /* we're running now */
5015fb1d1dcSdlg SET(ifp->if_flags, IFF_RUNNING);
5025fb1d1dcSdlg bpe_link_state(sc, ifp0->if_link_state, ifp0->if_baudrate);
5035fb1d1dcSdlg
5045fb1d1dcSdlg if_put(ifp0);
5055fb1d1dcSdlg
5065fb1d1dcSdlg return (0);
5075fb1d1dcSdlg
5085fb1d1dcSdlg remove:
5095fb1d1dcSdlg rw_enter(&bpe_lock, RW_WRITE);
5105fb1d1dcSdlg RBT_REMOVE(bpe_tree, &bpe_interfaces, (struct bpe_key *)sc);
5115fb1d1dcSdlg rw_exit(&bpe_lock);
5125fb1d1dcSdlg scrub:
5135fb1d1dcSdlg CLR(ifp->if_flags, IFF_SIMPLEX);
5145fb1d1dcSdlg ifp->if_hardmtu = 0xffff;
5155fb1d1dcSdlg put:
5165fb1d1dcSdlg if_put(ifp0);
517ea0a6b3dSdlg down:
518ea0a6b3dSdlg etherbridge_down(&sc->sc_eb);
5195fb1d1dcSdlg
5205fb1d1dcSdlg return (error);
5215fb1d1dcSdlg }
5225fb1d1dcSdlg
5235fb1d1dcSdlg static int
bpe_down(struct bpe_softc * sc)5245fb1d1dcSdlg bpe_down(struct bpe_softc *sc)
5255fb1d1dcSdlg {
5265fb1d1dcSdlg struct ifnet *ifp = &sc->sc_ac.ac_if;
5275fb1d1dcSdlg struct ifnet *ifp0;
5285fb1d1dcSdlg
5295fb1d1dcSdlg NET_ASSERT_LOCKED();
5305fb1d1dcSdlg
5315fb1d1dcSdlg CLR(ifp->if_flags, IFF_RUNNING);
5325fb1d1dcSdlg
5335fb1d1dcSdlg ifp0 = if_get(sc->sc_key.k_if);
5345fb1d1dcSdlg if (ifp0 != NULL) {
5353fe9d1bdSdlg if_detachhook_del(ifp0, &sc->sc_dtask);
5364f5e51a4Sdlg if_linkstatehook_del(ifp0, &sc->sc_ltask);
5375fb1d1dcSdlg bpe_multi(sc, ifp0, SIOCDELMULTI);
5385fb1d1dcSdlg }
5395fb1d1dcSdlg if_put(ifp0);
5405fb1d1dcSdlg
5415fb1d1dcSdlg rw_enter(&bpe_lock, RW_WRITE);
5425fb1d1dcSdlg RBT_REMOVE(bpe_tree, &bpe_interfaces, (struct bpe_key *)sc);
5435fb1d1dcSdlg rw_exit(&bpe_lock);
5445fb1d1dcSdlg
5455fb1d1dcSdlg CLR(ifp->if_flags, IFF_SIMPLEX);
5465fb1d1dcSdlg ifp->if_hardmtu = 0xffff;
5475fb1d1dcSdlg
548ea0a6b3dSdlg etherbridge_down(&sc->sc_eb);
549ea0a6b3dSdlg
5505fb1d1dcSdlg return (0);
5515fb1d1dcSdlg }
5525fb1d1dcSdlg
5535fb1d1dcSdlg static int
bpe_multi(struct bpe_softc * sc,struct ifnet * ifp0,u_long cmd)5545fb1d1dcSdlg bpe_multi(struct bpe_softc *sc, struct ifnet *ifp0, u_long cmd)
5555fb1d1dcSdlg {
5565fb1d1dcSdlg struct ifreq ifr;
5575fb1d1dcSdlg struct sockaddr *sa;
5585fb1d1dcSdlg
5595fb1d1dcSdlg /* make it convincing */
5605fb1d1dcSdlg CTASSERT(sizeof(ifr.ifr_name) == sizeof(ifp0->if_xname));
5615fb1d1dcSdlg memcpy(ifr.ifr_name, ifp0->if_xname, sizeof(ifr.ifr_name));
5625fb1d1dcSdlg
5635fb1d1dcSdlg sa = &ifr.ifr_addr;
5645fb1d1dcSdlg CTASSERT(sizeof(sa->sa_data) >= sizeof(sc->sc_group));
5655fb1d1dcSdlg
5665fb1d1dcSdlg sa->sa_family = AF_UNSPEC;
567ea0a6b3dSdlg memcpy(sa->sa_data, &sc->sc_group, sizeof(sc->sc_group));
5685fb1d1dcSdlg
5695fb1d1dcSdlg return ((*ifp0->if_ioctl)(ifp0, cmd, (caddr_t)&ifr));
5705fb1d1dcSdlg }
5715fb1d1dcSdlg
5725fb1d1dcSdlg static void
bpe_set_group(struct bpe_softc * sc,uint32_t isid)5735fb1d1dcSdlg bpe_set_group(struct bpe_softc *sc, uint32_t isid)
5745fb1d1dcSdlg {
575ea0a6b3dSdlg uint8_t *group = sc->sc_group.ether_addr_octet;
5765fb1d1dcSdlg
5775fb1d1dcSdlg group[0] = 0x01;
5785fb1d1dcSdlg group[1] = 0x1e;
5795fb1d1dcSdlg group[2] = 0x83;
5805fb1d1dcSdlg group[3] = isid >> 16;
5815fb1d1dcSdlg group[4] = isid >> 8;
5825fb1d1dcSdlg group[5] = isid >> 0;
5835fb1d1dcSdlg }
5845fb1d1dcSdlg
5855fb1d1dcSdlg static int
bpe_set_vnetid(struct bpe_softc * sc,const struct ifreq * ifr)5865fb1d1dcSdlg bpe_set_vnetid(struct bpe_softc *sc, const struct ifreq *ifr)
5875fb1d1dcSdlg {
5885fb1d1dcSdlg struct ifnet *ifp = &sc->sc_ac.ac_if;
5895fb1d1dcSdlg uint32_t isid;
5905fb1d1dcSdlg
5915fb1d1dcSdlg if (ifr->ifr_vnetid < PBB_ITAG_ISID_MIN ||
5925fb1d1dcSdlg ifr->ifr_vnetid > PBB_ITAG_ISID_MAX)
5935fb1d1dcSdlg return (EINVAL);
5945fb1d1dcSdlg
5955fb1d1dcSdlg isid = ifr->ifr_vnetid;
5965fb1d1dcSdlg if (isid == sc->sc_key.k_isid)
5975fb1d1dcSdlg return (0);
5985fb1d1dcSdlg
5995fb1d1dcSdlg if (ISSET(ifp->if_flags, IFF_RUNNING))
6005fb1d1dcSdlg return (EBUSY);
6015fb1d1dcSdlg
6025fb1d1dcSdlg /* commit */
6035fb1d1dcSdlg sc->sc_key.k_isid = isid;
6045fb1d1dcSdlg bpe_set_group(sc, isid);
605ea0a6b3dSdlg etherbridge_flush(&sc->sc_eb, IFBF_FLUSHALL);
6065fb1d1dcSdlg
6075fb1d1dcSdlg return (0);
6085fb1d1dcSdlg }
6095fb1d1dcSdlg
6105fb1d1dcSdlg static int
bpe_set_parent(struct bpe_softc * sc,const struct if_parent * p)6115fb1d1dcSdlg bpe_set_parent(struct bpe_softc *sc, const struct if_parent *p)
6125fb1d1dcSdlg {
6135fb1d1dcSdlg struct ifnet *ifp = &sc->sc_ac.ac_if;
6145fb1d1dcSdlg struct ifnet *ifp0;
615f9e2b984Smvs int error = 0;
6165fb1d1dcSdlg
617f9e2b984Smvs ifp0 = if_unit(p->ifp_parent);
6185fb1d1dcSdlg if (ifp0 == NULL)
6195fb1d1dcSdlg return (ENXIO);
6205fb1d1dcSdlg
621f9e2b984Smvs if (ifp0->if_type != IFT_ETHER) {
622f9e2b984Smvs error = ENXIO;
623f9e2b984Smvs goto put;
624f9e2b984Smvs }
6255fb1d1dcSdlg
6265fb1d1dcSdlg if (ifp0->if_index == sc->sc_key.k_if)
627f9e2b984Smvs goto put;
6285fb1d1dcSdlg
629f9e2b984Smvs if (ISSET(ifp->if_flags, IFF_RUNNING)) {
630f9e2b984Smvs error = EBUSY;
631f9e2b984Smvs goto put;
632f9e2b984Smvs }
6335fb1d1dcSdlg
634bb2d1618Sjan ifsetlro(ifp0, 0);
635bb2d1618Sjan
6365fb1d1dcSdlg /* commit */
6375fb1d1dcSdlg sc->sc_key.k_if = ifp0->if_index;
638ea0a6b3dSdlg etherbridge_flush(&sc->sc_eb, IFBF_FLUSHALL);
6395fb1d1dcSdlg
640f9e2b984Smvs put:
641f9e2b984Smvs if_put(ifp0);
642f9e2b984Smvs return (error);
6435fb1d1dcSdlg }
6445fb1d1dcSdlg
6455fb1d1dcSdlg static int
bpe_get_parent(struct bpe_softc * sc,struct if_parent * p)6465fb1d1dcSdlg bpe_get_parent(struct bpe_softc *sc, struct if_parent *p)
6475fb1d1dcSdlg {
6485fb1d1dcSdlg struct ifnet *ifp0;
6495fb1d1dcSdlg int error = 0;
6505fb1d1dcSdlg
6515fb1d1dcSdlg ifp0 = if_get(sc->sc_key.k_if);
6525fb1d1dcSdlg if (ifp0 == NULL)
6535fb1d1dcSdlg error = EADDRNOTAVAIL;
6545fb1d1dcSdlg else
6555fb1d1dcSdlg memcpy(p->ifp_parent, ifp0->if_xname, sizeof(p->ifp_parent));
6565fb1d1dcSdlg if_put(ifp0);
6575fb1d1dcSdlg
6585fb1d1dcSdlg return (error);
6595fb1d1dcSdlg }
6605fb1d1dcSdlg
6615fb1d1dcSdlg static int
bpe_del_parent(struct bpe_softc * sc)6625fb1d1dcSdlg bpe_del_parent(struct bpe_softc *sc)
6635fb1d1dcSdlg {
6645fb1d1dcSdlg struct ifnet *ifp = &sc->sc_ac.ac_if;
6655fb1d1dcSdlg
6665fb1d1dcSdlg if (ISSET(ifp->if_flags, IFF_RUNNING))
6675fb1d1dcSdlg return (EBUSY);
6685fb1d1dcSdlg
6695fb1d1dcSdlg /* commit */
6705fb1d1dcSdlg sc->sc_key.k_if = 0;
671ea0a6b3dSdlg etherbridge_flush(&sc->sc_eb, IFBF_FLUSHALL);
6725fb1d1dcSdlg
6735fb1d1dcSdlg return (0);
6745fb1d1dcSdlg }
6755fb1d1dcSdlg
676f00572e7Sdlg static int
bpe_add_addr(struct bpe_softc * sc,const struct ifbareq * ifba)677f00572e7Sdlg bpe_add_addr(struct bpe_softc *sc, const struct ifbareq *ifba)
678f00572e7Sdlg {
679f00572e7Sdlg const struct sockaddr_dl *sdl;
680f00572e7Sdlg const struct ether_addr *endpoint;
681f00572e7Sdlg unsigned int type;
682f00572e7Sdlg
683f00572e7Sdlg /* ignore ifba_ifsname */
684f00572e7Sdlg
685f00572e7Sdlg if (ISSET(ifba->ifba_flags, ~IFBAF_TYPEMASK))
686f00572e7Sdlg return (EINVAL);
687f00572e7Sdlg switch (ifba->ifba_flags & IFBAF_TYPEMASK) {
688f00572e7Sdlg case IFBAF_DYNAMIC:
689f00572e7Sdlg type = EBE_DYNAMIC;
690f00572e7Sdlg break;
691f00572e7Sdlg case IFBAF_STATIC:
692f00572e7Sdlg type = EBE_STATIC;
693f00572e7Sdlg break;
694f00572e7Sdlg default:
695f00572e7Sdlg return (EINVAL);
696f00572e7Sdlg }
697f00572e7Sdlg
698f00572e7Sdlg if (ifba->ifba_dstsa.ss_family != AF_LINK)
699f00572e7Sdlg return (EAFNOSUPPORT);
700f00572e7Sdlg sdl = (struct sockaddr_dl *)&ifba->ifba_dstsa;
701f00572e7Sdlg if (sdl->sdl_type != IFT_ETHER)
702f00572e7Sdlg return (EAFNOSUPPORT);
703f00572e7Sdlg if (sdl->sdl_alen != ETHER_ADDR_LEN)
704f00572e7Sdlg return (EINVAL);
705f00572e7Sdlg endpoint = (struct ether_addr *)LLADDR(sdl);
706f00572e7Sdlg /* check endpoint for multicast or broadcast? */
707f00572e7Sdlg
708f00572e7Sdlg return (etherbridge_add_addr(&sc->sc_eb, (void *)endpoint,
709f00572e7Sdlg &ifba->ifba_dst, type));
710f00572e7Sdlg }
711f00572e7Sdlg
712f00572e7Sdlg static int
bpe_del_addr(struct bpe_softc * sc,const struct ifbareq * ifba)713f00572e7Sdlg bpe_del_addr(struct bpe_softc *sc, const struct ifbareq *ifba)
714f00572e7Sdlg {
715f00572e7Sdlg return (etherbridge_del_addr(&sc->sc_eb, &ifba->ifba_dst));
716f00572e7Sdlg }
717f00572e7Sdlg
7185fb1d1dcSdlg static inline struct bpe_softc *
bpe_find(struct ifnet * ifp0,uint32_t isid)7195fb1d1dcSdlg bpe_find(struct ifnet *ifp0, uint32_t isid)
7205fb1d1dcSdlg {
7215fb1d1dcSdlg struct bpe_key k = { .k_if = ifp0->if_index, .k_isid = isid };
7225fb1d1dcSdlg struct bpe_softc *sc;
7235fb1d1dcSdlg
7245fb1d1dcSdlg rw_enter_read(&bpe_lock);
7255fb1d1dcSdlg sc = (struct bpe_softc *)RBT_FIND(bpe_tree, &bpe_interfaces, &k);
7265fb1d1dcSdlg rw_exit_read(&bpe_lock);
7275fb1d1dcSdlg
7285fb1d1dcSdlg return (sc);
7295fb1d1dcSdlg }
7305fb1d1dcSdlg
7315fb1d1dcSdlg void
bpe_input(struct ifnet * ifp0,struct mbuf * m)7325fb1d1dcSdlg bpe_input(struct ifnet *ifp0, struct mbuf *m)
7335fb1d1dcSdlg {
7345fb1d1dcSdlg struct bpe_softc *sc;
7355fb1d1dcSdlg struct ifnet *ifp;
7365fb1d1dcSdlg struct ether_header *beh, *ceh;
7375fb1d1dcSdlg uint32_t *itagp, itag;
7385fb1d1dcSdlg unsigned int hlen = sizeof(*beh) + sizeof(*itagp) + sizeof(*ceh);
7395fb1d1dcSdlg struct mbuf *n;
7405fb1d1dcSdlg int off;
7418400c33fSdlg int prio;
7425fb1d1dcSdlg
7435fb1d1dcSdlg if (m->m_len < hlen) {
7445fb1d1dcSdlg m = m_pullup(m, hlen);
7455fb1d1dcSdlg if (m == NULL) {
7465fb1d1dcSdlg /* pbb short ++ */
7475fb1d1dcSdlg return;
7485fb1d1dcSdlg }
7495fb1d1dcSdlg }
7505fb1d1dcSdlg
7515fb1d1dcSdlg beh = mtod(m, struct ether_header *);
7525fb1d1dcSdlg itagp = (uint32_t *)(beh + 1);
7535fb1d1dcSdlg itag = bemtoh32(itagp);
7545fb1d1dcSdlg
7555fb1d1dcSdlg if (itag & PBB_ITAG_RES2) {
7565fb1d1dcSdlg /* dropped by res2 ++ */
7575fb1d1dcSdlg goto drop;
7585fb1d1dcSdlg }
7595fb1d1dcSdlg
7605fb1d1dcSdlg sc = bpe_find(ifp0, itag & PBB_ITAG_ISID);
7615fb1d1dcSdlg if (sc == NULL) {
7625fb1d1dcSdlg /* no interface found */
7635fb1d1dcSdlg goto drop;
7645fb1d1dcSdlg }
7655fb1d1dcSdlg
7665fb1d1dcSdlg ceh = (struct ether_header *)(itagp + 1);
7675fb1d1dcSdlg
7689703528fSdlg etherbridge_map_ea(&sc->sc_eb, ceh->ether_shost,
769ea0a6b3dSdlg (struct ether_addr *)beh->ether_shost);
7705fb1d1dcSdlg
7715fb1d1dcSdlg m_adj(m, sizeof(*beh) + sizeof(*itagp));
7725fb1d1dcSdlg
7735fb1d1dcSdlg n = m_getptr(m, sizeof(*ceh), &off);
7745fb1d1dcSdlg if (n == NULL) {
7755fb1d1dcSdlg /* no data ++ */
7765fb1d1dcSdlg goto drop;
7775fb1d1dcSdlg }
7785fb1d1dcSdlg
7795fb1d1dcSdlg if (!ALIGNED_POINTER(mtod(n, caddr_t) + off, uint32_t)) {
7805fb1d1dcSdlg /* unaligned ++ */
7815fb1d1dcSdlg n = m_dup_pkt(m, ETHER_ALIGN, M_NOWAIT);
7825fb1d1dcSdlg m_freem(m);
7835fb1d1dcSdlg if (n == NULL)
7845fb1d1dcSdlg return;
7855fb1d1dcSdlg
7865fb1d1dcSdlg m = n;
7875fb1d1dcSdlg }
7885fb1d1dcSdlg
7895fb1d1dcSdlg ifp = &sc->sc_ac.ac_if;
7905fb1d1dcSdlg
7918400c33fSdlg prio = sc->sc_rxhprio;
7928400c33fSdlg switch (prio) {
7938400c33fSdlg case IF_HDRPRIO_PACKET:
7948400c33fSdlg break;
7958400c33fSdlg case IF_HDRPRIO_OUTER:
7968400c33fSdlg m->m_pkthdr.pf.prio = (itag & PBB_ITAG_PCP_MASK) >>
7978400c33fSdlg PBB_ITAG_PCP_SHIFT;
7988400c33fSdlg break;
7998400c33fSdlg default:
8008400c33fSdlg m->m_pkthdr.pf.prio = prio;
8018400c33fSdlg break;
8028400c33fSdlg }
8038400c33fSdlg
8045fb1d1dcSdlg m->m_flags &= ~(M_BCAST|M_MCAST);
8055fb1d1dcSdlg m->m_pkthdr.ph_ifidx = ifp->if_index;
8065fb1d1dcSdlg m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
8075fb1d1dcSdlg
8085fb1d1dcSdlg #if NPF > 0
8095fb1d1dcSdlg pf_pkt_addr_changed(m);
8105fb1d1dcSdlg #endif
8115fb1d1dcSdlg
81226415d92Sdlg if_vinput(ifp, m);
8135fb1d1dcSdlg return;
8145fb1d1dcSdlg
8155fb1d1dcSdlg drop:
8165fb1d1dcSdlg m_freem(m);
8175fb1d1dcSdlg }
8185fb1d1dcSdlg
8195fb1d1dcSdlg void
bpe_detach_hook(void * arg)8205fb1d1dcSdlg bpe_detach_hook(void *arg)
8215fb1d1dcSdlg {
8225fb1d1dcSdlg struct bpe_softc *sc = arg;
8235fb1d1dcSdlg struct ifnet *ifp = &sc->sc_ac.ac_if;
8245fb1d1dcSdlg
8255fb1d1dcSdlg if (ISSET(ifp->if_flags, IFF_RUNNING)) {
8265fb1d1dcSdlg bpe_down(sc);
8275fb1d1dcSdlg CLR(ifp->if_flags, IFF_UP);
8285fb1d1dcSdlg }
8295fb1d1dcSdlg
8305fb1d1dcSdlg sc->sc_key.k_if = 0;
8315fb1d1dcSdlg }
8325fb1d1dcSdlg
8335fb1d1dcSdlg static void
bpe_link_hook(void * arg)8345fb1d1dcSdlg bpe_link_hook(void *arg)
8355fb1d1dcSdlg {
8365fb1d1dcSdlg struct bpe_softc *sc = arg;
8375fb1d1dcSdlg struct ifnet *ifp0;
8385fb1d1dcSdlg u_char link = LINK_STATE_DOWN;
8395fb1d1dcSdlg uint64_t baud = 0;
8405fb1d1dcSdlg
8415fb1d1dcSdlg ifp0 = if_get(sc->sc_key.k_if);
8425fb1d1dcSdlg if (ifp0 != NULL) {
8435fb1d1dcSdlg link = ifp0->if_link_state;
8445fb1d1dcSdlg baud = ifp0->if_baudrate;
8455fb1d1dcSdlg }
8465fb1d1dcSdlg if_put(ifp0);
8475fb1d1dcSdlg
8485fb1d1dcSdlg bpe_link_state(sc, link, baud);
8495fb1d1dcSdlg }
8505fb1d1dcSdlg
8515fb1d1dcSdlg void
bpe_link_state(struct bpe_softc * sc,u_char link,uint64_t baud)8525fb1d1dcSdlg bpe_link_state(struct bpe_softc *sc, u_char link, uint64_t baud)
8535fb1d1dcSdlg {
8545fb1d1dcSdlg struct ifnet *ifp = &sc->sc_ac.ac_if;
8555fb1d1dcSdlg
8565fb1d1dcSdlg if (ifp->if_link_state == link)
8575fb1d1dcSdlg return;
8585fb1d1dcSdlg
8595fb1d1dcSdlg ifp->if_link_state = link;
8605fb1d1dcSdlg ifp->if_baudrate = baud;
8615fb1d1dcSdlg
8625fb1d1dcSdlg if_link_state_change(ifp);
8635fb1d1dcSdlg }
8645fb1d1dcSdlg
8655fb1d1dcSdlg static inline int
bpe_cmp(const struct bpe_key * a,const struct bpe_key * b)8665fb1d1dcSdlg bpe_cmp(const struct bpe_key *a, const struct bpe_key *b)
8675fb1d1dcSdlg {
8685fb1d1dcSdlg if (a->k_if > b->k_if)
8695fb1d1dcSdlg return (1);
8705fb1d1dcSdlg if (a->k_if < b->k_if)
8715fb1d1dcSdlg return (-1);
8725fb1d1dcSdlg if (a->k_isid > b->k_isid)
8735fb1d1dcSdlg return (1);
8745fb1d1dcSdlg if (a->k_isid < b->k_isid)
8755fb1d1dcSdlg return (-1);
8765fb1d1dcSdlg
8775fb1d1dcSdlg return (0);
8785fb1d1dcSdlg }
8795fb1d1dcSdlg
880ea0a6b3dSdlg static int
bpe_eb_port_eq(void * arg,void * a,void * b)881ea0a6b3dSdlg bpe_eb_port_eq(void *arg, void *a, void *b)
8825fb1d1dcSdlg {
883ea0a6b3dSdlg struct ether_addr *ea = a, *eb = b;
884ea0a6b3dSdlg
885ea0a6b3dSdlg return (memcmp(ea, eb, sizeof(*ea)) == 0);
886ea0a6b3dSdlg }
887ea0a6b3dSdlg
888ea0a6b3dSdlg static void *
bpe_eb_port_take(void * arg,void * port)889ea0a6b3dSdlg bpe_eb_port_take(void *arg, void *port)
890ea0a6b3dSdlg {
891ea0a6b3dSdlg struct ether_addr *ea = port;
892ea0a6b3dSdlg struct ether_addr *endpoint;
893ea0a6b3dSdlg
894ea0a6b3dSdlg endpoint = pool_get(&bpe_endpoint_pool, PR_NOWAIT);
895ea0a6b3dSdlg if (endpoint == NULL)
896ea0a6b3dSdlg return (NULL);
897ea0a6b3dSdlg
898ea0a6b3dSdlg memcpy(endpoint, ea, sizeof(*endpoint));
899ea0a6b3dSdlg
900ea0a6b3dSdlg return (endpoint);
901ea0a6b3dSdlg }
902ea0a6b3dSdlg
903ea0a6b3dSdlg static void
bpe_eb_port_rele(void * arg,void * port)904ea0a6b3dSdlg bpe_eb_port_rele(void *arg, void *port)
905ea0a6b3dSdlg {
906ea0a6b3dSdlg struct ether_addr *endpoint = port;
907ea0a6b3dSdlg
908ea0a6b3dSdlg pool_put(&bpe_endpoint_pool, endpoint);
909ea0a6b3dSdlg }
910ea0a6b3dSdlg
911ea0a6b3dSdlg static size_t
bpe_eb_port_ifname(void * arg,char * dst,size_t len,void * port)912ea0a6b3dSdlg bpe_eb_port_ifname(void *arg, char *dst, size_t len, void *port)
913ea0a6b3dSdlg {
914ea0a6b3dSdlg struct bpe_softc *sc = arg;
915ea0a6b3dSdlg
916ea0a6b3dSdlg return (strlcpy(dst, sc->sc_ac.ac_if.if_xname, len));
917ea0a6b3dSdlg }
918ea0a6b3dSdlg
919ea0a6b3dSdlg static void
bpe_eb_port_sa(void * arg,struct sockaddr_storage * ss,void * port)920ea0a6b3dSdlg bpe_eb_port_sa(void *arg, struct sockaddr_storage *ss, void *port)
921ea0a6b3dSdlg {
922ea0a6b3dSdlg struct ether_addr *endpoint = port;
923ea0a6b3dSdlg struct sockaddr_dl *sdl;
924ea0a6b3dSdlg
925ea0a6b3dSdlg sdl = (struct sockaddr_dl *)ss;
926ea0a6b3dSdlg sdl->sdl_len = sizeof(sdl);
927ea0a6b3dSdlg sdl->sdl_family = AF_LINK;
928ea0a6b3dSdlg sdl->sdl_index = 0;
929ea0a6b3dSdlg sdl->sdl_type = IFT_ETHER;
930ea0a6b3dSdlg sdl->sdl_nlen = 0;
931ea0a6b3dSdlg sdl->sdl_alen = sizeof(*endpoint);
932ea0a6b3dSdlg CTASSERT(sizeof(sdl->sdl_data) >= sizeof(*endpoint));
933ea0a6b3dSdlg memcpy(sdl->sdl_data, endpoint, sizeof(*endpoint));
9345fb1d1dcSdlg }
935