int chksum6(struct pkt_ip6hdr_t *iph) { struct pkt_ip6pseudo_t hdr; uint32_t sum = 0; switch (iph->next_header) { case ICMPv6_NEXT_HEADER: { struct pkt_icmphdr_t *icmp = (struct pkt_icmphdr_t *)(((uint8_t *) iph) + sizeof(struct pkt_ip6hdr_t)); memcpy(hdr.src_addr, iph->src_addr, PKT_IPv6_ALEN); memcpy(hdr.dst_addr, iph->dst_addr, PKT_IPv6_ALEN); hdr.packet_len = htonl((uint32_t) ntohs(iph->data_len)); hdr.zero[0] = hdr.zero[1] = hdr.zero[2] = 0; hdr.next_header = iph->next_header; icmp->check = 0; sum = in_cksum((uint16_t *) & hdr, sizeof(hdr)); sum += in_cksum((uint16_t *) icmp, ntohs(iph->data_len)); icmp->check = cksum_wrap(sum); break; } case PKT_IP_PROTO_UDP: { struct pkt_udphdr_t *udphdr = (struct pkt_udphdr_t *) (((uint8_t *) iph) + sizeof(struct pkt_ip6hdr_t)); uint16_t udplen = ntohs(udphdr->len); memcpy(hdr.src_addr, iph->src_addr, PKT_IPv6_ALEN); memcpy(hdr.dst_addr, iph->dst_addr, PKT_IPv6_ALEN); hdr.packet_len = htonl((uint32_t) ntohs(iph->data_len)); hdr.zero[0] = hdr.zero[1] = hdr.zero[2] = 0; hdr.next_header = iph->next_header; udphdr->check = 0; sum = in_cksum((uint16_t *) & hdr, sizeof(hdr)); sum += in_cksum((uint16_t *) udphdr, udplen); udphdr->check = cksum_wrap(sum); } break; case PKT_IP_PROTO_TCP: { struct pkt_tcphdr_t *tcphdr = (struct pkt_tcphdr_t *) (((uint8_t *) iph) + sizeof(struct pkt_ip6hdr_t)); uint16_t tcplen = ntohs(iph->data_len); memcpy(hdr.src_addr, iph->src_addr, PKT_IPv6_ALEN); memcpy(hdr.dst_addr, iph->dst_addr, PKT_IPv6_ALEN); hdr.packet_len = htonl((uint32_t) ntohs(iph->data_len)); hdr.zero[0] = hdr.zero[1] = hdr.zero[2] = 0; hdr.next_header = iph->next_header; tcphdr->check = 0; sum = in_cksum((uint16_t *) & hdr, sizeof(hdr)); sum += in_cksum((uint16_t *) tcphdr, tcplen); tcphdr->check = cksum_wrap(sum); } break; } return 0; }
int chksum(struct pkt_iphdr_t *iph) { uint16_t hlen; uint32_t sum; uint16_t len; /* Only IPv4 currently */ if ((iph->version_ihl & 0xf0) != 0x40) return -1; /* Header length */ hlen = iph->version_ihl & 0x0f; hlen <<= 2; len = ntohs(iph->tot_len); /* XXX: redundant */ if (hlen < PKT_IP_HLEN) return -1; #if(PKT_BUFFER < 65535) if (len > PKT_BUFFER) return -1; /* too long? */ #endif if (len < hlen) return -1; /* too short? */ switch(iph->protocol) { case PKT_IP_PROTO_TCP: { struct pkt_tcphdr_t *tcph = (struct pkt_tcphdr_t *)(((void *)iph) + hlen); len -= hlen; /* length of tcp header + data */ tcph->check = 0; sum = in_cksum(((uint16_t *)iph)+6/*saddr*/, 8); sum += ntohs(IPPROTO_TCP + len); sum += in_cksum((uint16_t *)tcph, len); tcph->check = cksum_wrap(sum); } break; case PKT_IP_PROTO_UDP: { struct pkt_udphdr_t *udph = (struct pkt_udphdr_t *)(((void *)iph) + hlen); uint16_t udplen = ntohs(udph->len); if (udplen > len) return -1; udph->check = 0; sum = in_cksum(((uint16_t *)iph)+6/*saddr*/, 8); sum += ntohs(IPPROTO_UDP + udplen); sum += in_cksum((uint16_t *)udph, udplen); udph->check = cksum_wrap(sum); } break; case PKT_IP_PROTO_ICMP: { struct pkt_icmphdr_t *icmph = (struct pkt_icmphdr_t *)(((void *)iph) + hlen); len -= hlen; icmph->check = 0; sum = in_cksum((uint16_t *)icmph, len); icmph->check = cksum_wrap(sum); } break; } iph->check = 0; sum = in_cksum((uint16_t *)iph, hlen); iph->check = cksum_wrap(sum); return 0; }