]>
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 | ||
9 | #include <common.h> | |
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> | |
e721b882 | 16 | #include <dm/test.h> |
6d9764c2 BM |
17 | #include <dm/device-internal.h> |
18 | #include <dm/uclass-internal.h> | |
7ece1c61 | 19 | #include <asm/eth.h> |
e721b882 | 20 | #include <test/ut.h> |
bfacad7d | 21 | |
6d9764c2 BM |
22 | #define DM_TEST_ETH_NUM 4 |
23 | ||
e721b882 | 24 | static int dm_test_eth(struct unit_test_state *uts) |
bfacad7d | 25 | { |
049a95a7 | 26 | net_ping_ip = string_to_ip("1.1.2.2"); |
bfacad7d | 27 | |
382bee57 | 28 | env_set("ethact", "eth@10002000"); |
bc0571fc | 29 | ut_assertok(net_loop(PING)); |
00caae6d | 30 | ut_asserteq_str("eth@10002000", env_get("ethact")); |
bfacad7d | 31 | |
382bee57 | 32 | env_set("ethact", "eth@10003000"); |
bc0571fc | 33 | ut_assertok(net_loop(PING)); |
00caae6d | 34 | ut_asserteq_str("eth@10003000", env_get("ethact")); |
bfacad7d | 35 | |
382bee57 | 36 | env_set("ethact", "eth@10004000"); |
bc0571fc | 37 | ut_assertok(net_loop(PING)); |
00caae6d | 38 | ut_asserteq_str("eth@10004000", env_get("ethact")); |
bfacad7d JH |
39 | |
40 | return 0; | |
41 | } | |
42 | DM_TEST(dm_test_eth, DM_TESTF_SCAN_FDT); | |
e58780dc | 43 | |
e721b882 | 44 | static int dm_test_eth_alias(struct unit_test_state *uts) |
e58780dc | 45 | { |
049a95a7 | 46 | net_ping_ip = string_to_ip("1.1.2.2"); |
382bee57 | 47 | env_set("ethact", "eth0"); |
bc0571fc | 48 | ut_assertok(net_loop(PING)); |
00caae6d | 49 | ut_asserteq_str("eth@10002000", env_get("ethact")); |
e58780dc | 50 | |
be1a6e94 | 51 | env_set("ethact", "eth6"); |
bc0571fc | 52 | ut_assertok(net_loop(PING)); |
00caae6d | 53 | ut_asserteq_str("eth@10004000", env_get("ethact")); |
e58780dc JH |
54 | |
55 | /* Expected to fail since eth2 is not defined in the device tree */ | |
382bee57 | 56 | env_set("ethact", "eth2"); |
bc0571fc | 57 | ut_assertok(net_loop(PING)); |
00caae6d | 58 | ut_asserteq_str("eth@10002000", env_get("ethact")); |
e58780dc | 59 | |
382bee57 | 60 | env_set("ethact", "eth5"); |
bc0571fc | 61 | ut_assertok(net_loop(PING)); |
00caae6d | 62 | ut_asserteq_str("eth@10003000", env_get("ethact")); |
e58780dc JH |
63 | |
64 | return 0; | |
65 | } | |
66 | DM_TEST(dm_test_eth_alias, DM_TESTF_SCAN_FDT); | |
6536b9bb | 67 | |
e721b882 | 68 | static int dm_test_eth_prime(struct unit_test_state *uts) |
6536b9bb | 69 | { |
049a95a7 | 70 | net_ping_ip = string_to_ip("1.1.2.2"); |
6536b9bb JH |
71 | |
72 | /* Expected to be "eth@10003000" because of ethprime variable */ | |
382bee57 SG |
73 | env_set("ethact", NULL); |
74 | env_set("ethprime", "eth5"); | |
bc0571fc | 75 | ut_assertok(net_loop(PING)); |
00caae6d | 76 | ut_asserteq_str("eth@10003000", env_get("ethact")); |
6536b9bb JH |
77 | |
78 | /* Expected to be "eth@10002000" because it is first */ | |
382bee57 SG |
79 | env_set("ethact", NULL); |
80 | env_set("ethprime", NULL); | |
bc0571fc | 81 | ut_assertok(net_loop(PING)); |
00caae6d | 82 | ut_asserteq_str("eth@10002000", env_get("ethact")); |
6536b9bb JH |
83 | |
84 | return 0; | |
85 | } | |
86 | DM_TEST(dm_test_eth_prime, DM_TESTF_SCAN_FDT); | |
7d104eab | 87 | |
6d9764c2 BM |
88 | /** |
89 | * This test case is trying to test the following scenario: | |
90 | * - All ethernet devices are not probed | |
91 | * - "ethaddr" for all ethernet devices are not set | |
92 | * - "ethact" is set to a valid ethernet device name | |
93 | * | |
94 | * With Sandbox default test configuration, all ethernet devices are | |
95 | * probed after power-up, so we have to manually create such scenario: | |
96 | * - Remove all ethernet devices | |
97 | * - Remove all "ethaddr" environment variables | |
98 | * - Set "ethact" to the first ethernet device | |
99 | * | |
100 | * Do a ping test to see if anything goes wrong. | |
101 | */ | |
102 | static int dm_test_eth_act(struct unit_test_state *uts) | |
103 | { | |
104 | struct udevice *dev[DM_TEST_ETH_NUM]; | |
105 | const char *ethname[DM_TEST_ETH_NUM] = {"eth@10002000", "eth@10003000", | |
106 | "sbe5", "eth@10004000"}; | |
107 | const char *addrname[DM_TEST_ETH_NUM] = {"ethaddr", "eth5addr", | |
be1a6e94 | 108 | "eth3addr", "eth6addr"}; |
6d9764c2 BM |
109 | char ethaddr[DM_TEST_ETH_NUM][18]; |
110 | int i; | |
111 | ||
e2e6daed | 112 | memset(ethaddr, '\0', sizeof(ethaddr)); |
6d9764c2 BM |
113 | net_ping_ip = string_to_ip("1.1.2.2"); |
114 | ||
115 | /* Prepare the test scenario */ | |
116 | for (i = 0; i < DM_TEST_ETH_NUM; i++) { | |
117 | ut_assertok(uclass_find_device_by_name(UCLASS_ETH, | |
118 | ethname[i], &dev[i])); | |
706865af | 119 | ut_assertok(device_remove(dev[i], DM_REMOVE_NORMAL)); |
6d9764c2 BM |
120 | |
121 | /* Invalidate MAC address */ | |
e2e6daed | 122 | strncpy(ethaddr[i], env_get(addrname[i]), 17); |
6d9764c2 | 123 | /* Must disable access protection for ethaddr before clearing */ |
382bee57 SG |
124 | env_set(".flags", addrname[i]); |
125 | env_set(addrname[i], NULL); | |
6d9764c2 BM |
126 | } |
127 | ||
128 | /* Set ethact to "eth@10002000" */ | |
382bee57 | 129 | env_set("ethact", ethname[0]); |
6d9764c2 BM |
130 | |
131 | /* Segment fault might happen if something is wrong */ | |
132 | ut_asserteq(-ENODEV, net_loop(PING)); | |
133 | ||
134 | for (i = 0; i < DM_TEST_ETH_NUM; i++) { | |
135 | /* Restore the env */ | |
382bee57 SG |
136 | env_set(".flags", addrname[i]); |
137 | env_set(addrname[i], ethaddr[i]); | |
6d9764c2 BM |
138 | |
139 | /* Probe the device again */ | |
140 | ut_assertok(device_probe(dev[i])); | |
141 | } | |
382bee57 SG |
142 | env_set(".flags", NULL); |
143 | env_set("ethact", NULL); | |
6d9764c2 BM |
144 | |
145 | return 0; | |
146 | } | |
147 | DM_TEST(dm_test_eth_act, DM_TESTF_SCAN_FDT); | |
148 | ||
09129bec JH |
149 | /* The asserts include a return on fail; cleanup in the caller */ |
150 | static int _dm_test_eth_rotate1(struct unit_test_state *uts) | |
7d104eab | 151 | { |
7d104eab | 152 | /* Make sure that the default is to rotate to the next interface */ |
382bee57 | 153 | env_set("ethact", "eth@10004000"); |
bc0571fc | 154 | ut_assertok(net_loop(PING)); |
00caae6d | 155 | ut_asserteq_str("eth@10002000", env_get("ethact")); |
7d104eab JH |
156 | |
157 | /* If ethrotate is no, then we should fail on a bad MAC */ | |
382bee57 SG |
158 | env_set("ethact", "eth@10004000"); |
159 | env_set("ethrotate", "no"); | |
bc0571fc | 160 | ut_asserteq(-EINVAL, net_loop(PING)); |
00caae6d | 161 | ut_asserteq_str("eth@10004000", env_get("ethact")); |
7d104eab | 162 | |
09129bec JH |
163 | return 0; |
164 | } | |
7d104eab | 165 | |
09129bec JH |
166 | static int _dm_test_eth_rotate2(struct unit_test_state *uts) |
167 | { | |
7d104eab | 168 | /* Make sure we can skip invalid devices */ |
382bee57 | 169 | env_set("ethact", "eth@10004000"); |
bc0571fc | 170 | ut_assertok(net_loop(PING)); |
00caae6d | 171 | ut_asserteq_str("eth@10004000", env_get("ethact")); |
7d104eab | 172 | |
71d7971f | 173 | /* Make sure we can handle device name which is not eth# */ |
382bee57 | 174 | env_set("ethact", "sbe5"); |
71d7971f | 175 | ut_assertok(net_loop(PING)); |
00caae6d | 176 | ut_asserteq_str("sbe5", env_get("ethact")); |
71d7971f | 177 | |
09129bec JH |
178 | return 0; |
179 | } | |
180 | ||
181 | static int dm_test_eth_rotate(struct unit_test_state *uts) | |
182 | { | |
183 | char ethaddr[18]; | |
184 | int retval; | |
185 | ||
186 | /* Set target IP to mock ping */ | |
187 | net_ping_ip = string_to_ip("1.1.2.2"); | |
188 | ||
189 | /* Invalidate eth1's MAC address */ | |
e2e6daed | 190 | memset(ethaddr, '\0', sizeof(ethaddr)); |
be1a6e94 MW |
191 | strncpy(ethaddr, env_get("eth6addr"), 17); |
192 | /* Must disable access protection for eth6addr before clearing */ | |
193 | env_set(".flags", "eth6addr"); | |
194 | env_set("eth6addr", NULL); | |
09129bec JH |
195 | |
196 | retval = _dm_test_eth_rotate1(uts); | |
197 | ||
198 | /* Restore the env */ | |
be1a6e94 | 199 | env_set("eth6addr", ethaddr); |
382bee57 | 200 | env_set("ethrotate", NULL); |
09129bec JH |
201 | |
202 | if (!retval) { | |
203 | /* Invalidate eth0's MAC address */ | |
e2e6daed | 204 | strncpy(ethaddr, env_get("ethaddr"), 17); |
09129bec | 205 | /* Must disable access protection for ethaddr before clearing */ |
382bee57 SG |
206 | env_set(".flags", "ethaddr"); |
207 | env_set("ethaddr", NULL); | |
09129bec JH |
208 | |
209 | retval = _dm_test_eth_rotate2(uts); | |
210 | ||
211 | /* Restore the env */ | |
382bee57 | 212 | env_set("ethaddr", ethaddr); |
09129bec | 213 | } |
7d104eab | 214 | /* Restore the env */ |
382bee57 | 215 | env_set(".flags", NULL); |
7d104eab | 216 | |
09129bec | 217 | return retval; |
7d104eab JH |
218 | } |
219 | DM_TEST(dm_test_eth_rotate, DM_TESTF_SCAN_FDT); | |
7ece1c61 | 220 | |
09129bec JH |
221 | /* The asserts include a return on fail; cleanup in the caller */ |
222 | static int _dm_test_net_retry(struct unit_test_state *uts) | |
7ece1c61 | 223 | { |
7ece1c61 JH |
224 | /* |
225 | * eth1 is disabled and netretry is yes, so the ping should succeed and | |
226 | * the active device should be eth0 | |
227 | */ | |
228 | sandbox_eth_disable_response(1, true); | |
382bee57 SG |
229 | env_set("ethact", "eth@10004000"); |
230 | env_set("netretry", "yes"); | |
172a31bf | 231 | sandbox_eth_skip_timeout(); |
bc0571fc | 232 | ut_assertok(net_loop(PING)); |
00caae6d | 233 | ut_asserteq_str("eth@10002000", env_get("ethact")); |
7ece1c61 JH |
234 | |
235 | /* | |
236 | * eth1 is disabled and netretry is no, so the ping should fail and the | |
237 | * active device should be eth1 | |
238 | */ | |
382bee57 SG |
239 | env_set("ethact", "eth@10004000"); |
240 | env_set("netretry", "no"); | |
172a31bf | 241 | sandbox_eth_skip_timeout(); |
a735e6e9 | 242 | ut_asserteq(-ENONET, net_loop(PING)); |
00caae6d | 243 | ut_asserteq_str("eth@10004000", env_get("ethact")); |
7ece1c61 | 244 | |
09129bec JH |
245 | return 0; |
246 | } | |
247 | ||
248 | static int dm_test_net_retry(struct unit_test_state *uts) | |
249 | { | |
250 | int retval; | |
251 | ||
252 | net_ping_ip = string_to_ip("1.1.2.2"); | |
253 | ||
254 | retval = _dm_test_net_retry(uts); | |
255 | ||
7ece1c61 | 256 | /* Restore the env */ |
382bee57 | 257 | env_set("netretry", NULL); |
7ece1c61 JH |
258 | sandbox_eth_disable_response(1, false); |
259 | ||
09129bec | 260 | return retval; |
7ece1c61 JH |
261 | } |
262 | DM_TEST(dm_test_net_retry, DM_TESTF_SCAN_FDT); | |
45988dae JH |
263 | |
264 | static int sb_check_arp_reply(struct udevice *dev, void *packet, | |
265 | unsigned int len) | |
266 | { | |
267 | struct eth_sandbox_priv *priv = dev_get_priv(dev); | |
268 | struct ethernet_hdr *eth = packet; | |
269 | struct arp_hdr *arp; | |
270 | /* Used by all of the ut_assert macros */ | |
271 | struct unit_test_state *uts = priv->priv; | |
272 | ||
273 | if (ntohs(eth->et_protlen) != PROT_ARP) | |
274 | return 0; | |
275 | ||
276 | arp = packet + ETHER_HDR_SIZE; | |
277 | ||
278 | if (ntohs(arp->ar_op) != ARPOP_REPLY) | |
279 | return 0; | |
280 | ||
281 | /* This test would be worthless if we are not waiting */ | |
282 | ut_assert(arp_is_waiting()); | |
283 | ||
284 | /* Validate response */ | |
f91f366b SG |
285 | ut_asserteq_mem(eth->et_src, net_ethaddr, ARP_HLEN); |
286 | ut_asserteq_mem(eth->et_dest, priv->fake_host_hwaddr, ARP_HLEN); | |
45988dae JH |
287 | ut_assert(eth->et_protlen == htons(PROT_ARP)); |
288 | ||
289 | ut_assert(arp->ar_hrd == htons(ARP_ETHER)); | |
290 | ut_assert(arp->ar_pro == htons(PROT_IP)); | |
291 | ut_assert(arp->ar_hln == ARP_HLEN); | |
292 | ut_assert(arp->ar_pln == ARP_PLEN); | |
f91f366b | 293 | ut_asserteq_mem(&arp->ar_sha, net_ethaddr, ARP_HLEN); |
45988dae | 294 | ut_assert(net_read_ip(&arp->ar_spa).s_addr == net_ip.s_addr); |
f91f366b | 295 | ut_asserteq_mem(&arp->ar_tha, priv->fake_host_hwaddr, ARP_HLEN); |
45988dae JH |
296 | ut_assert(net_read_ip(&arp->ar_tpa).s_addr == |
297 | string_to_ip("1.1.2.4").s_addr); | |
298 | ||
299 | return 0; | |
300 | } | |
301 | ||
302 | static int sb_with_async_arp_handler(struct udevice *dev, void *packet, | |
303 | unsigned int len) | |
304 | { | |
305 | struct eth_sandbox_priv *priv = dev_get_priv(dev); | |
306 | struct ethernet_hdr *eth = packet; | |
307 | struct arp_hdr *arp = packet + ETHER_HDR_SIZE; | |
308 | int ret; | |
309 | ||
310 | /* | |
311 | * If we are about to generate a reply to ARP, first inject a request | |
312 | * from another host | |
313 | */ | |
314 | if (ntohs(eth->et_protlen) == PROT_ARP && | |
315 | ntohs(arp->ar_op) == ARPOP_REQUEST) { | |
316 | /* Make sure sandbox_eth_recv_arp_req() knows who is asking */ | |
317 | priv->fake_host_ipaddr = string_to_ip("1.1.2.4"); | |
318 | ||
319 | ret = sandbox_eth_recv_arp_req(dev); | |
320 | if (ret) | |
321 | return ret; | |
322 | } | |
323 | ||
324 | sandbox_eth_arp_req_to_reply(dev, packet, len); | |
325 | sandbox_eth_ping_req_to_reply(dev, packet, len); | |
326 | ||
327 | return sb_check_arp_reply(dev, packet, len); | |
328 | } | |
329 | ||
330 | static int dm_test_eth_async_arp_reply(struct unit_test_state *uts) | |
331 | { | |
332 | net_ping_ip = string_to_ip("1.1.2.2"); | |
333 | ||
334 | sandbox_eth_set_tx_handler(0, sb_with_async_arp_handler); | |
335 | /* Used by all of the ut_assert macros in the tx_handler */ | |
336 | sandbox_eth_set_priv(0, uts); | |
45988dae JH |
337 | |
338 | env_set("ethact", "eth@10002000"); | |
ac3f26cc | 339 | ut_assertok(net_loop(PING)); |
45988dae JH |
340 | ut_asserteq_str("eth@10002000", env_get("ethact")); |
341 | ||
342 | sandbox_eth_set_tx_handler(0, NULL); | |
343 | ||
344 | return 0; | |
345 | } | |
346 | ||
347 | DM_TEST(dm_test_eth_async_arp_reply, DM_TESTF_SCAN_FDT); | |
72ff0042 JH |
348 | |
349 | static int sb_check_ping_reply(struct udevice *dev, void *packet, | |
350 | unsigned int len) | |
351 | { | |
352 | struct eth_sandbox_priv *priv = dev_get_priv(dev); | |
353 | struct ethernet_hdr *eth = packet; | |
354 | struct ip_udp_hdr *ip; | |
355 | struct icmp_hdr *icmp; | |
356 | /* Used by all of the ut_assert macros */ | |
357 | struct unit_test_state *uts = priv->priv; | |
358 | ||
359 | if (ntohs(eth->et_protlen) != PROT_IP) | |
360 | return 0; | |
361 | ||
362 | ip = packet + ETHER_HDR_SIZE; | |
363 | ||
364 | if (ip->ip_p != IPPROTO_ICMP) | |
365 | return 0; | |
366 | ||
367 | icmp = (struct icmp_hdr *)&ip->udp_src; | |
368 | ||
369 | if (icmp->type != ICMP_ECHO_REPLY) | |
370 | return 0; | |
371 | ||
372 | /* This test would be worthless if we are not waiting */ | |
373 | ut_assert(arp_is_waiting()); | |
374 | ||
375 | /* Validate response */ | |
f91f366b SG |
376 | ut_asserteq_mem(eth->et_src, net_ethaddr, ARP_HLEN); |
377 | ut_asserteq_mem(eth->et_dest, priv->fake_host_hwaddr, ARP_HLEN); | |
72ff0042 JH |
378 | ut_assert(eth->et_protlen == htons(PROT_IP)); |
379 | ||
380 | ut_assert(net_read_ip(&ip->ip_src).s_addr == net_ip.s_addr); | |
381 | ut_assert(net_read_ip(&ip->ip_dst).s_addr == | |
382 | string_to_ip("1.1.2.4").s_addr); | |
383 | ||
384 | return 0; | |
385 | } | |
386 | ||
387 | static int sb_with_async_ping_handler(struct udevice *dev, void *packet, | |
388 | unsigned int len) | |
389 | { | |
390 | struct eth_sandbox_priv *priv = dev_get_priv(dev); | |
391 | struct ethernet_hdr *eth = packet; | |
392 | struct arp_hdr *arp = packet + ETHER_HDR_SIZE; | |
393 | int ret; | |
394 | ||
395 | /* | |
396 | * If we are about to generate a reply to ARP, first inject a request | |
397 | * from another host | |
398 | */ | |
399 | if (ntohs(eth->et_protlen) == PROT_ARP && | |
400 | ntohs(arp->ar_op) == ARPOP_REQUEST) { | |
401 | /* Make sure sandbox_eth_recv_arp_req() knows who is asking */ | |
402 | priv->fake_host_ipaddr = string_to_ip("1.1.2.4"); | |
403 | ||
404 | ret = sandbox_eth_recv_ping_req(dev); | |
405 | if (ret) | |
406 | return ret; | |
407 | } | |
408 | ||
409 | sandbox_eth_arp_req_to_reply(dev, packet, len); | |
410 | sandbox_eth_ping_req_to_reply(dev, packet, len); | |
411 | ||
412 | return sb_check_ping_reply(dev, packet, len); | |
413 | } | |
414 | ||
415 | static int dm_test_eth_async_ping_reply(struct unit_test_state *uts) | |
416 | { | |
417 | net_ping_ip = string_to_ip("1.1.2.2"); | |
418 | ||
419 | sandbox_eth_set_tx_handler(0, sb_with_async_ping_handler); | |
420 | /* Used by all of the ut_assert macros in the tx_handler */ | |
421 | sandbox_eth_set_priv(0, uts); | |
72ff0042 JH |
422 | |
423 | env_set("ethact", "eth@10002000"); | |
ac3f26cc | 424 | ut_assertok(net_loop(PING)); |
72ff0042 JH |
425 | ut_asserteq_str("eth@10002000", env_get("ethact")); |
426 | ||
427 | sandbox_eth_set_tx_handler(0, NULL); | |
428 | ||
429 | return 0; | |
430 | } | |
431 | ||
432 | DM_TEST(dm_test_eth_async_ping_reply, DM_TESTF_SCAN_FDT); |