xref: /kvmtool/net/uip/csum.c (revision 56ef7bdc6a7d7d2f354ee5baaa2fae7a374a0958)
1 #include "kvm/uip.h"
2 
uip_csum(u16 csum,u8 * addr,u16 count)3 static u16 uip_csum(u16 csum, u8 *addr, u16 count)
4 {
5 	long sum = csum;
6 
7 	while (count > 1) {
8 		sum	+= *(u16 *)addr;
9 		addr	+= 2;
10 		count	-= 2;
11 	}
12 
13 	if (count > 0)
14 		sum += *(unsigned char *)addr;
15 
16 	while (sum>>16)
17 		sum = (sum & 0xffff) + (sum >> 16);
18 
19 	return ~sum;
20 }
21 
uip_csum_ip(struct uip_ip * ip)22 u16 uip_csum_ip(struct uip_ip *ip)
23 {
24 	return uip_csum(0, &ip->vhl, uip_ip_hdrlen(ip));
25 }
26 
uip_csum_icmp(struct uip_icmp * icmp)27 u16 uip_csum_icmp(struct uip_icmp *icmp)
28 {
29 	struct uip_ip *ip;
30 
31 	ip = &icmp->ip;
32 	return icmp->csum = uip_csum(0, &icmp->type, htons(ip->len) - uip_ip_hdrlen(ip) - 8); /* icmp header len = 8 */
33 }
34 
uip_csum_udp(struct uip_udp * udp)35 u16 uip_csum_udp(struct uip_udp *udp)
36 {
37 	struct uip_pseudo_hdr hdr;
38 	struct uip_ip *ip;
39 	int udp_len;
40 	u8 *udp_hdr = (u8 *)udp + offsetof(struct uip_udp, sport);
41 
42 	ip	  = &udp->ip;
43 
44 	hdr.sip   = ip->sip;
45 	hdr.dip	  = ip->dip;
46 	hdr.zero  = 0;
47 	hdr.proto = ip->proto;
48 	hdr.len   = udp->len;
49 
50 	udp_len	  = uip_udp_len(udp);
51 
52 	if (udp_len % 2) {
53 		udp_hdr[udp_len] = 0;		/* zero padding */
54 		memcpy(udp_hdr + udp_len + 1, &hdr, sizeof(hdr));
55 		return uip_csum(0, udp_hdr, udp_len + 1 + sizeof(hdr));
56 	} else {
57 		memcpy(udp_hdr + udp_len, &hdr, sizeof(hdr));
58 		return uip_csum(0, udp_hdr, udp_len + sizeof(hdr));
59 	}
60 
61 }
62 
uip_csum_tcp(struct uip_tcp * tcp)63 u16 uip_csum_tcp(struct uip_tcp *tcp)
64 {
65 	struct uip_pseudo_hdr hdr;
66 	struct uip_ip *ip;
67 	u16 tcp_len;
68 	u8 *tcp_hdr = (u8 *)tcp + offsetof(struct uip_tcp, sport);
69 
70 	ip	  = &tcp->ip;
71 	tcp_len   = ntohs(ip->len) - uip_ip_hdrlen(ip);
72 
73 	hdr.sip   = ip->sip;
74 	hdr.dip	  = ip->dip;
75 	hdr.zero  = 0;
76 	hdr.proto = ip->proto;
77 	hdr.len   = htons(tcp_len);
78 
79 	if (tcp_len > UIP_MAX_TCP_PAYLOAD + 20)
80 		pr_warning("tcp_len(%d) is too large", tcp_len);
81 
82 	if (tcp_len % 2) {
83 		tcp_hdr[tcp_len] = 0;		/* zero padding */
84 		memcpy(tcp_hdr + tcp_len + 1, &hdr, sizeof(hdr));
85 		return uip_csum(0, tcp_hdr, tcp_len + 1 + sizeof(hdr));
86 	} else {
87 		memcpy(tcp_hdr + tcp_len, &hdr, sizeof(hdr));
88 		return uip_csum(0, tcp_hdr, tcp_len + sizeof(hdr));
89 	}
90 }
91