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