1 /* $OpenBSD: bridgectl.c,v 1.13 2018/12/12 14:19:15 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 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_iflist *, 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 ifbrlconf *bc = (struct ifbrlconf *)data; 68 struct ifbareq *bareq = (struct ifbareq *)data; 69 struct ifbrparam *bparam = (struct ifbrparam *)data; 70 struct bridge_iflist *bif; 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 bif = (struct bridge_iflist *)ifs->if_bridgeport; 88 if (bif == NULL || bif->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 bif = (struct bridge_iflist *)ifs->if_bridgeport; 129 if (bif == NULL || bif->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(bif, brlreq, 0); 141 if (error) 142 break; 143 } 144 if (brlreq->ifbr_flags & BRL_FLAG_OUT) { 145 error = bridge_addrule(bif, 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 bif = (struct bridge_iflist *)ifs->if_bridgeport; 157 if (bif == NULL || bif->bridge_sc != sc) { 158 error = ESRCH; 159 break; 160 } 161 bridge_flushrule(bif); 162 break; 163 case SIOCBRDGGRL: 164 ifs = ifunit(bc->ifbrl_ifsname); 165 if (ifs == NULL) { 166 error = ENOENT; 167 break; 168 } 169 bif = (struct bridge_iflist *)ifs->if_bridgeport; 170 if (bif == NULL || bif->bridge_sc != sc) { 171 error = ESRCH; 172 break; 173 } 174 error = bridge_brlconf(bif, bc); 175 break; 176 default: 177 break; 178 } 179 180 return (error); 181 } 182 183 struct ifnet * 184 bridge_rtupdate(struct bridge_softc *sc, struct ether_addr *ea, 185 struct ifnet *ifp, int setflags, u_int8_t flags, struct mbuf *m) 186 { 187 struct bridge_rtnode *p, *q; 188 struct bridge_tunneltag *brtag = NULL; 189 u_int32_t h; 190 int dir; 191 192 if (m != NULL) { 193 /* Check if the mbuf was tagged with a tunnel endpoint addr */ 194 brtag = bridge_tunnel(m); 195 } 196 197 h = bridge_hash(sc, ea); 198 p = LIST_FIRST(&sc->sc_rts[h]); 199 if (p == NULL) { 200 if (sc->sc_brtcnt >= sc->sc_brtmax) 201 goto done; 202 p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT); 203 if (p == NULL) 204 goto done; 205 206 bcopy(ea, &p->brt_addr, sizeof(p->brt_addr)); 207 p->brt_if = ifp; 208 p->brt_age = 1; 209 bridge_copytag(brtag, &p->brt_tunnel); 210 211 if (setflags) 212 p->brt_flags = flags; 213 else 214 p->brt_flags = IFBAF_DYNAMIC; 215 216 LIST_INSERT_HEAD(&sc->sc_rts[h], p, brt_next); 217 sc->sc_brtcnt++; 218 goto want; 219 } 220 221 do { 222 q = p; 223 p = LIST_NEXT(p, brt_next); 224 225 dir = memcmp(ea, &q->brt_addr, sizeof(q->brt_addr)); 226 if (dir == 0) { 227 if (setflags) { 228 q->brt_if = ifp; 229 q->brt_flags = flags; 230 } else if (!(q->brt_flags & IFBAF_STATIC)) 231 q->brt_if = ifp; 232 233 if (q->brt_if == ifp) 234 q->brt_age = 1; 235 ifp = q->brt_if; 236 bridge_copytag(brtag, &q->brt_tunnel); 237 238 goto want; 239 } 240 241 if (dir > 0) { 242 if (sc->sc_brtcnt >= sc->sc_brtmax) 243 goto done; 244 p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT); 245 if (p == NULL) 246 goto done; 247 248 bcopy(ea, &p->brt_addr, sizeof(p->brt_addr)); 249 p->brt_if = ifp; 250 p->brt_age = 1; 251 bridge_copytag(brtag, &p->brt_tunnel); 252 253 if (setflags) 254 p->brt_flags = flags; 255 else 256 p->brt_flags = IFBAF_DYNAMIC; 257 258 LIST_INSERT_BEFORE(q, p, brt_next); 259 sc->sc_brtcnt++; 260 goto want; 261 } 262 263 if (p == NULL) { 264 if (sc->sc_brtcnt >= sc->sc_brtmax) 265 goto done; 266 p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT); 267 if (p == NULL) 268 goto done; 269 270 bcopy(ea, &p->brt_addr, sizeof(p->brt_addr)); 271 p->brt_if = ifp; 272 p->brt_age = 1; 273 bridge_copytag(brtag, &p->brt_tunnel); 274 275 if (setflags) 276 p->brt_flags = flags; 277 else 278 p->brt_flags = IFBAF_DYNAMIC; 279 LIST_INSERT_AFTER(q, p, brt_next); 280 sc->sc_brtcnt++; 281 goto want; 282 } 283 } while (p != NULL); 284 285 done: 286 ifp = NULL; 287 want: 288 return (ifp); 289 } 290 291 struct bridge_rtnode * 292 bridge_rtlookup(struct bridge_softc *sc, struct ether_addr *ea) 293 { 294 struct bridge_rtnode *p; 295 u_int32_t h; 296 int dir; 297 298 h = bridge_hash(sc, ea); 299 LIST_FOREACH(p, &sc->sc_rts[h], brt_next) { 300 dir = memcmp(ea, &p->brt_addr, sizeof(p->brt_addr)); 301 if (dir == 0) 302 return (p); 303 if (dir > 0) 304 goto fail; 305 } 306 fail: 307 return (NULL); 308 } 309 310 u_int32_t 311 bridge_hash(struct bridge_softc *sc, struct ether_addr *addr) 312 { 313 return SipHash24((SIPHASH_KEY *)sc->sc_hashkey, addr, ETHER_ADDR_LEN) & 314 BRIDGE_RTABLE_MASK; 315 } 316 317 /* 318 * Perform an aging cycle 319 */ 320 void 321 bridge_rtage(void *vsc) 322 { 323 struct bridge_softc *sc = vsc; 324 struct bridge_rtnode *n, *p; 325 int i; 326 327 KERNEL_ASSERT_LOCKED(); 328 329 for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) { 330 n = LIST_FIRST(&sc->sc_rts[i]); 331 while (n != NULL) { 332 if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_STATIC) { 333 n->brt_age = !n->brt_age; 334 if (n->brt_age) 335 n->brt_age = 0; 336 n = LIST_NEXT(n, brt_next); 337 } else if (n->brt_age) { 338 n->brt_age = 0; 339 n = LIST_NEXT(n, brt_next); 340 } else { 341 p = LIST_NEXT(n, brt_next); 342 LIST_REMOVE(n, brt_next); 343 sc->sc_brtcnt--; 344 free(n, M_DEVBUF, sizeof *n); 345 n = p; 346 } 347 } 348 } 349 350 if (sc->sc_brttimeout != 0) 351 timeout_add_sec(&sc->sc_brtimeout, sc->sc_brttimeout); 352 } 353 354 void 355 bridge_rtagenode(struct ifnet *ifp, int age) 356 { 357 struct bridge_softc *sc; 358 struct bridge_iflist *bif; 359 struct bridge_rtnode *n; 360 int i; 361 362 bif = (struct bridge_iflist *)ifp->if_bridgeport; 363 if (bif == NULL) 364 return; 365 sc = bif->bridge_sc; 366 if (sc == NULL) 367 return; 368 369 /* 370 * If the age is zero then flush, otherwise set all the expiry times to 371 * age for the interface 372 */ 373 if (age == 0) 374 bridge_rtdelete(sc, ifp, 1); 375 else { 376 for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) { 377 LIST_FOREACH(n, &sc->sc_rts[i], brt_next) { 378 /* Cap the expiry time to 'age' */ 379 if (n->brt_if == ifp && 380 n->brt_age > time_uptime + age && 381 (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) 382 n->brt_age = time_uptime + age; 383 } 384 } 385 } 386 } 387 388 /* 389 * Remove all dynamic addresses from the cache 390 */ 391 void 392 bridge_rtflush(struct bridge_softc *sc, int full) 393 { 394 int i; 395 struct bridge_rtnode *p, *n; 396 397 for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) { 398 n = LIST_FIRST(&sc->sc_rts[i]); 399 while (n != NULL) { 400 if (full || 401 (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) { 402 p = LIST_NEXT(n, brt_next); 403 LIST_REMOVE(n, brt_next); 404 sc->sc_brtcnt--; 405 free(n, M_DEVBUF, sizeof *n); 406 n = p; 407 } else 408 n = LIST_NEXT(n, brt_next); 409 } 410 } 411 } 412 413 /* 414 * Remove an address from the cache 415 */ 416 int 417 bridge_rtdaddr(struct bridge_softc *sc, struct ether_addr *ea) 418 { 419 int h; 420 struct bridge_rtnode *p; 421 422 h = bridge_hash(sc, ea); 423 LIST_FOREACH(p, &sc->sc_rts[h], brt_next) { 424 if (memcmp(ea, &p->brt_addr, sizeof(p->brt_addr)) == 0) { 425 LIST_REMOVE(p, brt_next); 426 sc->sc_brtcnt--; 427 free(p, M_DEVBUF, sizeof *p); 428 return (0); 429 } 430 } 431 432 return (ENOENT); 433 } 434 435 /* 436 * Delete routes to a specific interface member. 437 */ 438 void 439 bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp, int dynonly) 440 { 441 int i; 442 struct bridge_rtnode *n, *p; 443 444 /* 445 * Loop through all of the hash buckets and traverse each 446 * chain looking for routes to this interface. 447 */ 448 for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) { 449 n = LIST_FIRST(&sc->sc_rts[i]); 450 while (n != NULL) { 451 if (n->brt_if != ifp) { 452 /* Not ours */ 453 n = LIST_NEXT(n, brt_next); 454 continue; 455 } 456 if (dynonly && 457 (n->brt_flags & IFBAF_TYPEMASK) != IFBAF_DYNAMIC) { 458 /* only deleting dynamics */ 459 n = LIST_NEXT(n, brt_next); 460 continue; 461 } 462 p = LIST_NEXT(n, brt_next); 463 LIST_REMOVE(n, brt_next); 464 sc->sc_brtcnt--; 465 free(n, M_DEVBUF, sizeof *n); 466 n = p; 467 } 468 } 469 } 470 471 /* 472 * Gather all of the routes for this interface. 473 */ 474 int 475 bridge_rtfind(struct bridge_softc *sc, struct ifbaconf *baconf) 476 { 477 struct ifbareq *bareq, *bareqs = NULL; 478 struct bridge_rtnode *n; 479 u_int32_t i = 0, total = 0; 480 int k, error = 0; 481 482 for (k = 0; k < BRIDGE_RTABLE_SIZE; k++) { 483 LIST_FOREACH(n, &sc->sc_rts[k], brt_next) 484 total++; 485 } 486 487 if (baconf->ifbac_len == 0) { 488 i = total; 489 goto done; 490 } 491 492 bareqs = mallocarray(total, sizeof(*bareqs), M_TEMP, M_NOWAIT|M_ZERO); 493 if (bareqs == NULL) 494 goto done; 495 496 for (k = 0; k < BRIDGE_RTABLE_SIZE; k++) { 497 LIST_FOREACH(n, &sc->sc_rts[k], brt_next) { 498 if (baconf->ifbac_len < (i + 1) * sizeof(*bareqs)) 499 goto done; 500 bareq = &bareqs[i]; 501 bcopy(sc->sc_if.if_xname, bareq->ifba_name, 502 sizeof(bareq->ifba_name)); 503 bcopy(n->brt_if->if_xname, bareq->ifba_ifsname, 504 sizeof(bareq->ifba_ifsname)); 505 bcopy(&n->brt_addr, &bareq->ifba_dst, 506 sizeof(bareq->ifba_dst)); 507 bridge_copyaddr(&n->brt_tunnel.brtag_peer.sa, 508 sstosa(&bareq->ifba_dstsa)); 509 bareq->ifba_age = n->brt_age; 510 bareq->ifba_flags = n->brt_flags; 511 i++; 512 } 513 } 514 515 error = copyout(bareqs, baconf->ifbac_req, i * sizeof(*bareqs)); 516 done: 517 free(bareqs, M_TEMP, total * sizeof(*bareqs)); 518 baconf->ifbac_len = i * sizeof(*bareqs); 519 return (error); 520 } 521 522 void 523 bridge_update(struct ifnet *ifp, struct ether_addr *ea, int delete) 524 { 525 struct bridge_softc *sc; 526 struct bridge_iflist *bif; 527 u_int8_t *addr; 528 529 addr = (u_int8_t *)ea; 530 531 bif = (struct bridge_iflist *)ifp->if_bridgeport; 532 if (bif == NULL) 533 return; 534 sc = bif->bridge_sc; 535 if (sc == NULL) 536 return; 537 538 /* 539 * Update the bridge interface if it is in 540 * the learning state. 541 */ 542 if ((bif->bif_flags & IFBIF_LEARNING) && 543 (ETHER_IS_MULTICAST(addr) == 0) && 544 !(addr[0] == 0 && addr[1] == 0 && addr[2] == 0 && 545 addr[3] == 0 && addr[4] == 0 && addr[5] == 0)) { 546 /* Care must be taken with spanning tree */ 547 if ((bif->bif_flags & IFBIF_STP) && 548 (bif->bif_state == BSTP_IFSTATE_DISCARDING)) 549 return; 550 551 /* Delete the address from the bridge */ 552 bridge_rtdaddr(sc, ea); 553 554 if (!delete) { 555 /* Update the bridge table */ 556 bridge_rtupdate(sc, ea, ifp, 0, IFBAF_DYNAMIC, NULL); 557 } 558 } 559 } 560 561 /* 562 * bridge filter/matching rules 563 */ 564 int 565 bridge_brlconf(struct bridge_iflist *bif, struct ifbrlconf *bc) 566 { 567 struct bridge_softc *sc = bif->bridge_sc; 568 struct brl_node *n; 569 struct ifbrlreq *req, *reqs = NULL; 570 int error = 0; 571 u_int32_t i = 0, total = 0; 572 573 SIMPLEQ_FOREACH(n, &bif->bif_brlin, brl_next) { 574 total++; 575 } 576 SIMPLEQ_FOREACH(n, &bif->bif_brlout, brl_next) { 577 total++; 578 } 579 580 if (bc->ifbrl_len == 0) { 581 i = total; 582 goto done; 583 } 584 585 reqs = mallocarray(total, sizeof(*reqs), M_TEMP, M_NOWAIT|M_ZERO); 586 if (reqs == NULL) 587 goto done; 588 589 SIMPLEQ_FOREACH(n, &bif->bif_brlin, brl_next) { 590 if (bc->ifbrl_len < (i + 1) * sizeof(*reqs)) 591 goto done; 592 req = &reqs[i]; 593 strlcpy(req->ifbr_name, sc->sc_if.if_xname, IFNAMSIZ); 594 strlcpy(req->ifbr_ifsname, bif->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 req->ifbr_arpf = n->brl_arpf; 600 #if NPF > 0 601 req->ifbr_tagname[0] = '\0'; 602 if (n->brl_tag) 603 pf_tag2tagname(n->brl_tag, req->ifbr_tagname); 604 #endif 605 i++; 606 } 607 608 SIMPLEQ_FOREACH(n, &bif->bif_brlout, brl_next) { 609 if (bc->ifbrl_len < (i + 1) * sizeof(*reqs)) 610 goto done; 611 req = &reqs[i]; 612 strlcpy(req->ifbr_name, sc->sc_if.if_xname, IFNAMSIZ); 613 strlcpy(req->ifbr_ifsname, bif->ifp->if_xname, IFNAMSIZ); 614 req->ifbr_action = n->brl_action; 615 req->ifbr_flags = n->brl_flags; 616 req->ifbr_src = n->brl_src; 617 req->ifbr_dst = n->brl_dst; 618 req->ifbr_arpf = n->brl_arpf; 619 #if NPF > 0 620 req->ifbr_tagname[0] = '\0'; 621 if (n->brl_tag) 622 pf_tag2tagname(n->brl_tag, req->ifbr_tagname); 623 #endif 624 i++; 625 } 626 627 error = copyout(reqs, bc->ifbrl_buf, i * sizeof(*reqs)); 628 done: 629 free(reqs, M_TEMP, total * sizeof(*reqs)); 630 bc->ifbrl_len = i * sizeof(*reqs); 631 return (error); 632 } 633 634 u_int8_t 635 bridge_arpfilter(struct brl_node *n, struct ether_header *eh, struct mbuf *m) 636 { 637 struct ether_arp ea; 638 639 if (!(n->brl_arpf.brla_flags & (BRLA_ARP|BRLA_RARP))) 640 return (1); 641 642 if (ntohs(eh->ether_type) != ETHERTYPE_ARP) 643 return (0); 644 if (m->m_pkthdr.len <= ETHER_HDR_LEN + sizeof(ea)) 645 return (0); /* log error? */ 646 m_copydata(m, ETHER_HDR_LEN, sizeof(ea), (caddr_t)&ea); 647 648 if (ntohs(ea.arp_hrd) != ARPHRD_ETHER || 649 ntohs(ea.arp_pro) != ETHERTYPE_IP || 650 ea.arp_hln != ETHER_ADDR_LEN || 651 ea.arp_pln != sizeof(struct in_addr)) 652 return (0); 653 if ((n->brl_arpf.brla_flags & BRLA_ARP) && 654 ntohs(ea.arp_op) != ARPOP_REQUEST && 655 ntohs(ea.arp_op) != ARPOP_REPLY) 656 return (0); 657 if ((n->brl_arpf.brla_flags & BRLA_RARP) && 658 ntohs(ea.arp_op) != ARPOP_REVREQUEST && 659 ntohs(ea.arp_op) != ARPOP_REVREPLY) 660 return (0); 661 if (n->brl_arpf.brla_op && ntohs(ea.arp_op) != n->brl_arpf.brla_op) 662 return (0); 663 if (n->brl_arpf.brla_flags & BRLA_SHA && 664 memcmp(ea.arp_sha, &n->brl_arpf.brla_sha, ETHER_ADDR_LEN)) 665 return (0); 666 if (n->brl_arpf.brla_flags & BRLA_THA && 667 memcmp(ea.arp_tha, &n->brl_arpf.brla_tha, ETHER_ADDR_LEN)) 668 return (0); 669 if (n->brl_arpf.brla_flags & BRLA_SPA && 670 memcmp(ea.arp_spa, &n->brl_arpf.brla_spa, sizeof(struct in_addr))) 671 return (0); 672 if (n->brl_arpf.brla_flags & BRLA_TPA && 673 memcmp(ea.arp_tpa, &n->brl_arpf.brla_tpa, sizeof(struct in_addr))) 674 return (0); 675 676 return (1); 677 } 678 679 u_int8_t 680 bridge_filterrule(struct brl_head *h, struct ether_header *eh, struct mbuf *m) 681 { 682 struct brl_node *n; 683 u_int8_t flags; 684 685 SIMPLEQ_FOREACH(n, h, brl_next) { 686 if (!bridge_arpfilter(n, eh, m)) 687 continue; 688 flags = n->brl_flags & (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID); 689 if (flags == 0) 690 goto return_action; 691 if (flags == (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID)) { 692 if (memcmp(eh->ether_shost, &n->brl_src, 693 ETHER_ADDR_LEN)) 694 continue; 695 if (memcmp(eh->ether_dhost, &n->brl_dst, 696 ETHER_ADDR_LEN)) 697 continue; 698 goto return_action; 699 } 700 if (flags == BRL_FLAG_SRCVALID) { 701 if (memcmp(eh->ether_shost, &n->brl_src, 702 ETHER_ADDR_LEN)) 703 continue; 704 goto return_action; 705 } 706 if (flags == BRL_FLAG_DSTVALID) { 707 if (memcmp(eh->ether_dhost, &n->brl_dst, 708 ETHER_ADDR_LEN)) 709 continue; 710 goto return_action; 711 } 712 } 713 return (BRL_ACTION_PASS); 714 715 return_action: 716 #if NPF > 0 717 pf_tag_packet(m, n->brl_tag, -1); 718 #endif 719 return (n->brl_action); 720 } 721 722 int 723 bridge_addrule(struct bridge_iflist *bif, struct ifbrlreq *req, int out) 724 { 725 struct brl_node *n; 726 727 n = malloc(sizeof(*n), M_DEVBUF, M_NOWAIT); 728 if (n == NULL) 729 return (ENOMEM); 730 bcopy(&req->ifbr_src, &n->brl_src, sizeof(struct ether_addr)); 731 bcopy(&req->ifbr_dst, &n->brl_dst, sizeof(struct ether_addr)); 732 n->brl_action = req->ifbr_action; 733 n->brl_flags = req->ifbr_flags; 734 n->brl_arpf = req->ifbr_arpf; 735 #if NPF > 0 736 if (req->ifbr_tagname[0]) 737 n->brl_tag = pf_tagname2tag(req->ifbr_tagname, 1); 738 else 739 n->brl_tag = 0; 740 #endif 741 if (out) { 742 n->brl_flags &= ~BRL_FLAG_IN; 743 n->brl_flags |= BRL_FLAG_OUT; 744 SIMPLEQ_INSERT_TAIL(&bif->bif_brlout, n, brl_next); 745 } else { 746 n->brl_flags &= ~BRL_FLAG_OUT; 747 n->brl_flags |= BRL_FLAG_IN; 748 SIMPLEQ_INSERT_TAIL(&bif->bif_brlin, n, brl_next); 749 } 750 return (0); 751 } 752 753 void 754 bridge_flushrule(struct bridge_iflist *bif) 755 { 756 struct brl_node *p; 757 758 while (!SIMPLEQ_EMPTY(&bif->bif_brlin)) { 759 p = SIMPLEQ_FIRST(&bif->bif_brlin); 760 SIMPLEQ_REMOVE_HEAD(&bif->bif_brlin, brl_next); 761 #if NPF > 0 762 pf_tag_unref(p->brl_tag); 763 #endif 764 free(p, M_DEVBUF, sizeof *p); 765 } 766 while (!SIMPLEQ_EMPTY(&bif->bif_brlout)) { 767 p = SIMPLEQ_FIRST(&bif->bif_brlout); 768 SIMPLEQ_REMOVE_HEAD(&bif->bif_brlout, brl_next); 769 #if NPF > 0 770 pf_tag_unref(p->brl_tag); 771 #endif 772 free(p, M_DEVBUF, sizeof *p); 773 } 774 } 775