iPXE
tcpip_test.c
Go to the documentation of this file.
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 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26/** @file
27 *
28 * TCP/IP self-tests
29 *
30 */
31
32/* Forcibly enable assertions */
33#undef NDEBUG
34
35#include <stdint.h>
36#include <stdlib.h>
37#include <string.h>
38#include <assert.h>
39#include <ipxe/test.h>
40#include <ipxe/profile.h>
41#include <ipxe/tcpip.h>
42
43/** Number of sample iterations for profiling */
44#define PROFILE_COUNT 16
45
46/** A TCP/IP fixed-data test */
47struct tcpip_test {
48 /** Data */
49 const void *data;
50 /** Length of data */
51 size_t len;
52};
53
54/** A TCP/IP pseudorandom-data test */
56 /** Seed */
57 unsigned int seed;
58 /** Length of data */
59 size_t len;
60 /** Alignment offset */
61 size_t offset;
62};
63
64/** Define inline data */
65#define DATA(...) { __VA_ARGS__ }
66
67/** Define a TCP/IP fixed-data test */
68#define TCPIP_TEST( name, DATA ) \
69 static const uint8_t __attribute__ (( aligned ( 16 ) )) \
70 name ## _data[] = DATA; \
71 static struct tcpip_test name = { \
72 .data = name ## _data, \
73 .len = sizeof ( name ## _data ), \
74 }
75
76/** Define a TCP/IP pseudorandom-data test */
77#define TCPIP_RANDOM_TEST( name, SEED, LEN, OFFSET ) \
78 static struct tcpip_random_test name = { \
79 .seed = SEED, \
80 .len = LEN, \
81 .offset = OFFSET, \
82 }
83
84/** Buffer for pseudorandom-data tests */
85static uint8_t __attribute__ (( aligned ( 16 ) ))
86 tcpip_data[ 4096 + 7 /* offset */ ];
87
88/** Empty data */
89TCPIP_TEST ( empty, DATA() );
90
91/** Single byte */
92TCPIP_TEST ( one_byte, DATA ( 0xeb ) );
93
94/** Double byte */
95TCPIP_TEST ( two_bytes, DATA ( 0xba, 0xbe ) );
96
97/** Positive zero data */
98TCPIP_TEST ( positive_zero, DATA ( 0x00, 0x00 ) );
99
100/** Negative zero data */
101TCPIP_TEST ( negative_zero, DATA ( 0xff, 0xff ) );
102
103/** Final wrap-around carry (big-endian) */
104TCPIP_TEST ( final_carry_big,
105 DATA ( 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ) );
106
107/** Final wrap-around carry (little-endian) */
108TCPIP_TEST ( final_carry_little,
109 DATA ( 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00 ) );
110
111/** Random data (aligned) */
112TCPIP_RANDOM_TEST ( random_aligned, 0x12345678UL, 4096, 0 );
113
114/** Random data (unaligned, +1) */
115TCPIP_RANDOM_TEST ( random_unaligned_1, 0x12345678UL, 4096, 1 );
116
117/** Random data (unaligned, +2) */
118TCPIP_RANDOM_TEST ( random_unaligned_2, 0x12345678UL, 4096, 2 );
119
120/** Random data (aligned, truncated) */
121TCPIP_RANDOM_TEST ( random_aligned_truncated, 0x12345678UL, 4095, 0 );
122
123/** Random data (unaligned start and finish) */
124TCPIP_RANDOM_TEST ( partial, 0xcafebabe, 121, 5 );
125
126/**
127 * Calculate TCP/IP checksum
128 *
129 * @v data Data to sum
130 * @v len Length of data
131 * @ret cksum Checksum
132 *
133 * This is a reference implementation taken from RFC1071 (and modified
134 * to fix compilation without warnings under gcc).
135 *
136 * The initial value of the one's complement @c sum is changed from
137 * positive zero (0x0000) to negative zero (0xffff). This ensures
138 * that the return value will always use the positive representation
139 * of zero (0x0000). Without this change, the return value would use
140 * negative zero (0xffff) if the input data is zero length (or all
141 * zeros) but positive zero (0x0000) for any other data which sums to
142 * zero.
143 */
144static uint16_t rfc_tcpip_chksum ( const void *data, size_t len ) {
145 unsigned long sum = 0xffff;
146
147 while ( len > 1 ) {
148 sum += *( ( uint16_t * ) data );
149 data += 2;
150 len -= 2;
151 }
152
153 if ( len > 0 )
154 sum += *( ( uint8_t * ) data );
155
156 while ( sum >> 16 )
157 sum = ( ( sum & 0xffff ) + ( sum >> 16 ) );
158
159 assert ( sum != 0x0000 );
160 return ~sum;
161}
162
163/**
164 * Report TCP/IP fixed-data test result
165 *
166 * @v test TCP/IP test
167 * @v file Test code file
168 * @v line Test code line
169 */
170static void tcpip_okx ( struct tcpip_test *test, const char *file,
171 unsigned int line ) {
172 uint16_t expected;
173 uint16_t generic_sum;
174 uint16_t sum;
175
176 /* Verify generic_tcpip_continue_chksum() result */
177 expected = rfc_tcpip_chksum ( test->data, test->len );
179 test->data, test->len );
180 okx ( generic_sum == expected, file, line );
181
182 /* Verify optimised tcpip_continue_chksum() result */
183 sum = tcpip_continue_chksum ( TCPIP_EMPTY_CSUM, test->data, test->len );
184 okx ( sum == expected, file, line );
185}
186#define tcpip_ok( test ) tcpip_okx ( test, __FILE__, __LINE__ )
187
188/**
189 * Report TCP/IP pseudorandom-data test result
190 *
191 * @v test TCP/IP test
192 * @v file Test code file
193 * @v line Test code line
194 */
196 const char *file, unsigned int line ) {
197 uint8_t *data = ( tcpip_data + test->offset );
198 struct profiler profiler;
199 uint16_t expected;
200 uint16_t generic_sum;
201 uint16_t sum;
202 unsigned int i;
203
204 /* Sanity check */
205 assert ( ( test->len + test->offset ) <= sizeof ( tcpip_data ) );
206
207 /* Generate random data */
208 srandom ( test->seed );
209 for ( i = 0 ; i < test->len ; i++ )
210 data[i] = random();
211
212 /* Verify generic_tcpip_continue_chksum() result */
213 expected = rfc_tcpip_chksum ( data, test->len );
215 data, test->len );
216 okx ( generic_sum == expected, file, line );
217
218 /* Verify optimised tcpip_continue_chksum() result */
220 okx ( sum == expected, file, line );
221
222 /* Profile optimised calculation */
223 memset ( &profiler, 0, sizeof ( profiler ) );
224 for ( i = 0 ; i < PROFILE_COUNT ; i++ ) {
227 test->len );
229 }
230 DBG ( "TCPIP checksummed %zd bytes (+%zd) in %ld +/- %ld ticks\n",
231 test->len, test->offset, profile_mean ( &profiler ),
233}
234#define tcpip_random_ok( test ) tcpip_random_okx ( test, __FILE__, __LINE__ )
235
236/**
237 * Perform TCP/IP self-tests
238 *
239 */
240static void tcpip_test_exec ( void ) {
241
242 tcpip_ok ( &empty );
243 tcpip_ok ( &one_byte );
244 tcpip_ok ( &two_bytes );
245 tcpip_ok ( &positive_zero );
246 tcpip_ok ( &negative_zero );
247 tcpip_ok ( &final_carry_big );
248 tcpip_ok ( &final_carry_little );
249 tcpip_random_ok ( &random_aligned );
250 tcpip_random_ok ( &random_unaligned_1 );
251 tcpip_random_ok ( &random_unaligned_2 );
252 tcpip_random_ok ( &random_aligned_truncated );
253 tcpip_random_ok ( &partial );
254}
255
256/** TCP/IP self-test */
258 .name = "tcpip",
259 .exec = tcpip_test_exec,
260};
#define DATA(...)
Define inline data.
Definition acpi_test.c:74
unsigned short uint16_t
Definition stdint.h:11
unsigned char uint8_t
Definition stdint.h:10
Assertions.
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
#define PROFILE_COUNT
Number of sample iterations for profiling.
Definition cipher_test.c:45
ring len
Length.
Definition dwmac.h:226
uint8_t data[48]
Additional event data.
Definition ena.h:11
static int test
Definition epic100.c:73
#define DBG(...)
Print a debugging message.
Definition compiler.h:498
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define __attribute__(x)
Definition compiler.h:10
Profiling.
static void profile_stop(struct profiler *profiler)
Stop profiling.
Definition profile.h:174
static void profile_start(struct profiler *profiler)
Start profiling.
Definition profile.h:161
Transport-network layer interface.
#define TCPIP_EMPTY_CSUM
Empty checksum value.
Definition tcpip.h:58
String functions.
void * memset(void *dest, int character, size_t len) __nonnull
unsigned long profile_mean(struct profiler *profiler)
Get mean sample value.
Definition profile.c:242
unsigned long profile_stddev(struct profiler *profiler)
Get sample standard deviation.
Definition profile.c:276
long int random(void)
Generate a pseudo-random number between 0 and 2147483647L or 2147483562?
Definition random.c:32
void srandom(unsigned int seed)
Seed the pseudo-random number generator.
Definition random.c:21
A data structure for storing profiling information.
Definition profile.h:27
A self-test set.
Definition test.h:15
A TCP/IP pseudorandom-data test.
Definition tcpip_test.c:55
unsigned int seed
Seed.
Definition tcpip_test.c:57
size_t len
Length of data.
Definition tcpip_test.c:59
size_t offset
Alignment offset.
Definition tcpip_test.c:61
A TCP/IP fixed-data test.
Definition tcpip_test.c:47
size_t len
Length of data.
Definition tcpip_test.c:51
const void * data
Data.
Definition tcpip_test.c:49
uint16_t generic_tcpip_continue_chksum(uint16_t partial, const void *data, size_t len)
Calculate continued TCP/IP checkum.
Definition tcpip.c:171
#define TCPIP_TEST(name, DATA)
Define a TCP/IP fixed-data test.
Definition tcpip_test.c:68
static void tcpip_test_exec(void)
Perform TCP/IP self-tests.
Definition tcpip_test.c:240
#define tcpip_ok(test)
Definition tcpip_test.c:186
static uint16_t rfc_tcpip_chksum(const void *data, size_t len)
Calculate TCP/IP checksum.
Definition tcpip_test.c:144
static void tcpip_okx(struct tcpip_test *test, const char *file, unsigned int line)
Report TCP/IP fixed-data test result.
Definition tcpip_test.c:170
static uint8_t tcpip_data[4096+7]
Buffer for pseudorandom-data tests.
Definition tcpip_test.c:86
#define tcpip_random_ok(test)
Definition tcpip_test.c:234
static void tcpip_random_okx(struct tcpip_random_test *test, const char *file, unsigned int line)
Report TCP/IP pseudorandom-data test result.
Definition tcpip_test.c:195
#define TCPIP_RANDOM_TEST(name, SEED, LEN, OFFSET)
Define a TCP/IP pseudorandom-data test.
Definition tcpip_test.c:77
Self-test infrastructure.
#define okx(success, file, line)
Report test result.
Definition test.h:44
#define __self_test
Declare a self-test.
Definition test.h:32
uint16_t tcpip_continue_chksum(uint16_t partial, const void *data, size_t len)
Calculate continued TCP/IP checkum.
Definition x86_tcpip.c:46