1 /* $OpenBSD: bridgectl.c,v 1.21 2020/06/24 22:03:42 cheloha 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 if (ifs->if_bridgeidx != ifp->if_index) { 88 error = ESRCH; 89 break; 90 } 91 92 if (bridge_rtupdate(sc, &bareq->ifba_dst, ifs, 1, 93 bareq->ifba_flags, NULL)) 94 error = ENOMEM; 95 break; 96 case SIOCBRDGDADDR: 97 error = bridge_rtdaddr(sc, &bareq->ifba_dst); 98 break; 99 case SIOCBRDGGCACHE: 100 bparam->ifbrp_csize = sc->sc_brtmax; 101 break; 102 case SIOCBRDGSCACHE: 103 mtx_enter(&sc->sc_mtx); 104 sc->sc_brtmax = bparam->ifbrp_csize; 105 mtx_leave(&sc->sc_mtx); 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 if (ifs->if_bridgeidx != ifp->if_index) { 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 bif = bridge_getbif(ifs); 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 if (ifs->if_bridgeidx != ifp->if_index) { 157 error = ESRCH; 158 break; 159 } 160 bif = bridge_getbif(ifs); 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 if (ifs->if_bridgeidx != ifp->if_index) { 170 error = ESRCH; 171 break; 172 } 173 bif = bridge_getbif(ifs); 174 error = bridge_brlconf(bif, bc); 175 break; 176 default: 177 break; 178 } 179 180 return (error); 181 } 182 183 int 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, error = 0; 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 mtx_enter(&sc->sc_mtx); 199 p = LIST_FIRST(&sc->sc_rts[h]); 200 if (p == NULL) { 201 if (sc->sc_brtcnt >= sc->sc_brtmax) 202 goto done; 203 p = malloc(sizeof(*p), M_DEVBUF, M_NOWAIT); 204 if (p == NULL) 205 goto done; 206 207 bcopy(ea, &p->brt_addr, sizeof(p->brt_addr)); 208 p->brt_ifidx = ifp->if_index; 209 p->brt_age = 1; 210 bridge_copytag(brtag, &p->brt_tunnel); 211 212 if (setflags) 213 p->brt_flags = flags; 214 else 215 p->brt_flags = IFBAF_DYNAMIC; 216 217 LIST_INSERT_HEAD(&sc->sc_rts[h], p, brt_next); 218 sc->sc_brtcnt++; 219 goto want; 220 } 221 222 do { 223 q = p; 224 p = LIST_NEXT(p, brt_next); 225 226 dir = memcmp(ea, &q->brt_addr, sizeof(q->brt_addr)); 227 if (dir == 0) { 228 if (setflags) { 229 q->brt_ifidx = ifp->if_index; 230 q->brt_flags = flags; 231 } else if (!(q->brt_flags & IFBAF_STATIC)) 232 q->brt_ifidx = ifp->if_index; 233 234 if (q->brt_ifidx == ifp->if_index) 235 q->brt_age = 1; 236 bridge_copytag(brtag, &q->brt_tunnel); 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_ifidx = ifp->if_index; 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_ifidx = ifp->if_index; 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 mtx_leave(&sc->sc_mtx); 288 return (error); 289 } 290 291 unsigned int 292 bridge_rtlookup(struct ifnet *brifp, struct ether_addr *ea, struct mbuf *m) 293 { 294 struct bridge_softc *sc = brifp->if_softc; 295 struct bridge_rtnode *p = NULL; 296 unsigned int ifidx = 0; 297 u_int32_t h; 298 int dir; 299 300 h = bridge_hash(sc, ea); 301 mtx_enter(&sc->sc_mtx); 302 LIST_FOREACH(p, &sc->sc_rts[h], brt_next) { 303 dir = memcmp(ea, &p->brt_addr, sizeof(p->brt_addr)); 304 if (dir == 0) 305 break; 306 if (dir > 0) { 307 p = NULL; 308 break; 309 } 310 } 311 if (p != NULL) { 312 ifidx = p->brt_ifidx; 313 314 if (p->brt_family != AF_UNSPEC && m != NULL) { 315 struct bridge_tunneltag *brtag; 316 317 brtag = bridge_tunneltag(m); 318 if (brtag != NULL) 319 bridge_copytag(&p->brt_tunnel, brtag); 320 } 321 } 322 mtx_leave(&sc->sc_mtx); 323 324 return (ifidx); 325 } 326 327 u_int32_t 328 bridge_hash(struct bridge_softc *sc, struct ether_addr *addr) 329 { 330 return SipHash24((SIPHASH_KEY *)sc->sc_hashkey, addr, ETHER_ADDR_LEN) & 331 BRIDGE_RTABLE_MASK; 332 } 333 334 /* 335 * Perform an aging cycle 336 */ 337 void 338 bridge_rtage(void *vsc) 339 { 340 struct bridge_softc *sc = vsc; 341 struct ifnet *ifp = &sc->sc_if; 342 struct bridge_rtnode *n, *p; 343 int i; 344 345 if (!ISSET(ifp->if_flags, IFF_RUNNING)) 346 return; 347 348 mtx_enter(&sc->sc_mtx); 349 for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) { 350 n = LIST_FIRST(&sc->sc_rts[i]); 351 while (n != NULL) { 352 if ((n->brt_flags & IFBAF_TYPEMASK) == IFBAF_STATIC) { 353 n->brt_age = !n->brt_age; 354 if (n->brt_age) 355 n->brt_age = 0; 356 n = LIST_NEXT(n, brt_next); 357 } else if (n->brt_age) { 358 n->brt_age = 0; 359 n = LIST_NEXT(n, brt_next); 360 } else { 361 p = LIST_NEXT(n, brt_next); 362 LIST_REMOVE(n, brt_next); 363 sc->sc_brtcnt--; 364 free(n, M_DEVBUF, sizeof *n); 365 n = p; 366 } 367 } 368 } 369 mtx_leave(&sc->sc_mtx); 370 371 if (sc->sc_brttimeout != 0) 372 timeout_add_sec(&sc->sc_brtimeout, sc->sc_brttimeout); 373 } 374 375 void 376 bridge_rtagenode(struct ifnet *ifp, int age) 377 { 378 struct bridge_softc *sc; 379 struct bridge_rtnode *n; 380 struct ifnet *bifp; 381 int i; 382 383 bifp = if_get(ifp->if_bridgeidx); 384 if (bifp == NULL) 385 return; 386 sc = bifp->if_softc; 387 388 /* 389 * If the age is zero then flush, otherwise set all the expiry times to 390 * age for the interface 391 */ 392 if (age == 0) 393 bridge_rtdelete(sc, ifp, 1); 394 else { 395 mtx_enter(&sc->sc_mtx); 396 for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) { 397 LIST_FOREACH(n, &sc->sc_rts[i], brt_next) { 398 /* Cap the expiry time to 'age' */ 399 if (n->brt_ifidx == ifp->if_index && 400 n->brt_age > getuptime() + age && 401 (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) 402 n->brt_age = getuptime() + age; 403 } 404 } 405 mtx_leave(&sc->sc_mtx); 406 } 407 408 if_put(bifp); 409 } 410 411 /* 412 * Remove all dynamic addresses from the cache 413 */ 414 void 415 bridge_rtflush(struct bridge_softc *sc, int full) 416 { 417 int i; 418 struct bridge_rtnode *p, *n; 419 420 mtx_enter(&sc->sc_mtx); 421 for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) { 422 n = LIST_FIRST(&sc->sc_rts[i]); 423 while (n != NULL) { 424 if (full || 425 (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) { 426 p = LIST_NEXT(n, brt_next); 427 LIST_REMOVE(n, brt_next); 428 sc->sc_brtcnt--; 429 free(n, M_DEVBUF, sizeof *n); 430 n = p; 431 } else 432 n = LIST_NEXT(n, brt_next); 433 } 434 } 435 mtx_leave(&sc->sc_mtx); 436 } 437 438 /* 439 * Remove an address from the cache 440 */ 441 int 442 bridge_rtdaddr(struct bridge_softc *sc, struct ether_addr *ea) 443 { 444 int h; 445 struct bridge_rtnode *p; 446 447 h = bridge_hash(sc, ea); 448 mtx_enter(&sc->sc_mtx); 449 LIST_FOREACH(p, &sc->sc_rts[h], brt_next) { 450 if (memcmp(ea, &p->brt_addr, sizeof(p->brt_addr)) == 0) { 451 LIST_REMOVE(p, brt_next); 452 sc->sc_brtcnt--; 453 mtx_leave(&sc->sc_mtx); 454 free(p, M_DEVBUF, sizeof *p); 455 return (0); 456 } 457 } 458 mtx_leave(&sc->sc_mtx); 459 460 return (ENOENT); 461 } 462 463 /* 464 * Delete routes to a specific interface member. 465 */ 466 void 467 bridge_rtdelete(struct bridge_softc *sc, struct ifnet *ifp, int dynonly) 468 { 469 int i; 470 struct bridge_rtnode *n, *p; 471 472 /* 473 * Loop through all of the hash buckets and traverse each 474 * chain looking for routes to this interface. 475 */ 476 mtx_enter(&sc->sc_mtx); 477 for (i = 0; i < BRIDGE_RTABLE_SIZE; i++) { 478 n = LIST_FIRST(&sc->sc_rts[i]); 479 while (n != NULL) { 480 if (n->brt_ifidx != ifp->if_index) { 481 /* Not ours */ 482 n = LIST_NEXT(n, brt_next); 483 continue; 484 } 485 if (dynonly && 486 (n->brt_flags & IFBAF_TYPEMASK) != IFBAF_DYNAMIC) { 487 /* only deleting dynamics */ 488 n = LIST_NEXT(n, brt_next); 489 continue; 490 } 491 p = LIST_NEXT(n, brt_next); 492 LIST_REMOVE(n, brt_next); 493 sc->sc_brtcnt--; 494 free(n, M_DEVBUF, sizeof *n); 495 n = p; 496 } 497 } 498 mtx_leave(&sc->sc_mtx); 499 } 500 501 /* 502 * Gather all of the routes for this interface. 503 */ 504 int 505 bridge_rtfind(struct bridge_softc *sc, struct ifbaconf *baconf) 506 { 507 struct ifbareq *bareq, *bareqs = NULL; 508 struct bridge_rtnode *n; 509 u_int32_t i = 0, total = 0; 510 int k, error = 0; 511 512 mtx_enter(&sc->sc_mtx); 513 for (k = 0; k < BRIDGE_RTABLE_SIZE; k++) { 514 LIST_FOREACH(n, &sc->sc_rts[k], brt_next) 515 total++; 516 } 517 mtx_leave(&sc->sc_mtx); 518 519 if (baconf->ifbac_len == 0) { 520 i = total; 521 goto done; 522 } 523 524 total = MIN(total, baconf->ifbac_len / sizeof(*bareqs)); 525 bareqs = mallocarray(total, sizeof(*bareqs), M_TEMP, M_NOWAIT|M_ZERO); 526 if (bareqs == NULL) 527 goto done; 528 529 mtx_enter(&sc->sc_mtx); 530 for (k = 0; k < BRIDGE_RTABLE_SIZE; k++) { 531 LIST_FOREACH(n, &sc->sc_rts[k], brt_next) { 532 struct ifnet *ifp; 533 534 if (i >= total) { 535 mtx_leave(&sc->sc_mtx); 536 goto done; 537 } 538 bareq = &bareqs[i]; 539 540 ifp = if_get(n->brt_ifidx); 541 if (ifp == NULL) 542 continue; 543 bcopy(ifp->if_xname, bareq->ifba_ifsname, 544 sizeof(bareq->ifba_ifsname)); 545 if_put(ifp); 546 547 bcopy(sc->sc_if.if_xname, bareq->ifba_name, 548 sizeof(bareq->ifba_name)); 549 bcopy(&n->brt_addr, &bareq->ifba_dst, 550 sizeof(bareq->ifba_dst)); 551 bridge_copyaddr(&n->brt_tunnel.brtag_peer.sa, 552 sstosa(&bareq->ifba_dstsa)); 553 bareq->ifba_age = n->brt_age; 554 bareq->ifba_flags = n->brt_flags; 555 i++; 556 } 557 } 558 mtx_leave(&sc->sc_mtx); 559 560 error = copyout(bareqs, baconf->ifbac_req, i * sizeof(*bareqs)); 561 done: 562 free(bareqs, M_TEMP, total * sizeof(*bareqs)); 563 baconf->ifbac_len = i * sizeof(*bareqs); 564 return (error); 565 } 566 567 void 568 bridge_update(struct ifnet *ifp, struct ether_addr *ea, int delete) 569 { 570 struct bridge_softc *sc; 571 struct bridge_iflist *bif; 572 u_int8_t *addr; 573 574 addr = (u_int8_t *)ea; 575 576 bif = bridge_getbif(ifp); 577 if (bif == NULL) 578 return; 579 sc = bif->bridge_sc; 580 if (sc == NULL) 581 return; 582 583 /* 584 * Update the bridge interface if it is in 585 * the learning state. 586 */ 587 if ((bif->bif_flags & IFBIF_LEARNING) && 588 (ETHER_IS_MULTICAST(addr) == 0) && 589 !(addr[0] == 0 && addr[1] == 0 && addr[2] == 0 && 590 addr[3] == 0 && addr[4] == 0 && addr[5] == 0)) { 591 /* Care must be taken with spanning tree */ 592 if ((bif->bif_flags & IFBIF_STP) && 593 (bif->bif_state == BSTP_IFSTATE_DISCARDING)) 594 return; 595 596 /* Delete the address from the bridge */ 597 bridge_rtdaddr(sc, ea); 598 599 if (!delete) { 600 /* Update the bridge table */ 601 bridge_rtupdate(sc, ea, ifp, 0, IFBAF_DYNAMIC, NULL); 602 } 603 } 604 } 605 606 /* 607 * bridge filter/matching rules 608 */ 609 int 610 bridge_brlconf(struct bridge_iflist *bif, struct ifbrlconf *bc) 611 { 612 struct bridge_softc *sc = bif->bridge_sc; 613 struct brl_node *n; 614 struct ifbrlreq *req, *reqs = NULL; 615 int error = 0; 616 u_int32_t i = 0, total = 0; 617 618 SIMPLEQ_FOREACH(n, &bif->bif_brlin, brl_next) { 619 total++; 620 } 621 SIMPLEQ_FOREACH(n, &bif->bif_brlout, brl_next) { 622 total++; 623 } 624 625 if (bc->ifbrl_len == 0) { 626 i = total; 627 goto done; 628 } 629 630 reqs = mallocarray(total, sizeof(*reqs), M_TEMP, M_NOWAIT|M_ZERO); 631 if (reqs == NULL) 632 goto done; 633 634 SIMPLEQ_FOREACH(n, &bif->bif_brlin, brl_next) { 635 if (bc->ifbrl_len < (i + 1) * sizeof(*reqs)) 636 goto done; 637 req = &reqs[i]; 638 strlcpy(req->ifbr_name, sc->sc_if.if_xname, IFNAMSIZ); 639 strlcpy(req->ifbr_ifsname, bif->ifp->if_xname, IFNAMSIZ); 640 req->ifbr_action = n->brl_action; 641 req->ifbr_flags = n->brl_flags; 642 req->ifbr_src = n->brl_src; 643 req->ifbr_dst = n->brl_dst; 644 req->ifbr_arpf = n->brl_arpf; 645 #if NPF > 0 646 req->ifbr_tagname[0] = '\0'; 647 if (n->brl_tag) 648 pf_tag2tagname(n->brl_tag, req->ifbr_tagname); 649 #endif 650 i++; 651 } 652 653 SIMPLEQ_FOREACH(n, &bif->bif_brlout, brl_next) { 654 if (bc->ifbrl_len < (i + 1) * sizeof(*reqs)) 655 goto done; 656 req = &reqs[i]; 657 strlcpy(req->ifbr_name, sc->sc_if.if_xname, IFNAMSIZ); 658 strlcpy(req->ifbr_ifsname, bif->ifp->if_xname, IFNAMSIZ); 659 req->ifbr_action = n->brl_action; 660 req->ifbr_flags = n->brl_flags; 661 req->ifbr_src = n->brl_src; 662 req->ifbr_dst = n->brl_dst; 663 req->ifbr_arpf = n->brl_arpf; 664 #if NPF > 0 665 req->ifbr_tagname[0] = '\0'; 666 if (n->brl_tag) 667 pf_tag2tagname(n->brl_tag, req->ifbr_tagname); 668 #endif 669 i++; 670 } 671 672 error = copyout(reqs, bc->ifbrl_buf, i * sizeof(*reqs)); 673 done: 674 free(reqs, M_TEMP, total * sizeof(*reqs)); 675 bc->ifbrl_len = i * sizeof(*reqs); 676 return (error); 677 } 678 679 u_int8_t 680 bridge_arpfilter(struct brl_node *n, struct ether_header *eh, struct mbuf *m) 681 { 682 struct ether_arp ea; 683 684 if (!(n->brl_arpf.brla_flags & (BRLA_ARP|BRLA_RARP))) 685 return (1); 686 687 if (ntohs(eh->ether_type) != ETHERTYPE_ARP) 688 return (0); 689 if (m->m_pkthdr.len <= ETHER_HDR_LEN + sizeof(ea)) 690 return (0); /* log error? */ 691 m_copydata(m, ETHER_HDR_LEN, sizeof(ea), (caddr_t)&ea); 692 693 if (ntohs(ea.arp_hrd) != ARPHRD_ETHER || 694 ntohs(ea.arp_pro) != ETHERTYPE_IP || 695 ea.arp_hln != ETHER_ADDR_LEN || 696 ea.arp_pln != sizeof(struct in_addr)) 697 return (0); 698 if ((n->brl_arpf.brla_flags & BRLA_ARP) && 699 ntohs(ea.arp_op) != ARPOP_REQUEST && 700 ntohs(ea.arp_op) != ARPOP_REPLY) 701 return (0); 702 if ((n->brl_arpf.brla_flags & BRLA_RARP) && 703 ntohs(ea.arp_op) != ARPOP_REVREQUEST && 704 ntohs(ea.arp_op) != ARPOP_REVREPLY) 705 return (0); 706 if (n->brl_arpf.brla_op && ntohs(ea.arp_op) != n->brl_arpf.brla_op) 707 return (0); 708 if (n->brl_arpf.brla_flags & BRLA_SHA && 709 memcmp(ea.arp_sha, &n->brl_arpf.brla_sha, ETHER_ADDR_LEN)) 710 return (0); 711 if (n->brl_arpf.brla_flags & BRLA_THA && 712 memcmp(ea.arp_tha, &n->brl_arpf.brla_tha, ETHER_ADDR_LEN)) 713 return (0); 714 if (n->brl_arpf.brla_flags & BRLA_SPA && 715 memcmp(ea.arp_spa, &n->brl_arpf.brla_spa, sizeof(struct in_addr))) 716 return (0); 717 if (n->brl_arpf.brla_flags & BRLA_TPA && 718 memcmp(ea.arp_tpa, &n->brl_arpf.brla_tpa, sizeof(struct in_addr))) 719 return (0); 720 721 return (1); 722 } 723 724 u_int8_t 725 bridge_filterrule(struct brl_head *h, struct ether_header *eh, struct mbuf *m) 726 { 727 struct brl_node *n; 728 u_int8_t action, flags; 729 730 if (SIMPLEQ_EMPTY(h)) 731 return (BRL_ACTION_PASS); 732 733 KERNEL_LOCK(); 734 SIMPLEQ_FOREACH(n, h, brl_next) { 735 if (!bridge_arpfilter(n, eh, m)) 736 continue; 737 flags = n->brl_flags & (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID); 738 if (flags == 0) 739 goto return_action; 740 if (flags == (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID)) { 741 if (memcmp(eh->ether_shost, &n->brl_src, 742 ETHER_ADDR_LEN)) 743 continue; 744 if (memcmp(eh->ether_dhost, &n->brl_dst, 745 ETHER_ADDR_LEN)) 746 continue; 747 goto return_action; 748 } 749 if (flags == BRL_FLAG_SRCVALID) { 750 if (memcmp(eh->ether_shost, &n->brl_src, 751 ETHER_ADDR_LEN)) 752 continue; 753 goto return_action; 754 } 755 if (flags == BRL_FLAG_DSTVALID) { 756 if (memcmp(eh->ether_dhost, &n->brl_dst, 757 ETHER_ADDR_LEN)) 758 continue; 759 goto return_action; 760 } 761 } 762 KERNEL_UNLOCK(); 763 return (BRL_ACTION_PASS); 764 765 return_action: 766 #if NPF > 0 767 pf_tag_packet(m, n->brl_tag, -1); 768 #endif 769 action = n->brl_action; 770 KERNEL_UNLOCK(); 771 return (action); 772 } 773 774 int 775 bridge_addrule(struct bridge_iflist *bif, struct ifbrlreq *req, int out) 776 { 777 struct brl_node *n; 778 779 n = malloc(sizeof(*n), M_DEVBUF, M_NOWAIT); 780 if (n == NULL) 781 return (ENOMEM); 782 bcopy(&req->ifbr_src, &n->brl_src, sizeof(struct ether_addr)); 783 bcopy(&req->ifbr_dst, &n->brl_dst, sizeof(struct ether_addr)); 784 n->brl_action = req->ifbr_action; 785 n->brl_flags = req->ifbr_flags; 786 n->brl_arpf = req->ifbr_arpf; 787 #if NPF > 0 788 if (req->ifbr_tagname[0]) 789 n->brl_tag = pf_tagname2tag(req->ifbr_tagname, 1); 790 else 791 n->brl_tag = 0; 792 #endif 793 794 KERNEL_ASSERT_LOCKED(); 795 796 if (out) { 797 n->brl_flags &= ~BRL_FLAG_IN; 798 n->brl_flags |= BRL_FLAG_OUT; 799 SIMPLEQ_INSERT_TAIL(&bif->bif_brlout, n, brl_next); 800 } else { 801 n->brl_flags &= ~BRL_FLAG_OUT; 802 n->brl_flags |= BRL_FLAG_IN; 803 SIMPLEQ_INSERT_TAIL(&bif->bif_brlin, n, brl_next); 804 } 805 return (0); 806 } 807 808 void 809 bridge_flushrule(struct bridge_iflist *bif) 810 { 811 struct brl_node *p; 812 813 KERNEL_ASSERT_LOCKED(); 814 815 while (!SIMPLEQ_EMPTY(&bif->bif_brlin)) { 816 p = SIMPLEQ_FIRST(&bif->bif_brlin); 817 SIMPLEQ_REMOVE_HEAD(&bif->bif_brlin, brl_next); 818 #if NPF > 0 819 pf_tag_unref(p->brl_tag); 820 #endif 821 free(p, M_DEVBUF, sizeof *p); 822 } 823 while (!SIMPLEQ_EMPTY(&bif->bif_brlout)) { 824 p = SIMPLEQ_FIRST(&bif->bif_brlout); 825 SIMPLEQ_REMOVE_HEAD(&bif->bif_brlout, brl_next); 826 #if NPF > 0 827 pf_tag_unref(p->brl_tag); 828 #endif 829 free(p, M_DEVBUF, sizeof *p); 830 } 831 } 832 833 struct bridge_tunneltag * 834 bridge_tunnel(struct mbuf *m) 835 { 836 struct m_tag *mtag; 837 838 if ((mtag = m_tag_find(m, PACKET_TAG_TUNNEL, NULL)) == NULL) 839 return (NULL); 840 841 return ((struct bridge_tunneltag *)(mtag + 1)); 842 } 843 844 struct bridge_tunneltag * 845 bridge_tunneltag(struct mbuf *m) 846 { 847 struct m_tag *mtag; 848 849 if ((mtag = m_tag_find(m, PACKET_TAG_TUNNEL, NULL)) == NULL) { 850 mtag = m_tag_get(PACKET_TAG_TUNNEL, 851 sizeof(struct bridge_tunneltag), M_NOWAIT); 852 if (mtag == NULL) 853 return (NULL); 854 bzero(mtag + 1, sizeof(struct bridge_tunneltag)); 855 m_tag_prepend(m, mtag); 856 } 857 858 return ((struct bridge_tunneltag *)(mtag + 1)); 859 } 860 861 void 862 bridge_tunneluntag(struct mbuf *m) 863 { 864 struct m_tag *mtag; 865 if ((mtag = m_tag_find(m, PACKET_TAG_TUNNEL, NULL)) != NULL) 866 m_tag_delete(m, mtag); 867 } 868 869 void 870 bridge_copyaddr(struct sockaddr *src, struct sockaddr *dst) 871 { 872 if (src != NULL && src->sa_family != AF_UNSPEC) 873 memcpy(dst, src, src->sa_len); 874 else { 875 dst->sa_family = AF_UNSPEC; 876 dst->sa_len = 0; 877 } 878 } 879 880 void 881 bridge_copytag(struct bridge_tunneltag *src, struct bridge_tunneltag *dst) 882 { 883 if (src == NULL) { 884 memset(dst, 0, sizeof(*dst)); 885 } else { 886 bridge_copyaddr(&src->brtag_peer.sa, &dst->brtag_peer.sa); 887 bridge_copyaddr(&src->brtag_local.sa, &dst->brtag_local.sa); 888 dst->brtag_id = src->brtag_id; 889 } 890 } 891