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: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 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 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) 258 static 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 277 U_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 286 static 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 setenv("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 setenv("nvlan", tmp); 302 net_native_vlan = cdp_native_vlan; 303 } 304 } 305 306 int 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 321 U_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) 329 int 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 = getenv_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 = getenv("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 362 U_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) 370 int 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 407 U_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) 416 static 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 setenv("gatewayip", tmp); 427 428 ip_to_string(net_netmask, tmp); 429 setenv("netmask", tmp); 430 431 ip_to_string(net_ip, tmp); 432 setenv("ipaddr", tmp); 433 setenv("llipaddr", tmp); /* store this for next time */ 434 435 return CMD_RET_SUCCESS; 436 } 437 438 U_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