aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r--net/ipv6/ip6_output.c37
1 files changed, 21 insertions, 16 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 4c882cf4e8a1..84d0bd5cac93 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -180,7 +180,7 @@ int ip6_output(struct sk_buff *skb)
180 */ 180 */
181 181
182int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, 182int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
183 struct ipv6_txoptions *opt) 183 struct ipv6_txoptions *opt, int tclass)
184{ 184{
185 struct net *net = sock_net(sk); 185 struct net *net = sock_net(sk);
186 struct ipv6_pinfo *np = inet6_sk(sk); 186 struct ipv6_pinfo *np = inet6_sk(sk);
@@ -190,7 +190,6 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
190 u8 proto = fl6->flowi6_proto; 190 u8 proto = fl6->flowi6_proto;
191 int seg_len = skb->len; 191 int seg_len = skb->len;
192 int hlimit = -1; 192 int hlimit = -1;
193 int tclass = 0;
194 u32 mtu; 193 u32 mtu;
195 194
196 if (opt) { 195 if (opt) {
@@ -228,10 +227,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6,
228 /* 227 /*
229 * Fill in the IPv6 header 228 * Fill in the IPv6 header
230 */ 229 */
231 if (np) { 230 if (np)
232 tclass = np->tclass;
233 hlimit = np->hop_limit; 231 hlimit = np->hop_limit;
234 }
235 if (hlimit < 0) 232 if (hlimit < 0)
236 hlimit = ip6_dst_hoplimit(dst); 233 hlimit = ip6_dst_hoplimit(dst);
237 234
@@ -1126,7 +1123,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
1126 hh_len + fragheaderlen + transhdrlen + 20, 1123 hh_len + fragheaderlen + transhdrlen + 20,
1127 (flags & MSG_DONTWAIT), &err); 1124 (flags & MSG_DONTWAIT), &err);
1128 if (skb == NULL) 1125 if (skb == NULL)
1129 return -ENOMEM; 1126 return err;
1130 1127
1131 /* reserve space for Hardware header */ 1128 /* reserve space for Hardware header */
1132 skb_reserve(skb, hh_len); 1129 skb_reserve(skb, hh_len);
@@ -1193,6 +1190,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
1193 struct sk_buff *skb; 1190 struct sk_buff *skb;
1194 unsigned int maxfraglen, fragheaderlen; 1191 unsigned int maxfraglen, fragheaderlen;
1195 int exthdrlen; 1192 int exthdrlen;
1193 int dst_exthdrlen;
1196 int hh_len; 1194 int hh_len;
1197 int mtu; 1195 int mtu;
1198 int copy; 1196 int copy;
@@ -1248,7 +1246,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
1248 np->cork.hop_limit = hlimit; 1246 np->cork.hop_limit = hlimit;
1249 np->cork.tclass = tclass; 1247 np->cork.tclass = tclass;
1250 mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ? 1248 mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ?
1251 rt->dst.dev->mtu : dst_mtu(rt->dst.path); 1249 rt->dst.dev->mtu : dst_mtu(&rt->dst);
1252 if (np->frag_size < mtu) { 1250 if (np->frag_size < mtu) {
1253 if (np->frag_size) 1251 if (np->frag_size)
1254 mtu = np->frag_size; 1252 mtu = np->frag_size;
@@ -1259,16 +1257,17 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
1259 cork->length = 0; 1257 cork->length = 0;
1260 sk->sk_sndmsg_page = NULL; 1258 sk->sk_sndmsg_page = NULL;
1261 sk->sk_sndmsg_off = 0; 1259 sk->sk_sndmsg_off = 0;
1262 exthdrlen = rt->dst.header_len + (opt ? opt->opt_flen : 0) - 1260 exthdrlen = (opt ? opt->opt_flen : 0) - rt->rt6i_nfheader_len;
1263 rt->rt6i_nfheader_len;
1264 length += exthdrlen; 1261 length += exthdrlen;
1265 transhdrlen += exthdrlen; 1262 transhdrlen += exthdrlen;
1263 dst_exthdrlen = rt->dst.header_len;
1266 } else { 1264 } else {
1267 rt = (struct rt6_info *)cork->dst; 1265 rt = (struct rt6_info *)cork->dst;
1268 fl6 = &inet->cork.fl.u.ip6; 1266 fl6 = &inet->cork.fl.u.ip6;
1269 opt = np->cork.opt; 1267 opt = np->cork.opt;
1270 transhdrlen = 0; 1268 transhdrlen = 0;
1271 exthdrlen = 0; 1269 exthdrlen = 0;
1270 dst_exthdrlen = 0;
1272 mtu = cork->fragsize; 1271 mtu = cork->fragsize;
1273 } 1272 }
1274 1273
@@ -1368,6 +1367,8 @@ alloc_new_skb:
1368 else 1367 else
1369 alloclen = datalen + fragheaderlen; 1368 alloclen = datalen + fragheaderlen;
1370 1369
1370 alloclen += dst_exthdrlen;
1371
1371 /* 1372 /*
1372 * The last fragment gets additional space at tail. 1373 * The last fragment gets additional space at tail.
1373 * Note: we overallocate on fragments with MSG_MODE 1374 * Note: we overallocate on fragments with MSG_MODE
@@ -1419,9 +1420,9 @@ alloc_new_skb:
1419 /* 1420 /*
1420 * Find where to start putting bytes 1421 * Find where to start putting bytes
1421 */ 1422 */
1422 data = skb_put(skb, fraglen); 1423 data = skb_put(skb, fraglen + dst_exthdrlen);
1423 skb_set_network_header(skb, exthdrlen); 1424 skb_set_network_header(skb, exthdrlen + dst_exthdrlen);
1424 data += fragheaderlen; 1425 data += fragheaderlen + dst_exthdrlen;
1425 skb->transport_header = (skb->network_header + 1426 skb->transport_header = (skb->network_header +
1426 fragheaderlen); 1427 fragheaderlen);
1427 if (fraggap) { 1428 if (fraggap) {
@@ -1434,6 +1435,7 @@ alloc_new_skb:
1434 pskb_trim_unique(skb_prev, maxfraglen); 1435 pskb_trim_unique(skb_prev, maxfraglen);
1435 } 1436 }
1436 copy = datalen - transhdrlen - fraggap; 1437 copy = datalen - transhdrlen - fraggap;
1438
1437 if (copy < 0) { 1439 if (copy < 0) {
1438 err = -EINVAL; 1440 err = -EINVAL;
1439 kfree_skb(skb); 1441 kfree_skb(skb);
@@ -1448,6 +1450,7 @@ alloc_new_skb:
1448 length -= datalen - fraggap; 1450 length -= datalen - fraggap;
1449 transhdrlen = 0; 1451 transhdrlen = 0;
1450 exthdrlen = 0; 1452 exthdrlen = 0;
1453 dst_exthdrlen = 0;
1451 csummode = CHECKSUM_NONE; 1454 csummode = CHECKSUM_NONE;
1452 1455
1453 /* 1456 /*
@@ -1480,13 +1483,13 @@ alloc_new_skb:
1480 if (page && (left = PAGE_SIZE - off) > 0) { 1483 if (page && (left = PAGE_SIZE - off) > 0) {
1481 if (copy >= left) 1484 if (copy >= left)
1482 copy = left; 1485 copy = left;
1483 if (page != frag->page) { 1486 if (page != skb_frag_page(frag)) {
1484 if (i == MAX_SKB_FRAGS) { 1487 if (i == MAX_SKB_FRAGS) {
1485 err = -EMSGSIZE; 1488 err = -EMSGSIZE;
1486 goto error; 1489 goto error;
1487 } 1490 }
1488 get_page(page);
1489 skb_fill_page_desc(skb, i, page, sk->sk_sndmsg_off, 0); 1491 skb_fill_page_desc(skb, i, page, sk->sk_sndmsg_off, 0);
1492 skb_frag_ref(skb, i);
1490 frag = &skb_shinfo(skb)->frags[i]; 1493 frag = &skb_shinfo(skb)->frags[i];
1491 } 1494 }
1492 } else if(i < MAX_SKB_FRAGS) { 1495 } else if(i < MAX_SKB_FRAGS) {
@@ -1506,12 +1509,14 @@ alloc_new_skb:
1506 err = -EMSGSIZE; 1509 err = -EMSGSIZE;
1507 goto error; 1510 goto error;
1508 } 1511 }
1509 if (getfrag(from, page_address(frag->page)+frag->page_offset+frag->size, offset, copy, skb->len, skb) < 0) { 1512 if (getfrag(from,
1513 skb_frag_address(frag) + skb_frag_size(frag),
1514 offset, copy, skb->len, skb) < 0) {
1510 err = -EFAULT; 1515 err = -EFAULT;
1511 goto error; 1516 goto error;
1512 } 1517 }
1513 sk->sk_sndmsg_off += copy; 1518 sk->sk_sndmsg_off += copy;
1514 frag->size += copy; 1519 skb_frag_size_add(frag, copy);
1515 skb->len += copy; 1520 skb->len += copy;
1516 skb->data_len += copy; 1521 skb->data_len += copy;
1517 skb->truesize += copy; 1522 skb->truesize += copy;