1d8db9f85SAsias He #include "kvm/uip.h"
2d8db9f85SAsias He
uip_csum(u16 csum,u8 * addr,u16 count)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
uip_csum_ip(struct uip_ip * ip)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
uip_csum_icmp(struct uip_icmp * icmp)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
uip_csum_udp(struct uip_udp * udp)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;
40*56ef7bdcSAndre Przywara u8 *udp_hdr = (u8 *)udp + offsetof(struct uip_udp, sport);
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) {
53*56ef7bdcSAndre Przywara udp_hdr[udp_len] = 0; /* zero padding */
54*56ef7bdcSAndre Przywara memcpy(udp_hdr + udp_len + 1, &hdr, sizeof(hdr));
55*56ef7bdcSAndre Przywara return uip_csum(0, udp_hdr, udp_len + 1 + sizeof(hdr));
5607197967SAsias He } else {
57*56ef7bdcSAndre Przywara memcpy(udp_hdr + udp_len, &hdr, sizeof(hdr));
58*56ef7bdcSAndre Przywara return uip_csum(0, udp_hdr, udp_len + sizeof(hdr));
5907197967SAsias He }
6007197967SAsias He
6107197967SAsias He }
6289fb0bf8SAsias He
uip_csum_tcp(struct uip_tcp * tcp)6389fb0bf8SAsias He u16 uip_csum_tcp(struct uip_tcp *tcp)
6489fb0bf8SAsias He {
6589fb0bf8SAsias He struct uip_pseudo_hdr hdr;
6689fb0bf8SAsias He struct uip_ip *ip;
6789fb0bf8SAsias He u16 tcp_len;
68*56ef7bdcSAndre Przywara u8 *tcp_hdr = (u8 *)tcp + offsetof(struct uip_tcp, sport);
6989fb0bf8SAsias He
7089fb0bf8SAsias He ip = &tcp->ip;
7189fb0bf8SAsias He tcp_len = ntohs(ip->len) - uip_ip_hdrlen(ip);
7289fb0bf8SAsias He
7389fb0bf8SAsias He hdr.sip = ip->sip;
7489fb0bf8SAsias He hdr.dip = ip->dip;
7589fb0bf8SAsias He hdr.zero = 0;
7689fb0bf8SAsias He hdr.proto = ip->proto;
7789fb0bf8SAsias He hdr.len = htons(tcp_len);
7889fb0bf8SAsias He
7989fb0bf8SAsias He if (tcp_len > UIP_MAX_TCP_PAYLOAD + 20)
8089fb0bf8SAsias He pr_warning("tcp_len(%d) is too large", tcp_len);
8189fb0bf8SAsias He
8289fb0bf8SAsias He if (tcp_len % 2) {
83*56ef7bdcSAndre Przywara tcp_hdr[tcp_len] = 0; /* zero padding */
84*56ef7bdcSAndre Przywara memcpy(tcp_hdr + tcp_len + 1, &hdr, sizeof(hdr));
85*56ef7bdcSAndre Przywara return uip_csum(0, tcp_hdr, tcp_len + 1 + sizeof(hdr));
8689fb0bf8SAsias He } else {
87*56ef7bdcSAndre Przywara memcpy(tcp_hdr + tcp_len, &hdr, sizeof(hdr));
88*56ef7bdcSAndre Przywara return uip_csum(0, tcp_hdr, tcp_len + sizeof(hdr));
8989fb0bf8SAsias He }
9089fb0bf8SAsias He }
91