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