]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0 |
bfacad7d JH |
2 | /* |
3 | * Copyright (c) 2015 National Instruments | |
4 | * | |
5 | * (C) Copyright 2015 | |
6 | * Joe Hershberger <[email protected]> | |
bfacad7d JH |
7 | */ |
8 | ||
d678a59d | 9 | #include <common.h> |
bfacad7d | 10 | #include <dm.h> |
9fb625ce | 11 | #include <env.h> |
bfacad7d | 12 | #include <fdtdec.h> |
f7ae49fc | 13 | #include <log.h> |
bfacad7d JH |
14 | #include <malloc.h> |
15 | #include <net.h> | |
184ded4b | 16 | #include <net6.h> |
0e1fad43 | 17 | #include <asm/eth.h> |
e721b882 | 18 | #include <dm/test.h> |
6d9764c2 BM |
19 | #include <dm/device-internal.h> |
20 | #include <dm/uclass-internal.h> | |
0e1fad43 | 21 | #include <test/test.h> |
e721b882 | 22 | #include <test/ut.h> |
4c516807 | 23 | #include <ndisc.h> |
bfacad7d | 24 | |
6d9764c2 BM |
25 | #define DM_TEST_ETH_NUM 4 |
26 | ||
184ded4b VM |
27 | #if IS_ENABLED(CONFIG_IPV6) |
28 | static int dm_test_string_to_ip6(struct unit_test_state *uts) | |
29 | { | |
30 | char *str; | |
31 | struct test_ip6_pair { | |
32 | char *string_addr; | |
33 | struct in6_addr ip6_addr; | |
34 | }; | |
35 | ||
36 | struct in6_addr ip6 = {0}; | |
37 | ||
38 | /* Correct statements */ | |
39 | struct test_ip6_pair test_suite[] = { | |
40 | {"2001:db8::0:1234:1", {.s6_addr32[0] = 0xb80d0120, | |
41 | .s6_addr32[1] = 0x00000000, | |
42 | .s6_addr32[2] = 0x00000000, | |
43 | .s6_addr32[3] = 0x01003412}}, | |
44 | {"2001:0db8:0000:0000:0000:0000:1234:0001", | |
45 | {.s6_addr32[0] = 0xb80d0120, | |
46 | .s6_addr32[1] = 0x00000000, | |
47 | .s6_addr32[2] = 0x00000000, | |
48 | .s6_addr32[3] = 0x01003412}}, | |
49 | {"::1", {.s6_addr32[0] = 0x00000000, | |
50 | .s6_addr32[1] = 0x00000000, | |
51 | .s6_addr32[2] = 0x00000000, | |
52 | .s6_addr32[3] = 0x01000000}}, | |
53 | {"::ffff:192.168.1.1", {.s6_addr32[0] = 0x00000000, | |
54 | .s6_addr32[1] = 0x00000000, | |
55 | .s6_addr32[2] = 0xffff0000, | |
56 | .s6_addr32[3] = 0x0101a8c0}}, | |
57 | }; | |
58 | ||
59 | for (int i = 0; i < ARRAY_SIZE(test_suite); ++i) { | |
60 | ut_assertok(string_to_ip6(test_suite[i].string_addr, | |
61 | strlen(test_suite[i].string_addr), &ip6)); | |
62 | ut_asserteq_mem(&ip6, &test_suite[i].ip6_addr, | |
63 | sizeof(struct in6_addr)); | |
64 | } | |
65 | ||
66 | /* Incorrect statements */ | |
67 | str = "hello:world"; | |
68 | ut_assertok(!string_to_ip6(str, strlen(str), &ip6)); | |
69 | str = "2001:db8::0::0"; | |
70 | ut_assertok(!string_to_ip6(str, strlen(str), &ip6)); | |
71 | str = "2001:db8:192.168.1.1::1"; | |
72 | ut_assertok(!string_to_ip6(str, strlen(str), &ip6)); | |
73 | str = "192.168.1.1"; | |
74 | ut_assertok(!string_to_ip6(str, strlen(str), &ip6)); | |
75 | ||
76 | return 0; | |
77 | } | |
78 | DM_TEST(dm_test_string_to_ip6, 0); | |
d9f5c41e VM |
79 | |
80 | static int dm_test_csum_ipv6_magic(struct unit_test_state *uts) | |
81 | { | |
82 | unsigned short csum = 0xbeef; | |
83 | /* Predefined correct parameters */ | |
84 | unsigned short correct_csum = 0xd8ac; | |
85 | struct in6_addr saddr = {.s6_addr32[0] = 0x000080fe, | |
86 | .s6_addr32[1] = 0x00000000, | |
87 | .s6_addr32[2] = 0xffe9f242, | |
88 | .s6_addr32[3] = 0xe8f66dfe}; | |
89 | struct in6_addr daddr = {.s6_addr32[0] = 0x000080fe, | |
90 | .s6_addr32[1] = 0x00000000, | |
91 | .s6_addr32[2] = 0xffd5b372, | |
92 | .s6_addr32[3] = 0x3ef692fe}; | |
93 | u16 len = 1460; | |
94 | unsigned short proto = 17; | |
95 | unsigned int head_csum = 0x91f0; | |
96 | ||
97 | csum = csum_ipv6_magic(&saddr, &daddr, len, proto, head_csum); | |
98 | ut_asserteq(csum, correct_csum); | |
99 | ||
100 | /* Broke a parameter */ | |
101 | proto--; | |
102 | csum = csum_ipv6_magic(&saddr, &daddr, len, proto, head_csum); | |
103 | ut_assert(csum != correct_csum); | |
104 | ||
105 | return 0; | |
106 | } | |
107 | DM_TEST(dm_test_csum_ipv6_magic, 0); | |
8576dcdf VM |
108 | |
109 | static int dm_test_ip6_addr_in_subnet(struct unit_test_state *uts) | |
110 | { | |
111 | struct in6_addr our = {.s6_addr32[0] = 0x000080fe, | |
112 | .s6_addr32[1] = 0x00000000, | |
113 | .s6_addr32[2] = 0xffe9f242, | |
114 | .s6_addr32[3] = 0xe8f66dfe}; | |
115 | struct in6_addr neigh1 = {.s6_addr32[0] = 0x000080fe, | |
116 | .s6_addr32[1] = 0x00000000, | |
117 | .s6_addr32[2] = 0xffd5b372, | |
118 | .s6_addr32[3] = 0x3ef692fe}; | |
119 | struct in6_addr neigh2 = {.s6_addr32[0] = 0x60480120, | |
120 | .s6_addr32[1] = 0x00006048, | |
121 | .s6_addr32[2] = 0x00000000, | |
122 | .s6_addr32[3] = 0x00008888}; | |
123 | ||
124 | /* in */ | |
125 | ut_assert(ip6_addr_in_subnet(&our, &neigh1, 64)); | |
126 | /* outside */ | |
127 | ut_assert(!ip6_addr_in_subnet(&our, &neigh2, 64)); | |
128 | ut_assert(!ip6_addr_in_subnet(&our, &neigh1, 128)); | |
129 | ||
130 | return 0; | |
131 | } | |
132 | DM_TEST(dm_test_ip6_addr_in_subnet, 0); | |
789a2c7d VM |
133 | |
134 | static int dm_test_ip6_make_snma(struct unit_test_state *uts) | |
135 | { | |
136 | struct in6_addr mult = {0}; | |
137 | struct in6_addr correct_addr = { | |
138 | .s6_addr32[0] = 0x000002ff, | |
139 | .s6_addr32[1] = 0x00000000, | |
140 | .s6_addr32[2] = 0x01000000, | |
141 | .s6_addr32[3] = 0xe8f66dff}; | |
142 | struct in6_addr addr = { .s6_addr32[0] = 0x000080fe, | |
143 | .s6_addr32[1] = 0x00000000, | |
144 | .s6_addr32[2] = 0xffe9f242, | |
145 | .s6_addr32[3] = 0xe8f66dfe}; | |
146 | ||
147 | ip6_make_snma(&mult, &addr); | |
148 | ut_asserteq_mem(&mult, &correct_addr, sizeof(struct in6_addr)); | |
149 | ||
150 | return 0; | |
151 | } | |
152 | DM_TEST(dm_test_ip6_make_snma, 0); | |
e4d30fd1 VM |
153 | |
154 | static int dm_test_ip6_make_lladdr(struct unit_test_state *uts) | |
155 | { | |
156 | struct in6_addr generated_lladdr = {0}; | |
157 | struct in6_addr correct_lladdr = { | |
158 | .s6_addr32[0] = 0x000080fe, | |
159 | .s6_addr32[1] = 0x00000000, | |
160 | .s6_addr32[2] = 0xffabf33a, | |
161 | .s6_addr32[3] = 0xfbb352fe}; | |
162 | const unsigned char mac[6] = {0x38, 0xf3, 0xab, 0x52, 0xb3, 0xfb}; | |
163 | ||
164 | ip6_make_lladdr(&generated_lladdr, mac); | |
165 | ut_asserteq_mem(&generated_lladdr, &correct_lladdr, | |
166 | sizeof(struct in6_addr)); | |
167 | ||
168 | return 0; | |
169 | } | |
170 | DM_TEST(dm_test_ip6_make_lladdr, UT_TESTF_SCAN_FDT); | |
184ded4b VM |
171 | #endif |
172 | ||
e721b882 | 173 | static int dm_test_eth(struct unit_test_state *uts) |
bfacad7d | 174 | { |
049a95a7 | 175 | net_ping_ip = string_to_ip("1.1.2.2"); |
bfacad7d | 176 | |
382bee57 | 177 | env_set("ethact", "eth@10002000"); |
bc0571fc | 178 | ut_assertok(net_loop(PING)); |
00caae6d | 179 | ut_asserteq_str("eth@10002000", env_get("ethact")); |
bfacad7d | 180 | |
382bee57 | 181 | env_set("ethact", "eth@10003000"); |
bc0571fc | 182 | ut_assertok(net_loop(PING)); |
00caae6d | 183 | ut_asserteq_str("eth@10003000", env_get("ethact")); |
bfacad7d | 184 | |
382bee57 | 185 | env_set("ethact", "eth@10004000"); |
bc0571fc | 186 | ut_assertok(net_loop(PING)); |
00caae6d | 187 | ut_asserteq_str("eth@10004000", env_get("ethact")); |
bfacad7d JH |
188 | |
189 | return 0; | |
190 | } | |
e180c2b1 | 191 | DM_TEST(dm_test_eth, UT_TESTF_SCAN_FDT); |
e58780dc | 192 | |
e721b882 | 193 | static int dm_test_eth_alias(struct unit_test_state *uts) |
e58780dc | 194 | { |
049a95a7 | 195 | net_ping_ip = string_to_ip("1.1.2.2"); |
382bee57 | 196 | env_set("ethact", "eth0"); |
bc0571fc | 197 | ut_assertok(net_loop(PING)); |
00caae6d | 198 | ut_asserteq_str("eth@10002000", env_get("ethact")); |
e58780dc | 199 | |
be1a6e94 | 200 | env_set("ethact", "eth6"); |
bc0571fc | 201 | ut_assertok(net_loop(PING)); |
00caae6d | 202 | ut_asserteq_str("eth@10004000", env_get("ethact")); |
e58780dc | 203 | |
ff98da06 CM |
204 | /* Expected to fail since eth1 is not defined in the device tree */ |
205 | env_set("ethact", "eth1"); | |
bc0571fc | 206 | ut_assertok(net_loop(PING)); |
00caae6d | 207 | ut_asserteq_str("eth@10002000", env_get("ethact")); |
e58780dc | 208 | |
382bee57 | 209 | env_set("ethact", "eth5"); |
bc0571fc | 210 | ut_assertok(net_loop(PING)); |
00caae6d | 211 | ut_asserteq_str("eth@10003000", env_get("ethact")); |
e58780dc JH |
212 | |
213 | return 0; | |
214 | } | |
e180c2b1 | 215 | DM_TEST(dm_test_eth_alias, UT_TESTF_SCAN_FDT); |
6536b9bb | 216 | |
e721b882 | 217 | static int dm_test_eth_prime(struct unit_test_state *uts) |
6536b9bb | 218 | { |
049a95a7 | 219 | net_ping_ip = string_to_ip("1.1.2.2"); |
6536b9bb JH |
220 | |
221 | /* Expected to be "eth@10003000" because of ethprime variable */ | |
382bee57 SG |
222 | env_set("ethact", NULL); |
223 | env_set("ethprime", "eth5"); | |
bc0571fc | 224 | ut_assertok(net_loop(PING)); |
00caae6d | 225 | ut_asserteq_str("eth@10003000", env_get("ethact")); |
6536b9bb JH |
226 | |
227 | /* Expected to be "eth@10002000" because it is first */ | |
382bee57 SG |
228 | env_set("ethact", NULL); |
229 | env_set("ethprime", NULL); | |
bc0571fc | 230 | ut_assertok(net_loop(PING)); |
00caae6d | 231 | ut_asserteq_str("eth@10002000", env_get("ethact")); |
6536b9bb JH |
232 | |
233 | return 0; | |
234 | } | |
e180c2b1 | 235 | DM_TEST(dm_test_eth_prime, UT_TESTF_SCAN_FDT); |
7d104eab | 236 | |
6d9764c2 BM |
237 | /** |
238 | * This test case is trying to test the following scenario: | |
239 | * - All ethernet devices are not probed | |
240 | * - "ethaddr" for all ethernet devices are not set | |
241 | * - "ethact" is set to a valid ethernet device name | |
242 | * | |
243 | * With Sandbox default test configuration, all ethernet devices are | |
244 | * probed after power-up, so we have to manually create such scenario: | |
245 | * - Remove all ethernet devices | |
246 | * - Remove all "ethaddr" environment variables | |
247 | * - Set "ethact" to the first ethernet device | |
248 | * | |
249 | * Do a ping test to see if anything goes wrong. | |
250 | */ | |
251 | static int dm_test_eth_act(struct unit_test_state *uts) | |
252 | { | |
253 | struct udevice *dev[DM_TEST_ETH_NUM]; | |
254 | const char *ethname[DM_TEST_ETH_NUM] = {"eth@10002000", "eth@10003000", | |
255 | "sbe5", "eth@10004000"}; | |
256 | const char *addrname[DM_TEST_ETH_NUM] = {"ethaddr", "eth5addr", | |
be1a6e94 | 257 | "eth3addr", "eth6addr"}; |
6d9764c2 BM |
258 | char ethaddr[DM_TEST_ETH_NUM][18]; |
259 | int i; | |
260 | ||
e2e6daed | 261 | memset(ethaddr, '\0', sizeof(ethaddr)); |
6d9764c2 BM |
262 | net_ping_ip = string_to_ip("1.1.2.2"); |
263 | ||
264 | /* Prepare the test scenario */ | |
265 | for (i = 0; i < DM_TEST_ETH_NUM; i++) { | |
2a1812de SA |
266 | char *addr; |
267 | ||
6d9764c2 BM |
268 | ut_assertok(uclass_find_device_by_name(UCLASS_ETH, |
269 | ethname[i], &dev[i])); | |
706865af | 270 | ut_assertok(device_remove(dev[i], DM_REMOVE_NORMAL)); |
6d9764c2 BM |
271 | |
272 | /* Invalidate MAC address */ | |
2a1812de SA |
273 | addr = env_get(addrname[i]); |
274 | ut_assertnonnull(addr); | |
275 | strncpy(ethaddr[i], addr, 17); | |
6d9764c2 | 276 | /* Must disable access protection for ethaddr before clearing */ |
382bee57 SG |
277 | env_set(".flags", addrname[i]); |
278 | env_set(addrname[i], NULL); | |
6d9764c2 BM |
279 | } |
280 | ||
281 | /* Set ethact to "eth@10002000" */ | |
382bee57 | 282 | env_set("ethact", ethname[0]); |
6d9764c2 BM |
283 | |
284 | /* Segment fault might happen if something is wrong */ | |
285 | ut_asserteq(-ENODEV, net_loop(PING)); | |
286 | ||
287 | for (i = 0; i < DM_TEST_ETH_NUM; i++) { | |
288 | /* Restore the env */ | |
382bee57 SG |
289 | env_set(".flags", addrname[i]); |
290 | env_set(addrname[i], ethaddr[i]); | |
6d9764c2 BM |
291 | |
292 | /* Probe the device again */ | |
293 | ut_assertok(device_probe(dev[i])); | |
294 | } | |
382bee57 SG |
295 | env_set(".flags", NULL); |
296 | env_set("ethact", NULL); | |
6d9764c2 BM |
297 | |
298 | return 0; | |
299 | } | |
e180c2b1 | 300 | DM_TEST(dm_test_eth_act, UT_TESTF_SCAN_FDT); |
6d9764c2 | 301 | |
df33fd28 SA |
302 | /* Ensure that all addresses are loaded properly */ |
303 | static int dm_test_ethaddr(struct unit_test_state *uts) | |
304 | { | |
305 | static const char *const addr[] = { | |
306 | "02:00:11:22:33:44", | |
307 | "02:00:11:22:33:48", /* dsa slave */ | |
308 | "02:00:11:22:33:45", | |
309 | "02:00:11:22:33:48", /* dsa master */ | |
310 | "02:00:11:22:33:46", | |
311 | "02:00:11:22:33:47", | |
312 | "02:00:11:22:33:48", /* dsa slave */ | |
313 | "02:00:11:22:33:49", | |
314 | }; | |
315 | int i; | |
316 | ||
317 | for (i = 0; i < ARRAY_SIZE(addr); i++) { | |
318 | char addrname[10]; | |
2a1812de | 319 | char *env_addr; |
df33fd28 SA |
320 | |
321 | if (i) | |
322 | snprintf(addrname, sizeof(addrname), "eth%daddr", i + 1); | |
323 | else | |
324 | strcpy(addrname, "ethaddr"); | |
2a1812de SA |
325 | |
326 | env_addr = env_get(addrname); | |
327 | ut_assertnonnull(env_addr); | |
328 | ut_asserteq_str(addr[i], env_addr); | |
df33fd28 SA |
329 | } |
330 | ||
331 | return 0; | |
332 | } | |
333 | DM_TEST(dm_test_ethaddr, UT_TESTF_SCAN_FDT); | |
334 | ||
09129bec JH |
335 | /* The asserts include a return on fail; cleanup in the caller */ |
336 | static int _dm_test_eth_rotate1(struct unit_test_state *uts) | |
7d104eab | 337 | { |
7d104eab | 338 | /* Make sure that the default is to rotate to the next interface */ |
382bee57 | 339 | env_set("ethact", "eth@10004000"); |
bc0571fc | 340 | ut_assertok(net_loop(PING)); |
00caae6d | 341 | ut_asserteq_str("eth@10002000", env_get("ethact")); |
7d104eab JH |
342 | |
343 | /* If ethrotate is no, then we should fail on a bad MAC */ | |
382bee57 SG |
344 | env_set("ethact", "eth@10004000"); |
345 | env_set("ethrotate", "no"); | |
bc0571fc | 346 | ut_asserteq(-EINVAL, net_loop(PING)); |
00caae6d | 347 | ut_asserteq_str("eth@10004000", env_get("ethact")); |
7d104eab | 348 | |
09129bec JH |
349 | return 0; |
350 | } | |
7d104eab | 351 | |
09129bec JH |
352 | static int _dm_test_eth_rotate2(struct unit_test_state *uts) |
353 | { | |
7d104eab | 354 | /* Make sure we can skip invalid devices */ |
382bee57 | 355 | env_set("ethact", "eth@10004000"); |
bc0571fc | 356 | ut_assertok(net_loop(PING)); |
00caae6d | 357 | ut_asserteq_str("eth@10004000", env_get("ethact")); |
7d104eab | 358 | |
71d7971f | 359 | /* Make sure we can handle device name which is not eth# */ |
382bee57 | 360 | env_set("ethact", "sbe5"); |
71d7971f | 361 | ut_assertok(net_loop(PING)); |
00caae6d | 362 | ut_asserteq_str("sbe5", env_get("ethact")); |
71d7971f | 363 | |
09129bec JH |
364 | return 0; |
365 | } | |
366 | ||
367 | static int dm_test_eth_rotate(struct unit_test_state *uts) | |
368 | { | |
369 | char ethaddr[18]; | |
370 | int retval; | |
371 | ||
372 | /* Set target IP to mock ping */ | |
373 | net_ping_ip = string_to_ip("1.1.2.2"); | |
374 | ||
375 | /* Invalidate eth1's MAC address */ | |
e2e6daed | 376 | memset(ethaddr, '\0', sizeof(ethaddr)); |
be1a6e94 MW |
377 | strncpy(ethaddr, env_get("eth6addr"), 17); |
378 | /* Must disable access protection for eth6addr before clearing */ | |
379 | env_set(".flags", "eth6addr"); | |
380 | env_set("eth6addr", NULL); | |
09129bec JH |
381 | |
382 | retval = _dm_test_eth_rotate1(uts); | |
383 | ||
384 | /* Restore the env */ | |
be1a6e94 | 385 | env_set("eth6addr", ethaddr); |
382bee57 | 386 | env_set("ethrotate", NULL); |
09129bec JH |
387 | |
388 | if (!retval) { | |
389 | /* Invalidate eth0's MAC address */ | |
e2e6daed | 390 | strncpy(ethaddr, env_get("ethaddr"), 17); |
09129bec | 391 | /* Must disable access protection for ethaddr before clearing */ |
382bee57 SG |
392 | env_set(".flags", "ethaddr"); |
393 | env_set("ethaddr", NULL); | |
09129bec JH |
394 | |
395 | retval = _dm_test_eth_rotate2(uts); | |
396 | ||
397 | /* Restore the env */ | |
382bee57 | 398 | env_set("ethaddr", ethaddr); |
09129bec | 399 | } |
7d104eab | 400 | /* Restore the env */ |
382bee57 | 401 | env_set(".flags", NULL); |
7d104eab | 402 | |
09129bec | 403 | return retval; |
7d104eab | 404 | } |
e180c2b1 | 405 | DM_TEST(dm_test_eth_rotate, UT_TESTF_SCAN_FDT); |
7ece1c61 | 406 | |
09129bec JH |
407 | /* The asserts include a return on fail; cleanup in the caller */ |
408 | static int _dm_test_net_retry(struct unit_test_state *uts) | |
7ece1c61 | 409 | { |
7ece1c61 JH |
410 | /* |
411 | * eth1 is disabled and netretry is yes, so the ping should succeed and | |
412 | * the active device should be eth0 | |
413 | */ | |
414 | sandbox_eth_disable_response(1, true); | |
ff98da06 | 415 | env_set("ethact", "lan1"); |
382bee57 | 416 | env_set("netretry", "yes"); |
172a31bf | 417 | sandbox_eth_skip_timeout(); |
bc0571fc | 418 | ut_assertok(net_loop(PING)); |
00caae6d | 419 | ut_asserteq_str("eth@10002000", env_get("ethact")); |
7ece1c61 JH |
420 | |
421 | /* | |
422 | * eth1 is disabled and netretry is no, so the ping should fail and the | |
423 | * active device should be eth1 | |
424 | */ | |
ff98da06 | 425 | env_set("ethact", "lan1"); |
382bee57 | 426 | env_set("netretry", "no"); |
172a31bf | 427 | sandbox_eth_skip_timeout(); |
a735e6e9 | 428 | ut_asserteq(-ENONET, net_loop(PING)); |
ff98da06 | 429 | ut_asserteq_str("lan1", env_get("ethact")); |
7ece1c61 | 430 | |
09129bec JH |
431 | return 0; |
432 | } | |
433 | ||
434 | static int dm_test_net_retry(struct unit_test_state *uts) | |
435 | { | |
436 | int retval; | |
437 | ||
438 | net_ping_ip = string_to_ip("1.1.2.2"); | |
439 | ||
440 | retval = _dm_test_net_retry(uts); | |
441 | ||
7ece1c61 | 442 | /* Restore the env */ |
382bee57 | 443 | env_set("netretry", NULL); |
7ece1c61 JH |
444 | sandbox_eth_disable_response(1, false); |
445 | ||
09129bec | 446 | return retval; |
7ece1c61 | 447 | } |
e180c2b1 | 448 | DM_TEST(dm_test_net_retry, UT_TESTF_SCAN_FDT); |
45988dae JH |
449 | |
450 | static int sb_check_arp_reply(struct udevice *dev, void *packet, | |
451 | unsigned int len) | |
452 | { | |
453 | struct eth_sandbox_priv *priv = dev_get_priv(dev); | |
454 | struct ethernet_hdr *eth = packet; | |
455 | struct arp_hdr *arp; | |
456 | /* Used by all of the ut_assert macros */ | |
457 | struct unit_test_state *uts = priv->priv; | |
458 | ||
459 | if (ntohs(eth->et_protlen) != PROT_ARP) | |
460 | return 0; | |
461 | ||
462 | arp = packet + ETHER_HDR_SIZE; | |
463 | ||
464 | if (ntohs(arp->ar_op) != ARPOP_REPLY) | |
465 | return 0; | |
466 | ||
467 | /* This test would be worthless if we are not waiting */ | |
468 | ut_assert(arp_is_waiting()); | |
469 | ||
470 | /* Validate response */ | |
f91f366b SG |
471 | ut_asserteq_mem(eth->et_src, net_ethaddr, ARP_HLEN); |
472 | ut_asserteq_mem(eth->et_dest, priv->fake_host_hwaddr, ARP_HLEN); | |
45988dae JH |
473 | ut_assert(eth->et_protlen == htons(PROT_ARP)); |
474 | ||
475 | ut_assert(arp->ar_hrd == htons(ARP_ETHER)); | |
476 | ut_assert(arp->ar_pro == htons(PROT_IP)); | |
477 | ut_assert(arp->ar_hln == ARP_HLEN); | |
478 | ut_assert(arp->ar_pln == ARP_PLEN); | |
f91f366b | 479 | ut_asserteq_mem(&arp->ar_sha, net_ethaddr, ARP_HLEN); |
45988dae | 480 | ut_assert(net_read_ip(&arp->ar_spa).s_addr == net_ip.s_addr); |
f91f366b | 481 | ut_asserteq_mem(&arp->ar_tha, priv->fake_host_hwaddr, ARP_HLEN); |
45988dae JH |
482 | ut_assert(net_read_ip(&arp->ar_tpa).s_addr == |
483 | string_to_ip("1.1.2.4").s_addr); | |
484 | ||
485 | return 0; | |
486 | } | |
487 | ||
488 | static int sb_with_async_arp_handler(struct udevice *dev, void *packet, | |
489 | unsigned int len) | |
490 | { | |
491 | struct eth_sandbox_priv *priv = dev_get_priv(dev); | |
492 | struct ethernet_hdr *eth = packet; | |
493 | struct arp_hdr *arp = packet + ETHER_HDR_SIZE; | |
494 | int ret; | |
495 | ||
496 | /* | |
497 | * If we are about to generate a reply to ARP, first inject a request | |
498 | * from another host | |
499 | */ | |
500 | if (ntohs(eth->et_protlen) == PROT_ARP && | |
501 | ntohs(arp->ar_op) == ARPOP_REQUEST) { | |
502 | /* Make sure sandbox_eth_recv_arp_req() knows who is asking */ | |
503 | priv->fake_host_ipaddr = string_to_ip("1.1.2.4"); | |
504 | ||
505 | ret = sandbox_eth_recv_arp_req(dev); | |
506 | if (ret) | |
507 | return ret; | |
508 | } | |
509 | ||
510 | sandbox_eth_arp_req_to_reply(dev, packet, len); | |
511 | sandbox_eth_ping_req_to_reply(dev, packet, len); | |
512 | ||
513 | return sb_check_arp_reply(dev, packet, len); | |
514 | } | |
515 | ||
516 | static int dm_test_eth_async_arp_reply(struct unit_test_state *uts) | |
517 | { | |
518 | net_ping_ip = string_to_ip("1.1.2.2"); | |
519 | ||
520 | sandbox_eth_set_tx_handler(0, sb_with_async_arp_handler); | |
521 | /* Used by all of the ut_assert macros in the tx_handler */ | |
522 | sandbox_eth_set_priv(0, uts); | |
45988dae JH |
523 | |
524 | env_set("ethact", "eth@10002000"); | |
ac3f26cc | 525 | ut_assertok(net_loop(PING)); |
45988dae JH |
526 | ut_asserteq_str("eth@10002000", env_get("ethact")); |
527 | ||
528 | sandbox_eth_set_tx_handler(0, NULL); | |
529 | ||
530 | return 0; | |
531 | } | |
532 | ||
e180c2b1 | 533 | DM_TEST(dm_test_eth_async_arp_reply, UT_TESTF_SCAN_FDT); |
72ff0042 JH |
534 | |
535 | static int sb_check_ping_reply(struct udevice *dev, void *packet, | |
536 | unsigned int len) | |
537 | { | |
538 | struct eth_sandbox_priv *priv = dev_get_priv(dev); | |
539 | struct ethernet_hdr *eth = packet; | |
540 | struct ip_udp_hdr *ip; | |
541 | struct icmp_hdr *icmp; | |
542 | /* Used by all of the ut_assert macros */ | |
543 | struct unit_test_state *uts = priv->priv; | |
544 | ||
545 | if (ntohs(eth->et_protlen) != PROT_IP) | |
546 | return 0; | |
547 | ||
548 | ip = packet + ETHER_HDR_SIZE; | |
549 | ||
550 | if (ip->ip_p != IPPROTO_ICMP) | |
551 | return 0; | |
552 | ||
553 | icmp = (struct icmp_hdr *)&ip->udp_src; | |
554 | ||
555 | if (icmp->type != ICMP_ECHO_REPLY) | |
556 | return 0; | |
557 | ||
558 | /* This test would be worthless if we are not waiting */ | |
559 | ut_assert(arp_is_waiting()); | |
560 | ||
561 | /* Validate response */ | |
f91f366b SG |
562 | ut_asserteq_mem(eth->et_src, net_ethaddr, ARP_HLEN); |
563 | ut_asserteq_mem(eth->et_dest, priv->fake_host_hwaddr, ARP_HLEN); | |
72ff0042 JH |
564 | ut_assert(eth->et_protlen == htons(PROT_IP)); |
565 | ||
566 | ut_assert(net_read_ip(&ip->ip_src).s_addr == net_ip.s_addr); | |
567 | ut_assert(net_read_ip(&ip->ip_dst).s_addr == | |
568 | string_to_ip("1.1.2.4").s_addr); | |
569 | ||
570 | return 0; | |
571 | } | |
572 | ||
573 | static int sb_with_async_ping_handler(struct udevice *dev, void *packet, | |
574 | unsigned int len) | |
575 | { | |
576 | struct eth_sandbox_priv *priv = dev_get_priv(dev); | |
577 | struct ethernet_hdr *eth = packet; | |
578 | struct arp_hdr *arp = packet + ETHER_HDR_SIZE; | |
579 | int ret; | |
580 | ||
581 | /* | |
582 | * If we are about to generate a reply to ARP, first inject a request | |
583 | * from another host | |
584 | */ | |
585 | if (ntohs(eth->et_protlen) == PROT_ARP && | |
586 | ntohs(arp->ar_op) == ARPOP_REQUEST) { | |
587 | /* Make sure sandbox_eth_recv_arp_req() knows who is asking */ | |
588 | priv->fake_host_ipaddr = string_to_ip("1.1.2.4"); | |
589 | ||
590 | ret = sandbox_eth_recv_ping_req(dev); | |
591 | if (ret) | |
592 | return ret; | |
593 | } | |
594 | ||
595 | sandbox_eth_arp_req_to_reply(dev, packet, len); | |
596 | sandbox_eth_ping_req_to_reply(dev, packet, len); | |
597 | ||
598 | return sb_check_ping_reply(dev, packet, len); | |
599 | } | |
600 | ||
601 | static int dm_test_eth_async_ping_reply(struct unit_test_state *uts) | |
602 | { | |
603 | net_ping_ip = string_to_ip("1.1.2.2"); | |
604 | ||
605 | sandbox_eth_set_tx_handler(0, sb_with_async_ping_handler); | |
606 | /* Used by all of the ut_assert macros in the tx_handler */ | |
607 | sandbox_eth_set_priv(0, uts); | |
72ff0042 JH |
608 | |
609 | env_set("ethact", "eth@10002000"); | |
ac3f26cc | 610 | ut_assertok(net_loop(PING)); |
72ff0042 JH |
611 | ut_asserteq_str("eth@10002000", env_get("ethact")); |
612 | ||
613 | sandbox_eth_set_tx_handler(0, NULL); | |
614 | ||
615 | return 0; | |
616 | } | |
617 | ||
e180c2b1 | 618 | DM_TEST(dm_test_eth_async_ping_reply, UT_TESTF_SCAN_FDT); |
4c516807 EM |
619 | |
620 | #if IS_ENABLED(CONFIG_IPV6_ROUTER_DISCOVERY) | |
621 | ||
622 | static u8 ip6_ra_buf[] = {0x60, 0xf, 0xc5, 0x4a, 0x0, 0x38, 0x3a, 0xff, 0xfe, | |
623 | 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x85, 0xe6, | |
624 | 0x29, 0x77, 0xcb, 0xc8, 0x53, 0xff, 0x2, 0x0, 0x0, | |
625 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
626 | 0x1, 0x86, 0x0, 0xdc, 0x90, 0x40, 0x80, 0x15, 0x18, | |
627 | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x4, | |
628 | 0x40, 0xc0, 0x0, 0x0, 0x37, 0xdc, 0x0, 0x0, 0x37, | |
629 | 0x78, 0x0, 0x0, 0x0, 0x0, 0x20, 0x1, 0xca, 0xfe, 0xca, | |
630 | 0xfe, 0xca, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, | |
631 | 0x0, 0x1, 0x1, 0x0, 0x15, 0x5d, 0xe2, 0x8a, 0x2}; | |
632 | ||
633 | static int dm_test_validate_ra(struct unit_test_state *uts) | |
634 | { | |
635 | struct ip6_hdr *ip6 = (struct ip6_hdr *)ip6_ra_buf; | |
636 | struct icmp6hdr *icmp = (struct icmp6hdr *)(ip6 + 1); | |
637 | __be16 temp = 0; | |
638 | ||
639 | ut_assert(validate_ra(ip6) == true); | |
640 | ||
641 | temp = ip6->payload_len; | |
642 | ip6->payload_len = 15; | |
643 | ut_assert(validate_ra(ip6) == false); | |
644 | ip6->payload_len = temp; | |
645 | ||
646 | temp = ip6->saddr.s6_addr16[0]; | |
647 | ip6->saddr.s6_addr16[0] = 0x2001; | |
648 | ut_assert(validate_ra(ip6) == false); | |
649 | ip6->saddr.s6_addr16[0] = temp; | |
650 | ||
651 | temp = ip6->hop_limit; | |
652 | ip6->hop_limit = 15; | |
653 | ut_assert(validate_ra(ip6) == false); | |
654 | ip6->hop_limit = temp; | |
655 | ||
656 | temp = icmp->icmp6_code; | |
657 | icmp->icmp6_code = 15; | |
658 | ut_assert(validate_ra(ip6) == false); | |
659 | icmp->icmp6_code = temp; | |
660 | ||
661 | return 0; | |
662 | } | |
663 | ||
664 | DM_TEST(dm_test_validate_ra, 0); | |
665 | ||
666 | static int dm_test_process_ra(struct unit_test_state *uts) | |
667 | { | |
668 | int len = sizeof(ip6_ra_buf); | |
669 | struct ip6_hdr *ip6 = (struct ip6_hdr *)ip6_ra_buf; | |
670 | struct icmp6hdr *icmp = (struct icmp6hdr *)(ip6 + 1); | |
671 | struct ra_msg *msg = (struct ra_msg *)icmp; | |
672 | unsigned char *option = msg->opt; | |
673 | struct icmp6_ra_prefix_info *prefix = | |
674 | (struct icmp6_ra_prefix_info *)option; | |
675 | __be16 temp = 0; | |
676 | unsigned char option_len = option[1]; | |
677 | ||
678 | ut_assert(process_ra(ip6, len) == 0); | |
679 | ||
680 | temp = icmp->icmp6_rt_lifetime; | |
681 | icmp->icmp6_rt_lifetime = 0; | |
682 | ut_assert(process_ra(ip6, len) != 0); | |
683 | icmp->icmp6_rt_lifetime = temp; | |
684 | ||
685 | ut_assert(process_ra(ip6, 0) != 0); | |
686 | ||
687 | option[1] = 0; | |
688 | ut_assert(process_ra(ip6, len) != 0); | |
689 | option[1] = option_len; | |
690 | ||
691 | prefix->on_link = false; | |
692 | ut_assert(process_ra(ip6, len) != 0); | |
693 | prefix->on_link = true; | |
694 | ||
695 | temp = prefix->prefix.s6_addr16[0]; | |
696 | prefix->prefix.s6_addr16[0] = 0x80fe; | |
697 | ut_assert(process_ra(ip6, len) != 0); | |
698 | prefix->prefix.s6_addr16[0] = temp; | |
699 | ||
700 | return 0; | |
701 | } | |
702 | ||
703 | DM_TEST(dm_test_process_ra, 0); | |
704 | ||
705 | #endif |