aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-05-08 23:48:01 -0400
committerDavid S. Miller <davem@davemloft.net>2014-05-08 23:48:01 -0400
commit1b5d35358effb776b1ef47b26ec0df54af79d842 (patch)
tree3e3a8bf63676f025cca73ac50fd7e3645d7b138e
parent1a91de28831a1bd913e14dacf25763f3672e24a9 (diff)
parent58d6085c14f5db61c092c90b59813397bc771417 (diff)
Merge branch 'inet_csums_part2'
Tom Herbert says: ==================== net: Checksum offload changes - Part II I am working on overhauling RX checksum offload. Goals of this effort are: - Specify what exactly it means when driver returns CHECKSUM_UNNECESSARY - Preserve CHECKSUM_COMPLETE through encapsulation layers - Don't do skb_checksum more than once per packet - Unify GRO and non-GRO csum verification as much as possible - Unify the checksum functions (checksum_init) - Simply code What is in this second patch set: - Call common inet checksum validation functions in ICMP{4,6}, GRE{4,6}, and IGMP. - In UDP, verify checksum before handing off to encap_rcv. - Remove custom UDP checksum validation code in L2TP. Please review carefully and test if possible, mucking with basic checksum functions is always a little precarious :-) ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/gre_demux.c24
-rw-r--r--net/ipv4/icmp.c12
-rw-r--r--net/ipv4/igmp.c12
-rw-r--r--net/ipv4/udp.c4
-rw-r--r--net/ipv6/icmp.c21
-rw-r--r--net/ipv6/ip6_gre.c12
-rw-r--r--net/ipv6/udp.c4
-rw-r--r--net/l2tp/l2tp_core.c57
8 files changed, 20 insertions, 126 deletions
diff --git a/net/ipv4/gre_demux.c b/net/ipv4/gre_demux.c
index 250be7421ab3..fbfd829f4049 100644
--- a/net/ipv4/gre_demux.c
+++ b/net/ipv4/gre_demux.c
@@ -93,28 +93,6 @@ void gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
93} 93}
94EXPORT_SYMBOL_GPL(gre_build_header); 94EXPORT_SYMBOL_GPL(gre_build_header);
95 95
96static __sum16 check_checksum(struct sk_buff *skb)
97{
98 __sum16 csum = 0;
99
100 switch (skb->ip_summed) {
101 case CHECKSUM_COMPLETE:
102 csum = csum_fold(skb->csum);
103
104 if (!csum)
105 break;
106 /* Fall through. */
107
108 case CHECKSUM_NONE:
109 skb->csum = 0;
110 csum = __skb_checksum_complete(skb);
111 skb->ip_summed = CHECKSUM_COMPLETE;
112 break;
113 }
114
115 return csum;
116}
117
118static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, 96static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
119 bool *csum_err) 97 bool *csum_err)
120{ 98{
@@ -141,7 +119,7 @@ static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
141 119
142 options = (__be32 *)(greh + 1); 120 options = (__be32 *)(greh + 1);
143 if (greh->flags & GRE_CSUM) { 121 if (greh->flags & GRE_CSUM) {
144 if (check_checksum(skb)) { 122 if (skb_checksum_simple_validate(skb)) {
145 *csum_err = true; 123 *csum_err = true;
146 return -EINVAL; 124 return -EINVAL;
147 } 125 }
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 0134663fdbce..fe52666dc43c 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -908,16 +908,8 @@ int icmp_rcv(struct sk_buff *skb)
908 908
909 ICMP_INC_STATS_BH(net, ICMP_MIB_INMSGS); 909 ICMP_INC_STATS_BH(net, ICMP_MIB_INMSGS);
910 910
911 switch (skb->ip_summed) { 911 if (skb_checksum_simple_validate(skb))
912 case CHECKSUM_COMPLETE: 912 goto csum_error;
913 if (!csum_fold(skb->csum))
914 break;
915 /* fall through */
916 case CHECKSUM_NONE:
917 skb->csum = 0;
918 if (__skb_checksum_complete(skb))
919 goto csum_error;
920 }
921 913
922 if (!pskb_pull(skb, sizeof(*icmph))) 914 if (!pskb_pull(skb, sizeof(*icmph)))
923 goto error; 915 goto error;
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 97e4d1655d26..17d34e3c2ac3 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -988,16 +988,8 @@ int igmp_rcv(struct sk_buff *skb)
988 if (!pskb_may_pull(skb, sizeof(struct igmphdr))) 988 if (!pskb_may_pull(skb, sizeof(struct igmphdr)))
989 goto drop; 989 goto drop;
990 990
991 switch (skb->ip_summed) { 991 if (skb_checksum_simple_validate(skb))
992 case CHECKSUM_COMPLETE: 992 goto drop;
993 if (!csum_fold(skb->csum))
994 break;
995 /* fall through */
996 case CHECKSUM_NONE:
997 skb->csum = 0;
998 if (__skb_checksum_complete(skb))
999 goto drop;
1000 }
1001 993
1002 ih = igmp_hdr(skb); 994 ih = igmp_hdr(skb);
1003 switch (ih->type) { 995 switch (ih->type) {
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index f2d05d7be743..54ea0a3a48f1 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1495,6 +1495,10 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
1495 if (skb->len > sizeof(struct udphdr) && encap_rcv != NULL) { 1495 if (skb->len > sizeof(struct udphdr) && encap_rcv != NULL) {
1496 int ret; 1496 int ret;
1497 1497
1498 /* Verify checksum before giving to encap */
1499 if (udp_lib_checksum_complete(skb))
1500 goto csum_error;
1501
1498 ret = encap_rcv(sk, skb); 1502 ret = encap_rcv(sk, skb);
1499 if (ret <= 0) { 1503 if (ret <= 0) {
1500 UDP_INC_STATS_BH(sock_net(sk), 1504 UDP_INC_STATS_BH(sock_net(sk),
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 3b0905b77127..8d3952796d39 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -692,22 +692,11 @@ static int icmpv6_rcv(struct sk_buff *skb)
692 saddr = &ipv6_hdr(skb)->saddr; 692 saddr = &ipv6_hdr(skb)->saddr;
693 daddr = &ipv6_hdr(skb)->daddr; 693 daddr = &ipv6_hdr(skb)->daddr;
694 694
695 /* Perform checksum. */ 695 if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) {
696 switch (skb->ip_summed) { 696 LIMIT_NETDEBUG(KERN_DEBUG
697 case CHECKSUM_COMPLETE: 697 "ICMPv6 checksum failed [%pI6c > %pI6c]\n",
698 if (!csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, 698 saddr, daddr);
699 skb->csum)) 699 goto csum_error;
700 break;
701 /* fall through */
702 case CHECKSUM_NONE:
703 skb->csum = ~csum_unfold(csum_ipv6_magic(saddr, daddr, skb->len,
704 IPPROTO_ICMPV6, 0));
705 if (__skb_checksum_complete(skb)) {
706 LIMIT_NETDEBUG(KERN_DEBUG
707 "ICMPv6 checksum failed [%pI6c > %pI6c]\n",
708 saddr, daddr);
709 goto csum_error;
710 }
711 } 700 }
712 701
713 if (!pskb_pull(skb, sizeof(*hdr))) 702 if (!pskb_pull(skb, sizeof(*hdr)))
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 75277b739b04..3873181ed856 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -468,17 +468,7 @@ static int ip6gre_rcv(struct sk_buff *skb)
468 goto drop; 468 goto drop;
469 469
470 if (flags&GRE_CSUM) { 470 if (flags&GRE_CSUM) {
471 switch (skb->ip_summed) { 471 csum = skb_checksum_simple_validate(skb);
472 case CHECKSUM_COMPLETE:
473 csum = csum_fold(skb->csum);
474 if (!csum)
475 break;
476 /* fall through */
477 case CHECKSUM_NONE:
478 skb->csum = 0;
479 csum = __skb_checksum_complete(skb);
480 skb->ip_summed = CHECKSUM_COMPLETE;
481 }
482 offset += 4; 472 offset += 4;
483 } 473 }
484 if (flags&GRE_KEY) { 474 if (flags&GRE_KEY) {
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index fc2be63e32d5..7edf096867c4 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -634,6 +634,10 @@ int udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
634 if (skb->len > sizeof(struct udphdr) && encap_rcv != NULL) { 634 if (skb->len > sizeof(struct udphdr) && encap_rcv != NULL) {
635 int ret; 635 int ret;
636 636
637 /* Verify checksum before giving to encap */
638 if (udp_lib_checksum_complete(skb))
639 goto csum_error;
640
637 ret = encap_rcv(sk, skb); 641 ret = encap_rcv(sk, skb);
638 if (ret <= 0) { 642 if (ret <= 0) {
639 UDP_INC_STATS_BH(sock_net(sk), 643 UDP_INC_STATS_BH(sock_net(sk),
diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index a4e37d7158dc..aa1a9d44c107 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -495,52 +495,6 @@ out:
495 spin_unlock_bh(&session->reorder_q.lock); 495 spin_unlock_bh(&session->reorder_q.lock);
496} 496}
497 497
498static inline int l2tp_verify_udp_checksum(struct sock *sk,
499 struct sk_buff *skb)
500{
501 struct udphdr *uh = udp_hdr(skb);
502 u16 ulen = ntohs(uh->len);
503 __wsum psum;
504
505 if (sk->sk_no_check || skb_csum_unnecessary(skb))
506 return 0;
507
508#if IS_ENABLED(CONFIG_IPV6)
509 if (sk->sk_family == PF_INET6 && !l2tp_tunnel(sk)->v4mapped) {
510 if (!uh->check) {
511 LIMIT_NETDEBUG(KERN_INFO "L2TP: IPv6: checksum is 0\n");
512 return 1;
513 }
514 if ((skb->ip_summed == CHECKSUM_COMPLETE) &&
515 !csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
516 &ipv6_hdr(skb)->daddr, ulen,
517 IPPROTO_UDP, skb->csum)) {
518 skb->ip_summed = CHECKSUM_UNNECESSARY;
519 return 0;
520 }
521 skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
522 &ipv6_hdr(skb)->daddr,
523 skb->len, IPPROTO_UDP,
524 0));
525 } else
526#endif
527 {
528 struct inet_sock *inet;
529 if (!uh->check)
530 return 0;
531 inet = inet_sk(sk);
532 psum = csum_tcpudp_nofold(inet->inet_saddr, inet->inet_daddr,
533 ulen, IPPROTO_UDP, 0);
534
535 if ((skb->ip_summed == CHECKSUM_COMPLETE) &&
536 !csum_fold(csum_add(psum, skb->csum)))
537 return 0;
538 skb->csum = psum;
539 }
540
541 return __skb_checksum_complete(skb);
542}
543
544static int l2tp_seq_check_rx_window(struct l2tp_session *session, u32 nr) 498static int l2tp_seq_check_rx_window(struct l2tp_session *session, u32 nr)
545{ 499{
546 u32 nws; 500 u32 nws;
@@ -895,8 +849,7 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
895 u16 version; 849 u16 version;
896 int length; 850 int length;
897 851
898 if (tunnel->sock && l2tp_verify_udp_checksum(tunnel->sock, skb)) 852 /* UDP has verifed checksum */
899 goto discard_bad_csum;
900 853
901 /* UDP always verifies the packet length. */ 854 /* UDP always verifies the packet length. */
902 __skb_pull(skb, sizeof(struct udphdr)); 855 __skb_pull(skb, sizeof(struct udphdr));
@@ -979,14 +932,6 @@ static int l2tp_udp_recv_core(struct l2tp_tunnel *tunnel, struct sk_buff *skb,
979 932
980 return 0; 933 return 0;
981 934
982discard_bad_csum:
983 LIMIT_NETDEBUG("%s: UDP: bad checksum\n", tunnel->name);
984 UDP_INC_STATS_USER(tunnel->l2tp_net, UDP_MIB_INERRORS, 0);
985 atomic_long_inc(&tunnel->stats.rx_errors);
986 kfree_skb(skb);
987
988 return 0;
989
990error: 935error:
991 /* Put UDP header back */ 936 /* Put UDP header back */
992 __skb_push(skb, sizeof(struct udphdr)); 937 __skb_push(skb, sizeof(struct udphdr));