]> err.no Git - linux-2.6/blobdiff - net/bridge/br_netfilter.c
Pull trivial2 into release branch
[linux-2.6] / net / bridge / br_netfilter.c
index ea34aa505af2476dfc3cfeccaab2aabe78450ab6..3da9264449f79d6d517fce1391af3f663bdde3a8 100644 (file)
@@ -61,15 +61,25 @@ static int brnf_filter_vlan_tagged = 1;
 #define brnf_filter_vlan_tagged 1
 #endif
 
-#define IS_VLAN_IP (skb->protocol == htons(ETH_P_8021Q) &&    \
-       hdr->h_vlan_encapsulated_proto == htons(ETH_P_IP) &&  \
-       brnf_filter_vlan_tagged)
-#define IS_VLAN_IPV6 (skb->protocol == htons(ETH_P_8021Q) &&    \
-       hdr->h_vlan_encapsulated_proto == htons(ETH_P_IPV6) &&  \
-       brnf_filter_vlan_tagged)
-#define IS_VLAN_ARP (skb->protocol == htons(ETH_P_8021Q) &&   \
-       hdr->h_vlan_encapsulated_proto == htons(ETH_P_ARP) && \
-       brnf_filter_vlan_tagged)
+static __be16 inline vlan_proto(const struct sk_buff *skb)
+{
+       return vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
+}
+
+#define IS_VLAN_IP(skb) \
+       (skb->protocol == htons(ETH_P_8021Q) && \
+        vlan_proto(skb) == htons(ETH_P_IP) &&  \
+        brnf_filter_vlan_tagged)
+
+#define IS_VLAN_IPV6(skb) \
+       (skb->protocol == htons(ETH_P_8021Q) && \
+        vlan_proto(skb) == htons(ETH_P_IPV6) &&\
+        brnf_filter_vlan_tagged)
+
+#define IS_VLAN_ARP(skb) \
+       (skb->protocol == htons(ETH_P_8021Q) && \
+        vlan_proto(skb) == htons(ETH_P_ARP) && \
+        brnf_filter_vlan_tagged)
 
 /* We need these fake structures to make netfilter happy --
  * lots of places assume that skb->dst != NULL, which isn't
@@ -103,6 +113,25 @@ static inline struct net_device *bridge_parent(const struct net_device *dev)
        return port ? port->br->dev : NULL;
 }
 
+static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb)
+{
+       skb->nf_bridge = kzalloc(sizeof(struct nf_bridge_info), GFP_ATOMIC);
+       if (likely(skb->nf_bridge))
+               atomic_set(&(skb->nf_bridge->use), 1);
+
+       return skb->nf_bridge;
+}
+
+static inline void nf_bridge_save_header(struct sk_buff *skb)
+{
+        int header_size = 16;
+
+       if (skb->protocol == htons(ETH_P_8021Q))
+               header_size = 18;
+
+       memcpy(skb->nf_bridge->data, skb->data - header_size, header_size);
+}
+
 /* PF_BRIDGE/PRE_ROUTING *********************************************/
 /* Undo the changes made for ip6tables PREROUTING and continue the
  * bridge PRE_ROUTING hook. */
@@ -361,7 +390,6 @@ static unsigned int br_nf_pre_routing_ipv6(unsigned int hook,
 {
        struct ipv6hdr *hdr;
        u32 pkt_len;
-       struct nf_bridge_info *nf_bridge;
 
        if (skb->len < sizeof(struct ipv6hdr))
                goto inhdr_error;
@@ -390,7 +418,7 @@ static unsigned int br_nf_pre_routing_ipv6(unsigned int hook,
                goto inhdr_error;
 
        nf_bridge_put(skb->nf_bridge);
-       if ((nf_bridge = nf_bridge_alloc(skb)) == NULL)
+       if (!nf_bridge_alloc(skb))
                return NF_DROP;
        if (!setup_pre_routing(skb))
                return NF_DROP;
@@ -418,10 +446,8 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb,
        struct iphdr *iph;
        __u32 len;
        struct sk_buff *skb = *pskb;
-       struct nf_bridge_info *nf_bridge;
-       struct vlan_ethhdr *hdr = vlan_eth_hdr(*pskb);
 
-       if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6) {
+       if (skb->protocol == htons(ETH_P_IPV6) || IS_VLAN_IPV6(skb)) {
 #ifdef CONFIG_SYSCTL
                if (!brnf_call_ip6tables)
                        return NF_ACCEPT;
@@ -440,7 +466,7 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb,
                return NF_ACCEPT;
 #endif
 
-       if (skb->protocol != htons(ETH_P_IP) && !IS_VLAN_IP)
+       if (skb->protocol != htons(ETH_P_IP) && !IS_VLAN_IP(skb))
                return NF_ACCEPT;
 
        if ((skb = skb_share_check(*pskb, GFP_ATOMIC)) == NULL)
@@ -476,7 +502,7 @@ static unsigned int br_nf_pre_routing(unsigned int hook, struct sk_buff **pskb,
        }
 
        nf_bridge_put(skb->nf_bridge);
-       if ((nf_bridge = nf_bridge_alloc(skb)) == NULL)
+       if (!nf_bridge_alloc(skb))
                return NF_DROP;
        if (!setup_pre_routing(skb))
                return NF_DROP;
@@ -521,9 +547,8 @@ static int br_nf_forward_finish(struct sk_buff *skb)
 {
        struct nf_bridge_info *nf_bridge = skb->nf_bridge;
        struct net_device *in;
-       struct vlan_ethhdr *hdr = vlan_eth_hdr(skb);
 
-       if (skb->protocol != htons(ETH_P_ARP) && !IS_VLAN_ARP) {
+       if (skb->protocol != htons(ETH_P_ARP) && !IS_VLAN_ARP(skb)) {
                in = nf_bridge->physindev;
                if (nf_bridge->mask & BRNF_PKT_TYPE) {
                        skb->pkt_type = PACKET_OTHERHOST;
@@ -553,7 +578,6 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff **pskb,
 {
        struct sk_buff *skb = *pskb;
        struct nf_bridge_info *nf_bridge;
-       struct vlan_ethhdr *hdr = vlan_eth_hdr(skb);
        struct net_device *parent;
        int pf;
 
@@ -564,7 +588,7 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff **pskb,
        if (!parent)
                return NF_DROP;
 
-       if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP)
+       if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb))
                pf = PF_INET;
        else
                pf = PF_INET6;
@@ -596,7 +620,6 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb,
                                      int (*okfn)(struct sk_buff *))
 {
        struct sk_buff *skb = *pskb;
-       struct vlan_ethhdr *hdr = vlan_eth_hdr(skb);
        struct net_device **d = (struct net_device **)(skb->cb);
 
 #ifdef CONFIG_SYSCTL
@@ -605,14 +628,14 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb,
 #endif
 
        if (skb->protocol != htons(ETH_P_ARP)) {
-               if (!IS_VLAN_ARP)
+               if (!IS_VLAN_ARP(skb))
                        return NF_ACCEPT;
                skb_pull(*pskb, VLAN_HLEN);
                (*pskb)->nh.raw += VLAN_HLEN;
        }
 
        if (skb->nh.arph->ar_pln != 4) {
-               if (IS_VLAN_ARP) {
+               if (IS_VLAN_ARP(skb)) {
                        skb_push(*pskb, VLAN_HLEN);
                        (*pskb)->nh.raw -= VLAN_HLEN;
                }
@@ -667,13 +690,12 @@ static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb,
        struct net_device *realindev, *realoutdev;
        struct sk_buff *skb = *pskb;
        struct nf_bridge_info *nf_bridge;
-       struct vlan_ethhdr *hdr = vlan_eth_hdr(skb);
        int pf;
 
        if (!skb->nf_bridge)
                return NF_ACCEPT;
 
-       if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP)
+       if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb))
                pf = PF_INET;
        else
                pf = PF_INET6;
@@ -743,6 +765,15 @@ out:
        return NF_STOLEN;
 }
 
+static int br_nf_dev_queue_xmit(struct sk_buff *skb)
+{
+       if (skb->protocol == htons(ETH_P_IP) &&
+           skb->len > skb->dev->mtu &&
+           !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
+               return ip_fragment(skb, br_dev_queue_push_xmit);
+       else
+               return br_dev_queue_push_xmit(skb);
+}
 
 /* PF_BRIDGE/POST_ROUTING ********************************************/
 static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb,
@@ -752,7 +783,6 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb,
 {
        struct sk_buff *skb = *pskb;
        struct nf_bridge_info *nf_bridge = (*pskb)->nf_bridge;
-       struct vlan_ethhdr *hdr = vlan_eth_hdr(skb);
        struct net_device *realoutdev = bridge_parent(skb->dev);
        int pf;
 
@@ -772,7 +802,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb,
        if (!realoutdev)
                return NF_DROP;
 
-       if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP)
+       if (skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb))
                pf = PF_INET;
        else
                pf = PF_INET6;
@@ -803,7 +833,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb,
                realoutdev = nf_bridge->netoutdev;
 #endif
        NF_HOOK(pf, NF_IP_POST_ROUTING, skb, NULL, realoutdev,
-               br_dev_queue_push_xmit);
+               br_nf_dev_queue_xmit);
 
        return NF_STOLEN;
 
@@ -848,7 +878,7 @@ static unsigned int ip_sabotage_out(unsigned int hook, struct sk_buff **pskb,
 
        if ((out->hard_start_xmit == br_dev_xmit &&
             okfn != br_nf_forward_finish &&
-            okfn != br_nf_local_out_finish && okfn != br_dev_queue_push_xmit)
+            okfn != br_nf_local_out_finish && okfn != br_nf_dev_queue_xmit)
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
            || ((out->priv_flags & IFF_802_1Q_VLAN) &&
                VLAN_DEV_INFO(out)->real_dev->hard_start_xmit == br_dev_xmit)