Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1#include <net/ip.h>
  2#include <net/udp.h>
  3#include <net/udplite.h>
  4#include <asm/checksum.h>
  5
  6#ifndef _HAVE_ARCH_IPV6_CSUM
  7__sum16 csum_ipv6_magic(const struct in6_addr *saddr,
  8			const struct in6_addr *daddr,
  9			__u32 len, __u8 proto, __wsum csum)
 10{
 11
 12	int carry;
 13	__u32 ulen;
 14	__u32 uproto;
 15	__u32 sum = (__force u32)csum;
 16
 17	sum += (__force u32)saddr->s6_addr32[0];
 18	carry = (sum < (__force u32)saddr->s6_addr32[0]);
 19	sum += carry;
 20
 21	sum += (__force u32)saddr->s6_addr32[1];
 22	carry = (sum < (__force u32)saddr->s6_addr32[1]);
 23	sum += carry;
 24
 25	sum += (__force u32)saddr->s6_addr32[2];
 26	carry = (sum < (__force u32)saddr->s6_addr32[2]);
 27	sum += carry;
 28
 29	sum += (__force u32)saddr->s6_addr32[3];
 30	carry = (sum < (__force u32)saddr->s6_addr32[3]);
 31	sum += carry;
 32
 33	sum += (__force u32)daddr->s6_addr32[0];
 34	carry = (sum < (__force u32)daddr->s6_addr32[0]);
 35	sum += carry;
 36
 37	sum += (__force u32)daddr->s6_addr32[1];
 38	carry = (sum < (__force u32)daddr->s6_addr32[1]);
 39	sum += carry;
 40
 41	sum += (__force u32)daddr->s6_addr32[2];
 42	carry = (sum < (__force u32)daddr->s6_addr32[2]);
 43	sum += carry;
 44
 45	sum += (__force u32)daddr->s6_addr32[3];
 46	carry = (sum < (__force u32)daddr->s6_addr32[3]);
 47	sum += carry;
 48
 49	ulen = (__force u32)htonl((__u32) len);
 50	sum += ulen;
 51	carry = (sum < ulen);
 52	sum += carry;
 53
 54	uproto = (__force u32)htonl(proto);
 55	sum += uproto;
 56	carry = (sum < uproto);
 57	sum += carry;
 58
 59	return csum_fold((__force __wsum)sum);
 60}
 61EXPORT_SYMBOL(csum_ipv6_magic);
 62#endif
 63
 64int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto)
 65{
 66	int err;
 67
 68	UDP_SKB_CB(skb)->partial_cov = 0;
 69	UDP_SKB_CB(skb)->cscov = skb->len;
 70
 71	if (proto == IPPROTO_UDPLITE) {
 72		err = udplite_checksum_init(skb, uh);
 73		if (err)
 74			return err;
 75	}
 76
 77	/* To support RFC 6936 (allow zero checksum in UDP/IPV6 for tunnels)
 78	 * we accept a checksum of zero here. When we find the socket
 79	 * for the UDP packet we'll check if that socket allows zero checksum
 80	 * for IPv6 (set by socket option).
 81	 */
 82	return skb_checksum_init_zero_check(skb, proto, uh->check,
 83					   ip6_compute_pseudo);
 84}
 85EXPORT_SYMBOL(udp6_csum_init);
 86
 87/* Function to set UDP checksum for an IPv6 UDP packet. This is intended
 88 * for the simple case like when setting the checksum for a UDP tunnel.
 89 */
 90void udp6_set_csum(bool nocheck, struct sk_buff *skb,
 91		   const struct in6_addr *saddr,
 92		   const struct in6_addr *daddr, int len)
 93{
 94	struct udphdr *uh = udp_hdr(skb);
 95
 96	if (nocheck)
 97		uh->check = 0;
 98	else if (skb_is_gso(skb))
 99		uh->check = ~udp_v6_check(len, saddr, daddr, 0);
100	else if (skb->ip_summed == CHECKSUM_PARTIAL) {
101		uh->check = 0;
102		uh->check = udp_v6_check(len, saddr, daddr, lco_csum(skb));
103		if (uh->check == 0)
104			uh->check = CSUM_MANGLED_0;
105	} else {
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	}
111}
112EXPORT_SYMBOL(udp6_set_csum);