kvm tools: Add ivshmem device
[linux-2.6/next.git] / tools / kvm / net / uip / csum.c
blob7ca8badaaeeeb87802442a83e6934adfbce9ced1
1 #include "kvm/uip.h"
3 static u16 uip_csum(u16 csum, u8 *addr, u16 count)
5 long sum = csum;
7 while (count > 1) {
8 sum += *(u16 *)addr;
9 addr += 2;
10 count -= 2;
13 if (count > 0)
14 sum += *(unsigned char *)addr;
16 while (sum>>16)
17 sum = (sum & 0xffff) + (sum >> 16);
19 return ~sum;
22 u16 uip_csum_ip(struct uip_ip *ip)
24 return uip_csum(0, &ip->vhl, uip_ip_hdrlen(ip));
27 u16 uip_csum_icmp(struct uip_icmp *icmp)
29 struct uip_ip *ip;
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 */
35 u16 uip_csum_udp(struct uip_udp *udp)
37 struct uip_pseudo_hdr hdr;
38 struct uip_ip *ip;
39 int udp_len;
40 u8 *pad;
42 ip = &udp->ip;
44 hdr.sip = ip->sip;
45 hdr.dip = ip->dip;
46 hdr.zero = 0;
47 hdr.proto = ip->proto;
48 hdr.len = udp->len;
50 udp_len = uip_udp_len(udp);
52 if (udp_len % 2) {
53 pad = (u8 *)&udp->sport + udp_len;
54 *pad = 0;
55 memcpy((u8 *)&udp->sport + udp_len + 1, &hdr, sizeof(hdr));
56 return uip_csum(0, (u8 *)&udp->sport, udp_len + 1 + sizeof(hdr));
57 } else {
58 memcpy((u8 *)&udp->sport + udp_len, &hdr, sizeof(hdr));
59 return uip_csum(0, (u8 *)&udp->sport, udp_len + sizeof(hdr));
64 u16 uip_csum_tcp(struct uip_tcp *tcp)
66 struct uip_pseudo_hdr hdr;
67 struct uip_ip *ip;
68 u16 tcp_len;
69 u8 *pad;
71 ip = &tcp->ip;
72 tcp_len = ntohs(ip->len) - uip_ip_hdrlen(ip);
74 hdr.sip = ip->sip;
75 hdr.dip = ip->dip;
76 hdr.zero = 0;
77 hdr.proto = ip->proto;
78 hdr.len = htons(tcp_len);
80 if (tcp_len > UIP_MAX_TCP_PAYLOAD + 20)
81 pr_warning("tcp_len(%d) is too large", tcp_len);
83 if (tcp_len % 2) {
84 pad = (u8 *)&tcp->sport + tcp_len;
85 *pad = 0;
86 memcpy((u8 *)&tcp->sport + tcp_len + 1, &hdr, sizeof(hdr));
87 return uip_csum(0, (u8 *)&tcp->sport, tcp_len + 1 + sizeof(hdr));
88 } else {
89 memcpy((u8 *)&tcp->sport + tcp_len, &hdr, sizeof(hdr));
90 return uip_csum(0, (u8 *)&tcp->sport, tcp_len + sizeof(hdr));