1 // SPDX-License-Identifier: GPL-2.0+
4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
11 #include <bootstage.h>
22 static int netboot_common(enum proto_t, struct cmd_tbl *, int, char * const []);
24 #ifdef CONFIG_CMD_BOOTP
25 static int do_bootp(struct cmd_tbl *cmdtp, int flag, int argc,
28 return netboot_common(BOOTP, cmdtp, argc, argv);
32 bootp, 3, 1, do_bootp,
33 "boot image via network using BOOTP/TFTP protocol",
34 "[loadAddress] [[hostIPaddr:]bootfilename]"
38 #ifdef CONFIG_CMD_TFTPBOOT
39 int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
43 bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start");
44 ret = netboot_common(TFTPGET, cmdtp, argc, argv);
45 bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done");
49 #if IS_ENABLED(CONFIG_IPV6)
51 tftpboot, 4, 1, do_tftpb,
52 "boot image via network using TFTP protocol\n"
53 "To use IPv6 add -ipv6 parameter or use IPv6 hostIPaddr framed "
55 "[loadAddress] [[hostIPaddr:]bootfilename] [" USE_IP6_CMD_PARAM "]"
59 tftpboot, 3, 1, do_tftpb,
60 "load file via network using TFTP protocol",
61 "[loadAddress] [[hostIPaddr:]bootfilename]"
66 #ifdef CONFIG_CMD_TFTPPUT
67 static int do_tftpput(struct cmd_tbl *cmdtp, int flag, int argc,
70 return netboot_common(TFTPPUT, cmdtp, argc, argv);
74 tftpput, 4, 1, do_tftpput,
75 "TFTP put command, for uploading files to a server",
76 "Address Size [[hostIPaddr:]filename]"
80 #ifdef CONFIG_CMD_TFTPSRV
81 static int do_tftpsrv(struct cmd_tbl *cmdtp, int flag, int argc,
84 return netboot_common(TFTPSRV, cmdtp, argc, argv);
88 tftpsrv, 2, 1, do_tftpsrv,
89 "act as a TFTP server and boot the first received file",
91 "Listen for an incoming TFTP transfer, receive a file and boot it.\n"
92 "The transfer is aborted if a transfer has not been started after\n"
93 "about 50 seconds or if Ctrl-C is pressed."
98 #ifdef CONFIG_CMD_RARP
99 int do_rarpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
101 return netboot_common(RARP, cmdtp, argc, argv);
105 rarpboot, 3, 1, do_rarpb,
106 "boot image via network using RARP/TFTP protocol",
107 "[loadAddress] [[hostIPaddr:]bootfilename]"
111 #if defined(CONFIG_CMD_DHCP)
112 static int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc,
115 return netboot_common(DHCP, cmdtp, argc, argv);
120 "boot image via network using DHCP/TFTP protocol",
121 "[loadAddress] [[hostIPaddr:]bootfilename]"
125 #if defined(CONFIG_CMD_NFS)
126 static int do_nfs(struct cmd_tbl *cmdtp, int flag, int argc,
129 return netboot_common(NFS, cmdtp, argc, argv);
134 "boot image via network using NFS protocol",
135 "[loadAddress] [[hostIPaddr:]bootfilename]"
139 #if defined(CONFIG_CMD_WGET)
140 static int do_wget(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
142 return netboot_common(WGET, cmdtp, argc, argv);
147 "boot image via network using HTTP protocol",
148 "[loadAddress] [[hostIPaddr:]path and image name]"
152 static void netboot_update_env(void)
156 if (net_gateway.s_addr) {
157 ip_to_string(net_gateway, tmp);
158 env_set("gatewayip", tmp);
161 if (net_netmask.s_addr) {
162 ip_to_string(net_netmask, tmp);
163 env_set("netmask", tmp);
166 #ifdef CONFIG_CMD_BOOTP
168 env_set("hostname", net_hostname);
171 #ifdef CONFIG_CMD_BOOTP
172 if (net_root_path[0])
173 env_set("rootpath", net_root_path);
177 ip_to_string(net_ip, tmp);
178 env_set("ipaddr", tmp);
181 * Only attempt to change serverip if net/bootp.c:store_net_params()
184 if (!IS_ENABLED(CONFIG_BOOTP_SERVERIP) && net_server_ip.s_addr) {
185 ip_to_string(net_server_ip, tmp);
186 env_set("serverip", tmp);
188 if (net_dns_server.s_addr) {
189 ip_to_string(net_dns_server, tmp);
190 env_set("dnsip", tmp);
192 #if defined(CONFIG_BOOTP_DNS2)
193 if (net_dns_server2.s_addr) {
194 ip_to_string(net_dns_server2, tmp);
195 env_set("dnsip2", tmp);
198 #ifdef CONFIG_CMD_BOOTP
199 if (net_nis_domain[0])
200 env_set("domain", net_nis_domain);
203 #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
204 if (net_ntp_time_offset) {
205 sprintf(tmp, "%d", net_ntp_time_offset);
206 env_set("timeoffset", tmp);
209 #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
210 if (net_ntp_server.s_addr) {
211 ip_to_string(net_ntp_server, tmp);
212 env_set("ntpserverip", tmp);
218 * parse_addr_size() - parse address and size arguments for tftpput
220 * @argv: command line arguments
221 * Return: 0 on success
223 static int parse_addr_size(char * const argv[])
225 if (strict_strtoul(argv[1], 16, &image_save_addr) < 0 ||
226 strict_strtoul(argv[2], 16, &image_save_size) < 0) {
227 printf("Invalid address/size\n");
228 return CMD_RET_USAGE;
234 * parse_args() - parse command line arguments
236 * @proto: command prototype
237 * @argc: number of arguments
238 * @argv: command line arguments
239 * Return: 0 on success
241 static int parse_args(enum proto_t proto, int argc, char *const argv[])
248 if (CONFIG_IS_ENABLED(CMD_TFTPPUT) && proto == TFTPPUT)
251 /* refresh bootfile name from env */
252 copy_filename(net_boot_file_name, env_get("bootfile"),
253 sizeof(net_boot_file_name));
257 if (CONFIG_IS_ENABLED(CMD_TFTPPUT) && proto == TFTPPUT)
260 * Only one arg - accept two forms:
261 * Just load address, or just boot file name. The latter
262 * form must be written in a format which can not be
263 * mis-interpreted as a valid number.
265 addr = hextoul(argv[1], &end);
266 if (end == (argv[1] + strlen(argv[1]))) {
267 image_load_addr = addr;
268 /* refresh bootfile name from env */
269 copy_filename(net_boot_file_name, env_get("bootfile"),
270 sizeof(net_boot_file_name));
272 net_boot_file_name_explicit = true;
273 copy_filename(net_boot_file_name, argv[1],
274 sizeof(net_boot_file_name));
279 if (CONFIG_IS_ENABLED(CMD_TFTPPUT) && proto == TFTPPUT) {
280 if (parse_addr_size(argv))
283 image_load_addr = hextoul(argv[1], NULL);
284 net_boot_file_name_explicit = true;
285 copy_filename(net_boot_file_name, argv[2],
286 sizeof(net_boot_file_name));
290 #ifdef CONFIG_CMD_TFTPPUT
292 if (parse_addr_size(argv))
294 net_boot_file_name_explicit = true;
295 copy_filename(net_boot_file_name, argv[3],
296 sizeof(net_boot_file_name));
305 static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc,
312 net_boot_file_name_explicit = false;
313 *net_boot_file_name = '\0';
315 /* pre-set image_load_addr */
316 s = env_get("loadaddr");
318 image_load_addr = hextoul(s, NULL);
320 if (IS_ENABLED(CONFIG_IPV6)) {
323 /* IPv6 parameter has to be always *last* */
324 if (!strcmp(argv[argc - 1], USE_IP6_CMD_PARAM)) {
326 /* It is a hack not to break switch/case code */
331 if (parse_args(proto, argc, argv)) {
332 bootstage_error(BOOTSTAGE_ID_NET_START);
333 return CMD_RET_USAGE;
336 bootstage_mark(BOOTSTAGE_ID_NET_START);
338 if (IS_ENABLED(CONFIG_IPV6) && !use_ip6) {
342 s = strchr(net_boot_file_name, '[');
343 e = strchr(net_boot_file_name, ']');
346 if (!string_to_ip6(s + 1, len - 1, &net_server_ip6))
351 size = net_loop(proto);
353 bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK);
354 return CMD_RET_FAILURE;
356 bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK);
358 /* net_loop ok, update environment */
359 netboot_update_env();
361 /* done if no file was loaded (no errors though) */
363 bootstage_error(BOOTSTAGE_ID_NET_LOADED);
364 return CMD_RET_SUCCESS;
367 bootstage_mark(BOOTSTAGE_ID_NET_LOADED);
369 rcode = bootm_maybe_autostart(cmdtp, argv[0]);
371 if (rcode == CMD_RET_SUCCESS)
372 bootstage_mark(BOOTSTAGE_ID_NET_DONE);
374 bootstage_error(BOOTSTAGE_ID_NET_DONE_ERR);
378 #if defined(CONFIG_CMD_PING)
379 static int do_ping(struct cmd_tbl *cmdtp, int flag, int argc,
383 return CMD_RET_USAGE;
385 net_ping_ip = string_to_ip(argv[1]);
386 if (net_ping_ip.s_addr == 0)
387 return CMD_RET_USAGE;
389 if (net_loop(PING) < 0) {
390 printf("ping failed; host %s is not alive\n", argv[1]);
391 return CMD_RET_FAILURE;
394 printf("host %s is alive\n", argv[1]);
396 return CMD_RET_SUCCESS;
401 "send ICMP ECHO_REQUEST to network host",
406 #if IS_ENABLED(CONFIG_CMD_PING6)
407 int do_ping6(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
409 if (string_to_ip6(argv[1], strlen(argv[1]), &net_ping_ip6))
410 return CMD_RET_USAGE;
413 if (net_loop(PING6) < 0) {
415 printf("ping6 failed; host %pI6c is not alive\n",
421 printf("host %pI6c is alive\n", &net_ping_ip6);
426 ping6, 2, 1, do_ping6,
427 "send ICMPv6 ECHO_REQUEST to network host",
430 #endif /* CONFIG_CMD_PING6 */
432 #if defined(CONFIG_CMD_CDP)
434 static void cdp_update_env(void)
438 if (cdp_appliance_vlan != htons(-1)) {
439 printf("CDP offered appliance VLAN %d\n",
440 ntohs(cdp_appliance_vlan));
441 vlan_to_string(cdp_appliance_vlan, tmp);
442 env_set("vlan", tmp);
443 net_our_vlan = cdp_appliance_vlan;
446 if (cdp_native_vlan != htons(-1)) {
447 printf("CDP offered native VLAN %d\n", ntohs(cdp_native_vlan));
448 vlan_to_string(cdp_native_vlan, tmp);
449 env_set("nvlan", tmp);
450 net_native_vlan = cdp_native_vlan;
454 int do_cdp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
460 printf("cdp failed; perhaps not a CISCO switch?\n");
461 return CMD_RET_FAILURE;
466 return CMD_RET_SUCCESS;
471 "Perform CDP network configuration",
476 #if defined(CONFIG_CMD_SNTP)
477 static struct udp_ops sntp_ops = {
478 .prereq = sntp_prereq,
483 int do_sntp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
488 net_ntp_server = env_get_ip("ntpserverip");
489 if (net_ntp_server.s_addr == 0) {
490 printf("ntpserverip not set\n");
491 return CMD_RET_FAILURE;
494 net_ntp_server = string_to_ip(argv[1]);
495 if (net_ntp_server.s_addr == 0) {
496 printf("Bad NTP server IP address\n");
497 return CMD_RET_FAILURE;
501 toff = env_get("timeoffset");
503 net_ntp_time_offset = 0;
505 net_ntp_time_offset = simple_strtol(toff, NULL, 10);
507 if (udp_loop(&sntp_ops) < 0) {
508 printf("SNTP failed: host %pI4 not responding\n",
510 return CMD_RET_FAILURE;
513 return CMD_RET_SUCCESS;
518 "synchronize RTC via network",
523 #if defined(CONFIG_CMD_DNS)
524 int do_dns(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
527 return CMD_RET_USAGE;
530 * We should check for a valid hostname:
531 * - Each label must be between 1 and 63 characters long
532 * - the entire hostname has a maximum of 255 characters
533 * - only the ASCII letters 'a' through 'z' (case-insensitive),
534 * the digits '0' through '9', and the hyphen
535 * - cannot begin or end with a hyphen
536 * - no other symbols, punctuation characters, or blank spaces are
538 * but hey - this is a minimalist implmentation, so only check length
539 * and let the name server deal with things.
541 if (strlen(argv[1]) >= 255) {
542 printf("dns error: hostname too long\n");
543 return CMD_RET_FAILURE;
546 net_dns_resolve = argv[1];
549 net_dns_env_var = argv[2];
551 net_dns_env_var = NULL;
553 if (net_loop(DNS) < 0) {
554 printf("dns lookup of %s failed, check setup\n", argv[1]);
555 return CMD_RET_FAILURE;
558 return CMD_RET_SUCCESS;
563 "lookup the IP of a hostname",
567 #endif /* CONFIG_CMD_DNS */
569 #if defined(CONFIG_CMD_LINK_LOCAL)
570 static int do_link_local(struct cmd_tbl *cmdtp, int flag, int argc,
575 if (net_loop(LINKLOCAL) < 0)
576 return CMD_RET_FAILURE;
578 net_gateway.s_addr = 0;
579 ip_to_string(net_gateway, tmp);
580 env_set("gatewayip", tmp);
582 ip_to_string(net_netmask, tmp);
583 env_set("netmask", tmp);
585 ip_to_string(net_ip, tmp);
586 env_set("ipaddr", tmp);
587 env_set("llipaddr", tmp); /* store this for next time */
589 return CMD_RET_SUCCESS;
593 linklocal, 1, 1, do_link_local,
594 "acquire a network IP address using the link-local protocol",
598 #endif /* CONFIG_CMD_LINK_LOCAL */
600 static int do_net_list(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
602 const struct udevice *current = eth_get_dev();
603 unsigned char env_enetaddr[ARP_HLEN];
604 const struct udevice *dev;
607 uclass_id_foreach_dev(UCLASS_ETH, dev, uc) {
608 eth_env_get_enetaddr_by_index("eth", dev_seq(dev), env_enetaddr);
609 printf("eth%d : %s %pM %s\n", dev_seq(dev), dev->name, env_enetaddr,
610 current == dev ? "active" : "");
612 return CMD_RET_SUCCESS;
615 static struct cmd_tbl cmd_net[] = {
616 U_BOOT_CMD_MKENT(list, 1, 0, do_net_list, "", ""),
619 static int do_net(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
623 cp = find_cmd_tbl(argv[1], cmd_net, ARRAY_SIZE(cmd_net));
625 /* Drop the net command */
629 if (!cp || argc > cp->maxargs)
630 return CMD_RET_USAGE;
631 if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
632 return CMD_RET_SUCCESS;
634 return cp->cmd(cmdtp, flag, argc, argv);
640 "list - list available devices\n"
643 #if defined(CONFIG_CMD_NCSI)
644 static int do_ncsi(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[])
646 if (!phy_interface_is_ncsi() || !ncsi_active()) {
647 printf("Device not configured for NC-SI\n");
648 return CMD_RET_FAILURE;
651 if (net_loop(NCSI) < 0)
652 return CMD_RET_FAILURE;
654 return CMD_RET_SUCCESS;
659 "Configure attached NIC via NC-SI",
662 #endif /* CONFIG_CMD_NCSI */