Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
[cascardo/linux.git] / net / ipv6 / ip6_output.c
index 4c882cf..84d0bd5 100644 (file)
@@ -180,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);
@@ -190,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) {
@@ -228,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);
 
@@ -1126,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);
@@ -1193,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;
@@ -1248,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;
@@ -1259,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;
        }
 
@@ -1368,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
@@ -1419,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) {
@@ -1434,6 +1435,7 @@ alloc_new_skb:
                                pskb_trim_unique(skb_prev, maxfraglen);
                        }
                        copy = datalen - transhdrlen - fraggap;
+
                        if (copy < 0) {
                                err = -EINVAL;
                                kfree_skb(skb);
@@ -1448,6 +1450,7 @@ alloc_new_skb:
                        length -= datalen - fraggap;
                        transhdrlen = 0;
                        exthdrlen = 0;
+                       dst_exthdrlen = 0;
                        csummode = CHECKSUM_NONE;
 
                        /*
@@ -1480,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) {
@@ -1506,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;