uboot/cmd/net.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2000
   4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   5 */
   6
   7/*
   8 * Boot support
   9 */
  10#include <common.h>
  11#include <command.h>
  12#include <env.h>
  13#include <net.h>
  14
  15static int netboot_common(enum proto_t, cmd_tbl_t *, int, char * const []);
  16
  17#ifdef CONFIG_CMD_BOOTP
  18static int do_bootp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  19{
  20        return netboot_common(BOOTP, cmdtp, argc, argv);
  21}
  22
  23U_BOOT_CMD(
  24        bootp,  3,      1,      do_bootp,
  25        "boot image via network using BOOTP/TFTP protocol",
  26        "[loadAddress] [[hostIPaddr:]bootfilename]"
  27);
  28#endif
  29
  30#ifdef CONFIG_CMD_TFTPBOOT
  31int do_tftpb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  32{
  33        int ret;
  34
  35        bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start");
  36        ret = netboot_common(TFTPGET, cmdtp, argc, argv);
  37        bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done");
  38        return ret;
  39}
  40
  41U_BOOT_CMD(
  42        tftpboot,       3,      1,      do_tftpb,
  43        "boot image via network using TFTP protocol",
  44        "[loadAddress] [[hostIPaddr:]bootfilename]"
  45);
  46#endif
  47
  48#ifdef CONFIG_CMD_TFTPPUT
  49static int do_tftpput(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  50{
  51        return netboot_common(TFTPPUT, cmdtp, argc, argv);
  52}
  53
  54U_BOOT_CMD(
  55        tftpput,        4,      1,      do_tftpput,
  56        "TFTP put command, for uploading files to a server",
  57        "Address Size [[hostIPaddr:]filename]"
  58);
  59#endif
  60
  61#ifdef CONFIG_CMD_TFTPSRV
  62static int do_tftpsrv(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
  63{
  64        return netboot_common(TFTPSRV, cmdtp, argc, argv);
  65}
  66
  67U_BOOT_CMD(
  68        tftpsrv,        2,      1,      do_tftpsrv,
  69        "act as a TFTP server and boot the first received file",
  70        "[loadAddress]\n"
  71        "Listen for an incoming TFTP transfer, receive a file and boot it.\n"
  72        "The transfer is aborted if a transfer has not been started after\n"
  73        "about 50 seconds or if Ctrl-C is pressed."
  74);
  75#endif
  76
  77
  78#ifdef CONFIG_CMD_RARP
  79int do_rarpb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  80{
  81        return netboot_common(RARP, cmdtp, argc, argv);
  82}
  83
  84U_BOOT_CMD(
  85        rarpboot,       3,      1,      do_rarpb,
  86        "boot image via network using RARP/TFTP protocol",
  87        "[loadAddress] [[hostIPaddr:]bootfilename]"
  88);
  89#endif
  90
  91#if defined(CONFIG_CMD_DHCP)
  92static int do_dhcp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  93{
  94        return netboot_common(DHCP, cmdtp, argc, argv);
  95}
  96
  97U_BOOT_CMD(
  98        dhcp,   3,      1,      do_dhcp,
  99        "boot image via network using DHCP/TFTP protocol",
 100        "[loadAddress] [[hostIPaddr:]bootfilename]"
 101);
 102#endif
 103
 104#if defined(CONFIG_CMD_NFS)
 105static int do_nfs(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 106{
 107        return netboot_common(NFS, cmdtp, argc, argv);
 108}
 109
 110U_BOOT_CMD(
 111        nfs,    3,      1,      do_nfs,
 112        "boot image via network using NFS protocol",
 113        "[loadAddress] [[hostIPaddr:]bootfilename]"
 114);
 115#endif
 116
 117static void netboot_update_env(void)
 118{
 119        char tmp[22];
 120
 121        if (net_gateway.s_addr) {
 122                ip_to_string(net_gateway, tmp);
 123                env_set("gatewayip", tmp);
 124        }
 125
 126        if (net_netmask.s_addr) {
 127                ip_to_string(net_netmask, tmp);
 128                env_set("netmask", tmp);
 129        }
 130
 131        if (net_hostname[0])
 132                env_set("hostname", net_hostname);
 133
 134        if (net_root_path[0])
 135                env_set("rootpath", net_root_path);
 136
 137        if (net_ip.s_addr) {
 138                ip_to_string(net_ip, tmp);
 139                env_set("ipaddr", tmp);
 140        }
 141#if !defined(CONFIG_BOOTP_SERVERIP)
 142        /*
 143         * Only attempt to change serverip if net/bootp.c:store_net_params()
 144         * could have set it
 145         */
 146        if (net_server_ip.s_addr) {
 147                ip_to_string(net_server_ip, tmp);
 148                env_set("serverip", tmp);
 149        }
 150#endif
 151        if (net_dns_server.s_addr) {
 152                ip_to_string(net_dns_server, tmp);
 153                env_set("dnsip", tmp);
 154        }
 155#if defined(CONFIG_BOOTP_DNS2)
 156        if (net_dns_server2.s_addr) {
 157                ip_to_string(net_dns_server2, tmp);
 158                env_set("dnsip2", tmp);
 159        }
 160#endif
 161        if (net_nis_domain[0])
 162                env_set("domain", net_nis_domain);
 163
 164#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
 165        if (net_ntp_time_offset) {
 166                sprintf(tmp, "%d", net_ntp_time_offset);
 167                env_set("timeoffset", tmp);
 168        }
 169#endif
 170#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
 171        if (net_ntp_server.s_addr) {
 172                ip_to_string(net_ntp_server, tmp);
 173                env_set("ntpserverip", tmp);
 174        }
 175#endif
 176}
 177
 178static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc,
 179                char * const argv[])
 180{
 181        char *s;
 182        char *end;
 183        int   rcode = 0;
 184        int   size;
 185        ulong addr;
 186
 187        net_boot_file_name_explicit = false;
 188
 189        /* pre-set load_addr */
 190        s = env_get("loadaddr");
 191        if (s != NULL)
 192                load_addr = simple_strtoul(s, NULL, 16);
 193
 194        switch (argc) {
 195        case 1:
 196                /* refresh bootfile name from env */
 197                copy_filename(net_boot_file_name, env_get("bootfile"),
 198                              sizeof(net_boot_file_name));
 199                break;
 200
 201        case 2: /*
 202                 * Only one arg - accept two forms:
 203                 * Just load address, or just boot file name. The latter
 204                 * form must be written in a format which can not be
 205                 * mis-interpreted as a valid number.
 206                 */
 207                addr = simple_strtoul(argv[1], &end, 16);
 208                if (end == (argv[1] + strlen(argv[1]))) {
 209                        load_addr = addr;
 210                        /* refresh bootfile name from env */
 211                        copy_filename(net_boot_file_name, env_get("bootfile"),
 212                                      sizeof(net_boot_file_name));
 213                } else {
 214                        net_boot_file_name_explicit = true;
 215                        copy_filename(net_boot_file_name, argv[1],
 216                                      sizeof(net_boot_file_name));
 217                }
 218                break;
 219
 220        case 3:
 221                load_addr = simple_strtoul(argv[1], NULL, 16);
 222                net_boot_file_name_explicit = true;
 223                copy_filename(net_boot_file_name, argv[2],
 224                              sizeof(net_boot_file_name));
 225
 226                break;
 227
 228#ifdef CONFIG_CMD_TFTPPUT
 229        case 4:
 230                if (strict_strtoul(argv[1], 16, &save_addr) < 0 ||
 231                    strict_strtoul(argv[2], 16, &save_size) < 0) {
 232                        printf("Invalid address/size\n");
 233                        return CMD_RET_USAGE;
 234                }
 235                net_boot_file_name_explicit = true;
 236                copy_filename(net_boot_file_name, argv[3],
 237                              sizeof(net_boot_file_name));
 238                break;
 239#endif
 240        default:
 241                bootstage_error(BOOTSTAGE_ID_NET_START);
 242                return CMD_RET_USAGE;
 243        }
 244        bootstage_mark(BOOTSTAGE_ID_NET_START);
 245
 246        size = net_loop(proto);
 247        if (size < 0) {
 248                bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK);
 249                return CMD_RET_FAILURE;
 250        }
 251        bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK);
 252
 253        /* net_loop ok, update environment */
 254        netboot_update_env();
 255
 256        /* done if no file was loaded (no errors though) */
 257        if (size == 0) {
 258                bootstage_error(BOOTSTAGE_ID_NET_LOADED);
 259                return CMD_RET_SUCCESS;
 260        }
 261
 262        bootstage_mark(BOOTSTAGE_ID_NET_LOADED);
 263
 264        rcode = bootm_maybe_autostart(cmdtp, argv[0]);
 265
 266        if (rcode == CMD_RET_SUCCESS)
 267                bootstage_mark(BOOTSTAGE_ID_NET_DONE);
 268        else
 269                bootstage_error(BOOTSTAGE_ID_NET_DONE_ERR);
 270        return rcode;
 271}
 272
 273#if defined(CONFIG_CMD_PING)
 274static int do_ping(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 275{
 276        if (argc < 2)
 277                return CMD_RET_USAGE;
 278
 279        net_ping_ip = string_to_ip(argv[1]);
 280        if (net_ping_ip.s_addr == 0)
 281                return CMD_RET_USAGE;
 282
 283        if (net_loop(PING) < 0) {
 284                printf("ping failed; host %s is not alive\n", argv[1]);
 285                return CMD_RET_FAILURE;
 286        }
 287
 288        printf("host %s is alive\n", argv[1]);
 289
 290        return CMD_RET_SUCCESS;
 291}
 292
 293U_BOOT_CMD(
 294        ping,   2,      1,      do_ping,
 295        "send ICMP ECHO_REQUEST to network host",
 296        "pingAddress"
 297);
 298#endif
 299
 300#if defined(CONFIG_CMD_CDP)
 301
 302static void cdp_update_env(void)
 303{
 304        char tmp[16];
 305
 306        if (cdp_appliance_vlan != htons(-1)) {
 307                printf("CDP offered appliance VLAN %d\n",
 308                       ntohs(cdp_appliance_vlan));
 309                vlan_to_string(cdp_appliance_vlan, tmp);
 310                env_set("vlan", tmp);
 311                net_our_vlan = cdp_appliance_vlan;
 312        }
 313
 314        if (cdp_native_vlan != htons(-1)) {
 315                printf("CDP offered native VLAN %d\n", ntohs(cdp_native_vlan));
 316                vlan_to_string(cdp_native_vlan, tmp);
 317                env_set("nvlan", tmp);
 318                net_native_vlan = cdp_native_vlan;
 319        }
 320}
 321
 322int do_cdp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 323{
 324        int r;
 325
 326        r = net_loop(CDP);
 327        if (r < 0) {
 328                printf("cdp failed; perhaps not a CISCO switch?\n");
 329                return CMD_RET_FAILURE;
 330        }
 331
 332        cdp_update_env();
 333
 334        return CMD_RET_SUCCESS;
 335}
 336
 337U_BOOT_CMD(
 338        cdp,    1,      1,      do_cdp,
 339        "Perform CDP network configuration",
 340        "\n"
 341);
 342#endif
 343
 344#if defined(CONFIG_CMD_SNTP)
 345int do_sntp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 346{
 347        char *toff;
 348
 349        if (argc < 2) {
 350                net_ntp_server = env_get_ip("ntpserverip");
 351                if (net_ntp_server.s_addr == 0) {
 352                        printf("ntpserverip not set\n");
 353                        return CMD_RET_FAILURE;
 354                }
 355        } else {
 356                net_ntp_server = string_to_ip(argv[1]);
 357                if (net_ntp_server.s_addr == 0) {
 358                        printf("Bad NTP server IP address\n");
 359                        return CMD_RET_FAILURE;
 360                }
 361        }
 362
 363        toff = env_get("timeoffset");
 364        if (toff == NULL)
 365                net_ntp_time_offset = 0;
 366        else
 367                net_ntp_time_offset = simple_strtol(toff, NULL, 10);
 368
 369        if (net_loop(SNTP) < 0) {
 370                printf("SNTP failed: host %pI4 not responding\n",
 371                       &net_ntp_server);
 372                return CMD_RET_FAILURE;
 373        }
 374
 375        return CMD_RET_SUCCESS;
 376}
 377
 378U_BOOT_CMD(
 379        sntp,   2,      1,      do_sntp,
 380        "synchronize RTC via network",
 381        "[NTP server IP]\n"
 382);
 383#endif
 384
 385#if defined(CONFIG_CMD_DNS)
 386int do_dns(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 387{
 388        if (argc == 1)
 389                return CMD_RET_USAGE;
 390
 391        /*
 392         * We should check for a valid hostname:
 393         * - Each label must be between 1 and 63 characters long
 394         * - the entire hostname has a maximum of 255 characters
 395         * - only the ASCII letters 'a' through 'z' (case-insensitive),
 396         *   the digits '0' through '9', and the hyphen
 397         * - cannot begin or end with a hyphen
 398         * - no other symbols, punctuation characters, or blank spaces are
 399         *   permitted
 400         * but hey - this is a minimalist implmentation, so only check length
 401         * and let the name server deal with things.
 402         */
 403        if (strlen(argv[1]) >= 255) {
 404                printf("dns error: hostname too long\n");
 405                return CMD_RET_FAILURE;
 406        }
 407
 408        net_dns_resolve = argv[1];
 409
 410        if (argc == 3)
 411                net_dns_env_var = argv[2];
 412        else
 413                net_dns_env_var = NULL;
 414
 415        if (net_loop(DNS) < 0) {
 416                printf("dns lookup of %s failed, check setup\n", argv[1]);
 417                return CMD_RET_FAILURE;
 418        }
 419
 420        return CMD_RET_SUCCESS;
 421}
 422
 423U_BOOT_CMD(
 424        dns,    3,      1,      do_dns,
 425        "lookup the IP of a hostname",
 426        "hostname [envvar]"
 427);
 428
 429#endif  /* CONFIG_CMD_DNS */
 430
 431#if defined(CONFIG_CMD_LINK_LOCAL)
 432static int do_link_local(cmd_tbl_t *cmdtp, int flag, int argc,
 433                        char * const argv[])
 434{
 435        char tmp[22];
 436
 437        if (net_loop(LINKLOCAL) < 0)
 438                return CMD_RET_FAILURE;
 439
 440        net_gateway.s_addr = 0;
 441        ip_to_string(net_gateway, tmp);
 442        env_set("gatewayip", tmp);
 443
 444        ip_to_string(net_netmask, tmp);
 445        env_set("netmask", tmp);
 446
 447        ip_to_string(net_ip, tmp);
 448        env_set("ipaddr", tmp);
 449        env_set("llipaddr", tmp); /* store this for next time */
 450
 451        return CMD_RET_SUCCESS;
 452}
 453
 454U_BOOT_CMD(
 455        linklocal,      1,      1,      do_link_local,
 456        "acquire a network IP address using the link-local protocol",
 457        ""
 458);
 459
 460#endif  /* CONFIG_CMD_LINK_LOCAL */
 461