1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2000 4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 5 */ 6 7 /* 8 * Boot support 9 */ 10 #include <common.h> 11 #include <command.h> 12 #include <net.h> 13 14 static int netboot_common(enum proto_t, cmd_tbl_t *, int, char * const []); 15 16 #ifdef CONFIG_CMD_BOOTP 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 #endif 28 29 #ifdef CONFIG_CMD_TFTPBOOT 30 int do_tftpb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 31 { 32 int ret; 33 34 bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start"); 35 ret = netboot_common(TFTPGET, cmdtp, argc, argv); 36 bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done"); 37 return ret; 38 } 39 40 U_BOOT_CMD( 41 tftpboot, 3, 1, do_tftpb, 42 "boot image via network using TFTP protocol", 43 "[loadAddress] [[hostIPaddr:]bootfilename]" 44 ); 45 #endif 46 47 #ifdef CONFIG_CMD_TFTPPUT 48 static int do_tftpput(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 49 { 50 return netboot_common(TFTPPUT, cmdtp, argc, argv); 51 } 52 53 U_BOOT_CMD( 54 tftpput, 4, 1, do_tftpput, 55 "TFTP put command, for uploading files to a server", 56 "Address Size [[hostIPaddr:]filename]" 57 ); 58 #endif 59 60 #ifdef CONFIG_CMD_TFTPSRV 61 static int do_tftpsrv(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) 62 { 63 return netboot_common(TFTPSRV, cmdtp, argc, argv); 64 } 65 66 U_BOOT_CMD( 67 tftpsrv, 2, 1, do_tftpsrv, 68 "act as a TFTP server and boot the first received file", 69 "[loadAddress]\n" 70 "Listen for an incoming TFTP transfer, receive a file and boot it.\n" 71 "The transfer is aborted if a transfer has not been started after\n" 72 "about 50 seconds or if Ctrl-C is pressed." 73 ); 74 #endif 75 76 77 #ifdef CONFIG_CMD_RARP 78 int do_rarpb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 79 { 80 return netboot_common(RARP, cmdtp, argc, argv); 81 } 82 83 U_BOOT_CMD( 84 rarpboot, 3, 1, do_rarpb, 85 "boot image via network using RARP/TFTP protocol", 86 "[loadAddress] [[hostIPaddr:]bootfilename]" 87 ); 88 #endif 89 90 #if defined(CONFIG_CMD_DHCP) 91 static int do_dhcp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 92 { 93 return netboot_common(DHCP, cmdtp, argc, argv); 94 } 95 96 U_BOOT_CMD( 97 dhcp, 3, 1, do_dhcp, 98 "boot image via network using DHCP/TFTP protocol", 99 "[loadAddress] [[hostIPaddr:]bootfilename]" 100 ); 101 #endif 102 103 #if defined(CONFIG_CMD_NFS) 104 static int do_nfs(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 105 { 106 return netboot_common(NFS, cmdtp, argc, argv); 107 } 108 109 U_BOOT_CMD( 110 nfs, 3, 1, do_nfs, 111 "boot image via network using NFS protocol", 112 "[loadAddress] [[hostIPaddr:]bootfilename]" 113 ); 114 #endif 115 116 static void netboot_update_env(void) 117 { 118 char tmp[22]; 119 120 if (net_gateway.s_addr) { 121 ip_to_string(net_gateway, tmp); 122 env_set("gatewayip", tmp); 123 } 124 125 if (net_netmask.s_addr) { 126 ip_to_string(net_netmask, tmp); 127 env_set("netmask", tmp); 128 } 129 130 if (net_hostname[0]) 131 env_set("hostname", net_hostname); 132 133 if (net_root_path[0]) 134 env_set("rootpath", net_root_path); 135 136 if (net_ip.s_addr) { 137 ip_to_string(net_ip, tmp); 138 env_set("ipaddr", tmp); 139 } 140 #if !defined(CONFIG_BOOTP_SERVERIP) 141 /* 142 * Only attempt to change serverip if net/bootp.c:store_net_params() 143 * could have set it 144 */ 145 if (net_server_ip.s_addr) { 146 ip_to_string(net_server_ip, tmp); 147 env_set("serverip", tmp); 148 } 149 #endif 150 if (net_dns_server.s_addr) { 151 ip_to_string(net_dns_server, tmp); 152 env_set("dnsip", tmp); 153 } 154 #if defined(CONFIG_BOOTP_DNS2) 155 if (net_dns_server2.s_addr) { 156 ip_to_string(net_dns_server2, tmp); 157 env_set("dnsip2", tmp); 158 } 159 #endif 160 if (net_nis_domain[0]) 161 env_set("domain", net_nis_domain); 162 163 #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET) 164 if (net_ntp_time_offset) { 165 sprintf(tmp, "%d", net_ntp_time_offset); 166 env_set("timeoffset", tmp); 167 } 168 #endif 169 #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER) 170 if (net_ntp_server.s_addr) { 171 ip_to_string(net_ntp_server, tmp); 172 env_set("ntpserverip", tmp); 173 } 174 #endif 175 } 176 177 static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc, 178 char * const argv[]) 179 { 180 char *s; 181 char *end; 182 int rcode = 0; 183 int size; 184 ulong addr; 185 186 /* pre-set load_addr */ 187 s = env_get("loadaddr"); 188 if (s != NULL) 189 load_addr = simple_strtoul(s, NULL, 16); 190 191 switch (argc) { 192 case 1: 193 break; 194 195 case 2: /* 196 * Only one arg - accept two forms: 197 * Just load address, or just boot file name. The latter 198 * form must be written in a format which can not be 199 * mis-interpreted as a valid number. 200 */ 201 addr = simple_strtoul(argv[1], &end, 16); 202 if (end == (argv[1] + strlen(argv[1]))) 203 load_addr = addr; 204 else 205 copy_filename(net_boot_file_name, argv[1], 206 sizeof(net_boot_file_name)); 207 break; 208 209 case 3: 210 load_addr = simple_strtoul(argv[1], NULL, 16); 211 copy_filename(net_boot_file_name, argv[2], 212 sizeof(net_boot_file_name)); 213 214 break; 215 216 #ifdef CONFIG_CMD_TFTPPUT 217 case 4: 218 if (strict_strtoul(argv[1], 16, &save_addr) < 0 || 219 strict_strtoul(argv[2], 16, &save_size) < 0) { 220 printf("Invalid address/size\n"); 221 return CMD_RET_USAGE; 222 } 223 copy_filename(net_boot_file_name, argv[3], 224 sizeof(net_boot_file_name)); 225 break; 226 #endif 227 default: 228 bootstage_error(BOOTSTAGE_ID_NET_START); 229 return CMD_RET_USAGE; 230 } 231 bootstage_mark(BOOTSTAGE_ID_NET_START); 232 233 size = net_loop(proto); 234 if (size < 0) { 235 bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK); 236 return CMD_RET_FAILURE; 237 } 238 bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK); 239 240 /* net_loop ok, update environment */ 241 netboot_update_env(); 242 243 /* done if no file was loaded (no errors though) */ 244 if (size == 0) { 245 bootstage_error(BOOTSTAGE_ID_NET_LOADED); 246 return CMD_RET_SUCCESS; 247 } 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 env_set("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 env_set("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 = env_get_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 = env_get("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 env_set("gatewayip", tmp); 430 431 ip_to_string(net_netmask, tmp); 432 env_set("netmask", tmp); 433 434 ip_to_string(net_ip, tmp); 435 env_set("ipaddr", tmp); 436 env_set("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