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 15 static int netboot_common(enum proto_t, cmd_tbl_t *, int, char * const []); 16 17 #ifdef CONFIG_CMD_BOOTP 18 static 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 23 U_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 31 int 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 41 U_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 49 static 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 54 U_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 62 static 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 67 U_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 79 int do_rarpb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 80 { 81 return netboot_common(RARP, cmdtp, argc, argv); 82 } 83 84 U_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) 92 static 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 97 U_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) 105 static 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 110 U_BOOT_CMD( 111 nfs, 3, 1, do_nfs, 112 "boot image via network using NFS protocol", 113 "[loadAddress] [[hostIPaddr:]bootfilename]" 114 ); 115 #endif 116 117 static 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 178 static 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 /* pre-set load_addr */ 188 s = env_get("loadaddr"); 189 if (s != NULL) 190 load_addr = simple_strtoul(s, NULL, 16); 191 192 switch (argc) { 193 case 1: 194 break; 195 196 case 2: /* 197 * Only one arg - accept two forms: 198 * Just load address, or just boot file name. The latter 199 * form must be written in a format which can not be 200 * mis-interpreted as a valid number. 201 */ 202 addr = simple_strtoul(argv[1], &end, 16); 203 if (end == (argv[1] + strlen(argv[1]))) 204 load_addr = addr; 205 else 206 copy_filename(net_boot_file_name, argv[1], 207 sizeof(net_boot_file_name)); 208 break; 209 210 case 3: 211 load_addr = simple_strtoul(argv[1], NULL, 16); 212 copy_filename(net_boot_file_name, argv[2], 213 sizeof(net_boot_file_name)); 214 215 break; 216 217 #ifdef CONFIG_CMD_TFTPPUT 218 case 4: 219 if (strict_strtoul(argv[1], 16, &save_addr) < 0 || 220 strict_strtoul(argv[2], 16, &save_size) < 0) { 221 printf("Invalid address/size\n"); 222 return CMD_RET_USAGE; 223 } 224 copy_filename(net_boot_file_name, argv[3], 225 sizeof(net_boot_file_name)); 226 break; 227 #endif 228 default: 229 bootstage_error(BOOTSTAGE_ID_NET_START); 230 return CMD_RET_USAGE; 231 } 232 bootstage_mark(BOOTSTAGE_ID_NET_START); 233 234 size = net_loop(proto); 235 if (size < 0) { 236 bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK); 237 return CMD_RET_FAILURE; 238 } 239 bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK); 240 241 /* net_loop ok, update environment */ 242 netboot_update_env(); 243 244 /* done if no file was loaded (no errors though) */ 245 if (size == 0) { 246 bootstage_error(BOOTSTAGE_ID_NET_LOADED); 247 return CMD_RET_SUCCESS; 248 } 249 250 bootstage_mark(BOOTSTAGE_ID_NET_LOADED); 251 252 rcode = bootm_maybe_autostart(cmdtp, argv[0]); 253 254 if (rcode == CMD_RET_SUCCESS) 255 bootstage_mark(BOOTSTAGE_ID_NET_DONE); 256 else 257 bootstage_error(BOOTSTAGE_ID_NET_DONE_ERR); 258 return rcode; 259 } 260 261 #if defined(CONFIG_CMD_PING) 262 static int do_ping(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 263 { 264 if (argc < 2) 265 return CMD_RET_USAGE; 266 267 net_ping_ip = string_to_ip(argv[1]); 268 if (net_ping_ip.s_addr == 0) 269 return CMD_RET_USAGE; 270 271 if (net_loop(PING) < 0) { 272 printf("ping failed; host %s is not alive\n", argv[1]); 273 return CMD_RET_FAILURE; 274 } 275 276 printf("host %s is alive\n", argv[1]); 277 278 return CMD_RET_SUCCESS; 279 } 280 281 U_BOOT_CMD( 282 ping, 2, 1, do_ping, 283 "send ICMP ECHO_REQUEST to network host", 284 "pingAddress" 285 ); 286 #endif 287 288 #if defined(CONFIG_CMD_CDP) 289 290 static void cdp_update_env(void) 291 { 292 char tmp[16]; 293 294 if (cdp_appliance_vlan != htons(-1)) { 295 printf("CDP offered appliance VLAN %d\n", 296 ntohs(cdp_appliance_vlan)); 297 vlan_to_string(cdp_appliance_vlan, tmp); 298 env_set("vlan", tmp); 299 net_our_vlan = cdp_appliance_vlan; 300 } 301 302 if (cdp_native_vlan != htons(-1)) { 303 printf("CDP offered native VLAN %d\n", ntohs(cdp_native_vlan)); 304 vlan_to_string(cdp_native_vlan, tmp); 305 env_set("nvlan", tmp); 306 net_native_vlan = cdp_native_vlan; 307 } 308 } 309 310 int do_cdp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 311 { 312 int r; 313 314 r = net_loop(CDP); 315 if (r < 0) { 316 printf("cdp failed; perhaps not a CISCO switch?\n"); 317 return CMD_RET_FAILURE; 318 } 319 320 cdp_update_env(); 321 322 return CMD_RET_SUCCESS; 323 } 324 325 U_BOOT_CMD( 326 cdp, 1, 1, do_cdp, 327 "Perform CDP network configuration", 328 "\n" 329 ); 330 #endif 331 332 #if defined(CONFIG_CMD_SNTP) 333 int do_sntp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 334 { 335 char *toff; 336 337 if (argc < 2) { 338 net_ntp_server = env_get_ip("ntpserverip"); 339 if (net_ntp_server.s_addr == 0) { 340 printf("ntpserverip not set\n"); 341 return CMD_RET_FAILURE; 342 } 343 } else { 344 net_ntp_server = string_to_ip(argv[1]); 345 if (net_ntp_server.s_addr == 0) { 346 printf("Bad NTP server IP address\n"); 347 return CMD_RET_FAILURE; 348 } 349 } 350 351 toff = env_get("timeoffset"); 352 if (toff == NULL) 353 net_ntp_time_offset = 0; 354 else 355 net_ntp_time_offset = simple_strtol(toff, NULL, 10); 356 357 if (net_loop(SNTP) < 0) { 358 printf("SNTP failed: host %pI4 not responding\n", 359 &net_ntp_server); 360 return CMD_RET_FAILURE; 361 } 362 363 return CMD_RET_SUCCESS; 364 } 365 366 U_BOOT_CMD( 367 sntp, 2, 1, do_sntp, 368 "synchronize RTC via network", 369 "[NTP server IP]\n" 370 ); 371 #endif 372 373 #if defined(CONFIG_CMD_DNS) 374 int do_dns(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 375 { 376 if (argc == 1) 377 return CMD_RET_USAGE; 378 379 /* 380 * We should check for a valid hostname: 381 * - Each label must be between 1 and 63 characters long 382 * - the entire hostname has a maximum of 255 characters 383 * - only the ASCII letters 'a' through 'z' (case-insensitive), 384 * the digits '0' through '9', and the hyphen 385 * - cannot begin or end with a hyphen 386 * - no other symbols, punctuation characters, or blank spaces are 387 * permitted 388 * but hey - this is a minimalist implmentation, so only check length 389 * and let the name server deal with things. 390 */ 391 if (strlen(argv[1]) >= 255) { 392 printf("dns error: hostname too long\n"); 393 return CMD_RET_FAILURE; 394 } 395 396 net_dns_resolve = argv[1]; 397 398 if (argc == 3) 399 net_dns_env_var = argv[2]; 400 else 401 net_dns_env_var = NULL; 402 403 if (net_loop(DNS) < 0) { 404 printf("dns lookup of %s failed, check setup\n", argv[1]); 405 return CMD_RET_FAILURE; 406 } 407 408 return CMD_RET_SUCCESS; 409 } 410 411 U_BOOT_CMD( 412 dns, 3, 1, do_dns, 413 "lookup the IP of a hostname", 414 "hostname [envvar]" 415 ); 416 417 #endif /* CONFIG_CMD_DNS */ 418 419 #if defined(CONFIG_CMD_LINK_LOCAL) 420 static int do_link_local(cmd_tbl_t *cmdtp, int flag, int argc, 421 char * const argv[]) 422 { 423 char tmp[22]; 424 425 if (net_loop(LINKLOCAL) < 0) 426 return CMD_RET_FAILURE; 427 428 net_gateway.s_addr = 0; 429 ip_to_string(net_gateway, tmp); 430 env_set("gatewayip", tmp); 431 432 ip_to_string(net_netmask, tmp); 433 env_set("netmask", tmp); 434 435 ip_to_string(net_ip, tmp); 436 env_set("ipaddr", tmp); 437 env_set("llipaddr", tmp); /* store this for next time */ 438 439 return CMD_RET_SUCCESS; 440 } 441 442 U_BOOT_CMD( 443 linklocal, 1, 1, do_link_local, 444 "acquire a network IP address using the link-local protocol", 445 "" 446 ); 447 448 #endif /* CONFIG_CMD_LINK_LOCAL */ 449