]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/ipv4/ip_output.c
[NETFILTER]: Fix fragmentation issues with bridge netfilter
[net-next-2.6.git] / net / ipv4 / ip_output.c
index 3324fbfe528a048b279c7b7f44e25810a750dbca..8dcba3887f04eb647df01ae404b3b9bda955408d 100644 (file)
@@ -86,8 +86,6 @@
 
 int sysctl_ip_default_ttl = IPDEFTTL;
 
-static int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*));
-
 /* Generate a checksum for an outgoing IP datagram. */
 __inline__ void ip_send_check(struct iphdr *iph)
 {
@@ -207,8 +205,10 @@ static inline int ip_finish_output(struct sk_buff *skb)
 {
 #if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
        /* Policy lookup after SNAT yielded a new policy */
-       if (skb->dst->xfrm != NULL)
-               return xfrm4_output_finish(skb);
+       if (skb->dst->xfrm != NULL) {
+               IPCB(skb)->flags |= IPSKB_REROUTED;
+               return dst_output(skb);
+       }
 #endif
        if (skb->len > dst_mtu(skb->dst) &&
            !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
@@ -271,8 +271,9 @@ int ip_mc_output(struct sk_buff *skb)
                                newskb->dev, ip_dev_loopback_xmit);
        }
 
-       return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dev,
-                      ip_finish_output);
+       return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dev,
+                           ip_finish_output,
+                           !(IPCB(skb)->flags & IPSKB_REROUTED));
 }
 
 int ip_output(struct sk_buff *skb)
@@ -284,8 +285,9 @@ int ip_output(struct sk_buff *skb)
        skb->dev = dev;
        skb->protocol = htons(ETH_P_IP);
 
-       return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,
-                      ip_finish_output);
+       return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,
+                           ip_finish_output,
+                           !(IPCB(skb)->flags & IPSKB_REROUTED));
 }
 
 int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
@@ -417,7 +419,7 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
  *     single device frame, and queue such a frame for sending.
  */
 
-static int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
+int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
 {
        struct iphdr *iph;
        int raw = 0;
@@ -669,6 +671,8 @@ fail:
        return err;
 }
 
+EXPORT_SYMBOL(ip_fragment);
+
 int
 ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
 {
@@ -843,10 +847,11 @@ int ip_append_data(struct sock *sk,
        if (((length > mtu) && (sk->sk_protocol == IPPROTO_UDP)) &&
                        (rt->u.dst.dev->features & NETIF_F_UFO)) {
 
-               if(ip_ufo_append_data(sk, getfrag, from, length, hh_len,
-                              fragheaderlen, transhdrlen, mtu, flags))
+               err = ip_ufo_append_data(sk, getfrag, from, length, hh_len,
+                                        fragheaderlen, transhdrlen, mtu,
+                                        flags);
+               if (err)
                        goto error;
-
                return 0;
        }
 
@@ -1244,11 +1249,7 @@ int ip_push_pending_frames(struct sock *sk)
        iph->tos = inet->tos;
        iph->tot_len = htons(skb->len);
        iph->frag_off = df;
-       if (!df) {
-               __ip_select_ident(iph, &rt->u.dst, 0);
-       } else {
-               iph->id = htons(inet->id++);
-       }
+       ip_select_ident(iph, &rt->u.dst, sk);
        iph->ttl = ttl;
        iph->protocol = sk->sk_protocol;
        iph->saddr = rt->rt_src;