-
Notifications
You must be signed in to change notification settings - Fork 7
/
udpChecksum.ino
70 lines (67 loc) · 3.79 KB
/
udpChecksum.ino
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
/* checksum calculation.
For UDP and TCP
*/
#define PSEUDO_HEADER_LEN 40
uint8_t pseudoHeader[PSEUDO_HEADER_LEN];
uint16_t calculateUdpAndTcpChecksumForIPv6(uint8_t *UdpOrTcpframe, uint16_t UdpOrTcpframeLen, const uint8_t *ipv6source, const uint8_t *ipv6dest, uint8_t nxt) {
uint16_t evenFrameLen, i, value16, checksum;
uint32_t totalSum;
// Parameters:
// UdpOrTcpframe: the udp frame or tcp frame, including udp/tcp header and udp/tcp payload
// ipv6source: the 16 byte IPv6 source address. Must be the same, which is used later for the transmission.
// ipv6source: the 16 byte IPv6 destination address. Must be the same, which is used later for the transmission.
// nxt: The next-protocol. 0x11 for UDP, ... for TCP.
//
// Goal: construct an array, consisting of a 40-byte-pseudo-ipv6-header, and the udp frame (consisting of udp header and udppayload).
// For memory efficienty reason, we do NOT copy the pseudoheader and the udp frame together into one new array. Instead, we are using
// a dedicated pseudo-header-array, and the original udp buffer.
evenFrameLen = UdpOrTcpframeLen;
if ((evenFrameLen & 1)!=0) {
/* if we have an odd buffer length, we need to add a padding byte in the end, because the sum calculation
will need 16-bit-aligned data. */
evenFrameLen++;
UdpOrTcpframe[evenFrameLen-1] = 0; /* Fill the padding byte with zero. */
}
for (i=0; i<PSEUDO_HEADER_LEN; i++) {
pseudoHeader[i]=0;
}
/* fill the pseudo-ipv6-header */
for (i=0; i<16; i++) { /* copy 16 bytes IPv6 addresses */
pseudoHeader[i] = ipv6source[i]; /* IPv6 source address */
pseudoHeader[16+i] = ipv6dest[i]; /* IPv6 destination address */
}
pseudoHeader[32] = 0; // # high byte of the FOUR byte length is always 0
pseudoHeader[33] = 0; // # 2nd byte of the FOUR byte length is always 0
pseudoHeader[34] = UdpOrTcpframeLen >> 8; // # 3rd
pseudoHeader[35] = UdpOrTcpframeLen & 0xFF; // # low byte of the FOUR byte length
pseudoHeader[36] = 0; // # 3 padding bytes with 0x00
pseudoHeader[37] = 0;
pseudoHeader[38] = 0;
pseudoHeader[39] = nxt; // # the nxt is at the end of the pseudo header
// pseudo-ipv6-header finished.
// Run the checksum over the concatenation of the pseudoheader and the buffer.
totalSum = 0;
for (i=0; i<PSEUDO_HEADER_LEN/2; i++) { // running through the pseudo header, in 2-byte-steps
value16 = pseudoHeader[2*i] * 256 + pseudoHeader[2*i+1]; // take the current 16-bit-word
totalSum += value16; // we start with a normal addition of the value to the totalSum
// But we do not want normal addition, we want a 16 bit one's complement sum,
// see https://en.wikipedia.org/wiki/User_Datagram_Protocol
if (totalSum>=65536) { // On each addition, if a carry-out (17th bit) is produced,
totalSum-=65536; // swing that 17th carry bit around
totalSum+=1; // and add it to the least significant bit of the running total.
}
}
for (i=0; i<evenFrameLen/2; i++) { // running through the udp buffer, in 2-byte-steps
value16 = UdpOrTcpframe[2*i] * 256 + UdpOrTcpframe[2*i+1]; // take the current 16-bit-word
totalSum += value16; // we start with a normal addition of the value to the totalSum
// But we do not want normal addition, we want a 16 bit one's complement sum,
// see https://en.wikipedia.org/wiki/User_Datagram_Protocol
if (totalSum>=65536) { // On each addition, if a carry-out (17th bit) is produced,
totalSum-=65536; // swing that 17th carry bit around
totalSum+=1; // and add it to the least significant bit of the running total.
}
}
// Finally, the sum is then one's complemented to yield the value of the UDP checksum field.
checksum = (uint16_t) (totalSum ^ 0xffff);
return checksum;
}