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