blob: 6f5c4b398c1cda84fc60f79f982d8deaffb23ebd [file] [log] [blame]
#include "kvm/uip.h"
static u16 uip_csum(u16 csum, u8 *addr, u16 count)
{
long sum = csum;
while (count > 1) {
sum += *(u16 *)addr;
addr += 2;
count -= 2;
}
if (count > 0)
sum += *(unsigned char *)addr;
while (sum>>16)
sum = (sum & 0xffff) + (sum >> 16);
return ~sum;
}
u16 uip_csum_ip(struct uip_ip *ip)
{
return uip_csum(0, &ip->vhl, uip_ip_hdrlen(ip));
}
u16 uip_csum_icmp(struct uip_icmp *icmp)
{
struct uip_ip *ip;
ip = &icmp->ip;
return icmp->csum = uip_csum(0, &icmp->type, htons(ip->len) - uip_ip_hdrlen(ip) - 8); /* icmp header len = 8 */
}
u16 uip_csum_udp(struct uip_udp *udp)
{
struct uip_pseudo_hdr hdr;
struct uip_ip *ip;
int udp_len;
u8 *udp_hdr = (u8 *)udp + offsetof(struct uip_udp, sport);
ip = &udp->ip;
hdr.sip = ip->sip;
hdr.dip = ip->dip;
hdr.zero = 0;
hdr.proto = ip->proto;
hdr.len = udp->len;
udp_len = uip_udp_len(udp);
if (udp_len % 2) {
udp_hdr[udp_len] = 0; /* zero padding */
memcpy(udp_hdr + udp_len + 1, &hdr, sizeof(hdr));
return uip_csum(0, udp_hdr, udp_len + 1 + sizeof(hdr));
} else {
memcpy(udp_hdr + udp_len, &hdr, sizeof(hdr));
return uip_csum(0, udp_hdr, udp_len + sizeof(hdr));
}
}
u16 uip_csum_tcp(struct uip_tcp *tcp)
{
struct uip_pseudo_hdr hdr;
struct uip_ip *ip;
u16 tcp_len;
u8 *tcp_hdr = (u8 *)tcp + offsetof(struct uip_tcp, sport);
ip = &tcp->ip;
tcp_len = ntohs(ip->len) - uip_ip_hdrlen(ip);
hdr.sip = ip->sip;
hdr.dip = ip->dip;
hdr.zero = 0;
hdr.proto = ip->proto;
hdr.len = htons(tcp_len);
if (tcp_len > UIP_MAX_TCP_PAYLOAD + 20)
pr_warning("tcp_len(%d) is too large", tcp_len);
if (tcp_len % 2) {
tcp_hdr[tcp_len] = 0; /* zero padding */
memcpy(tcp_hdr + tcp_len + 1, &hdr, sizeof(hdr));
return uip_csum(0, tcp_hdr, tcp_len + 1 + sizeof(hdr));
} else {
memcpy(tcp_hdr + tcp_len, &hdr, sizeof(hdr));
return uip_csum(0, tcp_hdr, tcp_len + sizeof(hdr));
}
}