2 * Copyright (c) 2009, 2010 Nicira Networks.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 #include <netinet/in.h>
32 size_t size; /* Test requires a multiple of 4. */
36 #define TEST_CASE(DATA, CSUM) { DATA, (sizeof DATA) - 1, CSUM }
38 static const struct test_case test_cases[] = {
39 /* RFC 1071 section 3. */
40 TEST_CASE("\x00\x01\xf2\x03"
44 /* http://www.sbprojects.com/projects/tcpip/theory/theory14.htm */
45 TEST_CASE("\x45\x00\x00\x28"
52 /* http://mathforum.org/library/drmath/view/54379.html */
53 TEST_CASE("\x86\x5e\xac\x60"
66 /* This code is useful for generating new test cases for RFC 1624 section 4. */
68 generate_rfc1624_test_case(void)
72 for (i = 0; i < 10000000; i++) {
76 for (j = 0; j < 8; j++) {
77 data[j] = random_uint32();
79 data[7] &= 0x0000ffff;
80 data[7] |= 0x55550000;
81 if (ntohs(~csum(data, sizeof data - 2)) == 0xcd7a) {
82 ovs_hex_dump(stdout, data, sizeof data, 0, false);
91 /* Make sure we get the calculation in RFC 1624 section 4 correct. */
95 /* "...an IP packet header in which a 16-bit field m = 0x5555..." */
97 "\xfe\x8f\xc1\x14\x4b\x6f\x70\x2a\x80\x29\x78\xc0\x58\x81\x77\xaa"
98 "\x66\x64\xfc\x96\x63\x97\x64\xee\x12\x53\x1d\xa9\x2d\xa9\x55\x55";
100 /* "...the one's complement sum of all other header octets is 0xCD7A." */
101 assert(ntohs(csum(data, sizeof data - 2)) == (uint16_t) ~0xcd7a);
103 /* "...the header checksum would be:
105 HC = ~(0xCD7A + 0x5555)
109 assert(ntohs(csum(data, sizeof data)) == 0xdd2f);
111 /* "a 16-bit field m = 0x5555 changes to m' = 0x3285..." */
115 /* "The new checksum via recomputation is:
117 HC' = ~(0xCD7A + 0x3285)
121 assert(ntohs(csum(data, sizeof data)) == 0x0000);
123 /* "Applying [Eqn. 3] to the example above, we get the correct result:
125 HC' = ~(C + (-m) + m')
126 = ~(0x22D0 + ~0x5555 + 0x3285)
129 assert(recalc_csum16(0xdd2f, 0x5555, 0x3285) == 0x0000);
137 const struct test_case *tc;
140 for (tc = test_cases; tc < &test_cases[ARRAY_SIZE(test_cases)]; tc++) {
141 const uint16_t *data16 = (const uint16_t *) tc->data;
142 const uint32_t *data32 = (const uint32_t *) tc->data;
146 assert(ntohs(csum(tc->data, tc->size)) == tc->csum);
149 /* Test csum_add16(). */
151 for (i = 0; i < tc->size / 2; i++) {
152 partial = csum_add16(partial, data16[i]);
154 assert(ntohs(csum_finish(partial)) == tc->csum);
157 /* Test csum_add32(). */
159 for (i = 0; i < tc->size / 4; i++) {
160 partial = csum_add32(partial, data32[i]);
162 assert(ntohs(csum_finish(partial)) == tc->csum);
165 /* Test alternating csum_add16() and csum_add32(). */
167 for (i = 0; i < tc->size / 4; i++) {
169 partial = csum_add32(partial, data32[i]);
171 partial = csum_add16(partial, data16[i * 2]);
172 partial = csum_add16(partial, data16[i * 2 + 1]);
175 assert(ntohs(csum_finish(partial)) == tc->csum);
178 /* Test csum_continue(). */
180 for (i = 0; i < tc->size / 4; i++) {
182 partial = csum_continue(partial, &data32[i], 4);
184 partial = csum_continue(partial, &data16[i * 2], 2);
185 partial = csum_continue(partial, &data16[i * 2 + 1], 2);
188 assert(ntohs(csum_finish(partial)) == tc->csum);
194 /* Test recalc_csum16(). */
195 for (i = 0; i < 32; i++) {
196 uint16_t old_u16, new_u16;
201 for (j = 0; j < ARRAY_SIZE(data); j++) {
202 data[j] = random_uint32();
204 old_csum = csum(data, sizeof data);
205 index = random_range(ARRAY_SIZE(data));
206 old_u16 = data[index];
207 new_u16 = data[index] = random_uint32();
208 assert(csum(data, sizeof data)
209 == recalc_csum16(old_csum, old_u16, new_u16));
214 /* Test recalc_csum32(). */
215 for (i = 0; i < 32; i++) {
216 uint32_t old_u32, new_u32;
221 for (j = 0; j < ARRAY_SIZE(data); j++) {
222 data[j] = random_uint32();
224 old_csum = csum(data, sizeof data);
225 index = random_range(ARRAY_SIZE(data));
226 old_u32 = data[index];
227 new_u32 = data[index] = random_uint32();
228 assert(csum(data, sizeof data)
229 == recalc_csum32(old_csum, old_u32, new_u32));