diff options
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r-- | net/ipv6/ip6_output.c | 37 |
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 | ||
182 | int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, | 182 | int 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; |