]> err.no Git - linux-2.6/blobdiff - net/bridge/br_forward.c
ALSA: wm8750: add missing VREF output
[linux-2.6] / net / bridge / br_forward.c
index 2d24fb400e0cbbd79ef064758b69bbebf07e0ccb..bdd9ccea17ceb992a956453f8c9611c5ed92c244 100644 (file)
@@ -5,8 +5,6 @@
  *     Authors:
  *     Lennert Buytenhek               <buytenh@gnu.org>
  *
- *     $Id: br_forward.c,v 1.4 2001/08/14 22:05:57 davem Exp $
- *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
  *     as published by the Free Software Foundation; either version
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
+#include <linux/if_vlan.h>
 #include <linux/netfilter_bridge.h>
 #include "br_private.h"
 
-static inline int should_deliver(const struct net_bridge_port *p, 
+/* Don't forward packets to originating port or forwarding diasabled */
+static inline int should_deliver(const struct net_bridge_port *p,
                                 const struct sk_buff *skb)
 {
-       if (skb->dev == p->dev ||
-           p->state != BR_STATE_FORWARDING)
-               return 0;
+       return (skb->dev != p->dev && p->state == BR_STATE_FORWARDING);
+}
 
-       return 1;
+static inline unsigned packet_length(const struct sk_buff *skb)
+{
+       return skb->len - (skb->protocol == htons(ETH_P_8021Q) ? VLAN_HLEN : 0);
 }
 
 int br_dev_queue_push_xmit(struct sk_buff *skb)
 {
-       /* drop mtu oversized packets except tso */
-       if (skb->len > skb->dev->mtu && !skb_shinfo(skb)->tso_size)
+       /* drop mtu oversized packets except gso */
+       if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb))
                kfree_skb(skb);
        else {
-#ifdef CONFIG_BRIDGE_NETFILTER
                /* ip_refrag calls ip_fragment, doesn't copy the MAC header. */
-               nf_bridge_maybe_copy_header(skb);
-#endif
-               skb_push(skb, ETH_HLEN);
+               if (nf_bridge_maybe_copy_header(skb))
+                       kfree_skb(skb);
+               else {
+                       skb_push(skb, ETH_HLEN);
 
-               dev_queue_xmit(skb);
+                       dev_queue_xmit(skb);
+               }
        }
 
        return 0;
@@ -49,10 +51,9 @@ int br_dev_queue_push_xmit(struct sk_buff *skb)
 
 int br_forward_finish(struct sk_buff *skb)
 {
-       NF_HOOK(PF_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev,
-                       br_dev_queue_push_xmit);
+       return NF_HOOK(PF_BRIDGE, NF_BR_POST_ROUTING, skb, NULL, skb->dev,
+                      br_dev_queue_push_xmit);
 
-       return 0;
 }
 
 static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
@@ -68,7 +69,7 @@ static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
 
        indev = skb->dev;
        skb->dev = to->dev;
-       skb->ip_summed = CHECKSUM_NONE;
+       skb_forward_csum(skb);
 
        NF_HOOK(PF_BRIDGE, NF_BR_FORWARD, skb, indev, skb->dev,
                        br_forward_finish);
@@ -88,7 +89,7 @@ void br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
 /* called with rcu_read_lock */
 void br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
 {
-       if (should_deliver(to, skb)) {
+       if (!skb_warn_if_lro(skb) && should_deliver(to, skb)) {
                __br_forward(to, skb);
                return;
        }
@@ -97,24 +98,13 @@ void br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
 }
 
 /* called under bridge lock */
-static void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone,
-       void (*__packet_hook)(const struct net_bridge_port *p, 
+static void br_flood(struct net_bridge *br, struct sk_buff *skb,
+       void (*__packet_hook)(const struct net_bridge_port *p,
                              struct sk_buff *skb))
 {
        struct net_bridge_port *p;
        struct net_bridge_port *prev;
 
-       if (clone) {
-               struct sk_buff *skb2;
-
-               if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {
-                       br->statistics.tx_dropped++;
-                       return;
-               }
-
-               skb = skb2;
-       }
-
        prev = NULL;
 
        list_for_each_entry_rcu(p, &br->port_list, list) {
@@ -123,7 +113,7 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone,
                                struct sk_buff *skb2;
 
                                if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {
-                                       br->statistics.tx_dropped++;
+                                       br->dev->stats.tx_dropped++;
                                        kfree_skb(skb);
                                        return;
                                }
@@ -145,13 +135,13 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb, int clone,
 
 
 /* called with rcu_read_lock */
-void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb, int clone)
+void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb)
 {
-       br_flood(br, skb, clone, __br_deliver);
+       br_flood(br, skb, __br_deliver);
 }
 
 /* called under bridge lock */
-void br_flood_forward(struct net_bridge *br, struct sk_buff *skb, int clone)
+void br_flood_forward(struct net_bridge *br, struct sk_buff *skb)
 {
-       br_flood(br, skb, clone, __br_forward);
+       br_flood(br, skb, __br_forward);
 }