|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright (c) 1998 Luigi Rizzo ! 24: * ! 25: * Redistribution and use in source and binary forms, with or without ! 26: * modification, are permitted provided that the following conditions ! 27: * are met: ! 28: * 1. Redistributions of source code must retain the above copyright ! 29: * notice, this list of conditions and the following disclaimer. ! 30: * 2. Redistributions in binary form must reproduce the above copyright ! 31: * notice, this list of conditions and the following disclaimer in the ! 32: * documentation and/or other materials provided with the distribution. ! 33: * ! 34: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ! 35: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 36: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 37: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 38: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 39: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 40: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 41: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 42: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 43: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 44: * SUCH DAMAGE. ! 45: * ! 46: */ ! 47: ! 48: /* ! 49: * This code implements bridging in FreeBSD. It only acts on ethernet ! 50: * type of interfaces (others are still usable for routing). ! 51: * A bridging table holds the source MAC address/dest. interface for each ! 52: * known node. The table is indexed using an hash of the source address. ! 53: * ! 54: * Input packets are tapped near the end of the input routine in each ! 55: * driver (near the call to bpf_mtap, or before the call to ether_input) ! 56: * and analysed calling bridge_in(). Depending on the result, the packet ! 57: * can be forwarded to one or more output interfaces using bdg_forward(), ! 58: * and/or sent to the upper layer (e.g. in case of multicast). ! 59: * ! 60: * Output packets are intercepted near the end of ether_output(), ! 61: * the correct destination is selected calling bdg_dst_lookup(), ! 62: * and then forwarding is done using bdg_forward(). ! 63: * Bridging is controlled by the sysctl variable net.link.ether.bridge ! 64: * ! 65: * The arp code is also modified to let a machine answer to requests ! 66: * irrespective of the port the request came from. ! 67: * ! 68: * In case of loops in the bridging topology, the bridge detects this ! 69: * event and temporarily mutes output bridging on one of the ports. ! 70: * Periodically, interfaces are unmuted by bdg_timeout(). (For the ! 71: * mute flag i am temporarily using IFF_LINK2 but this has to ! 72: * change.) Muting is only implemented as a safety measure, and also as ! 73: * a mechanism to support a user-space implementation of the spanning ! 74: * tree algorithm. In the final release, unmuting will only occur ! 75: * because of explicit action of the user-level daemon. ! 76: * ! 77: * To build a bridging kernel, use the following option ! 78: * option BRIDGE ! 79: * and then at runtime set the sysctl variable to enable bridging. ! 80: * ! 81: * Only one interface is supposed to have addresses set (but ! 82: * there are no problems in practice if you set addresses for more ! 83: * than one interface). ! 84: * Bridging will act before routing, but nothing prevents a machine ! 85: * from doing both (modulo bugs in the implementation...). ! 86: * ! 87: * THINGS TO REMEMBER ! 88: * - bridging requires some (small) modifications to the interface ! 89: * driver. Currently (980911) the "ed", "de", "tx", "lnc" drivers ! 90: * have been modified and tested. "fxp", "ep", "fe" have been ! 91: * modified but not tested. See the "ed" and "de" drivers as ! 92: * examples on how to operate. ! 93: * - bridging is incompatible with multicast routing on the same ! 94: * machine. There is not an easy fix to this. ! 95: * - loop detection is still not very robust. ! 96: * - the interface of bdg_forward() could be improved. ! 97: */ ! 98: ! 99: #include <sys/param.h> ! 100: #include <sys/mbuf.h> ! 101: #include <sys/malloc.h> ! 102: #include <sys/systm.h> ! 103: #include <sys/socket.h> /* for net/if.h */ ! 104: #include <sys/kernel.h> ! 105: #include <sys/sysctl.h> ! 106: ! 107: #include <net/if.h> ! 108: #include <net/if_types.h> ! 109: ! 110: #include <netinet/in.h> /* for struct arpcom */ ! 111: #include <netinet/in_systm.h> ! 112: #include <netinet/in_var.h> ! 113: #include <netinet/ip.h> ! 114: #include <netinet/if_ether.h> /* for struct arpcom */ ! 115: ! 116: #include "opt_ipfw.h" ! 117: #include "opt_ipdn.h" ! 118: ! 119: #if defined(IPFIREWALL) && defined(DUMMYNET) ! 120: #include <net/route.h> ! 121: #include <netinet/ip_fw.h> ! 122: #include <netinet/ip_dummynet.h> ! 123: #endif ! 124: ! 125: #include <net/bridge.h> ! 126: ! 127: /* ! 128: * For debugging, you can use the following macros. ! 129: * remember, rdtsc() only works on Pentium-class machines ! 130: ! 131: quad_t ticks; ! 132: DDB(ticks = rdtsc();) ! 133: ... interesting code ... ! 134: DDB(bdg_fw_ticks += (u_long)(rdtsc() - ticks) ; bdg_fw_count++ ;) ! 135: ! 136: * ! 137: */ ! 138: ! 139: #define DDB(x) x ! 140: #define DEB(x) ! 141: ! 142: /* ! 143: * System initialization ! 144: */ ! 145: ! 146: static void bdginit(void *); ! 147: static void flush_table(void); ! 148: ! 149: SYSINIT(interfaces, SI_SUB_PROTO_IF, SI_ORDER_FIRST, bdginit, NULL) ! 150: ! 151: static int bdg_ipfw = 0 ; ! 152: int do_bridge = 0; ! 153: bdg_hash_table *bdg_table = NULL ; ! 154: ! 155: /* ! 156: * we need additional info for the bridge. The bdg_ifp2sc[] array ! 157: * provides a pointer to this struct using the if_index. ! 158: * bdg_softc has a backpointer to the struct ifnet, the bridge ! 159: * flags, and a group (bridging occurs only between port of the ! 160: * same group). ! 161: */ ! 162: struct bdg_softc { ! 163: struct ifnet *ifp ; ! 164: /* ((struct arpcom *)ifp)->ac_enaddr is the eth. addr */ ! 165: int flags ; ! 166: int group ; ! 167: } ; ! 168: ! 169: static struct bdg_softc **ifp2sc = NULL ; ! 170: ! 171: #if 0 /* new code using ifp2sc */ ! 172: #define SAMEGROUP(ifp,src) (src == NULL || \ ! 173: ifp2sc[ifp->if_index]->group == ifp2sc[src->if_index]->group ) ! 174: #define MUTED(ifp) (ifp2sc[ifp->if_index]->flags & IFF_MUTE) ! 175: #define MUTE(ifp) ifp2sc[ifp->if_index]->flags |= IFF_MUTE ! 176: #define UNMUTE(ifp) ifp2sc[ifp->if_index]->flags &= ~IFF_MUTE ! 177: #else ! 178: #define SAMEGROUP(a,b) 1 ! 179: #define MUTED(ifp) (ifp->if_flags & IFF_MUTE) ! 180: #define MUTE(ifp) ifp->if_flags |= IFF_MUTE ! 181: #define UNMUTE(ifp) ifp->if_flags &= ~IFF_MUTE ! 182: #endif ! 183: ! 184: static int ! 185: sysctl_bdg SYSCTL_HANDLER_ARGS ! 186: { ! 187: int error, oldval = do_bridge ; ! 188: ! 189: error = sysctl_handle_int(oidp, ! 190: oidp->oid_arg1, oidp->oid_arg2, req); ! 191: printf("called sysctl for bridge name %s arg2 %d val %d->%d\n", ! 192: oidp->oid_name, oidp->oid_arg2, ! 193: oldval, do_bridge); ! 194: if (bdg_table == NULL) ! 195: do_bridge = 0 ; ! 196: if (oldval != do_bridge) { ! 197: flush_table(); ! 198: } ! 199: return error ; ! 200: } ! 201: ! 202: SYSCTL_DECL(_net_link_ether); ! 203: SYSCTL_PROC(_net_link_ether, OID_AUTO, bridge, CTLTYPE_INT|CTLFLAG_RW, ! 204: &do_bridge, 0, &sysctl_bdg, "I", "Bridging"); ! 205: ! 206: SYSCTL_INT(_net_link_ether, OID_AUTO, bridge_ipfw, CTLFLAG_RW, &bdg_ipfw,0,""); ! 207: #if 1 /* diagnostic vars */ ! 208: int bdg_in_count = 0 , bdg_in_ticks = 0 , bdg_fw_count = 0, bdg_fw_ticks = 0 ; ! 209: SYSCTL_INT(_net_link_ether, OID_AUTO, bdginc, CTLFLAG_RW, &bdg_in_count,0,""); ! 210: SYSCTL_INT(_net_link_ether, OID_AUTO, bdgint, CTLFLAG_RW, &bdg_in_ticks,0,""); ! 211: SYSCTL_INT(_net_link_ether, OID_AUTO, bdgfwc, CTLFLAG_RW, &bdg_fw_count,0,""); ! 212: SYSCTL_INT(_net_link_ether, OID_AUTO, bdgfwt, CTLFLAG_RW, &bdg_fw_ticks,0,""); ! 213: #endif ! 214: static struct bdg_stats bdg_stats ; ! 215: SYSCTL_STRUCT(_net_link_ether, PF_BDG, bdgstats, ! 216: CTLFLAG_RD, &bdg_stats , bdg_stats, "bridge statistics"); ! 217: ! 218: static int bdg_loops ; ! 219: ! 220: /* ! 221: * completely flush the bridge table. ! 222: */ ! 223: static void ! 224: flush_table() ! 225: { ! 226: int s,i; ! 227: ! 228: if (bdg_table == NULL) ! 229: return ; ! 230: s = splimp(); ! 231: for (i=0; i< HASH_SIZE; i++) ! 232: bdg_table[i].name= NULL; /* clear table */ ! 233: splx(s); ! 234: } ! 235: ! 236: /* ! 237: * called periodically to flush entries etc. ! 238: */ ! 239: static void ! 240: bdg_timeout(void *dummy) ! 241: { ! 242: struct ifnet *ifp ; ! 243: int s ; ! 244: static int slowtimer = 0 ; ! 245: ! 246: if (do_bridge) { ! 247: static int age_index = 0 ; /* index of table position to age */ ! 248: int l = age_index + HASH_SIZE/4 ; ! 249: /* ! 250: * age entries in the forwarding table. ! 251: */ ! 252: if (l > HASH_SIZE) ! 253: l = HASH_SIZE ; ! 254: for (; age_index < l ; age_index++) ! 255: if (bdg_table[age_index].used) ! 256: bdg_table[age_index].used = 0 ; ! 257: else if (bdg_table[age_index].name) { ! 258: /* printf("xx flushing stale entry %d\n", age_index); */ ! 259: bdg_table[age_index].name = NULL ; ! 260: } ! 261: if (age_index >= HASH_SIZE) ! 262: age_index = 0 ; ! 263: ! 264: if (--slowtimer <= 0 ) { ! 265: slowtimer = 5 ; ! 266: ! 267: for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) { ! 268: if (ifp->if_type != IFT_ETHER) ! 269: continue ; ! 270: if ( 0 == ( ifp->if_flags & IFF_UP) ) { ! 271: s = splimp(); ! 272: if_up(ifp); ! 273: splx(s); ! 274: } ! 275: if ( 0 == ( ifp->if_flags & IFF_PROMISC) ) { ! 276: int ret ; ! 277: s = splimp(); ! 278: ret = ifpromisc(ifp, 1); ! 279: splx(s); ! 280: printf(">> now %s%d flags 0x%x promisc %d\n", ! 281: ifp->if_name, ifp->if_unit, ! 282: ifp->if_flags, ret); ! 283: } ! 284: if (MUTED(ifp)) { ! 285: printf(">> unmuting %s%d\n", ifp->if_name, ifp->if_unit); ! 286: UNMUTE(ifp) ; ! 287: } ! 288: } ! 289: bdg_loops = 0 ; ! 290: } ! 291: } ! 292: timeout(bdg_timeout, (void *)0, 2*hz ); ! 293: } ! 294: ! 295: /* ! 296: * local MAC addresses are held in a small array. This makes comparisons ! 297: * much faster. ! 298: */ ! 299: unsigned char bdg_addresses[6*BDG_MAX_PORTS]; ! 300: int bdg_ports ; ! 301: ! 302: /* ! 303: * initialization of bridge code. ! 304: */ ! 305: static void ! 306: bdginit(dummy) ! 307: void *dummy; ! 308: { ! 309: int i ; ! 310: struct ifnet *ifp; ! 311: struct arpcom *ac ; ! 312: u_char *eth_addr ; ! 313: /* ! 314: * initialization of bridge code ! 315: */ ! 316: if (bdg_table == NULL) ! 317: bdg_table = (struct hash_table *) ! 318: _MALLOC(HASH_SIZE * sizeof(struct hash_table), ! 319: M_IFADDR, M_WAITOK); ! 320: flush_table(); ! 321: ! 322: ifp2sc = _MALLOC(if_index * sizeof(struct bdg_softc *), M_IFADDR, M_WAITOK ); ! 323: bzero(ifp2sc, if_index * sizeof(struct bdg_softc *) ); ! 324: ! 325: bzero(&bdg_stats, sizeof(bdg_stats) ); ! 326: bdg_ports = 0 ; ! 327: eth_addr = bdg_addresses ; ! 328: ! 329: printf("BRIDGE 981214, have %d interfaces\n", if_index); ! 330: for (i = 0 , ifp = ifnet.tqh_first ; i < if_index ; ! 331: i++, ifp = ifp->if_link.tqe_next) ! 332: if (ifp->if_type == IFT_ETHER) { /* ethernet ? */ ! 333: ac = (struct arpcom *)ifp; ! 334: sprintf(bdg_stats.s[ifp->if_index].name, ! 335: "%s%d", ifp->if_name, ifp->if_unit); ! 336: printf("-- index %d %s type %d phy %d addrl %d addr %6D\n", ! 337: ifp->if_index, ! 338: bdg_stats.s[ifp->if_index].name, ! 339: (int)ifp->if_type, (int) ifp->if_physical, ! 340: (int)ifp->if_addrlen, ! 341: ac->ac_enaddr, "." ); ! 342: bcopy(ac->ac_enaddr, eth_addr, 6); ! 343: eth_addr += 6 ; ! 344: ! 345: ifp2sc[bdg_ports] = _MALLOC(sizeof(struct bdg_softc), ! 346: M_IFADDR, M_WAITOK ); ! 347: ifp2sc[bdg_ports]->ifp = ifp ; ! 348: ifp2sc[bdg_ports]->flags = 0 ; ! 349: ifp2sc[bdg_ports]->group = 0 ; ! 350: bdg_ports ++ ; ! 351: } ! 352: bdg_timeout(0); ! 353: do_bridge=0; ! 354: } ! 355: ! 356: /* ! 357: * bridge_in() is invoked to perform bridging decision on input packets. ! 358: * On Input: ! 359: * m packet to be bridged. The mbuf need not to hold the ! 360: * whole packet, only the first 14 bytes suffice. We ! 361: * assume them to be contiguous. No alignment assumptions ! 362: * because they are not a problem on i386 class machines. ! 363: * ! 364: * On Return: destination of packet, one of ! 365: * BDG_BCAST broadcast ! 366: * BDG_MCAST multicast ! 367: * BDG_LOCAL is only for a local address (do not forward) ! 368: * BDG_DROP drop the packet ! 369: * ifp ifp of the destination interface. ! 370: * ! 371: * Forwarding is not done directly to give a chance to some drivers ! 372: * to fetch more of the packet, or simply drop it completely. ! 373: */ ! 374: ! 375: ! 376: struct ifnet * ! 377: bridge_in(struct mbuf *m) ! 378: { ! 379: int index; ! 380: struct ifnet *ifp = m->m_pkthdr.rcvif, *dst , *old ; ! 381: int dropit = MUTED(ifp) ; ! 382: struct ether_header *eh; ! 383: ! 384: eh = mtod(m, struct ether_header *); ! 385: ! 386: /* ! 387: * hash the source address ! 388: */ ! 389: index= HASH_FN(eh->ether_shost); ! 390: bdg_table[index].used = 1 ; ! 391: old = bdg_table[index].name ; ! 392: if ( old ) { /* the entry is valid. */ ! 393: if (!BDG_MATCH( eh->ether_shost, bdg_table[index].etheraddr) ) { ! 394: printf("collision at %d\n", index); ! 395: bdg_table[index].name = NULL ; ! 396: } else if (old != ifp) { ! 397: /* ! 398: * found a loop. Either a machine has moved, or there ! 399: * is a misconfiguration/reconfiguration of the network. ! 400: * First, do not forward this packet! ! 401: * Record the relocation anyways; then, if loops persist, ! 402: * suspect a reconfiguration and disable forwarding ! 403: * from the old interface. ! 404: */ ! 405: bdg_table[index].name = ifp ; /* relocate address */ ! 406: printf("-- loop (%d) %6D to %s%d from %s%d (%s)\n", ! 407: bdg_loops, eh->ether_shost, ".", ! 408: ifp->if_name, ifp->if_unit, ! 409: old->if_name, old->if_unit, ! 410: old->if_flags & IFF_MUTE ? "muted":"ignore"); ! 411: dropit = 1 ; ! 412: if ( !MUTED(old) ) { ! 413: if (++bdg_loops > 10) ! 414: MUTE(old) ; ! 415: } ! 416: } ! 417: } ! 418: ! 419: /* ! 420: * now write the source address into the table ! 421: */ ! 422: if (bdg_table[index].name == NULL) { ! 423: DEB(printf("new addr %6D at %d for %s%d\n", ! 424: eh->ether_shost, ".", index, ifp->if_name, ifp->if_unit);) ! 425: bcopy(eh->ether_shost, bdg_table[index].etheraddr, 6); ! 426: bdg_table[index].name = ifp ; ! 427: } ! 428: dst = bridge_dst_lookup(m); ! 429: /* Return values: ! 430: * BDG_BCAST, BDG_MCAST, BDG_LOCAL, BDG_UNKNOWN, BDG_DROP, ifp. ! 431: * For muted interfaces, the first 3 are changed in BDG_LOCAL, ! 432: * and others to BDG_DROP. Also, for incoming packets, ifp is changed ! 433: * to BDG_DROP in case ifp == src . These mods are not necessary ! 434: * for outgoing packets from ether_output(). ! 435: */ ! 436: BDG_STAT(ifp, BDG_IN); ! 437: switch ((int)dst) { ! 438: case (int)BDG_BCAST: ! 439: case (int)BDG_MCAST: ! 440: case (int)BDG_LOCAL: ! 441: case (int)BDG_UNKNOWN: ! 442: case (int)BDG_DROP: ! 443: BDG_STAT(ifp, dst); ! 444: break ; ! 445: default : ! 446: if (dst == ifp || dropit ) ! 447: BDG_STAT(ifp, BDG_DROP); ! 448: else ! 449: BDG_STAT(ifp, BDG_FORWARD); ! 450: break ; ! 451: } ! 452: ! 453: if ( dropit ) { ! 454: if (dst == BDG_BCAST || dst == BDG_MCAST || dst == BDG_LOCAL) ! 455: return BDG_LOCAL ; ! 456: else ! 457: return BDG_DROP ; ! 458: } else { ! 459: return (dst == ifp ? BDG_DROP : dst ) ; ! 460: } ! 461: } ! 462: ! 463: /* ! 464: * Forward to dst, excluding src port and (if not a single interface) ! 465: * muted interfaces. The packet is freed if marked as such ! 466: * and not for a local destination. ! 467: * A cleaner implementation would be to make bdg_forward() ! 468: * always consume the packet, leaving to the caller the task ! 469: * to make a copy if it needs it. As it is now, bdg_forward() ! 470: * can keep a copy alive in some cases. ! 471: */ ! 472: int ! 473: bdg_forward (struct mbuf **m0, struct ifnet *dst) ! 474: { ! 475: struct ifnet *src = (*m0)->m_pkthdr.rcvif; /* could be NULL in output */ ! 476: struct ifnet *ifp ; ! 477: struct ip *ip; ! 478: int error=0, s ; ! 479: int once = 0; /* execute the loop only once */ ! 480: int canfree = 1 ; /* can free the buf at the end */ ! 481: struct mbuf *m ; ! 482: ! 483: struct ether_header *eh = mtod(*m0, struct ether_header *); /* XXX */ ! 484: ! 485: if (dst == BDG_DROP) { /* this should not happen */ ! 486: printf("xx bdg_forward for BDG_DROP)\n"); ! 487: m_freem(*m0) ; ! 488: *m0 = NULL ; ! 489: return 0; ! 490: } ! 491: if (dst == BDG_LOCAL) { /* this should not happen as well */ ! 492: printf("xx ouch, bdg_forward for local pkt\n"); ! 493: return 0; ! 494: } ! 495: if (dst == BDG_BCAST || dst == BDG_MCAST || dst == BDG_UNKNOWN) { ! 496: ifp = ifnet.tqh_first ; ! 497: once = 0 ; ! 498: if (dst != BDG_UNKNOWN) ! 499: canfree = 0 ; ! 500: } else { ! 501: ifp = dst ; ! 502: once = 1 ; /* and also canfree */ ! 503: } ! 504: #if IPFIREWALL ! 505: /* ! 506: * do filtering in a very similar way to what is done ! 507: * in ip_output. Only for IP packets, and only pass/fail/dummynet ! 508: * is supported. The tricky thing is to make sure that enough of ! 509: * the packet (basically, Eth+IP+TCP/UDP headers) is contiguous ! 510: * so that calls to m_pullup in ip_fw_chk will not kill the ! 511: * ethernet header. ! 512: */ ! 513: if (ip_fw_chk_ptr) { ! 514: u_int16_t dummy ; ! 515: struct ip_fw_chain *rule; ! 516: int off; ! 517: ! 518: m = *m0 ; ! 519: if (m->m_type == MT_DUMMYNET) { ! 520: /* ! 521: * the packet was already tagged, so part of the ! 522: * processing was already done, and we need to go down. ! 523: */ ! 524: rule = (struct ip_fw_chain *)(m->m_data) ; ! 525: (*m0) = m = m->m_next ; ! 526: ! 527: src = m->m_pkthdr.rcvif; /* could be NULL in output */ ! 528: eh = mtod(m, struct ether_header *); /* XXX */ ! 529: canfree = 1 ; /* for sure, a copy is not needed later. */ ! 530: goto forward; /* HACK! */ ! 531: } else ! 532: rule = NULL ; ! 533: if (bdg_ipfw == 0) ! 534: goto forward ; ! 535: if (src == NULL) ! 536: goto forward ; /* do not apply to packets from ether_output */ ! 537: if (canfree == 0 ) /* need to make a copy */ ! 538: m = m_copypacket(*m0, M_DONTWAIT); ! 539: if (m == NULL) { ! 540: /* fail... */ ! 541: return 0 ; ! 542: } ! 543: ! 544: dummy = 0 ; ! 545: /* ! 546: * before calling the firewall, swap fields the same as IP does. ! 547: * here we assume the pkt is an IP one and the header is contiguous ! 548: */ ! 549: eh = mtod(m, struct ether_header *); ! 550: ip = (struct ip *)(eh + 1 ) ; ! 551: NTOHS(ip->ip_len); ! 552: NTOHS(ip->ip_id); ! 553: NTOHS(ip->ip_off); ! 554: ! 555: /* ! 556: * The third parameter to the firewall code is the dst. interface. ! 557: * Since we apply checks only on input pkts we use NULL. ! 558: */ ! 559: off = (*ip_fw_chk_ptr)(NULL, 0, NULL, &dummy, &m, &rule, NULL) ; ! 560: if (m == NULL) { /* pkt discarded by firewall */ ! 561: if (canfree) ! 562: *m0 = NULL ; ! 563: return 0 ; ! 564: } ! 565: /* ! 566: * on return, the mbuf pointer might have changed. Restore ! 567: * *m0 (if it was the same as m), eh, ip and then ! 568: * restore original ordering. ! 569: */ ! 570: eh = mtod(m, struct ether_header *); ! 571: ip = (struct ip *)(eh + 1 ) ; ! 572: if (canfree) /* m was a reference to *m0, so update *m0 */ ! 573: *m0 = m ; ! 574: HTONS(ip->ip_len); ! 575: HTONS(ip->ip_id); ! 576: HTONS(ip->ip_off); ! 577: if (off == 0) { ! 578: if (canfree == 0) ! 579: m_freem(m); ! 580: goto forward ; ! 581: } ! 582: #if DUMMYNET ! 583: if (off & 0x10000) { ! 584: /* ! 585: * pass the pkt to dummynet. Need to include m, dst, rule. ! 586: * Dummynet consumes the packet in all cases. ! 587: */ ! 588: dummynet_io((off & 0xffff), DN_TO_BDG_FWD, m, dst, NULL, 0, rule); ! 589: if (canfree) /* dummynet has consumed the original one */ ! 590: *m0 = NULL ; ! 591: return 0 ; ! 592: } ! 593: #endif ! 594: /* if none of the above matches, we have to drop the pkt */ ! 595: if (m) ! 596: m_freem(m); ! 597: if (canfree && m != *m0) { ! 598: m_freem(*m0); ! 599: *m0 = NULL ; ! 600: } ! 601: return 0 ; ! 602: } ! 603: forward: ! 604: #endif /* COMPAT_IPFW */ ! 605: if (canfree && once) ! 606: m = *m0 ; ! 607: else ! 608: m = NULL ; ! 609: ! 610: for ( ; ifp ; ifp = ifp->if_link.tqe_next ) { ! 611: if (ifp != src && ifp->if_type == IFT_ETHER && ! 612: (ifp->if_flags & (IFF_UP|IFF_RUNNING)) == (IFF_UP|IFF_RUNNING) && ! 613: SAMEGROUP(ifp, src) && !MUTED(ifp) ) { ! 614: if (m == NULL) { /* do i need to make a copy ? */ ! 615: if (canfree && ifp->if_link.tqe_next == NULL) /* last one! */ ! 616: m = *m0 ; ! 617: else /* on a P5-90, m_packetcopy takes 540 ticks */ ! 618: m = m_copypacket(*m0, M_DONTWAIT); ! 619: if (m == NULL) { ! 620: printf("bdg_forward: sorry, m_copy failed!\n"); ! 621: return ENOBUFS ; ! 622: } ! 623: } ! 624: /* ! 625: * execute last part of ether_output. ! 626: */ ! 627: s = splimp(); ! 628: /* ! 629: * Queue message on interface, and start output if interface ! 630: * not yet active. ! 631: */ ! 632: if (IF_QFULL(&ifp->if_snd)) { ! 633: IF_DROP(&ifp->if_snd); ! 634: MUTE(ifp); /* good measure... */ ! 635: splx(s); ! 636: error = ENOBUFS ; ! 637: } else { ! 638: ifp->if_obytes += m->m_pkthdr.len ; ! 639: if (m->m_flags & M_MCAST) ! 640: ifp->if_omcasts++; ! 641: IF_ENQUEUE(&ifp->if_snd, m); ! 642: if ((ifp->if_flags & IFF_OACTIVE) == 0) ! 643: (*ifp->if_start)(ifp); ! 644: splx(s); ! 645: if (m == *m0) ! 646: *m0 = NULL ; /* the packet is gone... */ ! 647: m = NULL ; ! 648: } ! 649: BDG_STAT(ifp, BDG_OUT); ! 650: } ! 651: if (once) ! 652: break ; ! 653: } ! 654: ! 655: /* cleanup any mbuf leftover. */ ! 656: if (m) ! 657: m_freem(m); ! 658: if (m == *m0) ! 659: *m0 = NULL ; ! 660: if (canfree && *m0) { ! 661: m_freem(*m0); ! 662: *m0 = NULL ; ! 663: } ! 664: return error ; ! 665: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.