xref: /kvmtool/net/uip/csum.c (revision 89fb0bf807240ce7ead51a824c5ddc2d42668da3)
1d8db9f85SAsias He #include "kvm/uip.h"
2d8db9f85SAsias He 
3d8db9f85SAsias He static u16 uip_csum(u16 csum, u8 *addr, u16 count)
4d8db9f85SAsias He {
5d8db9f85SAsias He 	long sum = csum;
6d8db9f85SAsias He 
7d8db9f85SAsias He 	while (count > 1) {
8d8db9f85SAsias He 		sum	+= *(u16 *)addr;
9d8db9f85SAsias He 		addr	+= 2;
10d8db9f85SAsias He 		count	-= 2;
11d8db9f85SAsias He 	}
12d8db9f85SAsias He 
13d8db9f85SAsias He 	if (count > 0)
14d8db9f85SAsias He 		sum += *(unsigned char *)addr;
15d8db9f85SAsias He 
16d8db9f85SAsias He 	while (sum>>16)
17d8db9f85SAsias He 		sum = (sum & 0xffff) + (sum >> 16);
18d8db9f85SAsias He 
19d8db9f85SAsias He 	return ~sum;
20d8db9f85SAsias He }
21d8db9f85SAsias He 
22d8db9f85SAsias He u16 uip_csum_ip(struct uip_ip *ip)
23d8db9f85SAsias He {
24d8db9f85SAsias He 	return uip_csum(0, &ip->vhl, uip_ip_hdrlen(ip));
25d8db9f85SAsias He }
260134a2a7SAsias He 
270134a2a7SAsias He u16 uip_csum_icmp(struct uip_icmp *icmp)
280134a2a7SAsias He {
290134a2a7SAsias He 	struct uip_ip *ip;
300134a2a7SAsias He 
310134a2a7SAsias He 	ip = &icmp->ip;
320134a2a7SAsias He 	return icmp->csum = uip_csum(0, &icmp->type, htons(ip->len) - uip_ip_hdrlen(ip) - 8); /* icmp header len = 8 */
330134a2a7SAsias He }
3407197967SAsias He 
3507197967SAsias He u16 uip_csum_udp(struct uip_udp *udp)
3607197967SAsias He {
3707197967SAsias He 	struct uip_pseudo_hdr hdr;
3807197967SAsias He 	struct uip_ip *ip;
3907197967SAsias He 	int udp_len;
4007197967SAsias He 	u8 *pad;
4107197967SAsias He 
4207197967SAsias He 	ip	  = &udp->ip;
4307197967SAsias He 
4407197967SAsias He 	hdr.sip   = ip->sip;
4507197967SAsias He 	hdr.dip	  = ip->dip;
4607197967SAsias He 	hdr.zero  = 0;
4707197967SAsias He 	hdr.proto = ip->proto;
4807197967SAsias He 	hdr.len   = udp->len;
4907197967SAsias He 
5007197967SAsias He 	udp_len	  = uip_udp_len(udp);
5107197967SAsias He 
5207197967SAsias He 	if (udp_len % 2) {
5307197967SAsias He 		pad = (u8 *)&udp->sport + udp_len;
5407197967SAsias He 		*pad = 0;
5507197967SAsias He 		memcpy((u8 *)&udp->sport + udp_len + 1, &hdr, sizeof(hdr));
5607197967SAsias He 		return uip_csum(0, (u8 *)&udp->sport, udp_len + 1 + sizeof(hdr));
5707197967SAsias He 	} else {
5807197967SAsias He 		memcpy((u8 *)&udp->sport + udp_len, &hdr, sizeof(hdr));
5907197967SAsias He 		return uip_csum(0, (u8 *)&udp->sport, udp_len + sizeof(hdr));
6007197967SAsias He 	}
6107197967SAsias He 
6207197967SAsias He }
63*89fb0bf8SAsias He 
64*89fb0bf8SAsias He u16 uip_csum_tcp(struct uip_tcp *tcp)
65*89fb0bf8SAsias He {
66*89fb0bf8SAsias He 	struct uip_pseudo_hdr hdr;
67*89fb0bf8SAsias He 	struct uip_ip *ip;
68*89fb0bf8SAsias He 	u16 tcp_len;
69*89fb0bf8SAsias He 	u8 *pad;
70*89fb0bf8SAsias He 
71*89fb0bf8SAsias He 	ip	  = &tcp->ip;
72*89fb0bf8SAsias He 	tcp_len   = ntohs(ip->len) - uip_ip_hdrlen(ip);
73*89fb0bf8SAsias He 
74*89fb0bf8SAsias He 	hdr.sip   = ip->sip;
75*89fb0bf8SAsias He 	hdr.dip	  = ip->dip;
76*89fb0bf8SAsias He 	hdr.zero  = 0;
77*89fb0bf8SAsias He 	hdr.proto = ip->proto;
78*89fb0bf8SAsias He 	hdr.len   = htons(tcp_len);
79*89fb0bf8SAsias He 
80*89fb0bf8SAsias He 	if (tcp_len > UIP_MAX_TCP_PAYLOAD + 20)
81*89fb0bf8SAsias He 		pr_warning("tcp_len(%d) is too large", tcp_len);
82*89fb0bf8SAsias He 
83*89fb0bf8SAsias He 	if (tcp_len % 2) {
84*89fb0bf8SAsias He 		pad = (u8 *)&tcp->sport + tcp_len;
85*89fb0bf8SAsias He 		*pad = 0;
86*89fb0bf8SAsias He 		memcpy((u8 *)&tcp->sport + tcp_len + 1, &hdr, sizeof(hdr));
87*89fb0bf8SAsias He 		return uip_csum(0, (u8 *)&tcp->sport, tcp_len + 1 + sizeof(hdr));
88*89fb0bf8SAsias He 	} else {
89*89fb0bf8SAsias He 		memcpy((u8 *)&tcp->sport + tcp_len, &hdr, sizeof(hdr));
90*89fb0bf8SAsias He 		return uip_csum(0, (u8 *)&tcp->sport, tcp_len + sizeof(hdr));
91*89fb0bf8SAsias He 	}
92*89fb0bf8SAsias He }
93