ip6_output.c (366e41d9774d7010cb63112b6db2fce6dc7809c0) ip6_output.c (0bbe84a67b0b5460c2e67101b3aa95cb828845f3)
1/*
2 * IPv6 output functions
3 * Linux INET6 implementation
4 *
5 * Authors:
6 * Pedro Roque <roque@di.fc.ul.pt>
7 *
8 * Based on linux/net/ipv4/ip_output.c

--- 1027 unchanged lines hidden (view full) ---

1036 if (final_dst)
1037 fl6->daddr = *final_dst;
1038
1039 return xfrm_lookup_route(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0);
1040}
1041EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow);
1042
1043static inline int ip6_ufo_append_data(struct sock *sk,
1/*
2 * IPv6 output functions
3 * Linux INET6 implementation
4 *
5 * Authors:
6 * Pedro Roque <roque@di.fc.ul.pt>
7 *
8 * Based on linux/net/ipv4/ip_output.c

--- 1027 unchanged lines hidden (view full) ---

1036 if (final_dst)
1037 fl6->daddr = *final_dst;
1038
1039 return xfrm_lookup_route(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0);
1040}
1041EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow);
1042
1043static inline int ip6_ufo_append_data(struct sock *sk,
1044 struct sk_buff_head *queue,
1044 int getfrag(void *from, char *to, int offset, int len,
1045 int odd, struct sk_buff *skb),
1046 void *from, int length, int hh_len, int fragheaderlen,
1047 int transhdrlen, int mtu, unsigned int flags,
1048 struct rt6_info *rt)
1049
1050{
1051 struct sk_buff *skb;
1052 struct frag_hdr fhdr;
1053 int err;
1054
1055 /* There is support for UDP large send offload by network
1056 * device, so create one single skb packet containing complete
1057 * udp datagram
1058 */
1045 int getfrag(void *from, char *to, int offset, int len,
1046 int odd, struct sk_buff *skb),
1047 void *from, int length, int hh_len, int fragheaderlen,
1048 int transhdrlen, int mtu, unsigned int flags,
1049 struct rt6_info *rt)
1050
1051{
1052 struct sk_buff *skb;
1053 struct frag_hdr fhdr;
1054 int err;
1055
1056 /* There is support for UDP large send offload by network
1057 * device, so create one single skb packet containing complete
1058 * udp datagram
1059 */
1059 skb = skb_peek_tail(&sk->sk_write_queue);
1060 skb = skb_peek_tail(queue);
1060 if (skb == NULL) {
1061 skb = sock_alloc_send_skb(sk,
1062 hh_len + fragheaderlen + transhdrlen + 20,
1063 (flags & MSG_DONTWAIT), &err);
1064 if (skb == NULL)
1065 return err;
1066
1067 /* reserve space for Hardware header */

--- 6 unchanged lines hidden (view full) ---

1074 skb_reset_network_header(skb);
1075
1076 /* initialize protocol header pointer */
1077 skb->transport_header = skb->network_header + fragheaderlen;
1078
1079 skb->protocol = htons(ETH_P_IPV6);
1080 skb->csum = 0;
1081
1061 if (skb == NULL) {
1062 skb = sock_alloc_send_skb(sk,
1063 hh_len + fragheaderlen + transhdrlen + 20,
1064 (flags & MSG_DONTWAIT), &err);
1065 if (skb == NULL)
1066 return err;
1067
1068 /* reserve space for Hardware header */

--- 6 unchanged lines hidden (view full) ---

1075 skb_reset_network_header(skb);
1076
1077 /* initialize protocol header pointer */
1078 skb->transport_header = skb->network_header + fragheaderlen;
1079
1080 skb->protocol = htons(ETH_P_IPV6);
1081 skb->csum = 0;
1082
1082 __skb_queue_tail(&sk->sk_write_queue, skb);
1083 __skb_queue_tail(queue, skb);
1083 } else if (skb_is_gso(skb)) {
1084 goto append;
1085 }
1086
1087 skb->ip_summed = CHECKSUM_PARTIAL;
1088 /* Specify the length of each IPv6 datagram fragment.
1089 * It has to be a multiple of 8.
1090 */

--- 107 unchanged lines hidden (view full) ---

1198 cork->base.fragsize = mtu;
1199 if (dst_allfrag(rt->dst.path))
1200 cork->base.flags |= IPCORK_ALLFRAG;
1201 cork->base.length = 0;
1202
1203 return 0;
1204}
1205
1084 } else if (skb_is_gso(skb)) {
1085 goto append;
1086 }
1087
1088 skb->ip_summed = CHECKSUM_PARTIAL;
1089 /* Specify the length of each IPv6 datagram fragment.
1090 * It has to be a multiple of 8.
1091 */

--- 107 unchanged lines hidden (view full) ---

1199 cork->base.fragsize = mtu;
1200 if (dst_allfrag(rt->dst.path))
1201 cork->base.flags |= IPCORK_ALLFRAG;
1202 cork->base.length = 0;
1203
1204 return 0;
1205}
1206
1206int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to,
1207 int offset, int len, int odd, struct sk_buff *skb),
1208 void *from, int length, int transhdrlen,
1209 int hlimit, int tclass, struct ipv6_txoptions *opt, struct flowi6 *fl6,
1210 struct rt6_info *rt, unsigned int flags, int dontfrag)
1207static int __ip6_append_data(struct sock *sk,
1208 struct flowi6 *fl6,
1209 struct sk_buff_head *queue,
1210 struct inet_cork *cork,
1211 struct inet6_cork *v6_cork,
1212 struct page_frag *pfrag,
1213 int getfrag(void *from, char *to, int offset,
1214 int len, int odd, struct sk_buff *skb),
1215 void *from, int length, int transhdrlen,
1216 unsigned int flags, int dontfrag)
1211{
1217{
1212 struct inet_sock *inet = inet_sk(sk);
1213 struct ipv6_pinfo *np = inet6_sk(sk);
1214 struct inet_cork *cork;
1215 struct sk_buff *skb, *skb_prev = NULL;
1216 unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu;
1218 struct sk_buff *skb, *skb_prev = NULL;
1219 unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu;
1217 int exthdrlen;
1218 int dst_exthdrlen;
1220 int exthdrlen = 0;
1221 int dst_exthdrlen = 0;
1219 int hh_len;
1220 int copy;
1221 int err;
1222 int offset = 0;
1223 __u8 tx_flags = 0;
1224 u32 tskey = 0;
1222 int hh_len;
1223 int copy;
1224 int err;
1225 int offset = 0;
1226 __u8 tx_flags = 0;
1227 u32 tskey = 0;
1228 struct rt6_info *rt = (struct rt6_info *)cork->dst;
1229 struct ipv6_txoptions *opt = v6_cork->opt;
1225
1230
1226 if (flags&MSG_PROBE)
1227 return 0;
1228 cork = &inet->cork.base;
1229 if (skb_queue_empty(&sk->sk_write_queue)) {
1230 /*
1231 * setup for corking
1232 */
1233 err = ip6_setup_cork(sk, &inet->cork, &np->cork, hlimit,
1234 tclass, opt, rt, fl6);
1235 if (err)
1236 return err;
1237 exthdrlen = (opt ? opt->opt_flen : 0);
1238 length += exthdrlen;
1239 transhdrlen += exthdrlen;
1231 skb = skb_peek_tail(queue);
1232 if (!skb) {
1233 exthdrlen = opt ? opt->opt_flen : 0;
1240 dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len;
1234 dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len;
1241 } else {
1242 rt = (struct rt6_info *)cork->dst;
1243 fl6 = &inet->cork.fl.u.ip6;
1244 opt = np->cork.opt;
1245 transhdrlen = 0;
1246 exthdrlen = 0;
1247 dst_exthdrlen = 0;
1248 }
1235 }
1236
1249 mtu = cork->fragsize;
1250 orig_mtu = mtu;
1251
1252 hh_len = LL_RESERVED_SPACE(rt->dst.dev);
1253
1254 fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len +
1255 (opt ? opt->opt_nflen : 0);
1256 maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen -

--- 49 unchanged lines hidden (view full) ---

1306 * the message.
1307 *
1308 * FIXME: It may be fragmented into multiple chunks
1309 * at once if non-fragmentable extension headers
1310 * are too large.
1311 * --yoshfuji
1312 */
1313
1237 mtu = cork->fragsize;
1238 orig_mtu = mtu;
1239
1240 hh_len = LL_RESERVED_SPACE(rt->dst.dev);
1241
1242 fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len +
1243 (opt ? opt->opt_nflen : 0);
1244 maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen -

--- 49 unchanged lines hidden (view full) ---

1294 * the message.
1295 *
1296 * FIXME: It may be fragmented into multiple chunks
1297 * at once if non-fragmentable extension headers
1298 * are too large.
1299 * --yoshfuji
1300 */
1301
1314 skb = skb_peek_tail(&sk->sk_write_queue);
1315 cork->length += length;
1316 if (((length > mtu) ||
1317 (skb && skb_is_gso(skb))) &&
1318 (sk->sk_protocol == IPPROTO_UDP) &&
1319 (rt->dst.dev->features & NETIF_F_UFO)) {
1302 cork->length += length;
1303 if (((length > mtu) ||
1304 (skb && skb_is_gso(skb))) &&
1305 (sk->sk_protocol == IPPROTO_UDP) &&
1306 (rt->dst.dev->features & NETIF_F_UFO)) {
1320 err = ip6_ufo_append_data(sk, getfrag, from, length,
1307 err = ip6_ufo_append_data(sk, queue, getfrag, from, length,
1321 hh_len, fragheaderlen,
1322 transhdrlen, mtu, flags, rt);
1323 if (err)
1324 goto error;
1325 return 0;
1326 }
1327
1328 if (!skb)

--- 124 unchanged lines hidden (view full) ---

1453 length -= datalen - fraggap;
1454 transhdrlen = 0;
1455 exthdrlen = 0;
1456 dst_exthdrlen = 0;
1457
1458 /*
1459 * Put the packet on the pending queue
1460 */
1308 hh_len, fragheaderlen,
1309 transhdrlen, mtu, flags, rt);
1310 if (err)
1311 goto error;
1312 return 0;
1313 }
1314
1315 if (!skb)

--- 124 unchanged lines hidden (view full) ---

1440 length -= datalen - fraggap;
1441 transhdrlen = 0;
1442 exthdrlen = 0;
1443 dst_exthdrlen = 0;
1444
1445 /*
1446 * Put the packet on the pending queue
1447 */
1461 __skb_queue_tail(&sk->sk_write_queue, skb);
1448 __skb_queue_tail(queue, skb);
1462 continue;
1463 }
1464
1465 if (copy > length)
1466 copy = length;
1467
1468 if (!(rt->dst.dev->features&NETIF_F_SG)) {
1469 unsigned int off;
1470
1471 off = skb->len;
1472 if (getfrag(from, skb_put(skb, copy),
1473 offset, copy, off, skb) < 0) {
1474 __skb_trim(skb, off);
1475 err = -EFAULT;
1476 goto error;
1477 }
1478 } else {
1479 int i = skb_shinfo(skb)->nr_frags;
1449 continue;
1450 }
1451
1452 if (copy > length)
1453 copy = length;
1454
1455 if (!(rt->dst.dev->features&NETIF_F_SG)) {
1456 unsigned int off;
1457
1458 off = skb->len;
1459 if (getfrag(from, skb_put(skb, copy),
1460 offset, copy, off, skb) < 0) {
1461 __skb_trim(skb, off);
1462 err = -EFAULT;
1463 goto error;
1464 }
1465 } else {
1466 int i = skb_shinfo(skb)->nr_frags;
1480 struct page_frag *pfrag = sk_page_frag(sk);
1481
1482 err = -ENOMEM;
1483 if (!sk_page_frag_refill(sk, pfrag))
1484 goto error;
1485
1486 if (!skb_can_coalesce(skb, i, pfrag->page,
1487 pfrag->offset)) {
1488 err = -EMSGSIZE;

--- 26 unchanged lines hidden (view full) ---

1515
1516error_efault:
1517 err = -EFAULT;
1518error:
1519 cork->length -= length;
1520 IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
1521 return err;
1522}
1467
1468 err = -ENOMEM;
1469 if (!sk_page_frag_refill(sk, pfrag))
1470 goto error;
1471
1472 if (!skb_can_coalesce(skb, i, pfrag->page,
1473 pfrag->offset)) {
1474 err = -EMSGSIZE;

--- 26 unchanged lines hidden (view full) ---

1501
1502error_efault:
1503 err = -EFAULT;
1504error:
1505 cork->length -= length;
1506 IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
1507 return err;
1508}
1509
1510int ip6_append_data(struct sock *sk,
1511 int getfrag(void *from, char *to, int offset, int len,
1512 int odd, struct sk_buff *skb),
1513 void *from, int length, int transhdrlen, int hlimit,
1514 int tclass, struct ipv6_txoptions *opt, struct flowi6 *fl6,
1515 struct rt6_info *rt, unsigned int flags, int dontfrag)
1516{
1517 struct inet_sock *inet = inet_sk(sk);
1518 struct ipv6_pinfo *np = inet6_sk(sk);
1519 int exthdrlen;
1520 int err;
1521
1522 if (flags&MSG_PROBE)
1523 return 0;
1524 if (skb_queue_empty(&sk->sk_write_queue)) {
1525 /*
1526 * setup for corking
1527 */
1528 err = ip6_setup_cork(sk, &inet->cork, &np->cork, hlimit,
1529 tclass, opt, rt, fl6);
1530 if (err)
1531 return err;
1532
1533 exthdrlen = (opt ? opt->opt_flen : 0);
1534 length += exthdrlen;
1535 transhdrlen += exthdrlen;
1536 } else {
1537 fl6 = &inet->cork.fl.u.ip6;
1538 transhdrlen = 0;
1539 }
1540
1541 return __ip6_append_data(sk, fl6, &sk->sk_write_queue, &inet->cork.base,
1542 &np->cork, sk_page_frag(sk), getfrag,
1543 from, length, transhdrlen, flags, dontfrag);
1544}
1523EXPORT_SYMBOL_GPL(ip6_append_data);
1524
1525static void ip6_cork_release(struct inet_cork_full *cork,
1526 struct inet6_cork *v6_cork)
1527{
1528 if (v6_cork->opt) {
1529 kfree(v6_cork->opt->dst0opt);
1530 kfree(v6_cork->opt->dst1opt);

--- 91 unchanged lines hidden (view full) ---

1622 ip6_cork_release(&inet->cork, &np->cork);
1623 return err;
1624error:
1625 IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
1626 goto out;
1627}
1628EXPORT_SYMBOL_GPL(ip6_push_pending_frames);
1629
1545EXPORT_SYMBOL_GPL(ip6_append_data);
1546
1547static void ip6_cork_release(struct inet_cork_full *cork,
1548 struct inet6_cork *v6_cork)
1549{
1550 if (v6_cork->opt) {
1551 kfree(v6_cork->opt->dst0opt);
1552 kfree(v6_cork->opt->dst1opt);

--- 91 unchanged lines hidden (view full) ---

1644 ip6_cork_release(&inet->cork, &np->cork);
1645 return err;
1646error:
1647 IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
1648 goto out;
1649}
1650EXPORT_SYMBOL_GPL(ip6_push_pending_frames);
1651
1630void ip6_flush_pending_frames(struct sock *sk)
1652static void __ip6_flush_pending_frames(struct sock *sk,
1653 struct sk_buff_head *queue)
1631{
1632 struct sk_buff *skb;
1633
1654{
1655 struct sk_buff *skb;
1656
1634 while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) {
1657 while ((skb = __skb_dequeue_tail(queue)) != NULL) {
1635 if (skb_dst(skb))
1636 IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)),
1637 IPSTATS_MIB_OUTDISCARDS);
1638 kfree_skb(skb);
1639 }
1640
1641 ip6_cork_release(&inet_sk(sk)->cork, &inet6_sk(sk)->cork);
1642}
1658 if (skb_dst(skb))
1659 IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)),
1660 IPSTATS_MIB_OUTDISCARDS);
1661 kfree_skb(skb);
1662 }
1663
1664 ip6_cork_release(&inet_sk(sk)->cork, &inet6_sk(sk)->cork);
1665}
1666
1667void ip6_flush_pending_frames(struct sock *sk)
1668{
1669 __ip6_flush_pending_frames(sk, &sk->sk_write_queue);
1670}
1643EXPORT_SYMBOL_GPL(ip6_flush_pending_frames);
1671EXPORT_SYMBOL_GPL(ip6_flush_pending_frames);