Revert "udp: remove redundant variable"
[linux-2.6.git] / net / ipv6 / ip6_output.c
index 32e5339..84d0bd5 100644 (file)
@@ -135,10 +135,15 @@ static int ip6_finish_output2(struct sk_buff *skb)
                                skb->len);
        }
 
+       rcu_read_lock();
        neigh = dst_get_neighbour(dst);
-       if (neigh)
-               return neigh_output(neigh, skb);
+       if (neigh) {
+               int res = neigh_output(neigh, skb);
 
+               rcu_read_unlock();
+               return res;
+       }
+       rcu_read_unlock();
        IP6_INC_STATS_BH(dev_net(dst->dev),
                         ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
        kfree_skb(skb);
@@ -175,7 +180,7 @@ int ip6_output(struct sk_buff *skb)
  */
 
 int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
-            struct ipv6_txoptions *opt)
+            struct ipv6_txoptions *opt, int tclass)
 {
        struct net *net = sock_net(sk);
        struct ipv6_pinfo *np = inet6_sk(sk);
@@ -185,7 +190,6 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
        u8  proto = fl6->flowi6_proto;
        int seg_len = skb->len;
        int hlimit = -1;
-       int tclass = 0;
        u32 mtu;
 
        if (opt) {
@@ -223,10 +227,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
        /*
         *      Fill in the IPv6 header
         */
-       if (np) {
-               tclass = np->tclass;
+       if (np)
                hlimit = np->hop_limit;
-       }
        if (hlimit < 0)
                hlimit = ip6_dst_hoplimit(dst);
 
@@ -975,12 +977,14 @@ static int ip6_dst_lookup_tail(struct sock *sk,
         * dst entry and replace it instead with the
         * dst entry of the nexthop router
         */
+       rcu_read_lock();
        n = dst_get_neighbour(*dst);
        if (n && !(n->nud_state & NUD_VALID)) {
                struct inet6_ifaddr *ifp;
                struct flowi6 fl_gw6;
                int redirect;
 
+               rcu_read_unlock();
                ifp = ipv6_get_ifaddr(net, &fl6->saddr,
                                      (*dst)->dev, 1);
 
@@ -1000,6 +1004,8 @@ static int ip6_dst_lookup_tail(struct sock *sk,
                        if ((err = (*dst)->error))
                                goto out_err_release;
                }
+       } else {
+               rcu_read_unlock();
        }
 #endif
 
@@ -1117,7 +1123,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
                        hh_len + fragheaderlen + transhdrlen + 20,
                        (flags & MSG_DONTWAIT), &err);
                if (skb == NULL)
-                       return -ENOMEM;
+                       return err;
 
                /* reserve space for Hardware header */
                skb_reserve(skb, hh_len);
@@ -1184,6 +1190,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
        struct sk_buff *skb;
        unsigned int maxfraglen, fragheaderlen;
        int exthdrlen;
+       int dst_exthdrlen;
        int hh_len;
        int mtu;
        int copy;
@@ -1239,7 +1246,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
                np->cork.hop_limit = hlimit;
                np->cork.tclass = tclass;
                mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ?
-                     rt->dst.dev->mtu : dst_mtu(rt->dst.path);
+                     rt->dst.dev->mtu : dst_mtu(&rt->dst);
                if (np->frag_size < mtu) {
                        if (np->frag_size)
                                mtu = np->frag_size;
@@ -1250,16 +1257,17 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
                cork->length = 0;
                sk->sk_sndmsg_page = NULL;
                sk->sk_sndmsg_off = 0;
-               exthdrlen = rt->dst.header_len + (opt ? opt->opt_flen : 0) -
-                           rt->rt6i_nfheader_len;
+               exthdrlen = (opt ? opt->opt_flen : 0) - rt->rt6i_nfheader_len;
                length += exthdrlen;
                transhdrlen += exthdrlen;
+               dst_exthdrlen = rt->dst.header_len;
        } else {
                rt = (struct rt6_info *)cork->dst;
                fl6 = &inet->cork.fl.u.ip6;
                opt = np->cork.opt;
                transhdrlen = 0;
                exthdrlen = 0;
+               dst_exthdrlen = 0;
                mtu = cork->fragsize;
        }
 
@@ -1359,6 +1367,8 @@ alloc_new_skb:
                        else
                                alloclen = datalen + fragheaderlen;
 
+                       alloclen += dst_exthdrlen;
+
                        /*
                         * The last fragment gets additional space at tail.
                         * Note: we overallocate on fragments with MSG_MODE
@@ -1410,9 +1420,9 @@ alloc_new_skb:
                        /*
                         *      Find where to start putting bytes
                         */
-                       data = skb_put(skb, fraglen);
-                       skb_set_network_header(skb, exthdrlen);
-                       data += fragheaderlen;
+                       data = skb_put(skb, fraglen + dst_exthdrlen);
+                       skb_set_network_header(skb, exthdrlen + dst_exthdrlen);
+                       data += fragheaderlen + dst_exthdrlen;
                        skb->transport_header = (skb->network_header +
                                                 fragheaderlen);
                        if (fraggap) {
@@ -1425,6 +1435,7 @@ alloc_new_skb:
                                pskb_trim_unique(skb_prev, maxfraglen);
                        }
                        copy = datalen - transhdrlen - fraggap;
+
                        if (copy < 0) {
                                err = -EINVAL;
                                kfree_skb(skb);
@@ -1439,6 +1450,7 @@ alloc_new_skb:
                        length -= datalen - fraggap;
                        transhdrlen = 0;
                        exthdrlen = 0;
+                       dst_exthdrlen = 0;
                        csummode = CHECKSUM_NONE;
 
                        /*
@@ -1471,13 +1483,13 @@ alloc_new_skb:
                        if (page && (left = PAGE_SIZE - off) > 0) {
                                if (copy >= left)
                                        copy = left;
-                               if (page != frag->page) {
+                               if (page != skb_frag_page(frag)) {
                                        if (i == MAX_SKB_FRAGS) {
                                                err = -EMSGSIZE;
                                                goto error;
                                        }
-                                       get_page(page);
                                        skb_fill_page_desc(skb, i, page, sk->sk_sndmsg_off, 0);
+                                       skb_frag_ref(skb, i);
                                        frag = &skb_shinfo(skb)->frags[i];
                                }
                        } else if(i < MAX_SKB_FRAGS) {
@@ -1497,12 +1509,14 @@ alloc_new_skb:
                                err = -EMSGSIZE;
                                goto error;
                        }
-                       if (getfrag(from, page_address(frag->page)+frag->page_offset+frag->size, offset, copy, skb->len, skb) < 0) {
+                       if (getfrag(from,
+                                   skb_frag_address(frag) + skb_frag_size(frag),
+                                   offset, copy, skb->len, skb) < 0) {
                                err = -EFAULT;
                                goto error;
                        }
                        sk->sk_sndmsg_off += copy;
-                       frag->size += copy;
+                       skb_frag_size_add(frag, copy);
                        skb->len += copy;
                        skb->data_len += copy;
                        skb->truesize += copy;