Merge branch 'staging-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[pandora-kernel.git] / net / bridge / br_input.c
index 6f6d8e1..0c7bada 100644 (file)
@@ -80,7 +80,7 @@ int br_handle_frame_finish(struct sk_buff *skb)
        if (is_multicast_ether_addr(dest)) {
                mdst = br_mdb_get(br, skb);
                if (mdst || BR_INPUT_SKB_CB_MROUTERS_ONLY(skb)) {
-                       if ((mdst && !hlist_unhashed(&mdst->mglist)) ||
+                       if ((mdst && mdst->mglist) ||
                            br_multicast_is_router(br))
                                skb2 = skb;
                        br_multicast_forward(mdst, skb, skb2);
@@ -139,21 +139,22 @@ static inline int is_link_local(const unsigned char *dest)
  * Return NULL if skb is handled
  * note: already called with rcu_read_lock
  */
-struct sk_buff *br_handle_frame(struct sk_buff *skb)
+rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
 {
        struct net_bridge_port *p;
+       struct sk_buff *skb = *pskb;
        const unsigned char *dest = eth_hdr(skb)->h_dest;
        br_should_route_hook_t *rhook;
 
        if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
-               return skb;
+               return RX_HANDLER_PASS;
 
        if (!is_valid_ether_addr(eth_hdr(skb)->h_source))
                goto drop;
 
        skb = skb_share_check(skb, GFP_ATOMIC);
        if (!skb)
-               return NULL;
+               return RX_HANDLER_CONSUMED;
 
        p = br_port_get_rcu(skb->dev);
 
@@ -163,14 +164,16 @@ struct sk_buff *br_handle_frame(struct sk_buff *skb)
                        goto drop;
 
                /* If STP is turned off, then forward */
-               if (p->br->stp_enabled == BR_NO_STP)
+               if (p->br->stp_enabled == BR_NO_STP && dest[5] == 0)
                        goto forward;
 
                if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, skb->dev,
-                           NULL, br_handle_local_finish))
-                       return NULL;    /* frame consumed by filter */
-               else
-                       return skb;     /* continue processing */
+                           NULL, br_handle_local_finish)) {
+                       return RX_HANDLER_CONSUMED; /* consumed by filter */
+               } else {
+                       *pskb = skb;
+                       return RX_HANDLER_PASS; /* continue processing */
+               }
        }
 
 forward:
@@ -178,8 +181,10 @@ forward:
        case BR_STATE_FORWARDING:
                rhook = rcu_dereference(br_should_route_hook);
                if (rhook) {
-                       if ((*rhook)(skb))
-                               return skb;
+                       if ((*rhook)(skb)) {
+                               *pskb = skb;
+                               return RX_HANDLER_PASS;
+                       }
                        dest = eth_hdr(skb)->h_dest;
                }
                /* fall through */
@@ -194,5 +199,5 @@ forward:
 drop:
                kfree_skb(skb);
        }
-       return NULL;
+       return RX_HANDLER_CONSUMED;
 }