xref: /openbsd/sys/net/bridgectl.c (revision 86bf02c9)
1 /*	$OpenBSD: bridgectl.c,v 1.2 2015/12/02 08:04:12 mpi 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 sockaddr *sa = 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 		sa = 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_copyaddr(sa, (struct sockaddr *)&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_copyaddr(sa,
227 			     (struct sockaddr *)&q->brt_tunnel);
228 
229 			goto want;
230 		}
231 
232 		if (dir > 0) {
233 			if (sc->sc_brtcnt >= sc->sc_brtmax)
234 				goto done;
235 			p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
236 			if (p == NULL)
237 				goto done;
238 
239 			bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
240 			p->brt_if = ifp;
241 			p->brt_age = 1;
242 			bridge_copyaddr(sa,
243 			    (struct sockaddr *)&p->brt_tunnel);
244 
245 			if (setflags)
246 				p->brt_flags = flags;
247 			else
248 				p->brt_flags = IFBAF_DYNAMIC;
249 
250 			LIST_INSERT_BEFORE(q, p, brt_next);
251 			sc->sc_brtcnt++;
252 			goto want;
253 		}
254 
255 		if (p == NULL) {
256 			if (sc->sc_brtcnt >= sc->sc_brtmax)
257 				goto done;
258 			p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT);
259 			if (p == NULL)
260 				goto done;
261 
262 			bcopy(ea, &p->brt_addr, sizeof(p->brt_addr));
263 			p->brt_if = ifp;
264 			p->brt_age = 1;
265 			bridge_copyaddr(sa,
266 			    (struct sockaddr *)&p->brt_tunnel);
267 
268 			if (setflags)
269 				p->brt_flags = flags;
270 			else
271 				p->brt_flags = IFBAF_DYNAMIC;
272 			LIST_INSERT_AFTER(q, p, brt_next);
273 			sc->sc_brtcnt++;
274 			goto want;
275 		}
276 	} while (p != NULL);
277 
278 done:
279 	ifp = NULL;
280 want:
281 	return (ifp);
282 }
283 
284 struct bridge_rtnode *
285 bridge_rtlookup(struct bridge_softc *sc, struct ether_addr *ea)
286 {
287 	struct bridge_rtnode *p;
288 	u_int32_t h;
289 	int dir;
290 
291 	h = bridge_hash(sc, ea);
292 	LIST_FOREACH(p, &sc->sc_rts[h], brt_next) {
293 		dir = memcmp(ea, &p->brt_addr, sizeof(p->brt_addr));
294 		if (dir == 0)
295 			return (p);
296 		if (dir > 0)
297 			goto fail;
298 	}
299 fail:
300 	return (NULL);
301 }
302 
303 u_int32_t
304 bridge_hash(struct bridge_softc *sc, struct ether_addr *addr)
305 {
306 	return SipHash24((SIPHASH_KEY *)sc->sc_hashkey, addr, ETHER_ADDR_LEN) &
307 	    BRIDGE_RTABLE_MASK;
308 }
309 
310 void
311 bridge_timer(void *vsc)
312 {
313 	struct bridge_softc *sc = vsc;
314 	int s;
315 
316 	s = splsoftnet();
317 	bridge_rtage(sc);
318 	splx(s);
319 }
320 
321 /*
322  * Perform an aging cycle
323  */
324 void
325 bridge_rtage(struct bridge_softc *sc)
326 {
327 	struct bridge_rtnode *n, *p;
328 	int i;
329 
330 	for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
331 		n = LIST_FIRST(&sc->sc_rts[i]);
332 		while (n != NULL) {
333 			if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_STATIC) {
334 				n->brt_age = !n->brt_age;
335 				if (n->brt_age)
336 					n->brt_age = 0;
337 				n = LIST_NEXT(n, brt_next);
338 			} else if (n->brt_age) {
339 				n->brt_age = 0;
340 				n = LIST_NEXT(n, brt_next);
341 			} else {
342 				p = LIST_NEXT(n, brt_next);
343 				LIST_REMOVE(n, brt_next);
344 				sc->sc_brtcnt--;
345 				free(n, M_DEVBUF, sizeof *n);
346 				n = p;
347 			}
348 		}
349 	}
350 
351 	if (sc->sc_brttimeout != 0)
352 		timeout_add_sec(&sc->sc_brtimeout, sc->sc_brttimeout);
353 }
354 
355 void
356 bridge_rtagenode(struct ifnet *ifp, int age)
357 {
358 	struct bridge_softc *sc;
359 	struct bridge_rtnode *n;
360 	int i;
361 
362 	sc = ((struct bridge_iflist *)ifp->if_bridgeport)->bridge_sc;
363 	if (sc == NULL)
364 		return;
365 
366 	/*
367 	 * If the age is zero then flush, otherwise set all the expiry times to
368 	 * age for the interface
369 	 */
370 	if (age == 0)
371 		bridge_rtdelete(sc, ifp, 1);
372 	else {
373 		for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
374 			LIST_FOREACH(n, &sc->sc_rts[i], brt_next) {
375 				/* Cap the expiry time to 'age' */
376 				if (n->brt_if == ifp &&
377 				    n->brt_age > time_uptime + age &&
378 				    (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC)
379 					n->brt_age = time_uptime + age;
380 			}
381 		}
382 	}
383 }
384 
385 /*
386  * Remove all dynamic addresses from the cache
387  */
388 void
389 bridge_rtflush(struct bridge_softc *sc, int full)
390 {
391 	int i;
392 	struct bridge_rtnode *p, *n;
393 
394 	for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
395 		n = LIST_FIRST(&sc->sc_rts[i]);
396 		while (n != NULL) {
397 			if (full ||
398 			    (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) {
399 				p = LIST_NEXT(n, brt_next);
400 				LIST_REMOVE(n, brt_next);
401 				sc->sc_brtcnt--;
402 				free(n, M_DEVBUF, sizeof *n);
403 				n = p;
404 			} else
405 				n = LIST_NEXT(n, brt_next);
406 		}
407 	}
408 }
409 
410 /*
411  * Remove an address from the cache
412  */
413 int
414 bridge_rtdaddr(struct bridge_softc *sc, struct ether_addr *ea)
415 {
416 	int h;
417 	struct bridge_rtnode *p;
418 
419 	h = bridge_hash(sc, ea);
420 	LIST_FOREACH(p, &sc->sc_rts[h], brt_next) {
421 		if (bcmp(ea, &p->brt_addr, sizeof(p->brt_addr)) == 0) {
422 			LIST_REMOVE(p, brt_next);
423 			sc->sc_brtcnt--;
424 			free(p, M_DEVBUF, sizeof *p);
425 			return (0);
426 		}
427 	}
428 
429 	return (ENOENT);
430 }
431 
432 /*
433  * Delete routes to a specific interface member.
434  */
435 void
436 bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp, int dynonly)
437 {
438 	int i;
439 	struct bridge_rtnode *n, *p;
440 
441 	/*
442 	 * Loop through all of the hash buckets and traverse each
443 	 * chain looking for routes to this interface.
444 	 */
445 	for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) {
446 		n = LIST_FIRST(&sc->sc_rts[i]);
447 		while (n != NULL) {
448 			if (n->brt_if != ifp) {
449 				/* Not ours */
450 				n = LIST_NEXT(n, brt_next);
451 				continue;
452 			}
453 			if (dynonly &&
454 			    (n->brt_flags & IFBAF_TYPEMASK) != IFBAF_DYNAMIC) {
455 				/* only deleting dynamics */
456 				n = LIST_NEXT(n, brt_next);
457 				continue;
458 			}
459 			p = LIST_NEXT(n, brt_next);
460 			LIST_REMOVE(n, brt_next);
461 			sc->sc_brtcnt--;
462 			free(n, M_DEVBUF, sizeof *n);
463 			n = p;
464 		}
465 	}
466 }
467 
468 /*
469  * Gather all of the routes for this interface.
470  */
471 int
472 bridge_rtfind(struct bridge_softc *sc, struct ifbaconf *baconf)
473 {
474 	int i, error = 0, onlycnt = 0;
475 	u_int32_t cnt = 0;
476 	struct bridge_rtnode *n;
477 	struct ifbareq bareq;
478 
479 	if (baconf->ifbac_len == 0)
480 		onlycnt = 1;
481 
482 	for (i = 0, cnt = 0; i < BRIDGE_RTABLE_SIZE; i++) {
483 		LIST_FOREACH(n, &sc->sc_rts[i], brt_next) {
484 			if (!onlycnt) {
485 				if (baconf->ifbac_len < sizeof(struct ifbareq))
486 					goto done;
487 				bcopy(sc->sc_if.if_xname, bareq.ifba_name,
488 				    sizeof(bareq.ifba_name));
489 				bcopy(n->brt_if->if_xname, bareq.ifba_ifsname,
490 				    sizeof(bareq.ifba_ifsname));
491 				bcopy(&n->brt_addr, &bareq.ifba_dst,
492 				    sizeof(bareq.ifba_dst));
493 				bridge_copyaddr(&n->brt_tunnel.sa,
494 				    (struct sockaddr *)&bareq.ifba_dstsa);
495 				bareq.ifba_age = n->brt_age;
496 				bareq.ifba_flags = n->brt_flags;
497 				error = copyout((caddr_t)&bareq,
498 				    (caddr_t)(baconf->ifbac_req + cnt), sizeof(bareq));
499 				if (error)
500 					goto done;
501 				baconf->ifbac_len -= sizeof(struct ifbareq);
502 			}
503 			cnt++;
504 		}
505 	}
506 done:
507 	baconf->ifbac_len = cnt * sizeof(struct ifbareq);
508 	return (error);
509 }
510 
511 void
512 bridge_update(struct ifnet *ifp, struct ether_addr *ea, int delete)
513 {
514 	struct bridge_softc *sc;
515 	struct bridge_iflist *bif;
516 	u_int8_t *addr;
517 
518 	addr = (u_int8_t *)ea;
519 
520 	bif = (struct bridge_iflist *)ifp->if_bridgeport;
521 	sc = bif->bridge_sc;
522 
523 	/*
524 	 * Update the bridge interface if it is in
525 	 * the learning state.
526 	 */
527 	if ((bif->bif_flags & IFBIF_LEARNING) &&
528 	    (ETHER_IS_MULTICAST(addr) == 0) &&
529 	    !(addr[0] == 0 && addr[1] == 0 && addr[2] == 0 &&
530 	      addr[3] == 0 && addr[4] == 0 && addr[5] == 0)) {
531 		/* Care must be taken with spanning tree */
532 		if ((bif->bif_flags & IFBIF_STP) &&
533 		    (bif->bif_state == BSTP_IFSTATE_DISCARDING))
534 			return;
535 
536 		/* Delete the address from the bridge */
537 		bridge_rtdaddr(sc, ea);
538 
539 		if (!delete) {
540 			/* Update the bridge table */
541 			bridge_rtupdate(sc, ea, ifp, 0, IFBAF_DYNAMIC, NULL);
542 		}
543 	}
544 }
545 
546 /*
547  * bridge filter/matching rules
548  */
549 int
550 bridge_brlconf(struct bridge_softc *sc, struct ifbrlconf *bc)
551 {
552 	struct ifnet *ifp;
553 	struct bridge_iflist *ifl;
554 	struct brl_node *n;
555 	struct ifbrlreq req;
556 	int error = 0;
557 	u_int32_t i = 0, total = 0;
558 
559 	ifp = ifunit(bc->ifbrl_ifsname);
560 	if (ifp == NULL)
561 		return (ENOENT);
562 	ifl = (struct bridge_iflist *)ifp->if_bridgeport;
563 	if (ifl == NULL || ifl->bridge_sc != sc)
564 		return (ESRCH);
565 
566 	SIMPLEQ_FOREACH(n, &ifl->bif_brlin, brl_next) {
567 		total++;
568 	}
569 	SIMPLEQ_FOREACH(n, &ifl->bif_brlout, brl_next) {
570 		total++;
571 	}
572 
573 	if (bc->ifbrl_len == 0) {
574 		i = total;
575 		goto done;
576 	}
577 
578 	SIMPLEQ_FOREACH(n, &ifl->bif_brlin, brl_next) {
579 		bzero(&req, sizeof req);
580 		if (bc->ifbrl_len < sizeof(req))
581 			goto done;
582 		strlcpy(req.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
583 		strlcpy(req.ifbr_ifsname, ifl->ifp->if_xname, IFNAMSIZ);
584 		req.ifbr_action = n->brl_action;
585 		req.ifbr_flags = n->brl_flags;
586 		req.ifbr_src = n->brl_src;
587 		req.ifbr_dst = n->brl_dst;
588 #if NPF > 0
589 		req.ifbr_tagname[0] = '\0';
590 		if (n->brl_tag)
591 			pf_tag2tagname(n->brl_tag, req.ifbr_tagname);
592 #endif
593 		error = copyout((caddr_t)&req,
594 		    (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
595 		if (error)
596 			goto done;
597 		i++;
598 		bc->ifbrl_len -= sizeof(req);
599 	}
600 
601 	SIMPLEQ_FOREACH(n, &ifl->bif_brlout, brl_next) {
602 		bzero(&req, sizeof req);
603 		if (bc->ifbrl_len < sizeof(req))
604 			goto done;
605 		strlcpy(req.ifbr_name, sc->sc_if.if_xname, IFNAMSIZ);
606 		strlcpy(req.ifbr_ifsname, ifl->ifp->if_xname, IFNAMSIZ);
607 		req.ifbr_action = n->brl_action;
608 		req.ifbr_flags = n->brl_flags;
609 		req.ifbr_src = n->brl_src;
610 		req.ifbr_dst = n->brl_dst;
611 #if NPF > 0
612 		req.ifbr_tagname[0] = '\0';
613 		if (n->brl_tag)
614 			pf_tag2tagname(n->brl_tag, req.ifbr_tagname);
615 #endif
616 		error = copyout((caddr_t)&req,
617 		    (caddr_t)(bc->ifbrl_buf + (i * sizeof(req))), sizeof(req));
618 		if (error)
619 			goto done;
620 		i++;
621 		bc->ifbrl_len -= sizeof(req);
622 	}
623 
624 done:
625 	bc->ifbrl_len = i * sizeof(req);
626 	return (error);
627 }
628 
629 u_int8_t
630 bridge_filterrule(struct brl_head *h, struct ether_header *eh, struct mbuf *m)
631 {
632 	struct brl_node *n;
633 	u_int8_t flags;
634 
635 	SIMPLEQ_FOREACH(n, h, brl_next) {
636 		flags = n->brl_flags & (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID);
637 		if (flags == 0)
638 			goto return_action;
639 		if (flags == (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID)) {
640 			if (bcmp(eh->ether_shost, &n->brl_src, ETHER_ADDR_LEN))
641 				continue;
642 			if (bcmp(eh->ether_dhost, &n->brl_dst, ETHER_ADDR_LEN))
643 				continue;
644 			goto return_action;
645 		}
646 		if (flags == BRL_FLAG_SRCVALID) {
647 			if (bcmp(eh->ether_shost, &n->brl_src, ETHER_ADDR_LEN))
648 				continue;
649 			goto return_action;
650 		}
651 		if (flags == BRL_FLAG_DSTVALID) {
652 			if (bcmp(eh->ether_dhost, &n->brl_dst, ETHER_ADDR_LEN))
653 				continue;
654 			goto return_action;
655 		}
656 	}
657 	return (BRL_ACTION_PASS);
658 
659 return_action:
660 #if NPF > 0
661 	pf_tag_packet(m, n->brl_tag, -1);
662 #endif
663 	return (n->brl_action);
664 }
665 
666 int
667 bridge_addrule(struct bridge_iflist *bif, struct ifbrlreq *req, int out)
668 {
669 	struct brl_node *n;
670 
671 	n = malloc(sizeof(*n), M_DEVBUF, M_NOWAIT);
672 	if (n == NULL)
673 		return (ENOMEM);
674 	bcopy(&req->ifbr_src, &n->brl_src, sizeof(struct ether_addr));
675 	bcopy(&req->ifbr_dst, &n->brl_dst, sizeof(struct ether_addr));
676 	n->brl_action = req->ifbr_action;
677 	n->brl_flags = req->ifbr_flags;
678 #if NPF > 0
679 	if (req->ifbr_tagname[0])
680 		n->brl_tag = pf_tagname2tag(req->ifbr_tagname, 1);
681 	else
682 		n->brl_tag = 0;
683 #endif
684 	if (out) {
685 		n->brl_flags &= ~BRL_FLAG_IN;
686 		n->brl_flags |= BRL_FLAG_OUT;
687 		SIMPLEQ_INSERT_TAIL(&bif->bif_brlout, n, brl_next);
688 	} else {
689 		n->brl_flags &= ~BRL_FLAG_OUT;
690 		n->brl_flags |= BRL_FLAG_IN;
691 		SIMPLEQ_INSERT_TAIL(&bif->bif_brlin, n, brl_next);
692 	}
693 	return (0);
694 }
695 
696 void
697 bridge_flushrule(struct bridge_iflist *bif)
698 {
699 	struct brl_node *p;
700 
701 	while (!SIMPLEQ_EMPTY(&bif->bif_brlin)) {
702 		p = SIMPLEQ_FIRST(&bif->bif_brlin);
703 		SIMPLEQ_REMOVE_HEAD(&bif->bif_brlin, brl_next);
704 #if NPF > 0
705 		pf_tag_unref(p->brl_tag);
706 #endif
707 		free(p, M_DEVBUF, sizeof *p);
708 	}
709 	while (!SIMPLEQ_EMPTY(&bif->bif_brlout)) {
710 		p = SIMPLEQ_FIRST(&bif->bif_brlout);
711 		SIMPLEQ_REMOVE_HEAD(&bif->bif_brlout, brl_next);
712 #if NPF > 0
713 		pf_tag_unref(p->brl_tag);
714 #endif
715 		free(p, M_DEVBUF, sizeof *p);
716 	}
717 }
718