upgrade to fedora-2.6.12-1.1398.FC4 + vserver 2.0.rc7
[linux-2.6.git] / net / ipv4 / ip_output.c
index 360765a..0fe94ef 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Version:    $Id: ip_output.c,v 1.100 2002/02/01 22:01:03 davem Exp $
  *
- * Authors:    Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors:    Ross Biro
  *             Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
  *             Donald Becker, <becker@super.org>
  *             Alan Cox, <Alan.Cox@linux.org>
@@ -111,11 +111,12 @@ static int ip_dev_loopback_xmit(struct sk_buff *newskb)
 #ifdef CONFIG_NETFILTER_DEBUG
        nf_debug_ip_loopback_xmit(newskb);
 #endif
+       nf_reset(newskb);
        netif_rx(newskb);
        return 0;
 }
 
-static inline int ip_select_ttl(struct inet_opt *inet, struct dst_entry *dst)
+static inline int ip_select_ttl(struct inet_sock *inet, struct dst_entry *dst)
 {
        int ttl = inet->uc_ttl;
 
@@ -131,7 +132,7 @@ static inline int ip_select_ttl(struct inet_opt *inet, struct dst_entry *dst)
 int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
                          u32 saddr, u32 daddr, struct ip_options *opt)
 {
-       struct inet_opt *inet = inet_sk(sk);
+       struct inet_sock *inet = inet_sk(sk);
        struct rtable *rt = (struct rtable *)skb->dst;
        struct iphdr *iph;
 
@@ -195,6 +196,14 @@ static inline int ip_finish_output2(struct sk_buff *skb)
        nf_debug_ip_finish_output2(skb);
 #endif /*CONFIG_NETFILTER_DEBUG*/
 
+#ifdef CONFIG_BRIDGE_NETFILTER
+       /* bridge-netfilter defers calling some IP hooks to the bridge layer
+        * and still needs the conntrack reference.
+        */
+       if (skb->nf_bridge == NULL)
+#endif
+               nf_reset(skb);
+
        if (hh) {
                int hh_alen;
 
@@ -278,7 +287,7 @@ int ip_mc_output(struct sk_buff *skb)
                                newskb->dev, ip_dev_loopback_xmit);
        }
 
-       if (skb->len > dst_pmtu(&rt->u.dst))
+       if (skb->len > dst_mtu(&rt->u.dst))
                return ip_fragment(skb, ip_finish_output);
        else
                return ip_finish_output(skb);
@@ -288,7 +297,7 @@ int ip_output(struct sk_buff *skb)
 {
        IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
 
-       if (skb->len > dst_pmtu(skb->dst) && !skb_shinfo(skb)->tso_size)
+       if (skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->tso_size)
                return ip_fragment(skb, ip_finish_output);
        else
                return ip_finish_output(skb);
@@ -297,7 +306,7 @@ int ip_output(struct sk_buff *skb)
 int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
 {
        struct sock *sk = skb->sk;
-       struct inet_opt *inet = inet_sk(sk);
+       struct inet_sock *inet = inet_sk(sk);
        struct ip_options *opt = inet->opt;
        struct rtable *rt;
        struct iphdr *iph;
@@ -448,7 +457,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
 
        if (unlikely((iph->frag_off & htons(IP_DF)) && !skb->local_df)) {
                icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
-                         htonl(dst_pmtu(&rt->u.dst)));
+                         htonl(dst_mtu(&rt->u.dst)));
                kfree_skb(skb);
                return -EMSGSIZE;
        }
@@ -458,7 +467,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
         */
 
        hlen = iph->ihl * 4;
-       mtu = dst_pmtu(&rt->u.dst) - hlen;      /* Size of data space */
+       mtu = dst_mtu(&rt->u.dst) - hlen;       /* Size of data space */
 
        /* When frag_list is given, use it. First, check its validity:
         * some transformers could create wrong frag_list or break existing
@@ -487,6 +496,14 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
                        /* Partially cloned skb? */
                        if (skb_shared(frag))
                                goto slow_path;
+
+                       BUG_ON(frag->sk);
+                       if (skb->sk) {
+                               sock_hold(skb->sk);
+                               frag->sk = skb->sk;
+                               frag->destructor = sock_wfree;
+                               skb->truesize -= frag->truesize;
+                       }
                }
 
                /* Everything is OK. Generate! */
@@ -498,13 +515,14 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
                skb->data_len = first_len - skb_headlen(skb);
                skb->len = first_len;
                iph->tot_len = htons(first_len);
-               iph->frag_off |= htons(IP_MF);
+               iph->frag_off = htons(IP_MF);
                ip_send_check(iph);
 
                for (;;) {
                        /* Prepare header of the next frame,
                         * before previous one went down. */
                        if (frag) {
+                               frag->ip_summed = CHECKSUM_NONE;
                                frag->h.raw = frag->data;
                                frag->nh.raw = __skb_push(frag, hlen);
                                memcpy(frag->nh.raw, iph, hlen);
@@ -713,7 +731,7 @@ int ip_append_data(struct sock *sk,
                   struct ipcm_cookie *ipc, struct rtable *rt,
                   unsigned int flags)
 {
-       struct inet_opt *inet = inet_sk(sk);
+       struct inet_sock *inet = inet_sk(sk);
        struct sk_buff *skb;
 
        struct ip_options *opt = NULL;
@@ -745,7 +763,7 @@ int ip_append_data(struct sock *sk,
                        inet->cork.addr = ipc->addr;
                }
                dst_hold(&rt->u.dst);
-               inet->cork.fragsize = mtu = dst_pmtu(&rt->u.dst);
+               inet->cork.fragsize = mtu = dst_mtu(rt->u.dst.path);
                inet->cork.rt = rt;
                inet->cork.length = 0;
                sk->sk_sndmsg_page = NULL;
@@ -974,7 +992,7 @@ error:
 ssize_t        ip_append_page(struct sock *sk, struct page *page,
                       int offset, size_t size, int flags)
 {
-       struct inet_opt *inet = inet_sk(sk);
+       struct inet_sock *inet = inet_sk(sk);
        struct sk_buff *skb;
        struct rtable *rt;
        struct ip_options *opt = NULL;
@@ -1113,7 +1131,7 @@ int ip_push_pending_frames(struct sock *sk)
 {
        struct sk_buff *skb, *tmp_skb;
        struct sk_buff **tail_skb;
-       struct inet_opt *inet = inet_sk(sk);
+       struct inet_sock *inet = inet_sk(sk);
        struct ip_options *opt = NULL;
        struct rtable *rt = inet->cork.rt;
        struct iphdr *iph;
@@ -1151,7 +1169,8 @@ int ip_push_pending_frames(struct sock *sk)
         * If local_df is set too, we still allow to fragment this frame
         * locally. */
        if (inet->pmtudisc == IP_PMTUDISC_DO ||
-           (!skb_shinfo(skb)->frag_list && ip_dont_fragment(sk, &rt->u.dst)))
+           (skb->len <= dst_mtu(&rt->u.dst) &&
+            ip_dont_fragment(sk, &rt->u.dst)))
                df = htons(IP_DF);
 
        if (inet->cork.flags & IPCORK_OPT)
@@ -1218,7 +1237,7 @@ error:
  */
 void ip_flush_pending_frames(struct sock *sk)
 {
-       struct inet_opt *inet = inet_sk(sk);
+       struct inet_sock *inet = inet_sk(sk);
        struct sk_buff *skb;
 
        while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL)
@@ -1261,7 +1280,7 @@ static int ip_reply_glue_bits(void *dptr, char *to, int offset,
 void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *arg,
                   unsigned int len)
 {
-       struct inet_opt *inet = inet_sk(sk);
+       struct inet_sock *inet = inet_sk(sk);
        struct {
                struct ip_options       opt;
                char                    data[40];