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 static 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 22 U_BOOT_CMD( 23 bootp, 3, 1, do_bootp, 24 "boot image via network using BOOTP/TFTP protocol", 25 "[loadAddress] [[hostIPaddr:]bootfilename]" 26 ); 27 28 int 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 38 U_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 45 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 50 U_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 58 static 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 63 U_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 75 int do_rarpb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 76 { 77 return netboot_common(RARP, cmdtp, argc, argv); 78 } 79 80 U_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) 88 static 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 93 U_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) 101 static 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 106 U_BOOT_CMD( 107 nfs, 3, 1, do_nfs, 108 "boot image via network using NFS protocol", 109 "[loadAddress] [[hostIPaddr:]bootfilename]" 110 ); 111 #endif 112 113 static 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 setenv("gatewayip", tmp); 120 } 121 122 if (net_netmask.s_addr) { 123 ip_to_string(net_netmask, tmp); 124 setenv("netmask", tmp); 125 } 126 127 if (net_hostname[0]) 128 setenv("hostname", net_hostname); 129 130 if (net_root_path[0]) 131 setenv("rootpath", net_root_path); 132 133 if (net_ip.s_addr) { 134 ip_to_string(net_ip, tmp); 135 setenv("ipaddr", tmp); 136 } 137 #if !defined(CONFIG_BOOTP_SERVERIP) 138 /* 139 * Only attempt to change serverip if net/bootp.c:BootpCopyNetParams() 140 * could have set it 141 */ 142 if (net_server_ip.s_addr) { 143 ip_to_string(net_server_ip, tmp); 144 setenv("serverip", tmp); 145 } 146 #endif 147 if (net_dns_server.s_addr) { 148 ip_to_string(net_dns_server, tmp); 149 setenv("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 setenv("dnsip2", tmp); 155 } 156 #endif 157 if (net_nis_domain[0]) 158 setenv("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 setenv("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 setenv("ntpserverip", tmp); 170 } 171 #endif 172 } 173 174 static 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 = getenv("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 /* flush cache */ 247 flush_cache(load_addr, size); 248 249 bootstage_mark(BOOTSTAGE_ID_NET_LOADED); 250 251 rcode = bootm_maybe_autostart(cmdtp, argv[0]); 252 253 if (rcode == CMD_RET_SUCCESS) 254 bootstage_mark(BOOTSTAGE_ID_NET_DONE); 255 else 256 bootstage_error(BOOTSTAGE_ID_NET_DONE_ERR); 257 return rcode; 258 } 259 260 #if defined(CONFIG_CMD_PING) 261 static int do_ping(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 262 { 263 if (argc < 2) 264 return CMD_RET_USAGE; 265 266 net_ping_ip = string_to_ip(argv[1]); 267 if (net_ping_ip.s_addr == 0) 268 return CMD_RET_USAGE; 269 270 if (net_loop(PING) < 0) { 271 printf("ping failed; host %s is not alive\n", argv[1]); 272 return CMD_RET_FAILURE; 273 } 274 275 printf("host %s is alive\n", argv[1]); 276 277 return CMD_RET_SUCCESS; 278 } 279 280 U_BOOT_CMD( 281 ping, 2, 1, do_ping, 282 "send ICMP ECHO_REQUEST to network host", 283 "pingAddress" 284 ); 285 #endif 286 287 #if defined(CONFIG_CMD_CDP) 288 289 static void cdp_update_env(void) 290 { 291 char tmp[16]; 292 293 if (cdp_appliance_vlan != htons(-1)) { 294 printf("CDP offered appliance VLAN %d\n", 295 ntohs(cdp_appliance_vlan)); 296 vlan_to_string(cdp_appliance_vlan, tmp); 297 setenv("vlan", tmp); 298 net_our_vlan = cdp_appliance_vlan; 299 } 300 301 if (cdp_native_vlan != htons(-1)) { 302 printf("CDP offered native VLAN %d\n", ntohs(cdp_native_vlan)); 303 vlan_to_string(cdp_native_vlan, tmp); 304 setenv("nvlan", tmp); 305 net_native_vlan = cdp_native_vlan; 306 } 307 } 308 309 int do_cdp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 310 { 311 int r; 312 313 r = net_loop(CDP); 314 if (r < 0) { 315 printf("cdp failed; perhaps not a CISCO switch?\n"); 316 return CMD_RET_FAILURE; 317 } 318 319 cdp_update_env(); 320 321 return CMD_RET_SUCCESS; 322 } 323 324 U_BOOT_CMD( 325 cdp, 1, 1, do_cdp, 326 "Perform CDP network configuration", 327 "\n" 328 ); 329 #endif 330 331 #if defined(CONFIG_CMD_SNTP) 332 int do_sntp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 333 { 334 char *toff; 335 336 if (argc < 2) { 337 net_ntp_server = getenv_ip("ntpserverip"); 338 if (net_ntp_server.s_addr == 0) { 339 printf("ntpserverip not set\n"); 340 return CMD_RET_FAILURE; 341 } 342 } else { 343 net_ntp_server = string_to_ip(argv[1]); 344 if (net_ntp_server.s_addr == 0) { 345 printf("Bad NTP server IP address\n"); 346 return CMD_RET_FAILURE; 347 } 348 } 349 350 toff = getenv("timeoffset"); 351 if (toff == NULL) 352 net_ntp_time_offset = 0; 353 else 354 net_ntp_time_offset = simple_strtol(toff, NULL, 10); 355 356 if (net_loop(SNTP) < 0) { 357 printf("SNTP failed: host %pI4 not responding\n", 358 &net_ntp_server); 359 return CMD_RET_FAILURE; 360 } 361 362 return CMD_RET_SUCCESS; 363 } 364 365 U_BOOT_CMD( 366 sntp, 2, 1, do_sntp, 367 "synchronize RTC via network", 368 "[NTP server IP]\n" 369 ); 370 #endif 371 372 #if defined(CONFIG_CMD_DNS) 373 int do_dns(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 374 { 375 if (argc == 1) 376 return CMD_RET_USAGE; 377 378 /* 379 * We should check for a valid hostname: 380 * - Each label must be between 1 and 63 characters long 381 * - the entire hostname has a maximum of 255 characters 382 * - only the ASCII letters 'a' through 'z' (case-insensitive), 383 * the digits '0' through '9', and the hyphen 384 * - cannot begin or end with a hyphen 385 * - no other symbols, punctuation characters, or blank spaces are 386 * permitted 387 * but hey - this is a minimalist implmentation, so only check length 388 * and let the name server deal with things. 389 */ 390 if (strlen(argv[1]) >= 255) { 391 printf("dns error: hostname too long\n"); 392 return CMD_RET_FAILURE; 393 } 394 395 net_dns_resolve = argv[1]; 396 397 if (argc == 3) 398 net_dns_env_var = argv[2]; 399 else 400 net_dns_env_var = NULL; 401 402 if (net_loop(DNS) < 0) { 403 printf("dns lookup of %s failed, check setup\n", argv[1]); 404 return CMD_RET_FAILURE; 405 } 406 407 return CMD_RET_SUCCESS; 408 } 409 410 U_BOOT_CMD( 411 dns, 3, 1, do_dns, 412 "lookup the IP of a hostname", 413 "hostname [envvar]" 414 ); 415 416 #endif /* CONFIG_CMD_DNS */ 417 418 #if defined(CONFIG_CMD_LINK_LOCAL) 419 static int do_link_local(cmd_tbl_t *cmdtp, int flag, int argc, 420 char * const argv[]) 421 { 422 char tmp[22]; 423 424 if (net_loop(LINKLOCAL) < 0) 425 return CMD_RET_FAILURE; 426 427 net_gateway.s_addr = 0; 428 ip_to_string(net_gateway, tmp); 429 setenv("gatewayip", tmp); 430 431 ip_to_string(net_netmask, tmp); 432 setenv("netmask", tmp); 433 434 ip_to_string(net_ip, tmp); 435 setenv("ipaddr", tmp); 436 setenv("llipaddr", tmp); /* store this for next time */ 437 438 return CMD_RET_SUCCESS; 439 } 440 441 U_BOOT_CMD( 442 linklocal, 1, 1, do_link_local, 443 "acquire a network IP address using the link-local protocol", 444 "" 445 ); 446 447 #endif /* CONFIG_CMD_LINK_LOCAL */ 448