1 /* $OpenBSD: bridgectl.c,v 1.19 2019/05/12 19:53:22 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 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 > time_uptime + age && 401 (n->brt_flags & IFBAF_TYPEMASK) == IFBAF_DYNAMIC) 402 n->brt_age = time_uptime + 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 goto done; 536 bareq = &bareqs[i]; 537 538 ifp = if_get(n->brt_ifidx); 539 if (ifp == NULL) 540 continue; 541 bcopy(ifp->if_xname, bareq->ifba_ifsname, 542 sizeof(bareq->ifba_ifsname)); 543 if_put(ifp); 544 545 bcopy(sc->sc_if.if_xname, bareq->ifba_name, 546 sizeof(bareq->ifba_name)); 547 bcopy(&n->brt_addr, &bareq->ifba_dst, 548 sizeof(bareq->ifba_dst)); 549 bridge_copyaddr(&n->brt_tunnel.brtag_peer.sa, 550 sstosa(&bareq->ifba_dstsa)); 551 bareq->ifba_age = n->brt_age; 552 bareq->ifba_flags = n->brt_flags; 553 i++; 554 } 555 } 556 mtx_leave(&sc->sc_mtx); 557 558 error = copyout(bareqs, baconf->ifbac_req, i * sizeof(*bareqs)); 559 done: 560 free(bareqs, M_TEMP, total * sizeof(*bareqs)); 561 baconf->ifbac_len = i * sizeof(*bareqs); 562 return (error); 563 } 564 565 void 566 bridge_update(struct ifnet *ifp, struct ether_addr *ea, int delete) 567 { 568 struct bridge_softc *sc; 569 struct bridge_iflist *bif; 570 u_int8_t *addr; 571 572 addr = (u_int8_t *)ea; 573 574 bif = bridge_getbif(ifp); 575 if (bif == NULL) 576 return; 577 sc = bif->bridge_sc; 578 if (sc == NULL) 579 return; 580 581 /* 582 * Update the bridge interface if it is in 583 * the learning state. 584 */ 585 if ((bif->bif_flags & IFBIF_LEARNING) && 586 (ETHER_IS_MULTICAST(addr) == 0) && 587 !(addr[0] == 0 && addr[1] == 0 && addr[2] == 0 && 588 addr[3] == 0 && addr[4] == 0 && addr[5] == 0)) { 589 /* Care must be taken with spanning tree */ 590 if ((bif->bif_flags & IFBIF_STP) && 591 (bif->bif_state == BSTP_IFSTATE_DISCARDING)) 592 return; 593 594 /* Delete the address from the bridge */ 595 bridge_rtdaddr(sc, ea); 596 597 if (!delete) { 598 /* Update the bridge table */ 599 bridge_rtupdate(sc, ea, ifp, 0, IFBAF_DYNAMIC, NULL); 600 } 601 } 602 } 603 604 /* 605 * bridge filter/matching rules 606 */ 607 int 608 bridge_brlconf(struct bridge_iflist *bif, struct ifbrlconf *bc) 609 { 610 struct bridge_softc *sc = bif->bridge_sc; 611 struct brl_node *n; 612 struct ifbrlreq *req, *reqs = NULL; 613 int error = 0; 614 u_int32_t i = 0, total = 0; 615 616 SIMPLEQ_FOREACH(n, &bif->bif_brlin, brl_next) { 617 total++; 618 } 619 SIMPLEQ_FOREACH(n, &bif->bif_brlout, brl_next) { 620 total++; 621 } 622 623 if (bc->ifbrl_len == 0) { 624 i = total; 625 goto done; 626 } 627 628 reqs = mallocarray(total, sizeof(*reqs), M_TEMP, M_NOWAIT|M_ZERO); 629 if (reqs == NULL) 630 goto done; 631 632 SIMPLEQ_FOREACH(n, &bif->bif_brlin, brl_next) { 633 if (bc->ifbrl_len < (i + 1) * sizeof(*reqs)) 634 goto done; 635 req = &reqs[i]; 636 strlcpy(req->ifbr_name, sc->sc_if.if_xname, IFNAMSIZ); 637 strlcpy(req->ifbr_ifsname, bif->ifp->if_xname, IFNAMSIZ); 638 req->ifbr_action = n->brl_action; 639 req->ifbr_flags = n->brl_flags; 640 req->ifbr_src = n->brl_src; 641 req->ifbr_dst = n->brl_dst; 642 req->ifbr_arpf = n->brl_arpf; 643 #if NPF > 0 644 req->ifbr_tagname[0] = '\0'; 645 if (n->brl_tag) 646 pf_tag2tagname(n->brl_tag, req->ifbr_tagname); 647 #endif 648 i++; 649 } 650 651 SIMPLEQ_FOREACH(n, &bif->bif_brlout, brl_next) { 652 if (bc->ifbrl_len < (i + 1) * sizeof(*reqs)) 653 goto done; 654 req = &reqs[i]; 655 strlcpy(req->ifbr_name, sc->sc_if.if_xname, IFNAMSIZ); 656 strlcpy(req->ifbr_ifsname, bif->ifp->if_xname, IFNAMSIZ); 657 req->ifbr_action = n->brl_action; 658 req->ifbr_flags = n->brl_flags; 659 req->ifbr_src = n->brl_src; 660 req->ifbr_dst = n->brl_dst; 661 req->ifbr_arpf = n->brl_arpf; 662 #if NPF > 0 663 req->ifbr_tagname[0] = '\0'; 664 if (n->brl_tag) 665 pf_tag2tagname(n->brl_tag, req->ifbr_tagname); 666 #endif 667 i++; 668 } 669 670 error = copyout(reqs, bc->ifbrl_buf, i * sizeof(*reqs)); 671 done: 672 free(reqs, M_TEMP, total * sizeof(*reqs)); 673 bc->ifbrl_len = i * sizeof(*reqs); 674 return (error); 675 } 676 677 u_int8_t 678 bridge_arpfilter(struct brl_node *n, struct ether_header *eh, struct mbuf *m) 679 { 680 struct ether_arp ea; 681 682 if (!(n->brl_arpf.brla_flags & (BRLA_ARP|BRLA_RARP))) 683 return (1); 684 685 if (ntohs(eh->ether_type) != ETHERTYPE_ARP) 686 return (0); 687 if (m->m_pkthdr.len <= ETHER_HDR_LEN + sizeof(ea)) 688 return (0); /* log error? */ 689 m_copydata(m, ETHER_HDR_LEN, sizeof(ea), (caddr_t)&ea); 690 691 if (ntohs(ea.arp_hrd) != ARPHRD_ETHER || 692 ntohs(ea.arp_pro) != ETHERTYPE_IP || 693 ea.arp_hln != ETHER_ADDR_LEN || 694 ea.arp_pln != sizeof(struct in_addr)) 695 return (0); 696 if ((n->brl_arpf.brla_flags & BRLA_ARP) && 697 ntohs(ea.arp_op) != ARPOP_REQUEST && 698 ntohs(ea.arp_op) != ARPOP_REPLY) 699 return (0); 700 if ((n->brl_arpf.brla_flags & BRLA_RARP) && 701 ntohs(ea.arp_op) != ARPOP_REVREQUEST && 702 ntohs(ea.arp_op) != ARPOP_REVREPLY) 703 return (0); 704 if (n->brl_arpf.brla_op && ntohs(ea.arp_op) != n->brl_arpf.brla_op) 705 return (0); 706 if (n->brl_arpf.brla_flags & BRLA_SHA && 707 memcmp(ea.arp_sha, &n->brl_arpf.brla_sha, ETHER_ADDR_LEN)) 708 return (0); 709 if (n->brl_arpf.brla_flags & BRLA_THA && 710 memcmp(ea.arp_tha, &n->brl_arpf.brla_tha, ETHER_ADDR_LEN)) 711 return (0); 712 if (n->brl_arpf.brla_flags & BRLA_SPA && 713 memcmp(ea.arp_spa, &n->brl_arpf.brla_spa, sizeof(struct in_addr))) 714 return (0); 715 if (n->brl_arpf.brla_flags & BRLA_TPA && 716 memcmp(ea.arp_tpa, &n->brl_arpf.brla_tpa, sizeof(struct in_addr))) 717 return (0); 718 719 return (1); 720 } 721 722 u_int8_t 723 bridge_filterrule(struct brl_head *h, struct ether_header *eh, struct mbuf *m) 724 { 725 struct brl_node *n; 726 u_int8_t action, flags; 727 728 if (SIMPLEQ_EMPTY(h)) 729 return (BRL_ACTION_PASS); 730 731 KERNEL_LOCK(); 732 SIMPLEQ_FOREACH(n, h, brl_next) { 733 if (!bridge_arpfilter(n, eh, m)) 734 continue; 735 flags = n->brl_flags & (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID); 736 if (flags == 0) 737 goto return_action; 738 if (flags == (BRL_FLAG_SRCVALID|BRL_FLAG_DSTVALID)) { 739 if (memcmp(eh->ether_shost, &n->brl_src, 740 ETHER_ADDR_LEN)) 741 continue; 742 if (memcmp(eh->ether_dhost, &n->brl_dst, 743 ETHER_ADDR_LEN)) 744 continue; 745 goto return_action; 746 } 747 if (flags == BRL_FLAG_SRCVALID) { 748 if (memcmp(eh->ether_shost, &n->brl_src, 749 ETHER_ADDR_LEN)) 750 continue; 751 goto return_action; 752 } 753 if (flags == BRL_FLAG_DSTVALID) { 754 if (memcmp(eh->ether_dhost, &n->brl_dst, 755 ETHER_ADDR_LEN)) 756 continue; 757 goto return_action; 758 } 759 } 760 KERNEL_UNLOCK(); 761 return (BRL_ACTION_PASS); 762 763 return_action: 764 #if NPF > 0 765 pf_tag_packet(m, n->brl_tag, -1); 766 #endif 767 action = n->brl_action; 768 KERNEL_UNLOCK(); 769 return (action); 770 } 771 772 int 773 bridge_addrule(struct bridge_iflist *bif, struct ifbrlreq *req, int out) 774 { 775 struct brl_node *n; 776 777 n = malloc(sizeof(*n), M_DEVBUF, M_NOWAIT); 778 if (n == NULL) 779 return (ENOMEM); 780 bcopy(&req->ifbr_src, &n->brl_src, sizeof(struct ether_addr)); 781 bcopy(&req->ifbr_dst, &n->brl_dst, sizeof(struct ether_addr)); 782 n->brl_action = req->ifbr_action; 783 n->brl_flags = req->ifbr_flags; 784 n->brl_arpf = req->ifbr_arpf; 785 #if NPF > 0 786 if (req->ifbr_tagname[0]) 787 n->brl_tag = pf_tagname2tag(req->ifbr_tagname, 1); 788 else 789 n->brl_tag = 0; 790 #endif 791 792 KERNEL_ASSERT_LOCKED(); 793 794 if (out) { 795 n->brl_flags &= ~BRL_FLAG_IN; 796 n->brl_flags |= BRL_FLAG_OUT; 797 SIMPLEQ_INSERT_TAIL(&bif->bif_brlout, n, brl_next); 798 } else { 799 n->brl_flags &= ~BRL_FLAG_OUT; 800 n->brl_flags |= BRL_FLAG_IN; 801 SIMPLEQ_INSERT_TAIL(&bif->bif_brlin, n, brl_next); 802 } 803 return (0); 804 } 805 806 void 807 bridge_flushrule(struct bridge_iflist *bif) 808 { 809 struct brl_node *p; 810 811 KERNEL_ASSERT_LOCKED(); 812 813 while (!SIMPLEQ_EMPTY(&bif->bif_brlin)) { 814 p = SIMPLEQ_FIRST(&bif->bif_brlin); 815 SIMPLEQ_REMOVE_HEAD(&bif->bif_brlin, brl_next); 816 #if NPF > 0 817 pf_tag_unref(p->brl_tag); 818 #endif 819 free(p, M_DEVBUF, sizeof *p); 820 } 821 while (!SIMPLEQ_EMPTY(&bif->bif_brlout)) { 822 p = SIMPLEQ_FIRST(&bif->bif_brlout); 823 SIMPLEQ_REMOVE_HEAD(&bif->bif_brlout, brl_next); 824 #if NPF > 0 825 pf_tag_unref(p->brl_tag); 826 #endif 827 free(p, M_DEVBUF, sizeof *p); 828 } 829 } 830 831 struct bridge_tunneltag * 832 bridge_tunnel(struct mbuf *m) 833 { 834 struct m_tag *mtag; 835 836 if ((mtag = m_tag_find(m, PACKET_TAG_TUNNEL, NULL)) == NULL) 837 return (NULL); 838 839 return ((struct bridge_tunneltag *)(mtag + 1)); 840 } 841 842 struct bridge_tunneltag * 843 bridge_tunneltag(struct mbuf *m) 844 { 845 struct m_tag *mtag; 846 847 if ((mtag = m_tag_find(m, PACKET_TAG_TUNNEL, NULL)) == NULL) { 848 mtag = m_tag_get(PACKET_TAG_TUNNEL, 849 sizeof(struct bridge_tunneltag), M_NOWAIT); 850 if (mtag == NULL) 851 return (NULL); 852 bzero(mtag + 1, sizeof(struct bridge_tunneltag)); 853 m_tag_prepend(m, mtag); 854 } 855 856 return ((struct bridge_tunneltag *)(mtag + 1)); 857 } 858 859 void 860 bridge_tunneluntag(struct mbuf *m) 861 { 862 struct m_tag *mtag; 863 if ((mtag = m_tag_find(m, PACKET_TAG_TUNNEL, NULL)) != NULL) 864 m_tag_delete(m, mtag); 865 } 866 867 void 868 bridge_copyaddr(struct sockaddr *src, struct sockaddr *dst) 869 { 870 if (src != NULL && src->sa_family != AF_UNSPEC) 871 memcpy(dst, src, src->sa_len); 872 else { 873 dst->sa_family = AF_UNSPEC; 874 dst->sa_len = 0; 875 } 876 } 877 878 void 879 bridge_copytag(struct bridge_tunneltag *src, struct bridge_tunneltag *dst) 880 { 881 if (src == NULL) { 882 memset(dst, 0, sizeof(*dst)); 883 } else { 884 bridge_copyaddr(&src->brtag_peer.sa, &dst->brtag_peer.sa); 885 bridge_copyaddr(&src->brtag_local.sa, &dst->brtag_local.sa); 886 dst->brtag_id = src->brtag_id; 887 } 888 } 889