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.c367
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
319static inline int ip6_forward_finish(struct sk_buff *skb) 319static 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,
1027EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow); 1029EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow);
1028 1030
1029static inline int ip6_ufo_append_data(struct sock *sk, 1031static 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
1124int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, 1127static 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
1195static 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
1508int 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}
1490EXPORT_SYMBOL_GPL(ip6_append_data); 1543EXPORT_SYMBOL_GPL(ip6_append_data);
1491 1544
1492static void ip6_cork_release(struct inet_sock *inet, struct ipv6_pinfo *np) 1545static 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
1511int ip6_push_pending_frames(struct sock *sk) 1565struct 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);
1635out:
1636 return skb;
1637}
1638
1639int 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
1587out:
1588 ip6_cork_release(inet, np);
1589 return err; 1654 return err;
1590error: 1655}
1591 IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); 1656
1592 goto out; 1657int 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}
1594EXPORT_SYMBOL_GPL(ip6_push_pending_frames); 1667EXPORT_SYMBOL_GPL(ip6_push_pending_frames);
1595 1668
1596void ip6_flush_pending_frames(struct sock *sk) 1669static 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
1686void 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}
1609EXPORT_SYMBOL_GPL(ip6_flush_pending_frames); 1691EXPORT_SYMBOL_GPL(ip6_flush_pending_frames);
1692
1693struct 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 &current->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}