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