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); |