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	 * Note, we are only interested in != 0 or == 0, thus the
 83	 * force to int.
 84	 */
 85	return (__force int)skb_checksum_init_zero_check(skb, proto, uh->check,
 86							 ip6_compute_pseudo);
 87}
 88EXPORT_SYMBOL(udp6_csum_init);
 89
 90/* Function to set UDP checksum for an IPv6 UDP packet. This is intended
 91 * for the simple case like when setting the checksum for a UDP tunnel.
 92 */
 93void udp6_set_csum(bool nocheck, struct sk_buff *skb,
 94		   const struct in6_addr *saddr,
 95		   const struct in6_addr *daddr, int len)
 96{
 97	struct udphdr *uh = udp_hdr(skb);
 98
 99	if (nocheck)
100		uh->check = 0;
101	else if (skb_is_gso(skb))
102		uh->check = ~udp_v6_check(len, saddr, daddr, 0);
103	else if (skb->ip_summed == CHECKSUM_PARTIAL) {
104		uh->check = 0;
105		uh->check = udp_v6_check(len, saddr, daddr, lco_csum(skb));
106		if (uh->check == 0)
107			uh->check = CSUM_MANGLED_0;
108	} else {
109		skb->ip_summed = CHECKSUM_PARTIAL;
110		skb->csum_start = skb_transport_header(skb) - skb->head;
111		skb->csum_offset = offsetof(struct udphdr, check);
112		uh->check = ~udp_v6_check(len, saddr, daddr, 0);
113	}
114}
115EXPORT_SYMBOL(udp6_set_csum);