1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
/*
* ip6.c
*
* Copyright (c) 2002 Dug Song <dugsong@monkey.org>
*
* $Id: ip6.c 539 2005-01-23 07:36:54Z dugsong $
*/
#ifdef _WIN32
#include "dnet_winconfig.h"
#else
#include "config.h"
#endif
#include "dnet.h"
#define IP6_IS_EXT(n) \
((n) == IP_PROTO_HOPOPTS || (n) == IP_PROTO_DSTOPTS || \
(n) == IP_PROTO_ROUTING || (n) == IP_PROTO_FRAGMENT)
void
ip6_checksum(void *buf, size_t len)
{
struct ip6_hdr *ip6 = (struct ip6_hdr *)buf;
struct ip6_ext_hdr *ext;
u_char *p, nxt;
int i, sum;
nxt = ip6->ip6_nxt;
for (i = IP6_HDR_LEN; IP6_IS_EXT(nxt); i += (ext->ext_len + 1) << 3) {
if (i >= (int)len) return;
ext = (struct ip6_ext_hdr *)((u_char *)buf + i);
nxt = ext->ext_nxt;
}
p = (u_char *)buf + i;
len -= i;
if (nxt == IP_PROTO_TCP) {
struct tcp_hdr *tcp = (struct tcp_hdr *)p;
if (len >= TCP_HDR_LEN) {
tcp->th_sum = 0;
sum = ip_cksum_add(tcp, len, 0) + htons(nxt + (u_short)len);
sum = ip_cksum_add(&ip6->ip6_src, 32, sum);
tcp->th_sum = ip_cksum_carry(sum);
}
} else if (nxt == IP_PROTO_UDP) {
struct udp_hdr *udp = (struct udp_hdr *)p;
if (len >= UDP_HDR_LEN) {
udp->uh_sum = 0;
sum = ip_cksum_add(udp, len, 0) + htons(nxt + (u_short)len);
sum = ip_cksum_add(&ip6->ip6_src, 32, sum);
if ((udp->uh_sum = ip_cksum_carry(sum)) == 0)
udp->uh_sum = 0xffff;
}
} else if (nxt == IP_PROTO_ICMPV6) {
struct icmp_hdr *icmp = (struct icmp_hdr *)p;
if (len >= ICMP_HDR_LEN) {
icmp->icmp_cksum = 0;
sum = ip_cksum_add(icmp, len, 0) + htons(nxt + (u_short)len);
sum = ip_cksum_add(&ip6->ip6_src, 32, sum);
icmp->icmp_cksum = ip_cksum_carry(sum);
}
} else if (nxt == IP_PROTO_ICMP || nxt == IP_PROTO_IGMP) {
struct icmp_hdr *icmp = (struct icmp_hdr *)p;
if (len >= ICMP_HDR_LEN) {
icmp->icmp_cksum = 0;
sum = ip_cksum_add(icmp, len, 0);
icmp->icmp_cksum = ip_cksum_carry(sum);
}
}
}
|