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