diff options
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r-- | net/ipv6/ip6_output.c | 367 |
1 files changed, 246 insertions, 121 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index d28f2a2efb32..36cf0ab685a0 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -318,6 +318,7 @@ static int ip6_forward_proxy_check(struct sk_buff *skb) | |||
318 | 318 | ||
319 | static inline int ip6_forward_finish(struct sk_buff *skb) | 319 | static inline int ip6_forward_finish(struct sk_buff *skb) |
320 | { | 320 | { |
321 | skb_sender_cpu_clear(skb); | ||
321 | return dst_output(skb); | 322 | return dst_output(skb); |
322 | } | 323 | } |
323 | 324 | ||
@@ -541,7 +542,8 @@ int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
541 | { | 542 | { |
542 | struct sk_buff *frag; | 543 | struct sk_buff *frag; |
543 | struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); | 544 | struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); |
544 | struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL; | 545 | struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ? |
546 | inet6_sk(skb->sk) : NULL; | ||
545 | struct ipv6hdr *tmp_hdr; | 547 | struct ipv6hdr *tmp_hdr; |
546 | struct frag_hdr *fh; | 548 | struct frag_hdr *fh; |
547 | unsigned int mtu, hlen, left, len; | 549 | unsigned int mtu, hlen, left, len; |
@@ -1027,6 +1029,7 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, | |||
1027 | EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow); | 1029 | EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow); |
1028 | 1030 | ||
1029 | static inline int ip6_ufo_append_data(struct sock *sk, | 1031 | static inline int ip6_ufo_append_data(struct sock *sk, |
1032 | struct sk_buff_head *queue, | ||
1030 | int getfrag(void *from, char *to, int offset, int len, | 1033 | int getfrag(void *from, char *to, int offset, int len, |
1031 | int odd, struct sk_buff *skb), | 1034 | int odd, struct sk_buff *skb), |
1032 | void *from, int length, int hh_len, int fragheaderlen, | 1035 | void *from, int length, int hh_len, int fragheaderlen, |
@@ -1042,7 +1045,7 @@ static inline int ip6_ufo_append_data(struct sock *sk, | |||
1042 | * device, so create one single skb packet containing complete | 1045 | * device, so create one single skb packet containing complete |
1043 | * udp datagram | 1046 | * udp datagram |
1044 | */ | 1047 | */ |
1045 | skb = skb_peek_tail(&sk->sk_write_queue); | 1048 | skb = skb_peek_tail(queue); |
1046 | if (skb == NULL) { | 1049 | if (skb == NULL) { |
1047 | skb = sock_alloc_send_skb(sk, | 1050 | skb = sock_alloc_send_skb(sk, |
1048 | hh_len + fragheaderlen + transhdrlen + 20, | 1051 | hh_len + fragheaderlen + transhdrlen + 20, |
@@ -1065,7 +1068,7 @@ static inline int ip6_ufo_append_data(struct sock *sk, | |||
1065 | skb->protocol = htons(ETH_P_IPV6); | 1068 | skb->protocol = htons(ETH_P_IPV6); |
1066 | skb->csum = 0; | 1069 | skb->csum = 0; |
1067 | 1070 | ||
1068 | __skb_queue_tail(&sk->sk_write_queue, skb); | 1071 | __skb_queue_tail(queue, skb); |
1069 | } else if (skb_is_gso(skb)) { | 1072 | } else if (skb_is_gso(skb)) { |
1070 | goto append; | 1073 | goto append; |
1071 | } | 1074 | } |
@@ -1121,99 +1124,106 @@ static void ip6_append_data_mtu(unsigned int *mtu, | |||
1121 | } | 1124 | } |
1122 | } | 1125 | } |
1123 | 1126 | ||
1124 | int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, | 1127 | static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork, |
1125 | int offset, int len, int odd, struct sk_buff *skb), | 1128 | struct inet6_cork *v6_cork, |
1126 | void *from, int length, int transhdrlen, | 1129 | int hlimit, int tclass, struct ipv6_txoptions *opt, |
1127 | int hlimit, int tclass, struct ipv6_txoptions *opt, struct flowi6 *fl6, | 1130 | struct rt6_info *rt, struct flowi6 *fl6) |
1128 | struct rt6_info *rt, unsigned int flags, int dontfrag) | ||
1129 | { | 1131 | { |
1130 | struct inet_sock *inet = inet_sk(sk); | ||
1131 | struct ipv6_pinfo *np = inet6_sk(sk); | 1132 | struct ipv6_pinfo *np = inet6_sk(sk); |
1132 | struct inet_cork *cork; | 1133 | unsigned int mtu; |
1134 | |||
1135 | /* | ||
1136 | * setup for corking | ||
1137 | */ | ||
1138 | if (opt) { | ||
1139 | if (WARN_ON(v6_cork->opt)) | ||
1140 | return -EINVAL; | ||
1141 | |||
1142 | v6_cork->opt = kzalloc(opt->tot_len, sk->sk_allocation); | ||
1143 | if (unlikely(v6_cork->opt == NULL)) | ||
1144 | return -ENOBUFS; | ||
1145 | |||
1146 | v6_cork->opt->tot_len = opt->tot_len; | ||
1147 | v6_cork->opt->opt_flen = opt->opt_flen; | ||
1148 | v6_cork->opt->opt_nflen = opt->opt_nflen; | ||
1149 | |||
1150 | v6_cork->opt->dst0opt = ip6_opt_dup(opt->dst0opt, | ||
1151 | sk->sk_allocation); | ||
1152 | if (opt->dst0opt && !v6_cork->opt->dst0opt) | ||
1153 | return -ENOBUFS; | ||
1154 | |||
1155 | v6_cork->opt->dst1opt = ip6_opt_dup(opt->dst1opt, | ||
1156 | sk->sk_allocation); | ||
1157 | if (opt->dst1opt && !v6_cork->opt->dst1opt) | ||
1158 | return -ENOBUFS; | ||
1159 | |||
1160 | v6_cork->opt->hopopt = ip6_opt_dup(opt->hopopt, | ||
1161 | sk->sk_allocation); | ||
1162 | if (opt->hopopt && !v6_cork->opt->hopopt) | ||
1163 | return -ENOBUFS; | ||
1164 | |||
1165 | v6_cork->opt->srcrt = ip6_rthdr_dup(opt->srcrt, | ||
1166 | sk->sk_allocation); | ||
1167 | if (opt->srcrt && !v6_cork->opt->srcrt) | ||
1168 | return -ENOBUFS; | ||
1169 | |||
1170 | /* need source address above miyazawa*/ | ||
1171 | } | ||
1172 | dst_hold(&rt->dst); | ||
1173 | cork->base.dst = &rt->dst; | ||
1174 | cork->fl.u.ip6 = *fl6; | ||
1175 | v6_cork->hop_limit = hlimit; | ||
1176 | v6_cork->tclass = tclass; | ||
1177 | if (rt->dst.flags & DST_XFRM_TUNNEL) | ||
1178 | mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? | ||
1179 | rt->dst.dev->mtu : dst_mtu(&rt->dst); | ||
1180 | else | ||
1181 | mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? | ||
1182 | rt->dst.dev->mtu : dst_mtu(rt->dst.path); | ||
1183 | if (np->frag_size < mtu) { | ||
1184 | if (np->frag_size) | ||
1185 | mtu = np->frag_size; | ||
1186 | } | ||
1187 | cork->base.fragsize = mtu; | ||
1188 | if (dst_allfrag(rt->dst.path)) | ||
1189 | cork->base.flags |= IPCORK_ALLFRAG; | ||
1190 | cork->base.length = 0; | ||
1191 | |||
1192 | return 0; | ||
1193 | } | ||
1194 | |||
1195 | static int __ip6_append_data(struct sock *sk, | ||
1196 | struct flowi6 *fl6, | ||
1197 | struct sk_buff_head *queue, | ||
1198 | struct inet_cork *cork, | ||
1199 | struct inet6_cork *v6_cork, | ||
1200 | struct page_frag *pfrag, | ||
1201 | int getfrag(void *from, char *to, int offset, | ||
1202 | int len, int odd, struct sk_buff *skb), | ||
1203 | void *from, int length, int transhdrlen, | ||
1204 | unsigned int flags, int dontfrag) | ||
1205 | { | ||
1133 | struct sk_buff *skb, *skb_prev = NULL; | 1206 | struct sk_buff *skb, *skb_prev = NULL; |
1134 | unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu; | 1207 | unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu; |
1135 | int exthdrlen; | 1208 | int exthdrlen = 0; |
1136 | int dst_exthdrlen; | 1209 | int dst_exthdrlen = 0; |
1137 | int hh_len; | 1210 | int hh_len; |
1138 | int copy; | 1211 | int copy; |
1139 | int err; | 1212 | int err; |
1140 | int offset = 0; | 1213 | int offset = 0; |
1141 | __u8 tx_flags = 0; | 1214 | __u8 tx_flags = 0; |
1142 | u32 tskey = 0; | 1215 | u32 tskey = 0; |
1216 | struct rt6_info *rt = (struct rt6_info *)cork->dst; | ||
1217 | struct ipv6_txoptions *opt = v6_cork->opt; | ||
1218 | int csummode = CHECKSUM_NONE; | ||
1143 | 1219 | ||
1144 | if (flags&MSG_PROBE) | 1220 | skb = skb_peek_tail(queue); |
1145 | return 0; | 1221 | if (!skb) { |
1146 | cork = &inet->cork.base; | 1222 | exthdrlen = opt ? opt->opt_flen : 0; |
1147 | if (skb_queue_empty(&sk->sk_write_queue)) { | ||
1148 | /* | ||
1149 | * setup for corking | ||
1150 | */ | ||
1151 | if (opt) { | ||
1152 | if (WARN_ON(np->cork.opt)) | ||
1153 | return -EINVAL; | ||
1154 | |||
1155 | np->cork.opt = kzalloc(opt->tot_len, sk->sk_allocation); | ||
1156 | if (unlikely(np->cork.opt == NULL)) | ||
1157 | return -ENOBUFS; | ||
1158 | |||
1159 | np->cork.opt->tot_len = opt->tot_len; | ||
1160 | np->cork.opt->opt_flen = opt->opt_flen; | ||
1161 | np->cork.opt->opt_nflen = opt->opt_nflen; | ||
1162 | |||
1163 | np->cork.opt->dst0opt = ip6_opt_dup(opt->dst0opt, | ||
1164 | sk->sk_allocation); | ||
1165 | if (opt->dst0opt && !np->cork.opt->dst0opt) | ||
1166 | return -ENOBUFS; | ||
1167 | |||
1168 | np->cork.opt->dst1opt = ip6_opt_dup(opt->dst1opt, | ||
1169 | sk->sk_allocation); | ||
1170 | if (opt->dst1opt && !np->cork.opt->dst1opt) | ||
1171 | return -ENOBUFS; | ||
1172 | |||
1173 | np->cork.opt->hopopt = ip6_opt_dup(opt->hopopt, | ||
1174 | sk->sk_allocation); | ||
1175 | if (opt->hopopt && !np->cork.opt->hopopt) | ||
1176 | return -ENOBUFS; | ||
1177 | |||
1178 | np->cork.opt->srcrt = ip6_rthdr_dup(opt->srcrt, | ||
1179 | sk->sk_allocation); | ||
1180 | if (opt->srcrt && !np->cork.opt->srcrt) | ||
1181 | return -ENOBUFS; | ||
1182 | |||
1183 | /* need source address above miyazawa*/ | ||
1184 | } | ||
1185 | dst_hold(&rt->dst); | ||
1186 | cork->dst = &rt->dst; | ||
1187 | inet->cork.fl.u.ip6 = *fl6; | ||
1188 | np->cork.hop_limit = hlimit; | ||
1189 | np->cork.tclass = tclass; | ||
1190 | if (rt->dst.flags & DST_XFRM_TUNNEL) | ||
1191 | mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? | ||
1192 | rt->dst.dev->mtu : dst_mtu(&rt->dst); | ||
1193 | else | ||
1194 | mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? | ||
1195 | rt->dst.dev->mtu : dst_mtu(rt->dst.path); | ||
1196 | if (np->frag_size < mtu) { | ||
1197 | if (np->frag_size) | ||
1198 | mtu = np->frag_size; | ||
1199 | } | ||
1200 | cork->fragsize = mtu; | ||
1201 | if (dst_allfrag(rt->dst.path)) | ||
1202 | cork->flags |= IPCORK_ALLFRAG; | ||
1203 | cork->length = 0; | ||
1204 | exthdrlen = (opt ? opt->opt_flen : 0); | ||
1205 | length += exthdrlen; | ||
1206 | transhdrlen += exthdrlen; | ||
1207 | dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len; | 1223 | dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len; |
1208 | } else { | ||
1209 | rt = (struct rt6_info *)cork->dst; | ||
1210 | fl6 = &inet->cork.fl.u.ip6; | ||
1211 | opt = np->cork.opt; | ||
1212 | transhdrlen = 0; | ||
1213 | exthdrlen = 0; | ||
1214 | dst_exthdrlen = 0; | ||
1215 | mtu = cork->fragsize; | ||
1216 | } | 1224 | } |
1225 | |||
1226 | mtu = cork->fragsize; | ||
1217 | orig_mtu = mtu; | 1227 | orig_mtu = mtu; |
1218 | 1228 | ||
1219 | hh_len = LL_RESERVED_SPACE(rt->dst.dev); | 1229 | hh_len = LL_RESERVED_SPACE(rt->dst.dev); |
@@ -1262,6 +1272,14 @@ emsgsize: | |||
1262 | tskey = sk->sk_tskey++; | 1272 | tskey = sk->sk_tskey++; |
1263 | } | 1273 | } |
1264 | 1274 | ||
1275 | /* If this is the first and only packet and device | ||
1276 | * supports checksum offloading, let's use it. | ||
1277 | */ | ||
1278 | if (!skb && sk->sk_protocol == IPPROTO_UDP && | ||
1279 | length + fragheaderlen < mtu && | ||
1280 | rt->dst.dev->features & NETIF_F_V6_CSUM && | ||
1281 | !exthdrlen) | ||
1282 | csummode = CHECKSUM_PARTIAL; | ||
1265 | /* | 1283 | /* |
1266 | * Let's try using as much space as possible. | 1284 | * Let's try using as much space as possible. |
1267 | * Use MTU if total length of the message fits into the MTU. | 1285 | * Use MTU if total length of the message fits into the MTU. |
@@ -1278,13 +1296,13 @@ emsgsize: | |||
1278 | * --yoshfuji | 1296 | * --yoshfuji |
1279 | */ | 1297 | */ |
1280 | 1298 | ||
1281 | skb = skb_peek_tail(&sk->sk_write_queue); | ||
1282 | cork->length += length; | 1299 | cork->length += length; |
1283 | if (((length > mtu) || | 1300 | if (((length > mtu) || |
1284 | (skb && skb_is_gso(skb))) && | 1301 | (skb && skb_is_gso(skb))) && |
1285 | (sk->sk_protocol == IPPROTO_UDP) && | 1302 | (sk->sk_protocol == IPPROTO_UDP) && |
1286 | (rt->dst.dev->features & NETIF_F_UFO)) { | 1303 | (rt->dst.dev->features & NETIF_F_UFO) && |
1287 | err = ip6_ufo_append_data(sk, getfrag, from, length, | 1304 | (sk->sk_type == SOCK_DGRAM)) { |
1305 | err = ip6_ufo_append_data(sk, queue, getfrag, from, length, | ||
1288 | hh_len, fragheaderlen, | 1306 | hh_len, fragheaderlen, |
1289 | transhdrlen, mtu, flags, rt); | 1307 | transhdrlen, mtu, flags, rt); |
1290 | if (err) | 1308 | if (err) |
@@ -1375,7 +1393,7 @@ alloc_new_skb: | |||
1375 | * Fill in the control structures | 1393 | * Fill in the control structures |
1376 | */ | 1394 | */ |
1377 | skb->protocol = htons(ETH_P_IPV6); | 1395 | skb->protocol = htons(ETH_P_IPV6); |
1378 | skb->ip_summed = CHECKSUM_NONE; | 1396 | skb->ip_summed = csummode; |
1379 | skb->csum = 0; | 1397 | skb->csum = 0; |
1380 | /* reserve for fragmentation and ipsec header */ | 1398 | /* reserve for fragmentation and ipsec header */ |
1381 | skb_reserve(skb, hh_len + sizeof(struct frag_hdr) + | 1399 | skb_reserve(skb, hh_len + sizeof(struct frag_hdr) + |
@@ -1425,7 +1443,7 @@ alloc_new_skb: | |||
1425 | /* | 1443 | /* |
1426 | * Put the packet on the pending queue | 1444 | * Put the packet on the pending queue |
1427 | */ | 1445 | */ |
1428 | __skb_queue_tail(&sk->sk_write_queue, skb); | 1446 | __skb_queue_tail(queue, skb); |
1429 | continue; | 1447 | continue; |
1430 | } | 1448 | } |
1431 | 1449 | ||
@@ -1444,7 +1462,6 @@ alloc_new_skb: | |||
1444 | } | 1462 | } |
1445 | } else { | 1463 | } else { |
1446 | int i = skb_shinfo(skb)->nr_frags; | 1464 | int i = skb_shinfo(skb)->nr_frags; |
1447 | struct page_frag *pfrag = sk_page_frag(sk); | ||
1448 | 1465 | ||
1449 | err = -ENOMEM; | 1466 | err = -ENOMEM; |
1450 | if (!sk_page_frag_refill(sk, pfrag)) | 1467 | if (!sk_page_frag_refill(sk, pfrag)) |
@@ -1487,43 +1504,81 @@ error: | |||
1487 | IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); | 1504 | IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); |
1488 | return err; | 1505 | return err; |
1489 | } | 1506 | } |
1507 | |||
1508 | int ip6_append_data(struct sock *sk, | ||
1509 | int getfrag(void *from, char *to, int offset, int len, | ||
1510 | int odd, struct sk_buff *skb), | ||
1511 | void *from, int length, int transhdrlen, int hlimit, | ||
1512 | int tclass, struct ipv6_txoptions *opt, struct flowi6 *fl6, | ||
1513 | struct rt6_info *rt, unsigned int flags, int dontfrag) | ||
1514 | { | ||
1515 | struct inet_sock *inet = inet_sk(sk); | ||
1516 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
1517 | int exthdrlen; | ||
1518 | int err; | ||
1519 | |||
1520 | if (flags&MSG_PROBE) | ||
1521 | return 0; | ||
1522 | if (skb_queue_empty(&sk->sk_write_queue)) { | ||
1523 | /* | ||
1524 | * setup for corking | ||
1525 | */ | ||
1526 | err = ip6_setup_cork(sk, &inet->cork, &np->cork, hlimit, | ||
1527 | tclass, opt, rt, fl6); | ||
1528 | if (err) | ||
1529 | return err; | ||
1530 | |||
1531 | exthdrlen = (opt ? opt->opt_flen : 0); | ||
1532 | length += exthdrlen; | ||
1533 | transhdrlen += exthdrlen; | ||
1534 | } else { | ||
1535 | fl6 = &inet->cork.fl.u.ip6; | ||
1536 | transhdrlen = 0; | ||
1537 | } | ||
1538 | |||
1539 | return __ip6_append_data(sk, fl6, &sk->sk_write_queue, &inet->cork.base, | ||
1540 | &np->cork, sk_page_frag(sk), getfrag, | ||
1541 | from, length, transhdrlen, flags, dontfrag); | ||
1542 | } | ||
1490 | EXPORT_SYMBOL_GPL(ip6_append_data); | 1543 | EXPORT_SYMBOL_GPL(ip6_append_data); |
1491 | 1544 | ||
1492 | static void ip6_cork_release(struct inet_sock *inet, struct ipv6_pinfo *np) | 1545 | static void ip6_cork_release(struct inet_cork_full *cork, |
1546 | struct inet6_cork *v6_cork) | ||
1493 | { | 1547 | { |
1494 | if (np->cork.opt) { | 1548 | if (v6_cork->opt) { |
1495 | kfree(np->cork.opt->dst0opt); | 1549 | kfree(v6_cork->opt->dst0opt); |
1496 | kfree(np->cork.opt->dst1opt); | 1550 | kfree(v6_cork->opt->dst1opt); |
1497 | kfree(np->cork.opt->hopopt); | 1551 | kfree(v6_cork->opt->hopopt); |
1498 | kfree(np->cork.opt->srcrt); | 1552 | kfree(v6_cork->opt->srcrt); |
1499 | kfree(np->cork.opt); | 1553 | kfree(v6_cork->opt); |
1500 | np->cork.opt = NULL; | 1554 | v6_cork->opt = NULL; |
1501 | } | 1555 | } |
1502 | 1556 | ||
1503 | if (inet->cork.base.dst) { | 1557 | if (cork->base.dst) { |
1504 | dst_release(inet->cork.base.dst); | 1558 | dst_release(cork->base.dst); |
1505 | inet->cork.base.dst = NULL; | 1559 | cork->base.dst = NULL; |
1506 | inet->cork.base.flags &= ~IPCORK_ALLFRAG; | 1560 | cork->base.flags &= ~IPCORK_ALLFRAG; |
1507 | } | 1561 | } |
1508 | memset(&inet->cork.fl, 0, sizeof(inet->cork.fl)); | 1562 | memset(&cork->fl, 0, sizeof(cork->fl)); |
1509 | } | 1563 | } |
1510 | 1564 | ||
1511 | int ip6_push_pending_frames(struct sock *sk) | 1565 | struct sk_buff *__ip6_make_skb(struct sock *sk, |
1566 | struct sk_buff_head *queue, | ||
1567 | struct inet_cork_full *cork, | ||
1568 | struct inet6_cork *v6_cork) | ||
1512 | { | 1569 | { |
1513 | struct sk_buff *skb, *tmp_skb; | 1570 | struct sk_buff *skb, *tmp_skb; |
1514 | struct sk_buff **tail_skb; | 1571 | struct sk_buff **tail_skb; |
1515 | struct in6_addr final_dst_buf, *final_dst = &final_dst_buf; | 1572 | struct in6_addr final_dst_buf, *final_dst = &final_dst_buf; |
1516 | struct inet_sock *inet = inet_sk(sk); | ||
1517 | struct ipv6_pinfo *np = inet6_sk(sk); | 1573 | struct ipv6_pinfo *np = inet6_sk(sk); |
1518 | struct net *net = sock_net(sk); | 1574 | struct net *net = sock_net(sk); |
1519 | struct ipv6hdr *hdr; | 1575 | struct ipv6hdr *hdr; |
1520 | struct ipv6_txoptions *opt = np->cork.opt; | 1576 | struct ipv6_txoptions *opt = v6_cork->opt; |
1521 | struct rt6_info *rt = (struct rt6_info *)inet->cork.base.dst; | 1577 | struct rt6_info *rt = (struct rt6_info *)cork->base.dst; |
1522 | struct flowi6 *fl6 = &inet->cork.fl.u.ip6; | 1578 | struct flowi6 *fl6 = &cork->fl.u.ip6; |
1523 | unsigned char proto = fl6->flowi6_proto; | 1579 | unsigned char proto = fl6->flowi6_proto; |
1524 | int err = 0; | ||
1525 | 1580 | ||
1526 | skb = __skb_dequeue(&sk->sk_write_queue); | 1581 | skb = __skb_dequeue(queue); |
1527 | if (skb == NULL) | 1582 | if (skb == NULL) |
1528 | goto out; | 1583 | goto out; |
1529 | tail_skb = &(skb_shinfo(skb)->frag_list); | 1584 | tail_skb = &(skb_shinfo(skb)->frag_list); |
@@ -1531,7 +1586,7 @@ int ip6_push_pending_frames(struct sock *sk) | |||
1531 | /* move skb->data to ip header from ext header */ | 1586 | /* move skb->data to ip header from ext header */ |
1532 | if (skb->data < skb_network_header(skb)) | 1587 | if (skb->data < skb_network_header(skb)) |
1533 | __skb_pull(skb, skb_network_offset(skb)); | 1588 | __skb_pull(skb, skb_network_offset(skb)); |
1534 | while ((tmp_skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) { | 1589 | while ((tmp_skb = __skb_dequeue(queue)) != NULL) { |
1535 | __skb_pull(tmp_skb, skb_network_header_len(skb)); | 1590 | __skb_pull(tmp_skb, skb_network_header_len(skb)); |
1536 | *tail_skb = tmp_skb; | 1591 | *tail_skb = tmp_skb; |
1537 | tail_skb = &(tmp_skb->next); | 1592 | tail_skb = &(tmp_skb->next); |
@@ -1556,10 +1611,10 @@ int ip6_push_pending_frames(struct sock *sk) | |||
1556 | skb_reset_network_header(skb); | 1611 | skb_reset_network_header(skb); |
1557 | hdr = ipv6_hdr(skb); | 1612 | hdr = ipv6_hdr(skb); |
1558 | 1613 | ||
1559 | ip6_flow_hdr(hdr, np->cork.tclass, | 1614 | ip6_flow_hdr(hdr, v6_cork->tclass, |
1560 | ip6_make_flowlabel(net, skb, fl6->flowlabel, | 1615 | ip6_make_flowlabel(net, skb, fl6->flowlabel, |
1561 | np->autoflowlabel)); | 1616 | np->autoflowlabel)); |
1562 | hdr->hop_limit = np->cork.hop_limit; | 1617 | hdr->hop_limit = v6_cork->hop_limit; |
1563 | hdr->nexthdr = proto; | 1618 | hdr->nexthdr = proto; |
1564 | hdr->saddr = fl6->saddr; | 1619 | hdr->saddr = fl6->saddr; |
1565 | hdr->daddr = *final_dst; | 1620 | hdr->daddr = *final_dst; |
@@ -1576,34 +1631,104 @@ int ip6_push_pending_frames(struct sock *sk) | |||
1576 | ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); | 1631 | ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); |
1577 | } | 1632 | } |
1578 | 1633 | ||
1634 | ip6_cork_release(cork, v6_cork); | ||
1635 | out: | ||
1636 | return skb; | ||
1637 | } | ||
1638 | |||
1639 | int ip6_send_skb(struct sk_buff *skb) | ||
1640 | { | ||
1641 | struct net *net = sock_net(skb->sk); | ||
1642 | struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); | ||
1643 | int err; | ||
1644 | |||
1579 | err = ip6_local_out(skb); | 1645 | err = ip6_local_out(skb); |
1580 | if (err) { | 1646 | if (err) { |
1581 | if (err > 0) | 1647 | if (err > 0) |
1582 | err = net_xmit_errno(err); | 1648 | err = net_xmit_errno(err); |
1583 | if (err) | 1649 | if (err) |
1584 | goto error; | 1650 | IP6_INC_STATS(net, rt->rt6i_idev, |
1651 | IPSTATS_MIB_OUTDISCARDS); | ||
1585 | } | 1652 | } |
1586 | 1653 | ||
1587 | out: | ||
1588 | ip6_cork_release(inet, np); | ||
1589 | return err; | 1654 | return err; |
1590 | error: | 1655 | } |
1591 | IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); | 1656 | |
1592 | goto out; | 1657 | int ip6_push_pending_frames(struct sock *sk) |
1658 | { | ||
1659 | struct sk_buff *skb; | ||
1660 | |||
1661 | skb = ip6_finish_skb(sk); | ||
1662 | if (!skb) | ||
1663 | return 0; | ||
1664 | |||
1665 | return ip6_send_skb(skb); | ||
1593 | } | 1666 | } |
1594 | EXPORT_SYMBOL_GPL(ip6_push_pending_frames); | 1667 | EXPORT_SYMBOL_GPL(ip6_push_pending_frames); |
1595 | 1668 | ||
1596 | void ip6_flush_pending_frames(struct sock *sk) | 1669 | static void __ip6_flush_pending_frames(struct sock *sk, |
1670 | struct sk_buff_head *queue, | ||
1671 | struct inet_cork_full *cork, | ||
1672 | struct inet6_cork *v6_cork) | ||
1597 | { | 1673 | { |
1598 | struct sk_buff *skb; | 1674 | struct sk_buff *skb; |
1599 | 1675 | ||
1600 | while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) { | 1676 | while ((skb = __skb_dequeue_tail(queue)) != NULL) { |
1601 | if (skb_dst(skb)) | 1677 | if (skb_dst(skb)) |
1602 | IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)), | 1678 | IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)), |
1603 | IPSTATS_MIB_OUTDISCARDS); | 1679 | IPSTATS_MIB_OUTDISCARDS); |
1604 | kfree_skb(skb); | 1680 | kfree_skb(skb); |
1605 | } | 1681 | } |
1606 | 1682 | ||
1607 | ip6_cork_release(inet_sk(sk), inet6_sk(sk)); | 1683 | ip6_cork_release(cork, v6_cork); |
1684 | } | ||
1685 | |||
1686 | void ip6_flush_pending_frames(struct sock *sk) | ||
1687 | { | ||
1688 | __ip6_flush_pending_frames(sk, &sk->sk_write_queue, | ||
1689 | &inet_sk(sk)->cork, &inet6_sk(sk)->cork); | ||
1608 | } | 1690 | } |
1609 | EXPORT_SYMBOL_GPL(ip6_flush_pending_frames); | 1691 | EXPORT_SYMBOL_GPL(ip6_flush_pending_frames); |
1692 | |||
1693 | struct sk_buff *ip6_make_skb(struct sock *sk, | ||
1694 | int getfrag(void *from, char *to, int offset, | ||
1695 | int len, int odd, struct sk_buff *skb), | ||
1696 | void *from, int length, int transhdrlen, | ||
1697 | int hlimit, int tclass, | ||
1698 | struct ipv6_txoptions *opt, struct flowi6 *fl6, | ||
1699 | struct rt6_info *rt, unsigned int flags, | ||
1700 | int dontfrag) | ||
1701 | { | ||
1702 | struct inet_cork_full cork; | ||
1703 | struct inet6_cork v6_cork; | ||
1704 | struct sk_buff_head queue; | ||
1705 | int exthdrlen = (opt ? opt->opt_flen : 0); | ||
1706 | int err; | ||
1707 | |||
1708 | if (flags & MSG_PROBE) | ||
1709 | return NULL; | ||
1710 | |||
1711 | __skb_queue_head_init(&queue); | ||
1712 | |||
1713 | cork.base.flags = 0; | ||
1714 | cork.base.addr = 0; | ||
1715 | cork.base.opt = NULL; | ||
1716 | v6_cork.opt = NULL; | ||
1717 | err = ip6_setup_cork(sk, &cork, &v6_cork, hlimit, tclass, opt, rt, fl6); | ||
1718 | if (err) | ||
1719 | return ERR_PTR(err); | ||
1720 | |||
1721 | if (dontfrag < 0) | ||
1722 | dontfrag = inet6_sk(sk)->dontfrag; | ||
1723 | |||
1724 | err = __ip6_append_data(sk, fl6, &queue, &cork.base, &v6_cork, | ||
1725 | ¤t->task_frag, getfrag, from, | ||
1726 | length + exthdrlen, transhdrlen + exthdrlen, | ||
1727 | flags, dontfrag); | ||
1728 | if (err) { | ||
1729 | __ip6_flush_pending_frames(sk, &queue, &cork, &v6_cork); | ||
1730 | return ERR_PTR(err); | ||
1731 | } | ||
1732 | |||
1733 | return __ip6_make_skb(sk, &queue, &cork, &v6_cork); | ||
1734 | } | ||