Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

udp: Generic functions to set checksum

Added udp_set_csum and udp6_set_csum functions to set UDP checksums
in packets. These are for simple UDP packets such as those that might
be created in UDP tunnels.

Signed-off-by: Tom Herbert <therbert@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Tom Herbert and committed by
David S. Miller
af5fcba7 6579867c

+96
+12
include/net/ip6_checksum.h
··· 82 82 } 83 83 #endif 84 84 85 + static inline __sum16 udp_v6_check(int len, 86 + const struct in6_addr *saddr, 87 + const struct in6_addr *daddr, 88 + __wsum base) 89 + { 90 + return csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, base); 91 + } 92 + 93 + void udp6_set_csum(bool nocheck, struct sk_buff *skb, 94 + const struct in6_addr *saddr, 95 + const struct in6_addr *daddr, int len); 96 + 85 97 int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto); 86 98 #endif
+9
include/net/udp.h
··· 147 147 return csum; 148 148 } 149 149 150 + static inline __sum16 udp_v4_check(int len, __be32 saddr, 151 + __be32 daddr, __wsum base) 152 + { 153 + return csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base); 154 + } 155 + 156 + void udp_set_csum(bool nocheck, struct sk_buff *skb, 157 + __be32 saddr, __be32 daddr, int len); 158 + 150 159 /* hash routines shared between UDPv4/6 and UDP-Litev4/6 */ 151 160 static inline void udp_lib_hash(struct sock *sk) 152 161 {
+37
net/ipv4/udp.c
··· 762 762 } 763 763 EXPORT_SYMBOL_GPL(udp4_hwcsum); 764 764 765 + /* Function to set UDP checksum for an IPv4 UDP packet. This is intended 766 + * for the simple case like when setting the checksum for a UDP tunnel. 767 + */ 768 + void udp_set_csum(bool nocheck, struct sk_buff *skb, 769 + __be32 saddr, __be32 daddr, int len) 770 + { 771 + struct udphdr *uh = udp_hdr(skb); 772 + 773 + if (nocheck) 774 + uh->check = 0; 775 + else if (skb_is_gso(skb)) 776 + uh->check = ~udp_v4_check(len, saddr, daddr, 0); 777 + else if (skb_dst(skb) && skb_dst(skb)->dev && 778 + (skb_dst(skb)->dev->features & NETIF_F_V4_CSUM)) { 779 + 780 + BUG_ON(skb->ip_summed == CHECKSUM_PARTIAL); 781 + 782 + skb->ip_summed = CHECKSUM_PARTIAL; 783 + skb->csum_start = skb_transport_header(skb) - skb->head; 784 + skb->csum_offset = offsetof(struct udphdr, check); 785 + uh->check = ~udp_v4_check(len, saddr, daddr, 0); 786 + } else { 787 + __wsum csum; 788 + 789 + BUG_ON(skb->ip_summed == CHECKSUM_PARTIAL); 790 + 791 + uh->check = 0; 792 + csum = skb_checksum(skb, 0, len, 0); 793 + uh->check = udp_v4_check(len, saddr, daddr, csum); 794 + if (uh->check == 0) 795 + uh->check = CSUM_MANGLED_0; 796 + 797 + skb->ip_summed = CHECKSUM_UNNECESSARY; 798 + } 799 + } 800 + EXPORT_SYMBOL(udp_set_csum); 801 + 765 802 static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4) 766 803 { 767 804 struct sock *sk = skb->sk;
+38
net/ipv6/ip6_checksum.c
··· 84 84 ip6_compute_pseudo); 85 85 } 86 86 EXPORT_SYMBOL(udp6_csum_init); 87 + 88 + /* Function to set UDP checksum for an IPv6 UDP packet. This is intended 89 + * for the simple case like when setting the checksum for a UDP tunnel. 90 + */ 91 + void udp6_set_csum(bool nocheck, struct sk_buff *skb, 92 + const struct in6_addr *saddr, 93 + const struct in6_addr *daddr, int len) 94 + { 95 + struct udphdr *uh = udp_hdr(skb); 96 + 97 + if (nocheck) 98 + uh->check = 0; 99 + else if (skb_is_gso(skb)) 100 + uh->check = ~udp_v6_check(len, saddr, daddr, 0); 101 + else if (skb_dst(skb) && skb_dst(skb)->dev && 102 + (skb_dst(skb)->dev->features & NETIF_F_IPV6_CSUM)) { 103 + 104 + BUG_ON(skb->ip_summed == CHECKSUM_PARTIAL); 105 + 106 + skb->ip_summed = CHECKSUM_PARTIAL; 107 + skb->csum_start = skb_transport_header(skb) - skb->head; 108 + skb->csum_offset = offsetof(struct udphdr, check); 109 + uh->check = ~udp_v6_check(len, saddr, daddr, 0); 110 + } else { 111 + __wsum csum; 112 + 113 + BUG_ON(skb->ip_summed == CHECKSUM_PARTIAL); 114 + 115 + uh->check = 0; 116 + csum = skb_checksum(skb, 0, len, 0); 117 + uh->check = udp_v6_check(len, saddr, daddr, csum); 118 + if (uh->check == 0) 119 + uh->check = CSUM_MANGLED_0; 120 + 121 + skb->ip_summed = CHECKSUM_UNNECESSARY; 122 + } 123 + } 124 + EXPORT_SYMBOL(udp6_set_csum);