xref: /openbsd/sys/net/bridgectl.c (revision 8eacc5b2)
1 /*	$OpenBSD: bridgectl.c,v 1.4 2016/09/29 11:37:43 reyk Exp $	*/
2 
3 /*
4  * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  *
28  * Effort sponsored in part by the Defense Advanced Research Projects
29  * Agency (DARPA) and Air Force Research Laboratory, Air Force
30  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
31  *
32  */
33 
34 #include "pf.h"
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/mbuf.h>
39 #include <sys/socket.h>
40 #include <sys/ioctl.h>
41 #include <sys/timeout.h>
42 #include <sys/kernel.h>
43 
44 #include <crypto/siphash.h>
45 
46 #include <net/if.h>
47 
48 #include <netinet/in.h>
49 #include <netinet/if_ether.h>
50 
51 #include <net/if_bridge.h>
52 
53 
54 int	bridge_rtfind(struct bridge_softc *, struct ifbaconf *);
55 void	bridge_rtage(struct bridge_softc *);
56 int	bridge_rtdaddr(struct bridge_softc *, struct ether_addr *);
57 u_int32_t bridge_hash(struct bridge_softc *, struct ether_addr *);
58 
59 int	bridge_brlconf(struct bridge_softc *, struct ifbrlconf *);
60 int	bridge_addrule(struct bridge_iflist *, struct ifbrlreq *, int out);
61 
62 int
63 bridgectl_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
64 {
65 	struct bridge_softc *sc = (struct bridge_softc *)ifp->if_softc;
66 	struct ifbreq *req = (struct ifbreq *)data;
67 	struct ifbrlreq *brlreq = (struct ifbrlreq *)data;
68 	struct ifbareq *bareq = (struct ifbareq *)data;
69 	struct ifbrparam *bparam = (struct ifbrparam *)data;
70 	struct bridge_iflist *p;
71 	struct ifnet *ifs;
72 	int error = 0;
73 
74 	switch (cmd) {
75 	case SIOCBRDGRTS:
76 		error = bridge_rtfind(sc, (struct ifbaconf *)data);
77 		break;
78 	case SIOCBRDGFLUSH:
79 		bridge_rtflush(sc, req->ifbr_ifsflags);
80 		break;
81 	case SIOCBRDGSADDR:
82 		ifs = ifunit(bareq->ifba_ifsname);
83 		if (ifs == NULL) {			/* no such interface */
84 			error = ENOENT;
85 			break;
86 		}
87 		p = (struct bridge_iflist *)ifs->if_bridgeport;
88 		if (p == NULL || p->bridge_sc != sc) {
89 			error = ESRCH;
90 			break;
91 		}
92 
93 		ifs = bridge_rtupdate(sc, &bareq->ifba_dst, ifs, 1,
94 		    bareq->ifba_flags, NULL);
95 		if (ifs == NULL)
96 			error = ENOMEM;
97 		break;
98 	case SIOCBRDGDADDR:
99 		error = bridge_rtdaddr(sc, &bareq->ifba_dst);
100 		break;
101 	case SIOCBRDGGCACHE:
102 		bparam->ifbrp_csize = sc->sc_brtmax;
103 		break;
104 	case SIOCBRDGSCACHE:
105 		sc->sc_brtmax = bparam->ifbrp_csize;
106 		break;
107 	case SIOCBRDGSTO:
108 		if (bparam->ifbrp_ctime < 0 ||
109 		    bparam->ifbrp_ctime > INT_MAX / hz) {
110 			error = EINVAL;
111 			break;
112 		}
113 		sc->sc_brttimeout = bparam->ifbrp_ctime;
114 		if (bparam->ifbrp_ctime != 0)
115 			timeout_add_sec(&sc->sc_brtimeout, sc->sc_brttimeout);
116 		else
117 			timeout_del(&sc->sc_brtimeout);
118 		break;
119 	case SIOCBRDGGTO:
120 		bparam->ifbrp_ctime = sc->sc_brttimeout;
121 		break;
122 	case SIOCBRDGARL:
123 		ifs = ifunit(brlreq->ifbr_ifsname);
124 		if (ifs == NULL) {
125 			error = ENOENT;
126 			break;
127 		}
128 		p = (struct bridge_iflist *)ifs->if_bridgeport;
129 		if (p == NULL || p->bridge_sc != sc) {
130 			error = ESRCH;
131 			break;
132 		}
133 		if ((brlreq->ifbr_action != BRL_ACTION_BLOCK &&
134 		    brlreq->ifbr_action != BRL_ACTION_PASS) ||
135 		    (brlreq->ifbr_flags & (BRL_FLAG_IN|BRL_FLAG_OUT)) == 0) {
136 			error = EINVAL;
137 			break;
138 		}
139 		if (brlreq->ifbr_flags & BRL_FLAG_IN) {
140 			error = bridge_addrule(p, brlreq, 0);
141 			if (error)
142 				break;
143 		}
144 		if (brlreq->ifbr_flags & BRL_FLAG_OUT) {
145 			error = bridge_addrule(p, brlreq, 1);
146 			if (error)
147 				break;
148 		}
149 		break;
150 	case SIOCBRDGFRL:
151 		ifs = ifunit(brlreq->ifbr_ifsname);
152 		if (ifs == NULL) {
153 			error = ENOENT;
154 			break;
155 		}
156 		p = (struct bridge_iflist *)ifs->if_bridgeport;
157 		if (p == NULL || p->bridge_sc != sc) {
158 			error = ESRCH;
159 			break;
160 		}
161 		bridge_flushrule(p);
162 		break;
163 	case SIOCBRDGGRL:
164 		error = bridge_brlconf(sc, (struct ifbrlconf *)data);
165 		break;
166 	default:
167 		break;
168 	}
169 
170 	return (error);
171 }
172 
173 struct ifnet *
174 bridge_rtupdate(struct bridge_softc *sc, struct ether_addr *ea,
175     struct ifnet *ifp, int setflags, u_int8_t flags, struct mbuf *m)
176 {
177 	struct bridge_rtnode *p, *q;
178 	struct bridge_tunneltag	*brtag = NULL;
179 	u_int32_t h;
180 	int dir;
181 
182 	if (m != NULL) {
183 		/* Check if the mbuf was tagged with a tunnel endpoint addr */
184 		brtag = bridge_tunnel(m);
185 	}
186 
187 	h = bridge_hash(sc, ea);
188 	p = LIST_FIRST(&sc->sc_rts[h]);
189 	if (p == NULL) {
190 		if (sc->sc_brtcnt >= sc->sc_brtmax)
191 			goto done;
192 		p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
193 		if (p == NULL)
194 			goto done;
195 
196 		bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
197 		p->brt_if = ifp;
198 		p->brt_age = 1;
199 		bridge_copytag(brtag, &p->brt_tunnel);
200 
201 		if (setflags)
202 			p->brt_flags = flags;
203 		else
204 			p->brt_flags = IFBAF_DYNAMIC;
205 
206 		LIST_INSERT_HEAD(&sc->sc_rts[h], p, brt_next);
207 		sc->sc_brtcnt++;
208 		goto want;
209 	}
210 
211 	do {
212 		q = p;
213 		p = LIST_NEXT(p, brt_next);
214 
215 		dir = memcmp(ea, &q->brt_addr, sizeof(q->brt_addr));
216 		if (dir == 0) {
217 			if (setflags) {
218 				q->brt_if = ifp;
219 				q->brt_flags = flags;
220 			} else if (!(q->brt_flags & IFBAF_STATIC))
221 				q->brt_if = ifp;
222 
223 			if (q->brt_if == ifp)
224 				q->brt_age = 1;
225 			ifp = q->brt_if;
226 			bridge_copytag(brtag, &q->brt_tunnel);
227 
228 			goto want;
229 		}
230 
231 		if (dir > 0) {
232 			if (sc->sc_brtcnt >= sc->sc_brtmax)
233 				goto done;
234 			p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
235 			if (p == NULL)
236 				goto done;
237 
238 			bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
239 			p->brt_if = ifp;
240 			p->brt_age = 1;
241 			bridge_copytag(brtag, &p->brt_tunnel);
242 
243 			if (setflags)
244 				p->brt_flags = flags;
245 			else
246 				p->brt_flags = IFBAF_DYNAMIC;
247 
248 			LIST_INSERT_BEFORE(q, p, brt_next);
249 			sc->sc_brtcnt++;
250 			goto want;
251 		}
252 
253 		if (p == NULL) {
254 			if (sc->sc_brtcnt >= sc->sc_brtmax)
255 				goto done;
256 			p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
257 			if (p == NULL)
258 				goto done;
259 
260 			bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
261 			p->brt_if = ifp;
262 			p->brt_age = 1;
263 			bridge_copytag(brtag, &p->brt_tunnel);
264 
265 			if (setflags)
266 				p->brt_flags = flags;
267 			else
268 				p->brt_flags = IFBAF_DYNAMIC;
269 			LIST_INSERT_AFTER(q, p, brt_next);
270 			sc->sc_brtcnt++;
271 			goto want;
272 		}
273 	} while (p != NULL);
274 
275 done:
276 	ifp = NULL;
277 want:
278 	return (ifp);
279 }
280 
281 struct bridge_rtnode *
282 bridge_rtlookup(struct bridge_softc *sc, struct ether_addr *ea)
283 {
284 	struct bridge_rtnode *p;
285 	u_int32_t h;
286 	int dir;
287 
288 	h = bridge_hash(sc, ea);
289 	LIST_FOREACH(p, &sc->sc_rts[h], brt_next) {
290 		dir = memcmp(ea, &p->brt_addr, sizeof(p->brt_addr));
291 		if (dir == 0)
292 			return (p);
293 		if (dir > 0)
294 			goto fail;
295 	}
296 fail:
297 	return (NULL);
298 }
299 
300 u_int32_t
301 bridge_hash(struct bridge_softc *sc, struct ether_addr *addr)
302 {
303 	return SipHash24((SIPHASH_KEY *)sc->sc_hashkey, addr, ETHER_ADDR_LEN) &
304 	    BRIDGE_RTABLE_MASK;
305 }
306 
307 void
308 bridge_timer(void *vsc)
309 {
310 	struct bridge_softc *sc = vsc;
311 	int s;
312 
313 	s = splsoftnet();
314 	bridge_rtage(sc);
315 	splx(s);
316 }
317 
318 /*
319  * Perform an aging cycle
320  */
321 void
322 bridge_rtage(struct bridge_softc *sc)
323 {
324 	struct bridge_rtnode *n, *p;
325 	int i;
326 
327 	for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
328 		n = LIST_FIRST(&sc->sc_rts[i]);
329 		while (n != NULL) {
330 			if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_STATIC) {
331 				n->brt_age = !n->brt_age;
332 				if (n->brt_age)
333 					n->brt_age = 0;
334 				n = LIST_NEXT(n, brt_next);
335 			} else if (n->brt_age) {
336 				n->brt_age = 0;
337 				n = LIST_NEXT(n, brt_next);
338 			} else {
339 				p = LIST_NEXT(n, brt_next);
340 				LIST_REMOVE(n, brt_next);
341 				sc->sc_brtcnt--;
342 				free(n, M_DEVBUF, sizeof *n);
343 				n = p;
344 			}
345 		}
346 	}
347 
348 	if (sc->sc_brttimeout != 0)
349 		timeout_add_sec(&sc->sc_brtimeout, sc->sc_brttimeout);
350 }
351 
352 void
353 bridge_rtagenode(struct ifnet *ifp, int age)
354 {
355 	struct bridge_softc *sc;
356 	struct bridge_rtnode *n;
357 	int i;
358 
359 	sc = ((struct bridge_iflist *)ifp->if_bridgeport)->bridge_sc;
360 	if (sc == NULL)
361 		return;
362 
363 	/*
364 	 * If the age is zero then flush, otherwise set all the expiry times to
365 	 * age for the interface
366 	 */
367 	if (age == 0)
368 		bridge_rtdelete(sc, ifp, 1);
369 	else {
370 		for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
371 			LIST_FOREACH(n, &sc->sc_rts[i], brt_next) {
372 				/* Cap the expiry time to 'age' */
373 				if (n->brt_if == ifp &&
374 				    n->brt_age > time_uptime + age &&
375 				    (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)
376 					n->brt_age = time_uptime + age;
377 			}
378 		}
379 	}
380 }
381 
382 /*
383  * Remove all dynamic addresses from the cache
384  */
385 void
386 bridge_rtflush(struct bridge_softc *sc, int full)
387 {
388 	int i;
389 	struct bridge_rtnode *p, *n;
390 
391 	for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
392 		n = LIST_FIRST(&sc->sc_rts[i]);
393 		while (n != NULL) {
394 			if (full ||
395 			    (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
396 				p = LIST_NEXT(n, brt_next);
397 				LIST_REMOVE(n, brt_next);
398 				sc->sc_brtcnt--;
399 				free(n, M_DEVBUF, sizeof *n);
400 				n = p;
401 			} else
402 				n = LIST_NEXT(n, brt_next);
403 		}
404 	}
405 }
406 
407 /*
408  * Remove an address from the cache
409  */
410 int
411 bridge_rtdaddr(struct bridge_softc *sc, struct ether_addr *ea)
412 {
413 	int h;
414 	struct bridge_rtnode *p;
415 
416 	h = bridge_hash(sc, ea);
417 	LIST_FOREACH(p, &sc->sc_rts[h], brt_next) {
418 		if (bcmp(ea, &p->brt_addr, sizeof(p->brt_addr)) == 0) {
419 			LIST_REMOVE(p, brt_next);
420 			sc->sc_brtcnt--;
421 			free(p, M_DEVBUF, sizeof *p);
422 			return (0);
423 		}
424 	}
425 
426 	return (ENOENT);
427 }
428 
429 /*
430  * Delete routes to a specific interface member.
431  */
432 void
433 bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp, int dynonly)
434 {
435 	int i;
436 	struct bridge_rtnode *n, *p;
437 
438 	/*
439 	 * Loop through all of the hash buckets and traverse each
440 	 * chain looking for routes to this interface.
441 	 */
442 	for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
443 		n = LIST_FIRST(&sc->sc_rts[i]);
444 		while (n != NULL) {
445 			if (n->brt_if != ifp) {
446 				/* Not ours */
447 				n = LIST_NEXT(n, brt_next);
448 				continue;
449 			}
450 			if (dynonly &&
451 			    (n->brt_flags & IFBAF_TYPEMASK) != IFBAF_DYNAMIC) {
452 				/* only deleting dynamics */
453 				n = LIST_NEXT(n, brt_next);
454 				continue;
455 			}
456 			p = LIST_NEXT(n, brt_next);
457 			LIST_REMOVE(n, brt_next);
458 			sc->sc_brtcnt--;
459 			free(n, M_DEVBUF, sizeof *n);
460 			n = p;
461 		}
462 	}
463 }
464 
465 /*
466  * Gather all of the routes for this interface.
467  */
468 int
469 bridge_rtfind(struct bridge_softc *sc, struct ifbaconf *baconf)
470 {
471 	int i, error = 0, onlycnt = 0;
472 	u_int32_t cnt = 0;
473 	struct bridge_rtnode *n;
474 	struct ifbareq bareq;
475 
476 	if (baconf->ifbac_len == 0)
477 		onlycnt = 1;
478 
479 	for (i = 0, cnt = 0; i < BRIDGE_RTABLE_SIZE; i++) {
480 		LIST_FOREACH(n, &sc->sc_rts[i], brt_next) {
481 			if (!onlycnt) {
482 				if (baconf->ifbac_len < sizeof(struct ifbareq))
483 					goto done;
484 				bcopy(sc->sc_if.if_xname, bareq.ifba_name,
485 				    sizeof(bareq.ifba_name));
486 				bcopy(n->brt_if->if_xname, bareq.ifba_ifsname,
487 				    sizeof(bareq.ifba_ifsname));
488 				bcopy(&n->brt_addr, &bareq.ifba_dst,
489 				    sizeof(bareq.ifba_dst));
490 				bridge_copyaddr(&n->brt_tunnel.brtag_peer.sa,
491 				    (struct sockaddr *)&bareq.ifba_dstsa);
492 				bareq.ifba_age = n->brt_age;
493 				bareq.ifba_flags = n->brt_flags;
494 				error = copyout((caddr_t)&bareq,
495 				    (caddr_t)(baconf->ifbac_req + cnt), sizeof(bareq));
496 				if (error)
497 					goto done;
498 				baconf->ifbac_len -= sizeof(struct ifbareq);
499 			}
500 			cnt++;
501 		}
502 	}
503 done:
504 	baconf->ifbac_len = cnt * sizeof(struct ifbareq);
505 	return (error);
506 }
507 
508 void
509 bridge_update(struct ifnet *ifp, struct ether_addr *ea, int delete)
510 {
511 	struct bridge_softc *sc;
512 	struct bridge_iflist *bif;
513 	u_int8_t *addr;
514 
515 	addr = (u_int8_t *)ea;
516 
517 	bif = (struct bridge_iflist *)ifp->if_bridgeport;
518 	sc = bif->bridge_sc;
519 
520 	/*
521 	 * Update the bridge interface if it is in
522 	 * the learning state.
523 	 */
524 	if ((bif->bif_flags & IFBIF_LEARNING) &&
525 	    (ETHER_IS_MULTICAST(addr) == 0) &&
526 	    !(addr[0] == 0 && addr[1] == 0 && addr[2] == 0 &&
527 	      addr[3] == 0 && addr[4] == 0 && addr[5] == 0)) {
528 		/* Care must be taken with spanning tree */
529 		if ((bif->bif_flags & IFBIF_STP) &&
530 		    (bif->bif_state == BSTP_IFSTATE_DISCARDING))
531 			return;
532 
533 		/* Delete the address from the bridge */
534 		bridge_rtdaddr(sc, ea);
535 
536 		if (!delete) {
537 			/* Update the bridge table */
538 			bridge_rtupdate(sc, ea, ifp, 0, IFBAF_DYNAMIC, NULL);
539 		}
540 	}
541 }
542 
543 /*
544  * bridge filter/matching rules
545  */
546 int
547 bridge_brlconf(struct bridge_softc *sc, struct ifbrlconf *bc)
548 {
549 	struct ifnet *ifp;
550 	struct bridge_iflist *ifl;
551 	struct brl_node *n;
552 	struct ifbrlreq req;
553 	int error = 0;
554 	u_int32_t i = 0, total = 0;
555 
556 	ifp = ifunit(bc->ifbrl_ifsname);
557 	if (ifp == NULL)
558 		return (ENOENT);
559 	ifl = (struct bridge_iflist *)ifp->if_bridgeport;
560 	if (ifl == NULL || ifl->bridge_sc != sc)
561 		return (ESRCH);
562 
563 	SIMPLEQ_FOREACH(n, &ifl->bif_brlin, brl_next) {
564 		total++;
565 	}
566 	SIMPLEQ_FOREACH(n, &ifl->bif_brlout, brl_next) {
567 		total++;
568 	}
569 
570 	if (bc->ifbrl_len == 0) {
571 		i = total;
572 		goto done;
573 	}
574 
575 	SIMPLEQ_FOREACH(n, &ifl->bif_brlin, brl_next) {
576 		bzero(&req, sizeof req);
577 		if (bc->ifbrl_len < sizeof(req))
578 			goto done;
579 		strlcpy(req.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
580 		strlcpy(req.ifbr_ifsname, ifl->ifp->if_xname, IFNAMSIZ);
581 		req.ifbr_action = n->brl_action;
582 		req.ifbr_flags = n->brl_flags;
583 		req.ifbr_src = n->brl_src;
584 		req.ifbr_dst = n->brl_dst;
585 #if NPF > 0
586 		req.ifbr_tagname[0] = '\0';
587 		if (n->brl_tag)
588 			pf_tag2tagname(n->brl_tag, req.ifbr_tagname);
589 #endif
590 		error = copyout((caddr_t)&req,
591 		    (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
592 		if (error)
593 			goto done;
594 		i++;
595 		bc->ifbrl_len -= sizeof(req);
596 	}
597 
598 	SIMPLEQ_FOREACH(n, &ifl->bif_brlout, brl_next) {
599 		bzero(&req, sizeof req);
600 		if (bc->ifbrl_len < sizeof(req))
601 			goto done;
602 		strlcpy(req.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
603 		strlcpy(req.ifbr_ifsname, ifl->ifp->if_xname, IFNAMSIZ);
604 		req.ifbr_action = n->brl_action;
605 		req.ifbr_flags = n->brl_flags;
606 		req.ifbr_src = n->brl_src;
607 		req.ifbr_dst = n->brl_dst;
608 #if NPF > 0
609 		req.ifbr_tagname[0] = '\0';
610 		if (n->brl_tag)
611 			pf_tag2tagname(n->brl_tag, req.ifbr_tagname);
612 #endif
613 		error = copyout((caddr_t)&req,
614 		    (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
615 		if (error)
616 			goto done;
617 		i++;
618 		bc->ifbrl_len -= sizeof(req);
619 	}
620 
621 done:
622 	bc->ifbrl_len = i * sizeof(req);
623 	return (error);
624 }
625 
626 u_int8_t
627 bridge_filterrule(struct brl_head *h, struct ether_header *eh, struct mbuf *m)
628 {
629 	struct brl_node *n;
630 	u_int8_t flags;
631 
632 	SIMPLEQ_FOREACH(n, h, brl_next) {
633 		flags = n->brl_flags & (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID);
634 		if (flags == 0)
635 			goto return_action;
636 		if (flags == (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID)) {
637 			if (bcmp(eh->ether_shost, &n->brl_src, ETHER_ADDR_LEN))
638 				continue;
639 			if (bcmp(eh->ether_dhost, &n->brl_dst, ETHER_ADDR_LEN))
640 				continue;
641 			goto return_action;
642 		}
643 		if (flags == BRL_FLAG_SRCVALID) {
644 			if (bcmp(eh->ether_shost, &n->brl_src, ETHER_ADDR_LEN))
645 				continue;
646 			goto return_action;
647 		}
648 		if (flags == BRL_FLAG_DSTVALID) {
649 			if (bcmp(eh->ether_dhost, &n->brl_dst, ETHER_ADDR_LEN))
650 				continue;
651 			goto return_action;
652 		}
653 	}
654 	return (BRL_ACTION_PASS);
655 
656 return_action:
657 #if NPF > 0
658 	pf_tag_packet(m, n->brl_tag, -1);
659 #endif
660 	return (n->brl_action);
661 }
662 
663 int
664 bridge_addrule(struct bridge_iflist *bif, struct ifbrlreq *req, int out)
665 {
666 	struct brl_node *n;
667 
668 	n = malloc(sizeof(*n), M_DEVBUF, M_NOWAIT);
669 	if (n == NULL)
670 		return (ENOMEM);
671 	bcopy(&req->ifbr_src, &n->brl_src, sizeof(struct ether_addr));
672 	bcopy(&req->ifbr_dst, &n->brl_dst, sizeof(struct ether_addr));
673 	n->brl_action = req->ifbr_action;
674 	n->brl_flags = req->ifbr_flags;
675 #if NPF > 0
676 	if (req->ifbr_tagname[0])
677 		n->brl_tag = pf_tagname2tag(req->ifbr_tagname, 1);
678 	else
679 		n->brl_tag = 0;
680 #endif
681 	if (out) {
682 		n->brl_flags &= ~BRL_FLAG_IN;
683 		n->brl_flags |= BRL_FLAG_OUT;
684 		SIMPLEQ_INSERT_TAIL(&bif->bif_brlout, n, brl_next);
685 	} else {
686 		n->brl_flags &= ~BRL_FLAG_OUT;
687 		n->brl_flags |= BRL_FLAG_IN;
688 		SIMPLEQ_INSERT_TAIL(&bif->bif_brlin, n, brl_next);
689 	}
690 	return (0);
691 }
692 
693 void
694 bridge_flushrule(struct bridge_iflist *bif)
695 {
696 	struct brl_node *p;
697 
698 	while (!SIMPLEQ_EMPTY(&bif->bif_brlin)) {
699 		p = SIMPLEQ_FIRST(&bif->bif_brlin);
700 		SIMPLEQ_REMOVE_HEAD(&bif->bif_brlin, brl_next);
701 #if NPF > 0
702 		pf_tag_unref(p->brl_tag);
703 #endif
704 		free(p, M_DEVBUF, sizeof *p);
705 	}
706 	while (!SIMPLEQ_EMPTY(&bif->bif_brlout)) {
707 		p = SIMPLEQ_FIRST(&bif->bif_brlout);
708 		SIMPLEQ_REMOVE_HEAD(&bif->bif_brlout, brl_next);
709 #if NPF > 0
710 		pf_tag_unref(p->brl_tag);
711 #endif
712 		free(p, M_DEVBUF, sizeof *p);
713 	}
714 }
715