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