Browse Source

[test] Add self-tests for TCP/IP checksum calculation

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 12 years ago
parent
commit
bb9961fb54
2 changed files with 214 additions and 0 deletions
  1. 213
    0
      src/tests/tcpip_test.c
  2. 1
    0
      src/tests/tests.c

+ 213
- 0
src/tests/tcpip_test.c View File

@@ -0,0 +1,213 @@
1
+/*
2
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or (at your option) any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ */
19
+
20
+FILE_LICENCE ( GPL2_OR_LATER );
21
+
22
+/** @file
23
+ *
24
+ * TCP/IP self-tests
25
+ *
26
+ */
27
+
28
+/* Forcibly enable assertions */
29
+#undef NDEBUG
30
+
31
+#include <stdint.h>
32
+#include <stdlib.h>
33
+#include <string.h>
34
+#include <assert.h>
35
+#include <ipxe/test.h>
36
+#include <ipxe/profile.h>
37
+#include <ipxe/tcpip.h>
38
+
39
+/** A TCP/IP fixed-data test */
40
+struct tcpip_test {
41
+	/** Data */
42
+	const void *data;
43
+	/** Length of data */
44
+	size_t len;
45
+};
46
+
47
+/** A TCP/IP pseudorandom-data test */
48
+struct tcpip_random_test {
49
+	/** Seed */
50
+	unsigned int seed;
51
+	/** Length of data */
52
+	size_t len;
53
+	/** Alignment offset */
54
+	size_t offset;
55
+};
56
+
57
+/** Define inline data */
58
+#define DATA(...) { __VA_ARGS__ }
59
+
60
+/** Define a TCP/IP fixed-data test */
61
+#define TCPIP_TEST( name, DATA )					\
62
+	static const uint8_t __attribute__ (( aligned ( 16 ) ))		\
63
+		name ## _data[] = DATA;					\
64
+	static struct tcpip_test name = {				\
65
+		.data = name ## _data,					\
66
+		.len = sizeof ( name ## _data ),			\
67
+	}
68
+
69
+/** Define a TCP/IP pseudorandom-data test */
70
+#define TCPIP_RANDOM_TEST( name, SEED, LEN, OFFSET )			\
71
+	static struct tcpip_random_test name = {			\
72
+		.seed = SEED,						\
73
+		.len = LEN,						\
74
+		.offset = OFFSET,					\
75
+	}
76
+
77
+/** Buffer for pseudorandom-data tests */
78
+static uint8_t __attribute__ (( aligned ( 16 ) ))
79
+	tcpip_data[ 4096 + 7 /* offset */ ];
80
+
81
+/** Empty data */
82
+TCPIP_TEST ( empty, DATA() );
83
+
84
+/** Single byte */
85
+TCPIP_TEST ( one_byte, DATA ( 0xeb ) );
86
+
87
+/** Double byte */
88
+TCPIP_TEST ( two_bytes, DATA ( 0xba, 0xbe ) );
89
+
90
+/** Final wrap-around carry (big-endian) */
91
+TCPIP_TEST ( final_carry_big,
92
+	     DATA ( 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ) );
93
+
94
+/** Final wrap-around carry (little-endian) */
95
+TCPIP_TEST ( final_carry_little,
96
+	     DATA ( 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 ) );
97
+
98
+/** Random data (aligned) */
99
+TCPIP_RANDOM_TEST ( random_aligned, 0x12345678UL, 4096, 0 );
100
+
101
+/** Random data (unaligned, +1) */
102
+TCPIP_RANDOM_TEST ( random_unaligned_1, 0x12345678UL, 4096, 1 );
103
+
104
+/** Random data (unaligned, +2) */
105
+TCPIP_RANDOM_TEST ( random_unaligned_2, 0x12345678UL, 4096, 2 );
106
+
107
+/** Random data (aligned, truncated) */
108
+TCPIP_RANDOM_TEST ( random_aligned_truncated, 0x12345678UL, 4095, 0 );
109
+
110
+/** Random data (unaligned start and finish) */
111
+TCPIP_RANDOM_TEST ( partial, 0xcafebabe, 121, 5 );
112
+
113
+/**
114
+ * Calculate TCP/IP checksum
115
+ *
116
+ * @v data		Data to sum
117
+ * @v len		Length of data
118
+ * @ret cksum		Checksum
119
+ *
120
+ * This is a reference implementation taken from RFC1071 (and modified
121
+ * to fix compilation without warnings under gcc).
122
+ */
123
+static uint16_t rfc_tcpip_chksum ( const void *data, size_t len ) {
124
+	unsigned long sum = 0;
125
+
126
+        while ( len > 1 )  {
127
+		sum += *( ( uint16_t * ) data );
128
+		data += 2;
129
+		len -= 2;
130
+	}
131
+
132
+	if ( len > 0 )
133
+		sum += *( ( uint8_t * ) data );
134
+
135
+	while ( sum >> 16 )
136
+		sum = ( ( sum & 0xffff ) + ( sum >> 16 ) );
137
+
138
+	return ~sum;
139
+}
140
+
141
+/**
142
+ * Report TCP/IP fixed-data test result
143
+ *
144
+ * @v test		TCP/IP test
145
+ */
146
+#define tcpip_ok( test ) do {						\
147
+	uint16_t expected;						\
148
+	uint16_t generic_sum;						\
149
+	uint16_t sum;							\
150
+	expected = rfc_tcpip_chksum ( (test)->data, (test)->len );	\
151
+	generic_sum = generic_tcpip_continue_chksum ( TCPIP_EMPTY_CSUM,	\
152
+						      (test)->data,	\
153
+						      (test)->len );	\
154
+	ok ( generic_sum == expected );					\
155
+	sum = tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, (test)->data,	\
156
+				      (test)->len );			\
157
+	ok ( sum == expected );						\
158
+	} while ( 0 )
159
+
160
+/**
161
+ * Report TCP/IP pseudorandom-data test result
162
+ *
163
+ * @v test		TCP/IP test
164
+ */
165
+#define tcpip_random_ok( test ) do {					\
166
+	uint8_t *data = ( tcpip_data + (test)->offset );		\
167
+	uint16_t expected;						\
168
+	uint16_t generic_sum;						\
169
+	uint16_t sum;							\
170
+	unsigned long elapsed;						\
171
+	unsigned int i;							\
172
+	assert ( ( (test)->len + (test)->offset ) <=			\
173
+		 sizeof ( tcpip_data ) );				\
174
+	srandom ( (test)->seed );					\
175
+	for ( i = 0 ; i < (test)->len ; i++ )				\
176
+		data[i] = random();					\
177
+	expected = rfc_tcpip_chksum ( data, (test)->len );		\
178
+	generic_sum = generic_tcpip_continue_chksum ( TCPIP_EMPTY_CSUM,	\
179
+						      data,		\
180
+						      (test)->len );	\
181
+	ok ( generic_sum == expected );					\
182
+	simple_profile();						\
183
+	sum = tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, data,		\
184
+				      (test)->len );			\
185
+	elapsed = simple_profile();					\
186
+	ok ( sum == expected );						\
187
+	DBG ( "TCPIP checksummed %zd bytes (+%zd) in %ld ticks\n",	\
188
+	      (test)->len, (test)->offset, elapsed );			\
189
+	} while ( 0 )
190
+
191
+/**
192
+ * Perform TCP/IP self-tests
193
+ *
194
+ */
195
+static void tcpip_test_exec ( void ) {
196
+
197
+	tcpip_ok ( &empty );
198
+	tcpip_ok ( &one_byte );
199
+	tcpip_ok ( &two_bytes );
200
+	tcpip_ok ( &final_carry_big );
201
+	tcpip_ok ( &final_carry_little );
202
+	tcpip_random_ok ( &random_aligned );
203
+	tcpip_random_ok ( &random_unaligned_1 );
204
+	tcpip_random_ok ( &random_unaligned_2 );
205
+	tcpip_random_ok ( &random_aligned_truncated );
206
+	tcpip_random_ok ( &partial );
207
+}
208
+
209
+/** TCP/IP self-test */
210
+struct self_test tcpip_test __self_test = {
211
+	.name = "tcpip",
212
+	.exec = tcpip_test_exec,
213
+};

+ 1
- 0
src/tests/tests.c View File

@@ -31,6 +31,7 @@ REQUIRE_OBJECT ( byteswap_test );
31 31
 REQUIRE_OBJECT ( base64_test );
32 32
 REQUIRE_OBJECT ( settings_test );
33 33
 REQUIRE_OBJECT ( time_test );
34
+REQUIRE_OBJECT ( tcpip_test );
34 35
 REQUIRE_OBJECT ( crc32_test );
35 36
 REQUIRE_OBJECT ( md5_test );
36 37
 REQUIRE_OBJECT ( sha1_test );

Loading…
Cancel
Save