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