1*5c7fed39Sdlg /* $OpenBSD: bridgectl.c,v 1.25 2021/02/25 02:48:21 dlg Exp $ */
2062b28b9Sgoda
3062b28b9Sgoda /*
4062b28b9Sgoda * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
5062b28b9Sgoda * All rights reserved.
6062b28b9Sgoda *
7062b28b9Sgoda * Redistribution and use in source and binary forms, with or without
8062b28b9Sgoda * modification, are permitted provided that the following conditions
9062b28b9Sgoda * are met:
10062b28b9Sgoda * 1. Redistributions of source code must retain the above copyright
11062b28b9Sgoda * notice, this list of conditions and the following disclaimer.
12062b28b9Sgoda * 2. Redistributions in binary form must reproduce the above copyright
13062b28b9Sgoda * notice, this list of conditions and the following disclaimer in the
14062b28b9Sgoda * documentation and/or other materials provided with the distribution.
15062b28b9Sgoda *
16062b28b9Sgoda * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17062b28b9Sgoda * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18062b28b9Sgoda * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19062b28b9Sgoda * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20062b28b9Sgoda * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21062b28b9Sgoda * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22062b28b9Sgoda * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23062b28b9Sgoda * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24062b28b9Sgoda * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25062b28b9Sgoda * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26062b28b9Sgoda * POSSIBILITY OF SUCH DAMAGE.
27062b28b9Sgoda *
28062b28b9Sgoda * Effort sponsored in part by the Defense Advanced Research Projects
29062b28b9Sgoda * Agency (DARPA) and Air Force Research Laboratory, Air Force
30062b28b9Sgoda * Materiel Command, USAF, under agreement number F30602-01-2-0537.
31062b28b9Sgoda *
32062b28b9Sgoda */
33062b28b9Sgoda
34062b28b9Sgoda #include "pf.h"
35062b28b9Sgoda
36062b28b9Sgoda #include <sys/param.h>
37062b28b9Sgoda #include <sys/systm.h>
38062b28b9Sgoda #include <sys/mbuf.h>
39062b28b9Sgoda #include <sys/socket.h>
40062b28b9Sgoda #include <sys/ioctl.h>
41062b28b9Sgoda #include <sys/timeout.h>
42062b28b9Sgoda #include <sys/kernel.h>
43062b28b9Sgoda
44062b28b9Sgoda #include <crypto/siphash.h>
45062b28b9Sgoda
46062b28b9Sgoda #include <net/if.h>
47062b28b9Sgoda
48062b28b9Sgoda #include <netinet/in.h>
49062b28b9Sgoda #include <netinet/if_ether.h>
50062b28b9Sgoda
51062b28b9Sgoda #include <net/if_bridge.h>
52062b28b9Sgoda
53062b28b9Sgoda
54062b28b9Sgoda int bridge_rtfind(struct bridge_softc *, struct ifbaconf *);
55062b28b9Sgoda int bridge_rtdaddr(struct bridge_softc *, struct ether_addr *);
56062b28b9Sgoda u_int32_t bridge_hash(struct bridge_softc *, struct ether_addr *);
57062b28b9Sgoda
5818c5de22Smpi int bridge_brlconf(struct bridge_iflist *, struct ifbrlconf *);
59062b28b9Sgoda int bridge_addrule(struct bridge_iflist *, struct ifbrlreq *, int out);
60062b28b9Sgoda
61062b28b9Sgoda int
bridgectl_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data)62062b28b9Sgoda bridgectl_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
63062b28b9Sgoda {
64062b28b9Sgoda struct bridge_softc *sc = (struct bridge_softc *)ifp->if_softc;
65062b28b9Sgoda struct ifbreq *req = (struct ifbreq *)data;
66062b28b9Sgoda struct ifbrlreq *brlreq = (struct ifbrlreq *)data;
6718c5de22Smpi struct ifbrlconf *bc = (struct ifbrlconf *)data;
68062b28b9Sgoda struct ifbareq *bareq = (struct ifbareq *)data;
69062b28b9Sgoda struct ifbrparam *bparam = (struct ifbrparam *)data;
7067b85364Smpi struct bridge_iflist *bif;
71062b28b9Sgoda struct ifnet *ifs;
72062b28b9Sgoda int error = 0;
73062b28b9Sgoda
74062b28b9Sgoda switch (cmd) {
75062b28b9Sgoda case SIOCBRDGRTS:
76062b28b9Sgoda error = bridge_rtfind(sc, (struct ifbaconf *)data);
77062b28b9Sgoda break;
78062b28b9Sgoda case SIOCBRDGFLUSH:
79062b28b9Sgoda bridge_rtflush(sc, req->ifbr_ifsflags);
80062b28b9Sgoda break;
81062b28b9Sgoda case SIOCBRDGSADDR:
82eed7861eSmvs ifs = if_unit(bareq->ifba_ifsname);
83062b28b9Sgoda if (ifs == NULL) { /* no such interface */
84062b28b9Sgoda error = ENOENT;
85062b28b9Sgoda break;
86062b28b9Sgoda }
8796c4247cSmpi if (ifs->if_bridgeidx != ifp->if_index) {
88eed7861eSmvs if_put(ifs);
89062b28b9Sgoda error = ESRCH;
90062b28b9Sgoda break;
91062b28b9Sgoda }
92062b28b9Sgoda
9329016cb9Smpi if (bridge_rtupdate(sc, &bareq->ifba_dst, ifs, 1,
9429016cb9Smpi bareq->ifba_flags, NULL))
95062b28b9Sgoda error = ENOMEM;
96eed7861eSmvs if_put(ifs);
97062b28b9Sgoda break;
98062b28b9Sgoda case SIOCBRDGDADDR:
99062b28b9Sgoda error = bridge_rtdaddr(sc, &bareq->ifba_dst);
100062b28b9Sgoda break;
101062b28b9Sgoda case SIOCBRDGGCACHE:
102062b28b9Sgoda bparam->ifbrp_csize = sc->sc_brtmax;
103062b28b9Sgoda break;
104062b28b9Sgoda case SIOCBRDGSCACHE:
10596d0f2aeSmpi mtx_enter(&sc->sc_mtx);
106062b28b9Sgoda sc->sc_brtmax = bparam->ifbrp_csize;
10796d0f2aeSmpi mtx_leave(&sc->sc_mtx);
108062b28b9Sgoda break;
109062b28b9Sgoda case SIOCBRDGSTO:
110062b28b9Sgoda if (bparam->ifbrp_ctime < 0 ||
111062b28b9Sgoda bparam->ifbrp_ctime > INT_MAX / hz) {
112062b28b9Sgoda error = EINVAL;
113062b28b9Sgoda break;
114062b28b9Sgoda }
115062b28b9Sgoda sc->sc_brttimeout = bparam->ifbrp_ctime;
116062b28b9Sgoda if (bparam->ifbrp_ctime != 0)
117062b28b9Sgoda timeout_add_sec(&sc->sc_brtimeout, sc->sc_brttimeout);
118062b28b9Sgoda else
119062b28b9Sgoda timeout_del(&sc->sc_brtimeout);
120062b28b9Sgoda break;
121062b28b9Sgoda case SIOCBRDGGTO:
122062b28b9Sgoda bparam->ifbrp_ctime = sc->sc_brttimeout;
123062b28b9Sgoda break;
124062b28b9Sgoda case SIOCBRDGARL:
125062b28b9Sgoda if ((brlreq->ifbr_action != BRL_ACTION_BLOCK &&
126062b28b9Sgoda brlreq->ifbr_action != BRL_ACTION_PASS) ||
127062b28b9Sgoda (brlreq->ifbr_flags & (BRL_FLAG_IN|BRL_FLAG_OUT)) == 0) {
128062b28b9Sgoda error = EINVAL;
129062b28b9Sgoda break;
130062b28b9Sgoda }
131044aaac6Smvs error = bridge_findbif(sc, brlreq->ifbr_ifsname, &bif);
132044aaac6Smvs if (error != 0)
133044aaac6Smvs break;
134062b28b9Sgoda if (brlreq->ifbr_flags & BRL_FLAG_IN) {
13567b85364Smpi error = bridge_addrule(bif, brlreq, 0);
136062b28b9Sgoda if (error)
137062b28b9Sgoda break;
138062b28b9Sgoda }
139062b28b9Sgoda if (brlreq->ifbr_flags & BRL_FLAG_OUT) {
14067b85364Smpi error = bridge_addrule(bif, brlreq, 1);
141062b28b9Sgoda if (error)
142062b28b9Sgoda break;
143062b28b9Sgoda }
144062b28b9Sgoda break;
145062b28b9Sgoda case SIOCBRDGFRL:
146044aaac6Smvs error = bridge_findbif(sc, brlreq->ifbr_ifsname, &bif);
147044aaac6Smvs if (error != 0)
148062b28b9Sgoda break;
14967b85364Smpi bridge_flushrule(bif);
150062b28b9Sgoda break;
151062b28b9Sgoda case SIOCBRDGGRL:
152044aaac6Smvs error = bridge_findbif(sc, bc->ifbrl_ifsname, &bif);
153044aaac6Smvs if (error != 0)
15418c5de22Smpi break;
15518c5de22Smpi error = bridge_brlconf(bif, bc);
156062b28b9Sgoda break;
157062b28b9Sgoda default:
158062b28b9Sgoda break;
159062b28b9Sgoda }
160062b28b9Sgoda
161062b28b9Sgoda return (error);
162062b28b9Sgoda }
163062b28b9Sgoda
16429016cb9Smpi int
bridge_rtupdate(struct bridge_softc * sc,struct ether_addr * ea,struct ifnet * ifp,int setflags,u_int8_t flags,struct mbuf * m)165062b28b9Sgoda bridge_rtupdate(struct bridge_softc *sc, struct ether_addr *ea,
166062b28b9Sgoda struct ifnet *ifp, int setflags, u_int8_t flags, struct mbuf *m)
167062b28b9Sgoda {
168062b28b9Sgoda struct bridge_rtnode *p, *q;
16926334ce3Sreyk struct bridge_tunneltag *brtag = NULL;
170062b28b9Sgoda u_int32_t h;
17129016cb9Smpi int dir, error = 0;
172062b28b9Sgoda
173062b28b9Sgoda if (m != NULL) {
174062b28b9Sgoda /* Check if the mbuf was tagged with a tunnel endpoint addr */
17526334ce3Sreyk brtag = bridge_tunnel(m);
176062b28b9Sgoda }
177062b28b9Sgoda
178062b28b9Sgoda h = bridge_hash(sc, ea);
17996d0f2aeSmpi mtx_enter(&sc->sc_mtx);
180062b28b9Sgoda p = LIST_FIRST(&sc->sc_rts[h]);
181062b28b9Sgoda if (p == NULL) {
182062b28b9Sgoda if (sc->sc_brtcnt >= sc->sc_brtmax)
183062b28b9Sgoda goto done;
184062b28b9Sgoda p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
185062b28b9Sgoda if (p == NULL)
186062b28b9Sgoda goto done;
187062b28b9Sgoda
188062b28b9Sgoda bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
18996c4247cSmpi p->brt_ifidx = ifp->if_index;
190062b28b9Sgoda p->brt_age = 1;
19126334ce3Sreyk bridge_copytag(brtag, &p->brt_tunnel);
192062b28b9Sgoda
193062b28b9Sgoda if (setflags)
194062b28b9Sgoda p->brt_flags = flags;
195062b28b9Sgoda else
196062b28b9Sgoda p->brt_flags = IFBAF_DYNAMIC;
197062b28b9Sgoda
198062b28b9Sgoda LIST_INSERT_HEAD(&sc->sc_rts[h], p, brt_next);
199062b28b9Sgoda sc->sc_brtcnt++;
200062b28b9Sgoda goto want;
201062b28b9Sgoda }
202062b28b9Sgoda
203062b28b9Sgoda do {
204062b28b9Sgoda q = p;
205062b28b9Sgoda p = LIST_NEXT(p, brt_next);
206062b28b9Sgoda
207062b28b9Sgoda dir = memcmp(ea, &q->brt_addr, sizeof(q->brt_addr));
208062b28b9Sgoda if (dir == 0) {
209062b28b9Sgoda if (setflags) {
21096c4247cSmpi q->brt_ifidx = ifp->if_index;
211062b28b9Sgoda q->brt_flags = flags;
212062b28b9Sgoda } else if (!(q->brt_flags & IFBAF_STATIC))
21396c4247cSmpi q->brt_ifidx = ifp->if_index;
214062b28b9Sgoda
21596c4247cSmpi if (q->brt_ifidx == ifp->if_index)
216062b28b9Sgoda q->brt_age = 1;
21726334ce3Sreyk bridge_copytag(brtag, &q->brt_tunnel);
218062b28b9Sgoda goto want;
219062b28b9Sgoda }
220062b28b9Sgoda
221062b28b9Sgoda if (dir > 0) {
222062b28b9Sgoda if (sc->sc_brtcnt >= sc->sc_brtmax)
223062b28b9Sgoda goto done;
224062b28b9Sgoda p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
225062b28b9Sgoda if (p == NULL)
226062b28b9Sgoda goto done;
227062b28b9Sgoda
228062b28b9Sgoda bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
22996c4247cSmpi p->brt_ifidx = ifp->if_index;
230062b28b9Sgoda p->brt_age = 1;
23126334ce3Sreyk bridge_copytag(brtag, &p->brt_tunnel);
232062b28b9Sgoda
233062b28b9Sgoda if (setflags)
234062b28b9Sgoda p->brt_flags = flags;
235062b28b9Sgoda else
236062b28b9Sgoda p->brt_flags = IFBAF_DYNAMIC;
237062b28b9Sgoda
238062b28b9Sgoda LIST_INSERT_BEFORE(q, p, brt_next);
239062b28b9Sgoda sc->sc_brtcnt++;
240062b28b9Sgoda goto want;
241062b28b9Sgoda }
242062b28b9Sgoda
243062b28b9Sgoda if (p == NULL) {
244062b28b9Sgoda if (sc->sc_brtcnt >= sc->sc_brtmax)
245062b28b9Sgoda goto done;
246062b28b9Sgoda p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
247062b28b9Sgoda if (p == NULL)
248062b28b9Sgoda goto done;
249062b28b9Sgoda
250062b28b9Sgoda bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
25196c4247cSmpi p->brt_ifidx = ifp->if_index;
252062b28b9Sgoda p->brt_age = 1;
25326334ce3Sreyk bridge_copytag(brtag, &p->brt_tunnel);
254062b28b9Sgoda
255062b28b9Sgoda if (setflags)
256062b28b9Sgoda p->brt_flags = flags;
257062b28b9Sgoda else
258062b28b9Sgoda p->brt_flags = IFBAF_DYNAMIC;
259062b28b9Sgoda LIST_INSERT_AFTER(q, p, brt_next);
260062b28b9Sgoda sc->sc_brtcnt++;
261062b28b9Sgoda goto want;
262062b28b9Sgoda }
263062b28b9Sgoda } while (p != NULL);
264062b28b9Sgoda
265062b28b9Sgoda done:
26629016cb9Smpi error = 1;
267062b28b9Sgoda want:
26896d0f2aeSmpi mtx_leave(&sc->sc_mtx);
26929016cb9Smpi return (error);
270062b28b9Sgoda }
271062b28b9Sgoda
27296c4247cSmpi unsigned int
bridge_rtlookup(struct ifnet * brifp,struct ether_addr * ea,struct mbuf * m)27396c4247cSmpi bridge_rtlookup(struct ifnet *brifp, struct ether_addr *ea, struct mbuf *m)
274062b28b9Sgoda {
27596c4247cSmpi struct bridge_softc *sc = brifp->if_softc;
27696d0f2aeSmpi struct bridge_rtnode *p = NULL;
27796c4247cSmpi unsigned int ifidx = 0;
278062b28b9Sgoda u_int32_t h;
279062b28b9Sgoda int dir;
280062b28b9Sgoda
281062b28b9Sgoda h = bridge_hash(sc, ea);
28296d0f2aeSmpi mtx_enter(&sc->sc_mtx);
283062b28b9Sgoda LIST_FOREACH(p, &sc->sc_rts[h], brt_next) {
284062b28b9Sgoda dir = memcmp(ea, &p->brt_addr, sizeof(p->brt_addr));
285062b28b9Sgoda if (dir == 0)
28696d0f2aeSmpi break;
28796d0f2aeSmpi if (dir > 0) {
28896d0f2aeSmpi p = NULL;
28996d0f2aeSmpi break;
290062b28b9Sgoda }
29196d0f2aeSmpi }
29233d9f1d5Smpi if (p != NULL) {
29396c4247cSmpi ifidx = p->brt_ifidx;
29433d9f1d5Smpi
29533d9f1d5Smpi if (p->brt_family != AF_UNSPEC && m != NULL) {
29633d9f1d5Smpi struct bridge_tunneltag *brtag;
29733d9f1d5Smpi
29833d9f1d5Smpi brtag = bridge_tunneltag(m);
29933d9f1d5Smpi if (brtag != NULL)
30033d9f1d5Smpi bridge_copytag(&p->brt_tunnel, brtag);
30133d9f1d5Smpi }
30233d9f1d5Smpi }
30396d0f2aeSmpi mtx_leave(&sc->sc_mtx);
30496d0f2aeSmpi
30596c4247cSmpi return (ifidx);
306062b28b9Sgoda }
307062b28b9Sgoda
308062b28b9Sgoda u_int32_t
bridge_hash(struct bridge_softc * sc,struct ether_addr * addr)309062b28b9Sgoda bridge_hash(struct bridge_softc *sc, struct ether_addr *addr)
310062b28b9Sgoda {
311062b28b9Sgoda return SipHash24((SIPHASH_KEY *)sc->sc_hashkey, addr, ETHER_ADDR_LEN) &
312062b28b9Sgoda BRIDGE_RTABLE_MASK;
313062b28b9Sgoda }
314062b28b9Sgoda
315062b28b9Sgoda /*
316062b28b9Sgoda * Perform an aging cycle
317062b28b9Sgoda */
318062b28b9Sgoda void
bridge_rtage(void * vsc)319abb517abSmpi bridge_rtage(void *vsc)
320062b28b9Sgoda {
321abb517abSmpi struct bridge_softc *sc = vsc;
3222d276719Smpi struct ifnet *ifp = &sc->sc_if;
323062b28b9Sgoda struct bridge_rtnode *n, *p;
324062b28b9Sgoda int i;
325062b28b9Sgoda
3262d276719Smpi if (!ISSET(ifp->if_flags, IFF_RUNNING))
3272d276719Smpi return;
3282d276719Smpi
32996d0f2aeSmpi mtx_enter(&sc->sc_mtx);
330062b28b9Sgoda for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
331062b28b9Sgoda n = LIST_FIRST(&sc->sc_rts[i]);
332062b28b9Sgoda while (n != NULL) {
333062b28b9Sgoda if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_STATIC) {
334062b28b9Sgoda n->brt_age = !n->brt_age;
335062b28b9Sgoda if (n->brt_age)
336062b28b9Sgoda n->brt_age = 0;
337062b28b9Sgoda n = LIST_NEXT(n, brt_next);
338062b28b9Sgoda } else if (n->brt_age) {
339062b28b9Sgoda n->brt_age = 0;
340062b28b9Sgoda n = LIST_NEXT(n, brt_next);
341062b28b9Sgoda } else {
342062b28b9Sgoda p = LIST_NEXT(n, brt_next);
343062b28b9Sgoda LIST_REMOVE(n, brt_next);
344062b28b9Sgoda sc->sc_brtcnt--;
345062b28b9Sgoda free(n, M_DEVBUF, sizeof *n);
346062b28b9Sgoda n = p;
347062b28b9Sgoda }
348062b28b9Sgoda }
349062b28b9Sgoda }
35096d0f2aeSmpi mtx_leave(&sc->sc_mtx);
351062b28b9Sgoda
352062b28b9Sgoda if (sc->sc_brttimeout != 0)
353062b28b9Sgoda timeout_add_sec(&sc->sc_brtimeout, sc->sc_brttimeout);
354062b28b9Sgoda }
355062b28b9Sgoda
356062b28b9Sgoda void
bridge_rtagenode(struct ifnet * ifp,int age)357062b28b9Sgoda bridge_rtagenode(struct ifnet *ifp, int age)
358062b28b9Sgoda {
359062b28b9Sgoda struct bridge_softc *sc;
360062b28b9Sgoda struct bridge_rtnode *n;
36196c4247cSmpi struct ifnet *bifp;
362062b28b9Sgoda int i;
363062b28b9Sgoda
36496c4247cSmpi bifp = if_get(ifp->if_bridgeidx);
36596c4247cSmpi if (bifp == NULL)
36637ceae02Smpi return;
36796c4247cSmpi sc = bifp->if_softc;
368062b28b9Sgoda
369062b28b9Sgoda /*
370062b28b9Sgoda * If the age is zero then flush, otherwise set all the expiry times to
371062b28b9Sgoda * age for the interface
372062b28b9Sgoda */
373062b28b9Sgoda if (age == 0)
374062b28b9Sgoda bridge_rtdelete(sc, ifp, 1);
375062b28b9Sgoda else {
37696d0f2aeSmpi mtx_enter(&sc->sc_mtx);
377062b28b9Sgoda for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
378062b28b9Sgoda LIST_FOREACH(n, &sc->sc_rts[i], brt_next) {
379062b28b9Sgoda /* Cap the expiry time to 'age' */
38096c4247cSmpi if (n->brt_ifidx == ifp->if_index &&
3813209772dScheloha n->brt_age > getuptime() + age &&
382062b28b9Sgoda (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)
3833209772dScheloha n->brt_age = getuptime() + age;
384062b28b9Sgoda }
385062b28b9Sgoda }
38696d0f2aeSmpi mtx_leave(&sc->sc_mtx);
387062b28b9Sgoda }
38896c4247cSmpi
38996c4247cSmpi if_put(bifp);
390062b28b9Sgoda }
391062b28b9Sgoda
392062b28b9Sgoda /*
393062b28b9Sgoda * Remove all dynamic addresses from the cache
394062b28b9Sgoda */
395062b28b9Sgoda void
bridge_rtflush(struct bridge_softc * sc,int full)396062b28b9Sgoda bridge_rtflush(struct bridge_softc *sc, int full)
397062b28b9Sgoda {
398062b28b9Sgoda int i;
399062b28b9Sgoda struct bridge_rtnode *p, *n;
400062b28b9Sgoda
40196d0f2aeSmpi mtx_enter(&sc->sc_mtx);
402062b28b9Sgoda for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
403062b28b9Sgoda n = LIST_FIRST(&sc->sc_rts[i]);
404062b28b9Sgoda while (n != NULL) {
405062b28b9Sgoda if (full ||
406062b28b9Sgoda (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
407062b28b9Sgoda p = LIST_NEXT(n, brt_next);
408062b28b9Sgoda LIST_REMOVE(n, brt_next);
409062b28b9Sgoda sc->sc_brtcnt--;
410062b28b9Sgoda free(n, M_DEVBUF, sizeof *n);
411062b28b9Sgoda n = p;
412062b28b9Sgoda } else
413062b28b9Sgoda n = LIST_NEXT(n, brt_next);
414062b28b9Sgoda }
415062b28b9Sgoda }
41696d0f2aeSmpi mtx_leave(&sc->sc_mtx);
417062b28b9Sgoda }
418062b28b9Sgoda
419062b28b9Sgoda /*
420062b28b9Sgoda * Remove an address from the cache
421062b28b9Sgoda */
422062b28b9Sgoda int
bridge_rtdaddr(struct bridge_softc * sc,struct ether_addr * ea)423062b28b9Sgoda bridge_rtdaddr(struct bridge_softc *sc, struct ether_addr *ea)
424062b28b9Sgoda {
425062b28b9Sgoda int h;
426062b28b9Sgoda struct bridge_rtnode *p;
427062b28b9Sgoda
428062b28b9Sgoda h = bridge_hash(sc, ea);
42996d0f2aeSmpi mtx_enter(&sc->sc_mtx);
430062b28b9Sgoda LIST_FOREACH(p, &sc->sc_rts[h], brt_next) {
43134fbf967Shenning if (memcmp(ea, &p->brt_addr, sizeof(p->brt_addr)) == 0) {
432062b28b9Sgoda LIST_REMOVE(p, brt_next);
433062b28b9Sgoda sc->sc_brtcnt--;
43496d0f2aeSmpi mtx_leave(&sc->sc_mtx);
435062b28b9Sgoda free(p, M_DEVBUF, sizeof *p);
436062b28b9Sgoda return (0);
437062b28b9Sgoda }
438062b28b9Sgoda }
43996d0f2aeSmpi mtx_leave(&sc->sc_mtx);
440062b28b9Sgoda
441062b28b9Sgoda return (ENOENT);
442062b28b9Sgoda }
443062b28b9Sgoda
444062b28b9Sgoda /*
445062b28b9Sgoda * Delete routes to a specific interface member.
446062b28b9Sgoda */
447062b28b9Sgoda void
bridge_rtdelete(struct bridge_softc * sc,struct ifnet * ifp,int dynonly)448062b28b9Sgoda bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp, int dynonly)
449062b28b9Sgoda {
450062b28b9Sgoda int i;
451062b28b9Sgoda struct bridge_rtnode *n, *p;
452062b28b9Sgoda
453062b28b9Sgoda /*
454062b28b9Sgoda * Loop through all of the hash buckets and traverse each
455062b28b9Sgoda * chain looking for routes to this interface.
456062b28b9Sgoda */
45796d0f2aeSmpi mtx_enter(&sc->sc_mtx);
458062b28b9Sgoda for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
459062b28b9Sgoda n = LIST_FIRST(&sc->sc_rts[i]);
460062b28b9Sgoda while (n != NULL) {
46196c4247cSmpi if (n->brt_ifidx != ifp->if_index) {
462062b28b9Sgoda /* Not ours */
463062b28b9Sgoda n = LIST_NEXT(n, brt_next);
464062b28b9Sgoda continue;
465062b28b9Sgoda }
466062b28b9Sgoda if (dynonly &&
467062b28b9Sgoda (n->brt_flags & IFBAF_TYPEMASK) != IFBAF_DYNAMIC) {
468062b28b9Sgoda /* only deleting dynamics */
469062b28b9Sgoda n = LIST_NEXT(n, brt_next);
470062b28b9Sgoda continue;
471062b28b9Sgoda }
472062b28b9Sgoda p = LIST_NEXT(n, brt_next);
473062b28b9Sgoda LIST_REMOVE(n, brt_next);
474062b28b9Sgoda sc->sc_brtcnt--;
475062b28b9Sgoda free(n, M_DEVBUF, sizeof *n);
476062b28b9Sgoda n = p;
477062b28b9Sgoda }
478062b28b9Sgoda }
47996d0f2aeSmpi mtx_leave(&sc->sc_mtx);
480062b28b9Sgoda }
481062b28b9Sgoda
482062b28b9Sgoda /*
483062b28b9Sgoda * Gather all of the routes for this interface.
484062b28b9Sgoda */
485062b28b9Sgoda int
bridge_rtfind(struct bridge_softc * sc,struct ifbaconf * baconf)486062b28b9Sgoda bridge_rtfind(struct bridge_softc *sc, struct ifbaconf *baconf)
487062b28b9Sgoda {
488f15d4156Smpi struct ifbareq *bareq, *bareqs = NULL;
489062b28b9Sgoda struct bridge_rtnode *n;
490f15d4156Smpi u_int32_t i = 0, total = 0;
491f15d4156Smpi int k, error = 0;
492062b28b9Sgoda
49396d0f2aeSmpi mtx_enter(&sc->sc_mtx);
494f15d4156Smpi for (k = 0; k < BRIDGE_RTABLE_SIZE; k++) {
495f15d4156Smpi LIST_FOREACH(n, &sc->sc_rts[k], brt_next)
496f15d4156Smpi total++;
497f15d4156Smpi }
49896d0f2aeSmpi mtx_leave(&sc->sc_mtx);
499062b28b9Sgoda
500f15d4156Smpi if (baconf->ifbac_len == 0) {
501f15d4156Smpi i = total;
502062b28b9Sgoda goto done;
503f15d4156Smpi }
504f15d4156Smpi
50596d0f2aeSmpi total = MIN(total, baconf->ifbac_len / sizeof(*bareqs));
506f15d4156Smpi bareqs = mallocarray(total, sizeof(*bareqs), M_TEMP, M_NOWAIT|M_ZERO);
507f15d4156Smpi if (bareqs == NULL)
508f15d4156Smpi goto done;
509f15d4156Smpi
51096d0f2aeSmpi mtx_enter(&sc->sc_mtx);
511f15d4156Smpi for (k = 0; k < BRIDGE_RTABLE_SIZE; k++) {
512f15d4156Smpi LIST_FOREACH(n, &sc->sc_rts[k], brt_next) {
51396c4247cSmpi struct ifnet *ifp;
51496c4247cSmpi
515c2e35fc4Smpi if (i >= total) {
516c2e35fc4Smpi mtx_leave(&sc->sc_mtx);
517f15d4156Smpi goto done;
518c2e35fc4Smpi }
519f15d4156Smpi bareq = &bareqs[i];
52096c4247cSmpi
52196c4247cSmpi ifp = if_get(n->brt_ifidx);
52296c4247cSmpi if (ifp == NULL)
52396c4247cSmpi continue;
52496c4247cSmpi bcopy(ifp->if_xname, bareq->ifba_ifsname,
52596c4247cSmpi sizeof(bareq->ifba_ifsname));
52696c4247cSmpi if_put(ifp);
52796c4247cSmpi
528f15d4156Smpi bcopy(sc->sc_if.if_xname, bareq->ifba_name,
529f15d4156Smpi sizeof(bareq->ifba_name));
530f15d4156Smpi bcopy(&n->brt_addr, &bareq->ifba_dst,
531f15d4156Smpi sizeof(bareq->ifba_dst));
5328eacc5b2Sreyk bridge_copyaddr(&n->brt_tunnel.brtag_peer.sa,
533f15d4156Smpi sstosa(&bareq->ifba_dstsa));
534f15d4156Smpi bareq->ifba_age = n->brt_age;
535f15d4156Smpi bareq->ifba_flags = n->brt_flags;
536f15d4156Smpi i++;
537062b28b9Sgoda }
538062b28b9Sgoda }
53996d0f2aeSmpi mtx_leave(&sc->sc_mtx);
540f15d4156Smpi
541f15d4156Smpi error = copyout(bareqs, baconf->ifbac_req, i * sizeof(*bareqs));
542062b28b9Sgoda done:
543f15d4156Smpi free(bareqs, M_TEMP, total * sizeof(*bareqs));
544f15d4156Smpi baconf->ifbac_len = i * sizeof(*bareqs);
545062b28b9Sgoda return (error);
546062b28b9Sgoda }
547062b28b9Sgoda
548062b28b9Sgoda void
bridge_update(struct ifnet * ifp,struct ether_addr * ea,int delete)549062b28b9Sgoda bridge_update(struct ifnet *ifp, struct ether_addr *ea, int delete)
550062b28b9Sgoda {
551062b28b9Sgoda struct bridge_softc *sc;
552062b28b9Sgoda struct bridge_iflist *bif;
553062b28b9Sgoda u_int8_t *addr;
554062b28b9Sgoda
555062b28b9Sgoda addr = (u_int8_t *)ea;
556062b28b9Sgoda
55796c4247cSmpi bif = bridge_getbif(ifp);
55837ceae02Smpi if (bif == NULL)
55937ceae02Smpi return;
560062b28b9Sgoda sc = bif->bridge_sc;
56137ceae02Smpi if (sc == NULL)
56237ceae02Smpi return;
563062b28b9Sgoda
564062b28b9Sgoda /*
565062b28b9Sgoda * Update the bridge interface if it is in
566062b28b9Sgoda * the learning state.
567062b28b9Sgoda */
568062b28b9Sgoda if ((bif->bif_flags & IFBIF_LEARNING) &&
569062b28b9Sgoda (ETHER_IS_MULTICAST(addr) == 0) &&
570062b28b9Sgoda !(addr[0] == 0 && addr[1] == 0 && addr[2] == 0 &&
571062b28b9Sgoda addr[3] == 0 && addr[4] == 0 && addr[5] == 0)) {
572062b28b9Sgoda /* Care must be taken with spanning tree */
573062b28b9Sgoda if ((bif->bif_flags & IFBIF_STP) &&
574062b28b9Sgoda (bif->bif_state == BSTP_IFSTATE_DISCARDING))
575062b28b9Sgoda return;
576062b28b9Sgoda
577062b28b9Sgoda /* Delete the address from the bridge */
578062b28b9Sgoda bridge_rtdaddr(sc, ea);
579062b28b9Sgoda
580062b28b9Sgoda if (!delete) {
581062b28b9Sgoda /* Update the bridge table */
582062b28b9Sgoda bridge_rtupdate(sc, ea, ifp, 0, IFBAF_DYNAMIC, NULL);
583062b28b9Sgoda }
584062b28b9Sgoda }
585062b28b9Sgoda }
586062b28b9Sgoda
587062b28b9Sgoda /*
588062b28b9Sgoda * bridge filter/matching rules
589062b28b9Sgoda */
590062b28b9Sgoda int
bridge_brlconf(struct bridge_iflist * bif,struct ifbrlconf * bc)59118c5de22Smpi bridge_brlconf(struct bridge_iflist *bif, struct ifbrlconf *bc)
592062b28b9Sgoda {
59318c5de22Smpi struct bridge_softc *sc = bif->bridge_sc;
594062b28b9Sgoda struct brl_node *n;
595f15d4156Smpi struct ifbrlreq *req, *reqs = NULL;
596062b28b9Sgoda int error = 0;
597062b28b9Sgoda u_int32_t i = 0, total = 0;
598062b28b9Sgoda
5999a0705b3Smpi SIMPLEQ_FOREACH(n, &bif->bif_brlin, brl_next) {
600062b28b9Sgoda total++;
601062b28b9Sgoda }
6029a0705b3Smpi SIMPLEQ_FOREACH(n, &bif->bif_brlout, brl_next) {
603062b28b9Sgoda total++;
604062b28b9Sgoda }
605062b28b9Sgoda
606062b28b9Sgoda if (bc->ifbrl_len == 0) {
607062b28b9Sgoda i = total;
608062b28b9Sgoda goto done;
609062b28b9Sgoda }
610062b28b9Sgoda
611f15d4156Smpi reqs = mallocarray(total, sizeof(*reqs), M_TEMP, M_NOWAIT|M_ZERO);
612f15d4156Smpi if (reqs == NULL)
613f15d4156Smpi goto done;
614f15d4156Smpi
6159a0705b3Smpi SIMPLEQ_FOREACH(n, &bif->bif_brlin, brl_next) {
616f15d4156Smpi if (bc->ifbrl_len < (i + 1) * sizeof(*reqs))
617062b28b9Sgoda goto done;
618f15d4156Smpi req = &reqs[i];
619f15d4156Smpi strlcpy(req->ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
620f15d4156Smpi strlcpy(req->ifbr_ifsname, bif->ifp->if_xname, IFNAMSIZ);
621f15d4156Smpi req->ifbr_action = n->brl_action;
622f15d4156Smpi req->ifbr_flags = n->brl_flags;
623f15d4156Smpi req->ifbr_src = n->brl_src;
624f15d4156Smpi req->ifbr_dst = n->brl_dst;
625f15d4156Smpi req->ifbr_arpf = n->brl_arpf;
626062b28b9Sgoda #if NPF > 0
627f15d4156Smpi req->ifbr_tagname[0] = '\0';
628062b28b9Sgoda if (n->brl_tag)
629f15d4156Smpi pf_tag2tagname(n->brl_tag, req->ifbr_tagname);
630062b28b9Sgoda #endif
631062b28b9Sgoda i++;
632062b28b9Sgoda }
633062b28b9Sgoda
6349a0705b3Smpi SIMPLEQ_FOREACH(n, &bif->bif_brlout, brl_next) {
635f15d4156Smpi if (bc->ifbrl_len < (i + 1) * sizeof(*reqs))
636062b28b9Sgoda goto done;
637f15d4156Smpi req = &reqs[i];
638f15d4156Smpi strlcpy(req->ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
639f15d4156Smpi strlcpy(req->ifbr_ifsname, bif->ifp->if_xname, IFNAMSIZ);
640f15d4156Smpi req->ifbr_action = n->brl_action;
641f15d4156Smpi req->ifbr_flags = n->brl_flags;
642f15d4156Smpi req->ifbr_src = n->brl_src;
643f15d4156Smpi req->ifbr_dst = n->brl_dst;
644f15d4156Smpi req->ifbr_arpf = n->brl_arpf;
645062b28b9Sgoda #if NPF > 0
646f15d4156Smpi req->ifbr_tagname[0] = '\0';
647062b28b9Sgoda if (n->brl_tag)
648f15d4156Smpi pf_tag2tagname(n->brl_tag, req->ifbr_tagname);
649062b28b9Sgoda #endif
650062b28b9Sgoda i++;
651062b28b9Sgoda }
652062b28b9Sgoda
653f15d4156Smpi error = copyout(reqs, bc->ifbrl_buf, i * sizeof(*reqs));
654062b28b9Sgoda done:
655f15d4156Smpi free(reqs, M_TEMP, total * sizeof(*reqs));
656f15d4156Smpi bc->ifbrl_len = i * sizeof(*reqs);
657062b28b9Sgoda return (error);
658062b28b9Sgoda }
659062b28b9Sgoda
660062b28b9Sgoda u_int8_t
bridge_arpfilter(struct brl_node * n,struct ether_header * eh,struct mbuf * m)661d6404d18Shenning bridge_arpfilter(struct brl_node *n, struct ether_header *eh, struct mbuf *m)
662d6404d18Shenning {
663d6404d18Shenning struct ether_arp ea;
664d6404d18Shenning
665d6404d18Shenning if (!(n->brl_arpf.brla_flags & (BRLA_ARP|BRLA_RARP)))
666d6404d18Shenning return (1);
667d6404d18Shenning
668d6404d18Shenning if (ntohs(eh->ether_type) != ETHERTYPE_ARP)
669d6404d18Shenning return (0);
6703a171105Sdlg if (m->m_pkthdr.len < ETHER_HDR_LEN + sizeof(ea))
671d6404d18Shenning return (0); /* log error? */
672*5c7fed39Sdlg m_copydata(m, ETHER_HDR_LEN, sizeof(ea), &ea);
673d6404d18Shenning
674d6404d18Shenning if (ntohs(ea.arp_hrd) != ARPHRD_ETHER ||
675d6404d18Shenning ntohs(ea.arp_pro) != ETHERTYPE_IP ||
676d6404d18Shenning ea.arp_hln != ETHER_ADDR_LEN ||
677d6404d18Shenning ea.arp_pln != sizeof(struct in_addr))
678d6404d18Shenning return (0);
679d6404d18Shenning if ((n->brl_arpf.brla_flags & BRLA_ARP) &&
680d6404d18Shenning ntohs(ea.arp_op) != ARPOP_REQUEST &&
681d6404d18Shenning ntohs(ea.arp_op) != ARPOP_REPLY)
682d6404d18Shenning return (0);
683d6404d18Shenning if ((n->brl_arpf.brla_flags & BRLA_RARP) &&
684d6404d18Shenning ntohs(ea.arp_op) != ARPOP_REVREQUEST &&
685d6404d18Shenning ntohs(ea.arp_op) != ARPOP_REVREPLY)
686d6404d18Shenning return (0);
687d6404d18Shenning if (n->brl_arpf.brla_op && ntohs(ea.arp_op) != n->brl_arpf.brla_op)
688d6404d18Shenning return (0);
689d6404d18Shenning if (n->brl_arpf.brla_flags & BRLA_SHA &&
69034fbf967Shenning memcmp(ea.arp_sha, &n->brl_arpf.brla_sha, ETHER_ADDR_LEN))
691d6404d18Shenning return (0);
692d6404d18Shenning if (n->brl_arpf.brla_flags & BRLA_THA &&
69334fbf967Shenning memcmp(ea.arp_tha, &n->brl_arpf.brla_tha, ETHER_ADDR_LEN))
694d6404d18Shenning return (0);
695d6404d18Shenning if (n->brl_arpf.brla_flags & BRLA_SPA &&
69634fbf967Shenning memcmp(ea.arp_spa, &n->brl_arpf.brla_spa, sizeof(struct in_addr)))
697d6404d18Shenning return (0);
698d6404d18Shenning if (n->brl_arpf.brla_flags & BRLA_TPA &&
69934fbf967Shenning memcmp(ea.arp_tpa, &n->brl_arpf.brla_tpa, sizeof(struct in_addr)))
700d6404d18Shenning return (0);
701d6404d18Shenning
702d6404d18Shenning return (1);
703d6404d18Shenning }
704d6404d18Shenning
705d6404d18Shenning u_int8_t
bridge_filterrule(struct brl_head * h,struct ether_header * eh,struct mbuf * m)706062b28b9Sgoda bridge_filterrule(struct brl_head *h, struct ether_header *eh, struct mbuf *m)
707062b28b9Sgoda {
708062b28b9Sgoda struct brl_node *n;
709282291edSmpi u_int8_t action, flags;
710062b28b9Sgoda
711282291edSmpi if (SIMPLEQ_EMPTY(h))
712282291edSmpi return (BRL_ACTION_PASS);
713282291edSmpi
714282291edSmpi KERNEL_LOCK();
715062b28b9Sgoda SIMPLEQ_FOREACH(n, h, brl_next) {
716d6404d18Shenning if (!bridge_arpfilter(n, eh, m))
717d6404d18Shenning continue;
718062b28b9Sgoda flags = n->brl_flags & (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID);
719062b28b9Sgoda if (flags == 0)
720062b28b9Sgoda goto return_action;
721062b28b9Sgoda if (flags == (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID)) {
72234fbf967Shenning if (memcmp(eh->ether_shost, &n->brl_src,
72334fbf967Shenning ETHER_ADDR_LEN))
724062b28b9Sgoda continue;
72534fbf967Shenning if (memcmp(eh->ether_dhost, &n->brl_dst,
72634fbf967Shenning ETHER_ADDR_LEN))
727062b28b9Sgoda continue;
728062b28b9Sgoda goto return_action;
729062b28b9Sgoda }
730062b28b9Sgoda if (flags == BRL_FLAG_SRCVALID) {
73134fbf967Shenning if (memcmp(eh->ether_shost, &n->brl_src,
73234fbf967Shenning ETHER_ADDR_LEN))
733062b28b9Sgoda continue;
734062b28b9Sgoda goto return_action;
735062b28b9Sgoda }
736062b28b9Sgoda if (flags == BRL_FLAG_DSTVALID) {
73734fbf967Shenning if (memcmp(eh->ether_dhost, &n->brl_dst,
73834fbf967Shenning ETHER_ADDR_LEN))
739062b28b9Sgoda continue;
740062b28b9Sgoda goto return_action;
741062b28b9Sgoda }
742062b28b9Sgoda }
743282291edSmpi KERNEL_UNLOCK();
744062b28b9Sgoda return (BRL_ACTION_PASS);
745062b28b9Sgoda
746062b28b9Sgoda return_action:
747062b28b9Sgoda #if NPF > 0
748062b28b9Sgoda pf_tag_packet(m, n->brl_tag, -1);
749062b28b9Sgoda #endif
750282291edSmpi action = n->brl_action;
751282291edSmpi KERNEL_UNLOCK();
752282291edSmpi return (action);
753062b28b9Sgoda }
754062b28b9Sgoda
755062b28b9Sgoda int
bridge_addrule(struct bridge_iflist * bif,struct ifbrlreq * req,int out)756062b28b9Sgoda bridge_addrule(struct bridge_iflist *bif, struct ifbrlreq *req, int out)
757062b28b9Sgoda {
758062b28b9Sgoda struct brl_node *n;
759062b28b9Sgoda
760062b28b9Sgoda n = malloc(sizeof(*n), M_DEVBUF, M_NOWAIT);
761062b28b9Sgoda if (n == NULL)
762062b28b9Sgoda return (ENOMEM);
763062b28b9Sgoda bcopy(&req->ifbr_src, &n->brl_src, sizeof(struct ether_addr));
764062b28b9Sgoda bcopy(&req->ifbr_dst, &n->brl_dst, sizeof(struct ether_addr));
765062b28b9Sgoda n->brl_action = req->ifbr_action;
766062b28b9Sgoda n->brl_flags = req->ifbr_flags;
767d6404d18Shenning n->brl_arpf = req->ifbr_arpf;
768062b28b9Sgoda #if NPF > 0
769062b28b9Sgoda if (req->ifbr_tagname[0])
770062b28b9Sgoda n->brl_tag = pf_tagname2tag(req->ifbr_tagname, 1);
771062b28b9Sgoda else
772062b28b9Sgoda n->brl_tag = 0;
773062b28b9Sgoda #endif
774282291edSmpi
775282291edSmpi KERNEL_ASSERT_LOCKED();
776282291edSmpi
777062b28b9Sgoda if (out) {
778062b28b9Sgoda n->brl_flags &= ~BRL_FLAG_IN;
779062b28b9Sgoda n->brl_flags |= BRL_FLAG_OUT;
780062b28b9Sgoda SIMPLEQ_INSERT_TAIL(&bif->bif_brlout, n, brl_next);
781062b28b9Sgoda } else {
782062b28b9Sgoda n->brl_flags &= ~BRL_FLAG_OUT;
783062b28b9Sgoda n->brl_flags |= BRL_FLAG_IN;
784062b28b9Sgoda SIMPLEQ_INSERT_TAIL(&bif->bif_brlin, n, brl_next);
785062b28b9Sgoda }
786062b28b9Sgoda return (0);
787062b28b9Sgoda }
788062b28b9Sgoda
789062b28b9Sgoda void
bridge_flushrule(struct bridge_iflist * bif)790062b28b9Sgoda bridge_flushrule(struct bridge_iflist *bif)
791062b28b9Sgoda {
792062b28b9Sgoda struct brl_node *p;
793062b28b9Sgoda
794282291edSmpi KERNEL_ASSERT_LOCKED();
795282291edSmpi
796062b28b9Sgoda while (!SIMPLEQ_EMPTY(&bif->bif_brlin)) {
797062b28b9Sgoda p = SIMPLEQ_FIRST(&bif->bif_brlin);
798062b28b9Sgoda SIMPLEQ_REMOVE_HEAD(&bif->bif_brlin, brl_next);
799062b28b9Sgoda #if NPF > 0
800062b28b9Sgoda pf_tag_unref(p->brl_tag);
801062b28b9Sgoda #endif
802062b28b9Sgoda free(p, M_DEVBUF, sizeof *p);
803062b28b9Sgoda }
804062b28b9Sgoda while (!SIMPLEQ_EMPTY(&bif->bif_brlout)) {
805062b28b9Sgoda p = SIMPLEQ_FIRST(&bif->bif_brlout);
806062b28b9Sgoda SIMPLEQ_REMOVE_HEAD(&bif->bif_brlout, brl_next);
807062b28b9Sgoda #if NPF > 0
808062b28b9Sgoda pf_tag_unref(p->brl_tag);
809062b28b9Sgoda #endif
810062b28b9Sgoda free(p, M_DEVBUF, sizeof *p);
811062b28b9Sgoda }
812062b28b9Sgoda }
81333d9f1d5Smpi
81433d9f1d5Smpi struct bridge_tunneltag *
bridge_tunnel(struct mbuf * m)81533d9f1d5Smpi bridge_tunnel(struct mbuf *m)
81633d9f1d5Smpi {
81733d9f1d5Smpi struct m_tag *mtag;
81833d9f1d5Smpi
81933d9f1d5Smpi if ((mtag = m_tag_find(m, PACKET_TAG_TUNNEL, NULL)) == NULL)
82033d9f1d5Smpi return (NULL);
82133d9f1d5Smpi
82233d9f1d5Smpi return ((struct bridge_tunneltag *)(mtag + 1));
82333d9f1d5Smpi }
82433d9f1d5Smpi
82533d9f1d5Smpi struct bridge_tunneltag *
bridge_tunneltag(struct mbuf * m)82633d9f1d5Smpi bridge_tunneltag(struct mbuf *m)
82733d9f1d5Smpi {
82833d9f1d5Smpi struct m_tag *mtag;
82933d9f1d5Smpi
83033d9f1d5Smpi if ((mtag = m_tag_find(m, PACKET_TAG_TUNNEL, NULL)) == NULL) {
83133d9f1d5Smpi mtag = m_tag_get(PACKET_TAG_TUNNEL,
83233d9f1d5Smpi sizeof(struct bridge_tunneltag), M_NOWAIT);
83333d9f1d5Smpi if (mtag == NULL)
83433d9f1d5Smpi return (NULL);
83533d9f1d5Smpi bzero(mtag + 1, sizeof(struct bridge_tunneltag));
83633d9f1d5Smpi m_tag_prepend(m, mtag);
83733d9f1d5Smpi }
83833d9f1d5Smpi
83933d9f1d5Smpi return ((struct bridge_tunneltag *)(mtag + 1));
84033d9f1d5Smpi }
84133d9f1d5Smpi
84233d9f1d5Smpi void
bridge_tunneluntag(struct mbuf * m)84333d9f1d5Smpi bridge_tunneluntag(struct mbuf *m)
84433d9f1d5Smpi {
84533d9f1d5Smpi struct m_tag *mtag;
84633d9f1d5Smpi if ((mtag = m_tag_find(m, PACKET_TAG_TUNNEL, NULL)) != NULL)
84733d9f1d5Smpi m_tag_delete(m, mtag);
84833d9f1d5Smpi }
84933d9f1d5Smpi
85033d9f1d5Smpi void
bridge_copyaddr(struct sockaddr * src,struct sockaddr * dst)85133d9f1d5Smpi bridge_copyaddr(struct sockaddr *src, struct sockaddr *dst)
85233d9f1d5Smpi {
85333d9f1d5Smpi if (src != NULL && src->sa_family != AF_UNSPEC)
85433d9f1d5Smpi memcpy(dst, src, src->sa_len);
85533d9f1d5Smpi else {
85633d9f1d5Smpi dst->sa_family = AF_UNSPEC;
85733d9f1d5Smpi dst->sa_len = 0;
85833d9f1d5Smpi }
85933d9f1d5Smpi }
86033d9f1d5Smpi
86133d9f1d5Smpi void
bridge_copytag(struct bridge_tunneltag * src,struct bridge_tunneltag * dst)86233d9f1d5Smpi bridge_copytag(struct bridge_tunneltag *src, struct bridge_tunneltag *dst)
86333d9f1d5Smpi {
86433d9f1d5Smpi if (src == NULL) {
86533d9f1d5Smpi memset(dst, 0, sizeof(*dst));
86633d9f1d5Smpi } else {
86733d9f1d5Smpi bridge_copyaddr(&src->brtag_peer.sa, &dst->brtag_peer.sa);
86833d9f1d5Smpi bridge_copyaddr(&src->brtag_local.sa, &dst->brtag_local.sa);
86933d9f1d5Smpi dst->brtag_id = src->brtag_id;
87033d9f1d5Smpi }
87133d9f1d5Smpi }
872