The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net/bridge.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 211db44d06df6795d0f14663200f486c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.