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