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.c374
1 files changed, 241 insertions, 133 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index ce69a12ae48c..d33df4cbd872 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -537,20 +537,6 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
537 skb_copy_secmark(to, from); 537 skb_copy_secmark(to, from);
538} 538}
539 539
540static void ipv6_select_ident(struct frag_hdr *fhdr, struct rt6_info *rt)
541{
542 static u32 ip6_idents_hashrnd __read_mostly;
543 u32 hash, id;
544
545 net_get_random_once(&ip6_idents_hashrnd, sizeof(ip6_idents_hashrnd));
546
547 hash = __ipv6_addr_jhash(&rt->rt6i_dst.addr, ip6_idents_hashrnd);
548 hash = __ipv6_addr_jhash(&rt->rt6i_src.addr, hash);
549
550 id = ip_idents_reserve(hash, 1);
551 fhdr->identification = htonl(id);
552}
553
554int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) 540int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
555{ 541{
556 struct sk_buff *frag; 542 struct sk_buff *frag;
@@ -1041,6 +1027,7 @@ struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6,
1041EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow); 1027EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow);
1042 1028
1043static inline int ip6_ufo_append_data(struct sock *sk, 1029static inline int ip6_ufo_append_data(struct sock *sk,
1030 struct sk_buff_head *queue,
1044 int getfrag(void *from, char *to, int offset, int len, 1031 int getfrag(void *from, char *to, int offset, int len,
1045 int odd, struct sk_buff *skb), 1032 int odd, struct sk_buff *skb),
1046 void *from, int length, int hh_len, int fragheaderlen, 1033 void *from, int length, int hh_len, int fragheaderlen,
@@ -1056,7 +1043,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
1056 * device, so create one single skb packet containing complete 1043 * device, so create one single skb packet containing complete
1057 * udp datagram 1044 * udp datagram
1058 */ 1045 */
1059 skb = skb_peek_tail(&sk->sk_write_queue); 1046 skb = skb_peek_tail(queue);
1060 if (skb == NULL) { 1047 if (skb == NULL) {
1061 skb = sock_alloc_send_skb(sk, 1048 skb = sock_alloc_send_skb(sk,
1062 hh_len + fragheaderlen + transhdrlen + 20, 1049 hh_len + fragheaderlen + transhdrlen + 20,
@@ -1079,7 +1066,7 @@ static inline int ip6_ufo_append_data(struct sock *sk,
1079 skb->protocol = htons(ETH_P_IPV6); 1066 skb->protocol = htons(ETH_P_IPV6);
1080 skb->csum = 0; 1067 skb->csum = 0;
1081 1068
1082 __skb_queue_tail(&sk->sk_write_queue, skb); 1069 __skb_queue_tail(queue, skb);
1083 } else if (skb_is_gso(skb)) { 1070 } else if (skb_is_gso(skb)) {
1084 goto append; 1071 goto append;
1085 } 1072 }
@@ -1135,99 +1122,106 @@ static void ip6_append_data_mtu(unsigned int *mtu,
1135 } 1122 }
1136} 1123}
1137 1124
1138int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, 1125static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,
1139 int offset, int len, int odd, struct sk_buff *skb), 1126 struct inet6_cork *v6_cork,
1140 void *from, int length, int transhdrlen, 1127 int hlimit, int tclass, struct ipv6_txoptions *opt,
1141 int hlimit, int tclass, struct ipv6_txoptions *opt, struct flowi6 *fl6, 1128 struct rt6_info *rt, struct flowi6 *fl6)
1142 struct rt6_info *rt, unsigned int flags, int dontfrag)
1143{ 1129{
1144 struct inet_sock *inet = inet_sk(sk);
1145 struct ipv6_pinfo *np = inet6_sk(sk); 1130 struct ipv6_pinfo *np = inet6_sk(sk);
1146 struct inet_cork *cork; 1131 unsigned int mtu;
1132
1133 /*
1134 * setup for corking
1135 */
1136 if (opt) {
1137 if (WARN_ON(v6_cork->opt))
1138 return -EINVAL;
1139
1140 v6_cork->opt = kzalloc(opt->tot_len, sk->sk_allocation);
1141 if (unlikely(v6_cork->opt == NULL))
1142 return -ENOBUFS;
1143
1144 v6_cork->opt->tot_len = opt->tot_len;
1145 v6_cork->opt->opt_flen = opt->opt_flen;
1146 v6_cork->opt->opt_nflen = opt->opt_nflen;
1147
1148 v6_cork->opt->dst0opt = ip6_opt_dup(opt->dst0opt,
1149 sk->sk_allocation);
1150 if (opt->dst0opt && !v6_cork->opt->dst0opt)
1151 return -ENOBUFS;
1152
1153 v6_cork->opt->dst1opt = ip6_opt_dup(opt->dst1opt,
1154 sk->sk_allocation);
1155 if (opt->dst1opt && !v6_cork->opt->dst1opt)
1156 return -ENOBUFS;
1157
1158 v6_cork->opt->hopopt = ip6_opt_dup(opt->hopopt,
1159 sk->sk_allocation);
1160 if (opt->hopopt && !v6_cork->opt->hopopt)
1161 return -ENOBUFS;
1162
1163 v6_cork->opt->srcrt = ip6_rthdr_dup(opt->srcrt,
1164 sk->sk_allocation);
1165 if (opt->srcrt && !v6_cork->opt->srcrt)
1166 return -ENOBUFS;
1167
1168 /* need source address above miyazawa*/
1169 }
1170 dst_hold(&rt->dst);
1171 cork->base.dst = &rt->dst;
1172 cork->fl.u.ip6 = *fl6;
1173 v6_cork->hop_limit = hlimit;
1174 v6_cork->tclass = tclass;
1175 if (rt->dst.flags & DST_XFRM_TUNNEL)
1176 mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
1177 rt->dst.dev->mtu : dst_mtu(&rt->dst);
1178 else
1179 mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
1180 rt->dst.dev->mtu : dst_mtu(rt->dst.path);
1181 if (np->frag_size < mtu) {
1182 if (np->frag_size)
1183 mtu = np->frag_size;
1184 }
1185 cork->base.fragsize = mtu;
1186 if (dst_allfrag(rt->dst.path))
1187 cork->base.flags |= IPCORK_ALLFRAG;
1188 cork->base.length = 0;
1189
1190 return 0;
1191}
1192
1193static int __ip6_append_data(struct sock *sk,
1194 struct flowi6 *fl6,
1195 struct sk_buff_head *queue,
1196 struct inet_cork *cork,
1197 struct inet6_cork *v6_cork,
1198 struct page_frag *pfrag,
1199 int getfrag(void *from, char *to, int offset,
1200 int len, int odd, struct sk_buff *skb),
1201 void *from, int length, int transhdrlen,
1202 unsigned int flags, int dontfrag)
1203{
1147 struct sk_buff *skb, *skb_prev = NULL; 1204 struct sk_buff *skb, *skb_prev = NULL;
1148 unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu; 1205 unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu;
1149 int exthdrlen; 1206 int exthdrlen = 0;
1150 int dst_exthdrlen; 1207 int dst_exthdrlen = 0;
1151 int hh_len; 1208 int hh_len;
1152 int copy; 1209 int copy;
1153 int err; 1210 int err;
1154 int offset = 0; 1211 int offset = 0;
1155 __u8 tx_flags = 0; 1212 __u8 tx_flags = 0;
1156 u32 tskey = 0; 1213 u32 tskey = 0;
1214 struct rt6_info *rt = (struct rt6_info *)cork->dst;
1215 struct ipv6_txoptions *opt = v6_cork->opt;
1216 int csummode = CHECKSUM_NONE;
1157 1217
1158 if (flags&MSG_PROBE) 1218 skb = skb_peek_tail(queue);
1159 return 0; 1219 if (!skb) {
1160 cork = &inet->cork.base; 1220 exthdrlen = opt ? opt->opt_flen : 0;
1161 if (skb_queue_empty(&sk->sk_write_queue)) {
1162 /*
1163 * setup for corking
1164 */
1165 if (opt) {
1166 if (WARN_ON(np->cork.opt))
1167 return -EINVAL;
1168
1169 np->cork.opt = kzalloc(opt->tot_len, sk->sk_allocation);
1170 if (unlikely(np->cork.opt == NULL))
1171 return -ENOBUFS;
1172
1173 np->cork.opt->tot_len = opt->tot_len;
1174 np->cork.opt->opt_flen = opt->opt_flen;
1175 np->cork.opt->opt_nflen = opt->opt_nflen;
1176
1177 np->cork.opt->dst0opt = ip6_opt_dup(opt->dst0opt,
1178 sk->sk_allocation);
1179 if (opt->dst0opt && !np->cork.opt->dst0opt)
1180 return -ENOBUFS;
1181
1182 np->cork.opt->dst1opt = ip6_opt_dup(opt->dst1opt,
1183 sk->sk_allocation);
1184 if (opt->dst1opt && !np->cork.opt->dst1opt)
1185 return -ENOBUFS;
1186
1187 np->cork.opt->hopopt = ip6_opt_dup(opt->hopopt,
1188 sk->sk_allocation);
1189 if (opt->hopopt && !np->cork.opt->hopopt)
1190 return -ENOBUFS;
1191
1192 np->cork.opt->srcrt = ip6_rthdr_dup(opt->srcrt,
1193 sk->sk_allocation);
1194 if (opt->srcrt && !np->cork.opt->srcrt)
1195 return -ENOBUFS;
1196
1197 /* need source address above miyazawa*/
1198 }
1199 dst_hold(&rt->dst);
1200 cork->dst = &rt->dst;
1201 inet->cork.fl.u.ip6 = *fl6;
1202 np->cork.hop_limit = hlimit;
1203 np->cork.tclass = tclass;
1204 if (rt->dst.flags & DST_XFRM_TUNNEL)
1205 mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
1206 rt->dst.dev->mtu : dst_mtu(&rt->dst);
1207 else
1208 mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ?
1209 rt->dst.dev->mtu : dst_mtu(rt->dst.path);
1210 if (np->frag_size < mtu) {
1211 if (np->frag_size)
1212 mtu = np->frag_size;
1213 }
1214 cork->fragsize = mtu;
1215 if (dst_allfrag(rt->dst.path))
1216 cork->flags |= IPCORK_ALLFRAG;
1217 cork->length = 0;
1218 exthdrlen = (opt ? opt->opt_flen : 0);
1219 length += exthdrlen;
1220 transhdrlen += exthdrlen;
1221 dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len; 1221 dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len;
1222 } else {
1223 rt = (struct rt6_info *)cork->dst;
1224 fl6 = &inet->cork.fl.u.ip6;
1225 opt = np->cork.opt;
1226 transhdrlen = 0;
1227 exthdrlen = 0;
1228 dst_exthdrlen = 0;
1229 mtu = cork->fragsize;
1230 } 1222 }
1223
1224 mtu = cork->fragsize;
1231 orig_mtu = mtu; 1225 orig_mtu = mtu;
1232 1226
1233 hh_len = LL_RESERVED_SPACE(rt->dst.dev); 1227 hh_len = LL_RESERVED_SPACE(rt->dst.dev);
@@ -1276,6 +1270,14 @@ emsgsize:
1276 tskey = sk->sk_tskey++; 1270 tskey = sk->sk_tskey++;
1277 } 1271 }
1278 1272
1273 /* If this is the first and only packet and device
1274 * supports checksum offloading, let's use it.
1275 */
1276 if (!skb &&
1277 length + fragheaderlen < mtu &&
1278 rt->dst.dev->features & NETIF_F_V6_CSUM &&
1279 !exthdrlen)
1280 csummode = CHECKSUM_PARTIAL;
1279 /* 1281 /*
1280 * Let's try using as much space as possible. 1282 * Let's try using as much space as possible.
1281 * Use MTU if total length of the message fits into the MTU. 1283 * Use MTU if total length of the message fits into the MTU.
@@ -1292,13 +1294,12 @@ emsgsize:
1292 * --yoshfuji 1294 * --yoshfuji
1293 */ 1295 */
1294 1296
1295 skb = skb_peek_tail(&sk->sk_write_queue);
1296 cork->length += length; 1297 cork->length += length;
1297 if (((length > mtu) || 1298 if (((length > mtu) ||
1298 (skb && skb_is_gso(skb))) && 1299 (skb && skb_is_gso(skb))) &&
1299 (sk->sk_protocol == IPPROTO_UDP) && 1300 (sk->sk_protocol == IPPROTO_UDP) &&
1300 (rt->dst.dev->features & NETIF_F_UFO)) { 1301 (rt->dst.dev->features & NETIF_F_UFO)) {
1301 err = ip6_ufo_append_data(sk, getfrag, from, length, 1302 err = ip6_ufo_append_data(sk, queue, getfrag, from, length,
1302 hh_len, fragheaderlen, 1303 hh_len, fragheaderlen,
1303 transhdrlen, mtu, flags, rt); 1304 transhdrlen, mtu, flags, rt);
1304 if (err) 1305 if (err)
@@ -1389,7 +1390,7 @@ alloc_new_skb:
1389 * Fill in the control structures 1390 * Fill in the control structures
1390 */ 1391 */
1391 skb->protocol = htons(ETH_P_IPV6); 1392 skb->protocol = htons(ETH_P_IPV6);
1392 skb->ip_summed = CHECKSUM_NONE; 1393 skb->ip_summed = csummode;
1393 skb->csum = 0; 1394 skb->csum = 0;
1394 /* reserve for fragmentation and ipsec header */ 1395 /* reserve for fragmentation and ipsec header */
1395 skb_reserve(skb, hh_len + sizeof(struct frag_hdr) + 1396 skb_reserve(skb, hh_len + sizeof(struct frag_hdr) +
@@ -1439,7 +1440,7 @@ alloc_new_skb:
1439 /* 1440 /*
1440 * Put the packet on the pending queue 1441 * Put the packet on the pending queue
1441 */ 1442 */
1442 __skb_queue_tail(&sk->sk_write_queue, skb); 1443 __skb_queue_tail(queue, skb);
1443 continue; 1444 continue;
1444 } 1445 }
1445 1446
@@ -1458,7 +1459,6 @@ alloc_new_skb:
1458 } 1459 }
1459 } else { 1460 } else {
1460 int i = skb_shinfo(skb)->nr_frags; 1461 int i = skb_shinfo(skb)->nr_frags;
1461 struct page_frag *pfrag = sk_page_frag(sk);
1462 1462
1463 err = -ENOMEM; 1463 err = -ENOMEM;
1464 if (!sk_page_frag_refill(sk, pfrag)) 1464 if (!sk_page_frag_refill(sk, pfrag))
@@ -1501,43 +1501,81 @@ error:
1501 IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); 1501 IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
1502 return err; 1502 return err;
1503} 1503}
1504
1505int ip6_append_data(struct sock *sk,
1506 int getfrag(void *from, char *to, int offset, int len,
1507 int odd, struct sk_buff *skb),
1508 void *from, int length, int transhdrlen, int hlimit,
1509 int tclass, struct ipv6_txoptions *opt, struct flowi6 *fl6,
1510 struct rt6_info *rt, unsigned int flags, int dontfrag)
1511{
1512 struct inet_sock *inet = inet_sk(sk);
1513 struct ipv6_pinfo *np = inet6_sk(sk);
1514 int exthdrlen;
1515 int err;
1516
1517 if (flags&MSG_PROBE)
1518 return 0;
1519 if (skb_queue_empty(&sk->sk_write_queue)) {
1520 /*
1521 * setup for corking
1522 */
1523 err = ip6_setup_cork(sk, &inet->cork, &np->cork, hlimit,
1524 tclass, opt, rt, fl6);
1525 if (err)
1526 return err;
1527
1528 exthdrlen = (opt ? opt->opt_flen : 0);
1529 length += exthdrlen;
1530 transhdrlen += exthdrlen;
1531 } else {
1532 fl6 = &inet->cork.fl.u.ip6;
1533 transhdrlen = 0;
1534 }
1535
1536 return __ip6_append_data(sk, fl6, &sk->sk_write_queue, &inet->cork.base,
1537 &np->cork, sk_page_frag(sk), getfrag,
1538 from, length, transhdrlen, flags, dontfrag);
1539}
1504EXPORT_SYMBOL_GPL(ip6_append_data); 1540EXPORT_SYMBOL_GPL(ip6_append_data);
1505 1541
1506static void ip6_cork_release(struct inet_sock *inet, struct ipv6_pinfo *np) 1542static void ip6_cork_release(struct inet_cork_full *cork,
1543 struct inet6_cork *v6_cork)
1507{ 1544{
1508 if (np->cork.opt) { 1545 if (v6_cork->opt) {
1509 kfree(np->cork.opt->dst0opt); 1546 kfree(v6_cork->opt->dst0opt);
1510 kfree(np->cork.opt->dst1opt); 1547 kfree(v6_cork->opt->dst1opt);
1511 kfree(np->cork.opt->hopopt); 1548 kfree(v6_cork->opt->hopopt);
1512 kfree(np->cork.opt->srcrt); 1549 kfree(v6_cork->opt->srcrt);
1513 kfree(np->cork.opt); 1550 kfree(v6_cork->opt);
1514 np->cork.opt = NULL; 1551 v6_cork->opt = NULL;
1515 } 1552 }
1516 1553
1517 if (inet->cork.base.dst) { 1554 if (cork->base.dst) {
1518 dst_release(inet->cork.base.dst); 1555 dst_release(cork->base.dst);
1519 inet->cork.base.dst = NULL; 1556 cork->base.dst = NULL;
1520 inet->cork.base.flags &= ~IPCORK_ALLFRAG; 1557 cork->base.flags &= ~IPCORK_ALLFRAG;
1521 } 1558 }
1522 memset(&inet->cork.fl, 0, sizeof(inet->cork.fl)); 1559 memset(&cork->fl, 0, sizeof(cork->fl));
1523} 1560}
1524 1561
1525int ip6_push_pending_frames(struct sock *sk) 1562struct sk_buff *__ip6_make_skb(struct sock *sk,
1563 struct sk_buff_head *queue,
1564 struct inet_cork_full *cork,
1565 struct inet6_cork *v6_cork)
1526{ 1566{
1527 struct sk_buff *skb, *tmp_skb; 1567 struct sk_buff *skb, *tmp_skb;
1528 struct sk_buff **tail_skb; 1568 struct sk_buff **tail_skb;
1529 struct in6_addr final_dst_buf, *final_dst = &final_dst_buf; 1569 struct in6_addr final_dst_buf, *final_dst = &final_dst_buf;
1530 struct inet_sock *inet = inet_sk(sk);
1531 struct ipv6_pinfo *np = inet6_sk(sk); 1570 struct ipv6_pinfo *np = inet6_sk(sk);
1532 struct net *net = sock_net(sk); 1571 struct net *net = sock_net(sk);
1533 struct ipv6hdr *hdr; 1572 struct ipv6hdr *hdr;
1534 struct ipv6_txoptions *opt = np->cork.opt; 1573 struct ipv6_txoptions *opt = v6_cork->opt;
1535 struct rt6_info *rt = (struct rt6_info *)inet->cork.base.dst; 1574 struct rt6_info *rt = (struct rt6_info *)cork->base.dst;
1536 struct flowi6 *fl6 = &inet->cork.fl.u.ip6; 1575 struct flowi6 *fl6 = &cork->fl.u.ip6;
1537 unsigned char proto = fl6->flowi6_proto; 1576 unsigned char proto = fl6->flowi6_proto;
1538 int err = 0;
1539 1577
1540 skb = __skb_dequeue(&sk->sk_write_queue); 1578 skb = __skb_dequeue(queue);
1541 if (skb == NULL) 1579 if (skb == NULL)
1542 goto out; 1580 goto out;
1543 tail_skb = &(skb_shinfo(skb)->frag_list); 1581 tail_skb = &(skb_shinfo(skb)->frag_list);
@@ -1545,7 +1583,7 @@ int ip6_push_pending_frames(struct sock *sk)
1545 /* move skb->data to ip header from ext header */ 1583 /* move skb->data to ip header from ext header */
1546 if (skb->data < skb_network_header(skb)) 1584 if (skb->data < skb_network_header(skb))
1547 __skb_pull(skb, skb_network_offset(skb)); 1585 __skb_pull(skb, skb_network_offset(skb));
1548 while ((tmp_skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) { 1586 while ((tmp_skb = __skb_dequeue(queue)) != NULL) {
1549 __skb_pull(tmp_skb, skb_network_header_len(skb)); 1587 __skb_pull(tmp_skb, skb_network_header_len(skb));
1550 *tail_skb = tmp_skb; 1588 *tail_skb = tmp_skb;
1551 tail_skb = &(tmp_skb->next); 1589 tail_skb = &(tmp_skb->next);
@@ -1570,10 +1608,10 @@ int ip6_push_pending_frames(struct sock *sk)
1570 skb_reset_network_header(skb); 1608 skb_reset_network_header(skb);
1571 hdr = ipv6_hdr(skb); 1609 hdr = ipv6_hdr(skb);
1572 1610
1573 ip6_flow_hdr(hdr, np->cork.tclass, 1611 ip6_flow_hdr(hdr, v6_cork->tclass,
1574 ip6_make_flowlabel(net, skb, fl6->flowlabel, 1612 ip6_make_flowlabel(net, skb, fl6->flowlabel,
1575 np->autoflowlabel)); 1613 np->autoflowlabel));
1576 hdr->hop_limit = np->cork.hop_limit; 1614 hdr->hop_limit = v6_cork->hop_limit;
1577 hdr->nexthdr = proto; 1615 hdr->nexthdr = proto;
1578 hdr->saddr = fl6->saddr; 1616 hdr->saddr = fl6->saddr;
1579 hdr->daddr = *final_dst; 1617 hdr->daddr = *final_dst;
@@ -1590,34 +1628,104 @@ int ip6_push_pending_frames(struct sock *sk)
1590 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); 1628 ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
1591 } 1629 }
1592 1630
1631 ip6_cork_release(cork, v6_cork);
1632out:
1633 return skb;
1634}
1635
1636int ip6_send_skb(struct sk_buff *skb)
1637{
1638 struct net *net = sock_net(skb->sk);
1639 struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
1640 int err;
1641
1593 err = ip6_local_out(skb); 1642 err = ip6_local_out(skb);
1594 if (err) { 1643 if (err) {
1595 if (err > 0) 1644 if (err > 0)
1596 err = net_xmit_errno(err); 1645 err = net_xmit_errno(err);
1597 if (err) 1646 if (err)
1598 goto error; 1647 IP6_INC_STATS(net, rt->rt6i_idev,
1648 IPSTATS_MIB_OUTDISCARDS);
1599 } 1649 }
1600 1650
1601out:
1602 ip6_cork_release(inet, np);
1603 return err; 1651 return err;
1604error: 1652}
1605 IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); 1653
1606 goto out; 1654int ip6_push_pending_frames(struct sock *sk)
1655{
1656 struct sk_buff *skb;
1657
1658 skb = ip6_finish_skb(sk);
1659 if (!skb)
1660 return 0;
1661
1662 return ip6_send_skb(skb);
1607} 1663}
1608EXPORT_SYMBOL_GPL(ip6_push_pending_frames); 1664EXPORT_SYMBOL_GPL(ip6_push_pending_frames);
1609 1665
1610void ip6_flush_pending_frames(struct sock *sk) 1666static void __ip6_flush_pending_frames(struct sock *sk,
1667 struct sk_buff_head *queue,
1668 struct inet_cork_full *cork,
1669 struct inet6_cork *v6_cork)
1611{ 1670{
1612 struct sk_buff *skb; 1671 struct sk_buff *skb;
1613 1672
1614 while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) { 1673 while ((skb = __skb_dequeue_tail(queue)) != NULL) {
1615 if (skb_dst(skb)) 1674 if (skb_dst(skb))
1616 IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)), 1675 IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)),
1617 IPSTATS_MIB_OUTDISCARDS); 1676 IPSTATS_MIB_OUTDISCARDS);
1618 kfree_skb(skb); 1677 kfree_skb(skb);
1619 } 1678 }
1620 1679
1621 ip6_cork_release(inet_sk(sk), inet6_sk(sk)); 1680 ip6_cork_release(cork, v6_cork);
1681}
1682
1683void ip6_flush_pending_frames(struct sock *sk)
1684{
1685 __ip6_flush_pending_frames(sk, &sk->sk_write_queue,
1686 &inet_sk(sk)->cork, &inet6_sk(sk)->cork);
1622} 1687}
1623EXPORT_SYMBOL_GPL(ip6_flush_pending_frames); 1688EXPORT_SYMBOL_GPL(ip6_flush_pending_frames);
1689
1690struct sk_buff *ip6_make_skb(struct sock *sk,
1691 int getfrag(void *from, char *to, int offset,
1692 int len, int odd, struct sk_buff *skb),
1693 void *from, int length, int transhdrlen,
1694 int hlimit, int tclass,
1695 struct ipv6_txoptions *opt, struct flowi6 *fl6,
1696 struct rt6_info *rt, unsigned int flags,
1697 int dontfrag)
1698{
1699 struct inet_cork_full cork;
1700 struct inet6_cork v6_cork;
1701 struct sk_buff_head queue;
1702 int exthdrlen = (opt ? opt->opt_flen : 0);
1703 int err;
1704
1705 if (flags & MSG_PROBE)
1706 return NULL;
1707
1708 __skb_queue_head_init(&queue);
1709
1710 cork.base.flags = 0;
1711 cork.base.addr = 0;
1712 cork.base.opt = NULL;
1713 v6_cork.opt = NULL;
1714 err = ip6_setup_cork(sk, &cork, &v6_cork, hlimit, tclass, opt, rt, fl6);
1715 if (err)
1716 return ERR_PTR(err);
1717
1718 if (dontfrag < 0)
1719 dontfrag = inet6_sk(sk)->dontfrag;
1720
1721 err = __ip6_append_data(sk, fl6, &queue, &cork.base, &v6_cork,
1722 &current->task_frag, getfrag, from,
1723 length + exthdrlen, transhdrlen + exthdrlen,
1724 flags, dontfrag);
1725 if (err) {
1726 __ip6_flush_pending_frames(sk, &queue, &cork, &v6_cork);
1727 return ERR_PTR(err);
1728 }
1729
1730 return __ip6_make_skb(sk, &queue, &cork, &v6_cork);
1731}