summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ldra.c55
1 files changed, 29 insertions, 26 deletions
diff --git a/ldra.c b/ldra.c
index a6074d9..d588a02 100644
--- a/ldra.c
+++ b/ldra.c
@@ -119,27 +119,13 @@ int print_hex(const char *buf, size_t len) {
}
-/* creating an UDP checksum isn't all that magic. you can checksum
- parts individually and add up the result and carry later, provided
- that all parts except possibly the last one has an even number of
- bytes.
-*/
-
-/* fixup carry and complement the sum, returning it in network byte order */
-u_int16_t complement(u_int32_t sum) {
- /* carry adjustment */
- while (sum >> 16)
- sum = (sum & 0xffff) + (sum >> 16);
+/* calulate a possibly partial checksum from a stream of 16bit
+ numbers in network byte order.
- /* return the complement sum in network byte order */
- return htons(~sum);
-}
-
-/* calulate a possibly partial checksum
- We consider buf a stream of 16bit numbers in network byte order.
- Just sum them up, and leave the carry adjustment for later
+ Just sum them up, leaving the carry for later adjustments
*/
-u_int32_t chksum(u_int8_t *buf, size_t n) {
+u_int32_t chksum(char *buf, size_t n)
+{
u_int32_t sum = 0;
int i;
@@ -154,6 +140,28 @@ u_int32_t chksum(u_int8_t *buf, size_t n) {
return sum;
}
+/* calculate IPv6 udp chksum, blindly assuming that there are no other headers in the packet */
+u_int16_t udp6chksum(struct ip6_hdr *ip6)
+{
+ int len = ntohs(ip6->ip6_plen);
+ struct udphdr *udp = (struct udphdr *)((char *)ip6 + sizeof(struct ip6_hdr));
+ u_int32_t sum = chksum((char *)udp, len); /* udp header + packet data */
+
+ /* add the pseudo header: src + dst + nxtheader + length */
+ sum += chksum((char *)&ip6->ip6_src, 2 * sizeof(ip6->ip6_src));
+ sum += IPPROTO_UDP + len;
+
+ /* subtract the old checksum instead of resetting it to 0 */
+ sum -= ntohs(udp->check);
+
+ /* adjust for carry */
+ while (sum >> 16)
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ /* return the complement sum */
+ return ~sum;
+}
+
int main(int argc, char *argv[]) {
int domain, s, i;
@@ -558,13 +566,8 @@ Steven McCanne and Van Jacobson of Lawrence Berkeley Laboratory.
udp->len = ip6->ip6_plen;
udp->dest = htons(546);
- /* calculate UDP checksum */
- udp->check = 0; /* reset before calculating new checksum */
-
- udp->check = complement(chksum((u_int8_t *)udp, sizeof(struct udphdr) + datalen) + /* udp header + packet data */
- chksum((u_int8_t *)&ip6->ip6_src, 2 * sizeof(ip6->ip6_src)) + /* src + dst address */
- IPPROTO_UDP + (u_int32_t)ntohs(udp->len)); /* final part of pseudo header */
-
+ /* update UDP checksum */
+ udp->check = htons(udp6chksum(ip6));
packetlen = sizeof(struct ethhdr) + VLANTAGZ + sizeof(struct ip6_hdr) + ntohs(udp->len);
fprintf(stderr, "packetlen=%d bytes\n", packetlen);