1 /* $OpenBSD: bridgectl.c,v 1.3 2016/09/03 13:46:57 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_src.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