xref: /OK3568_Linux_fs/u-boot/cmd/net.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 #include <boot_rkimg.h>
15 
16 static int netboot_common(enum proto_t, cmd_tbl_t *, int, char * const []);
17 
do_bootp(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])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 
do_tftpb(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])29 int do_tftpb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
30 {
31 	int ret;
32 
33 	bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start");
34 	ret = netboot_common(TFTPGET, cmdtp, argc, argv);
35 	bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done");
36 	return ret;
37 }
38 
39 U_BOOT_CMD(
40 	tftp,		3,	1,	do_tftpb,
41 	"download image via network using TFTP protocol",
42 	"[loadAddress] [[hostIPaddr:]bootfilename]"
43 );
44 
45 #ifdef CONFIG_CMD_TFTP_BOOTM
do_tftpbootm(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])46 int do_tftpbootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
47 {
48 	char *tftp_argv[] = { "tftp", NULL, NULL };
49 	char *bootm_argv[] = { "bootm", NULL };
50 	char *fileaddr;
51 	ulong filesize;
52 
53 	if (argc != 3)
54 		return CMD_RET_USAGE;
55 
56 	/* tftp download */
57 	tftp_argv[1] = argv[1];
58 	tftp_argv[2] = argv[2];
59 	if (do_tftpb(cmdtp, 0, 3, tftp_argv))
60 		return -ENOENT;
61 
62 	fileaddr = env_get("fileaddr");
63 	filesize = env_get_ulong("filesize", 16, 0);
64 	if (!fileaddr || !filesize)
65 		return -ENOENT;
66 
67 	/* bootm */
68 	bootm_argv[1] = fileaddr;
69 	printf("## TFTP bootm %s at %s size 0x%lx\n",
70 	       argv[2], fileaddr, filesize);
71 
72 	return do_bootm(NULL, 0, ARRAY_SIZE(bootm_argv), bootm_argv);
73 }
74 
75 U_BOOT_CMD(
76 	tftpbootm,	3,	1,	do_tftpbootm,
77 	"tftpbootm aosp/uImage/FIT image via network using TFTP protocol",
78 	"[loadAddress] [[hostIPaddr:]bootfilename]"
79 );
80 #endif
81 
82 #ifdef CONFIG_CMD_TFTP_FLASH
do_tftpflash(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])83 int do_tftpflash(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
84 {
85 	char *tftp_argv[] = { "tftp", NULL, NULL };
86 	struct blk_desc *dev_desc;
87 	disk_partition_t part;
88 	ulong fileaddr;
89 	ulong filesize;
90 	char *part_name;
91 	int ret, blknum;
92 
93 	if (argc != 4)
94 		return CMD_RET_USAGE;
95 
96 	/* search partition */
97 	dev_desc = rockchip_get_bootdev();
98 	if (!dev_desc) {
99 		printf("No boot device\n");
100 		return -ENODEV;
101 	}
102 
103 	part_name = argv[3];
104 	ret = part_get_info_by_name(dev_desc, part_name, &part);
105 	if (ret < 0) {
106 		printf("No partition '%s'\n", part_name);
107 		return -EINVAL;
108 	}
109 
110 	/* tftp download */
111 	tftp_argv[1] = argv[1];
112 	tftp_argv[2] = argv[2];
113 	if (do_tftpb(cmdtp, 0, ARRAY_SIZE(tftp_argv), tftp_argv))
114 		return -ENOENT;
115 
116 	fileaddr = env_get_ulong("fileaddr", 16, 0);
117 	filesize = env_get_ulong("filesize", 16, 0);
118 	if (!fileaddr || !filesize)
119 		return -ENOENT;
120 
121 	/* flash */
122 	blknum = DIV_ROUND_UP(filesize, dev_desc->blksz);
123 	if (blknum > part.size) {
124 		printf("File size 0x%lx is too large to flash\n", filesize);
125 		return -EINVAL;
126 	}
127 
128 	printf("## TFTP flash %s to partititon '%s' size 0x%lx ... ",
129 	       argv[2], part_name, filesize);
130 
131 	if (dev_desc->if_type == IF_TYPE_MTD)
132 		dev_desc->op_flag |= BLK_MTD_CONT_WRITE;
133 	ret = blk_dwrite(dev_desc, part.start, blknum, (void *)fileaddr);
134 	if (dev_desc->if_type == IF_TYPE_MTD)
135 		dev_desc->op_flag &= ~(BLK_MTD_CONT_WRITE);
136 	if (ret != blknum)
137 		printf("Failed(%d)\n", ret);
138 	else
139 		printf("OK\n");
140 
141 	return 0;
142 }
143 
144 U_BOOT_CMD(
145 	tftpflash,	4,	0,	do_tftpflash,
146 	"flash image via network using TFTP protocol",
147 	"[loadAddress] [[hostIPaddr:]bootfilename] [partition]"
148 );
149 #endif
150 
151 #ifdef CONFIG_CMD_TFTPPUT
do_tftpput(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])152 static int do_tftpput(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
153 {
154 	return netboot_common(TFTPPUT, cmdtp, argc, argv);
155 }
156 
157 U_BOOT_CMD(
158 	tftpput,	4,	1,	do_tftpput,
159 	"TFTP put command, for uploading files to a server",
160 	"Address Size [[hostIPaddr:]filename]"
161 );
162 #endif
163 
164 #ifdef CONFIG_CMD_TFTPSRV
do_tftpsrv(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])165 static int do_tftpsrv(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
166 {
167 	return netboot_common(TFTPSRV, cmdtp, argc, argv);
168 }
169 
170 U_BOOT_CMD(
171 	tftpsrv,	2,	1,	do_tftpsrv,
172 	"act as a TFTP server and boot the first received file",
173 	"[loadAddress]\n"
174 	"Listen for an incoming TFTP transfer, receive a file and boot it.\n"
175 	"The transfer is aborted if a transfer has not been started after\n"
176 	"about 50 seconds or if Ctrl-C is pressed."
177 );
178 #endif
179 
180 #ifdef CONFIG_UDP_FUNCTION_FASTBOOT
do_fastboot_udp(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])181 int do_fastboot_udp(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
182 {
183 	return netboot_common(FASTBOOT, cmdtp, argc, argv);
184 }
185 #endif
186 
187 #ifdef CONFIG_CMD_RARP
do_rarpb(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])188 int do_rarpb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
189 {
190 	return netboot_common(RARP, cmdtp, argc, argv);
191 }
192 
193 U_BOOT_CMD(
194 	rarpboot,	3,	1,	do_rarpb,
195 	"boot image via network using RARP/TFTP protocol",
196 	"[loadAddress] [[hostIPaddr:]bootfilename]"
197 );
198 #endif
199 
200 #if defined(CONFIG_CMD_DHCP)
do_dhcp(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])201 static int do_dhcp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
202 {
203 	return netboot_common(DHCP, cmdtp, argc, argv);
204 }
205 
206 U_BOOT_CMD(
207 	dhcp,	3,	1,	do_dhcp,
208 	"boot image via network using DHCP/TFTP protocol",
209 	"[loadAddress] [[hostIPaddr:]bootfilename]"
210 );
211 #endif
212 
213 #if defined(CONFIG_CMD_NFS)
do_nfs(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])214 static int do_nfs(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
215 {
216 	return netboot_common(NFS, cmdtp, argc, argv);
217 }
218 
219 U_BOOT_CMD(
220 	nfs,	3,	1,	do_nfs,
221 	"boot image via network using NFS protocol",
222 	"[loadAddress] [[hostIPaddr:]bootfilename]"
223 );
224 #endif
225 
netboot_update_env(void)226 static void netboot_update_env(void)
227 {
228 	char tmp[22];
229 
230 	if (net_gateway.s_addr) {
231 		ip_to_string(net_gateway, tmp);
232 		env_set("gatewayip", tmp);
233 	}
234 
235 	if (net_netmask.s_addr) {
236 		ip_to_string(net_netmask, tmp);
237 		env_set("netmask", tmp);
238 	}
239 
240 	if (net_hostname[0])
241 		env_set("hostname", net_hostname);
242 
243 	if (net_root_path[0])
244 		env_set("rootpath", net_root_path);
245 
246 	if (net_ip.s_addr) {
247 		ip_to_string(net_ip, tmp);
248 		env_set("ipaddr", tmp);
249 	}
250 #if !defined(CONFIG_BOOTP_SERVERIP)
251 	/*
252 	 * Only attempt to change serverip if net/bootp.c:store_net_params()
253 	 * could have set it
254 	 */
255 	if (net_server_ip.s_addr) {
256 		ip_to_string(net_server_ip, tmp);
257 		env_set("serverip", tmp);
258 	}
259 #endif
260 	if (net_dns_server.s_addr) {
261 		ip_to_string(net_dns_server, tmp);
262 		env_set("dnsip", tmp);
263 	}
264 #if defined(CONFIG_BOOTP_DNS2)
265 	if (net_dns_server2.s_addr) {
266 		ip_to_string(net_dns_server2, tmp);
267 		env_set("dnsip2", tmp);
268 	}
269 #endif
270 	if (net_nis_domain[0])
271 		env_set("domain", net_nis_domain);
272 
273 #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
274 	if (net_ntp_time_offset) {
275 		sprintf(tmp, "%d", net_ntp_time_offset);
276 		env_set("timeoffset", tmp);
277 	}
278 #endif
279 #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
280 	if (net_ntp_server.s_addr) {
281 		ip_to_string(net_ntp_server, tmp);
282 		env_set("ntpserverip", tmp);
283 	}
284 #endif
285 }
286 
netboot_common(enum proto_t proto,cmd_tbl_t * cmdtp,int argc,char * const argv[])287 static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc,
288 		char * const argv[])
289 {
290 	char *s;
291 	char *end;
292 	int   rcode = 0;
293 	int   size;
294 	ulong addr;
295 
296 	/* pre-set load_addr */
297 	s = env_get("loadaddr");
298 	if (s != NULL)
299 		load_addr = simple_strtoul(s, NULL, 16);
300 
301 	switch (argc) {
302 	case 1:
303 		break;
304 
305 	case 2:	/*
306 		 * Only one arg - accept two forms:
307 		 * Just load address, or just boot file name. The latter
308 		 * form must be written in a format which can not be
309 		 * mis-interpreted as a valid number.
310 		 */
311 		addr = simple_strtoul(argv[1], &end, 16);
312 		if (end == (argv[1] + strlen(argv[1])))
313 			load_addr = addr;
314 		else
315 			copy_filename(net_boot_file_name, argv[1],
316 				      sizeof(net_boot_file_name));
317 		break;
318 
319 	case 3:
320 		load_addr = simple_strtoul(argv[1], NULL, 16);
321 		copy_filename(net_boot_file_name, argv[2],
322 			      sizeof(net_boot_file_name));
323 
324 		break;
325 
326 #ifdef CONFIG_CMD_TFTPPUT
327 	case 4:
328 		if (strict_strtoul(argv[1], 16, &save_addr) < 0 ||
329 		    strict_strtoul(argv[2], 16, &save_size) < 0) {
330 			printf("Invalid address/size\n");
331 			return CMD_RET_USAGE;
332 		}
333 		copy_filename(net_boot_file_name, argv[3],
334 			      sizeof(net_boot_file_name));
335 		break;
336 #endif
337 	default:
338 		bootstage_error(BOOTSTAGE_ID_NET_START);
339 		return CMD_RET_USAGE;
340 	}
341 	bootstage_mark(BOOTSTAGE_ID_NET_START);
342 
343 	size = net_loop(proto);
344 	if (size < 0) {
345 		bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK);
346 		return CMD_RET_FAILURE;
347 	}
348 	bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK);
349 
350 	/* net_loop ok, update environment */
351 	netboot_update_env();
352 
353 	/* done if no file was loaded (no errors though) */
354 	if (size == 0) {
355 		bootstage_error(BOOTSTAGE_ID_NET_LOADED);
356 		return CMD_RET_SUCCESS;
357 	}
358 
359 	bootstage_mark(BOOTSTAGE_ID_NET_LOADED);
360 
361 	rcode = bootm_maybe_autostart(cmdtp, argv[0]);
362 
363 	if (rcode == CMD_RET_SUCCESS)
364 		bootstage_mark(BOOTSTAGE_ID_NET_DONE);
365 	else
366 		bootstage_error(BOOTSTAGE_ID_NET_DONE_ERR);
367 	return rcode;
368 }
369 
370 #if defined(CONFIG_CMD_PING)
do_ping(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])371 static int do_ping(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
372 {
373 	if (argc < 2)
374 		return CMD_RET_USAGE;
375 
376 	net_ping_ip = string_to_ip(argv[1]);
377 	if (net_ping_ip.s_addr == 0)
378 		return CMD_RET_USAGE;
379 
380 	if (net_loop(PING) < 0) {
381 		printf("ping failed; host %s is not alive\n", argv[1]);
382 		return CMD_RET_FAILURE;
383 	}
384 
385 	printf("host %s is alive\n", argv[1]);
386 
387 	return CMD_RET_SUCCESS;
388 }
389 
390 U_BOOT_CMD(
391 	ping,	2,	1,	do_ping,
392 	"send ICMP ECHO_REQUEST to network host",
393 	"pingAddress"
394 );
395 #endif
396 
397 #if defined(CONFIG_CMD_CDP)
398 
cdp_update_env(void)399 static void cdp_update_env(void)
400 {
401 	char tmp[16];
402 
403 	if (cdp_appliance_vlan != htons(-1)) {
404 		printf("CDP offered appliance VLAN %d\n",
405 		       ntohs(cdp_appliance_vlan));
406 		vlan_to_string(cdp_appliance_vlan, tmp);
407 		env_set("vlan", tmp);
408 		net_our_vlan = cdp_appliance_vlan;
409 	}
410 
411 	if (cdp_native_vlan != htons(-1)) {
412 		printf("CDP offered native VLAN %d\n", ntohs(cdp_native_vlan));
413 		vlan_to_string(cdp_native_vlan, tmp);
414 		env_set("nvlan", tmp);
415 		net_native_vlan = cdp_native_vlan;
416 	}
417 }
418 
do_cdp(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])419 int do_cdp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
420 {
421 	int r;
422 
423 	r = net_loop(CDP);
424 	if (r < 0) {
425 		printf("cdp failed; perhaps not a CISCO switch?\n");
426 		return CMD_RET_FAILURE;
427 	}
428 
429 	cdp_update_env();
430 
431 	return CMD_RET_SUCCESS;
432 }
433 
434 U_BOOT_CMD(
435 	cdp,	1,	1,	do_cdp,
436 	"Perform CDP network configuration",
437 	"\n"
438 );
439 #endif
440 
441 #if defined(CONFIG_CMD_SNTP)
do_sntp(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])442 int do_sntp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
443 {
444 	char *toff;
445 
446 	if (argc < 2) {
447 		net_ntp_server = env_get_ip("ntpserverip");
448 		if (net_ntp_server.s_addr == 0) {
449 			printf("ntpserverip not set\n");
450 			return CMD_RET_FAILURE;
451 		}
452 	} else {
453 		net_ntp_server = string_to_ip(argv[1]);
454 		if (net_ntp_server.s_addr == 0) {
455 			printf("Bad NTP server IP address\n");
456 			return CMD_RET_FAILURE;
457 		}
458 	}
459 
460 	toff = env_get("timeoffset");
461 	if (toff == NULL)
462 		net_ntp_time_offset = 0;
463 	else
464 		net_ntp_time_offset = simple_strtol(toff, NULL, 10);
465 
466 	if (net_loop(SNTP) < 0) {
467 		printf("SNTP failed: host %pI4 not responding\n",
468 		       &net_ntp_server);
469 		return CMD_RET_FAILURE;
470 	}
471 
472 	return CMD_RET_SUCCESS;
473 }
474 
475 U_BOOT_CMD(
476 	sntp,	2,	1,	do_sntp,
477 	"synchronize RTC via network",
478 	"[NTP server IP]\n"
479 );
480 #endif
481 
482 #if defined(CONFIG_CMD_DNS)
do_dns(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])483 int do_dns(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
484 {
485 	if (argc == 1)
486 		return CMD_RET_USAGE;
487 
488 	/*
489 	 * We should check for a valid hostname:
490 	 * - Each label must be between 1 and 63 characters long
491 	 * - the entire hostname has a maximum of 255 characters
492 	 * - only the ASCII letters 'a' through 'z' (case-insensitive),
493 	 *   the digits '0' through '9', and the hyphen
494 	 * - cannot begin or end with a hyphen
495 	 * - no other symbols, punctuation characters, or blank spaces are
496 	 *   permitted
497 	 * but hey - this is a minimalist implmentation, so only check length
498 	 * and let the name server deal with things.
499 	 */
500 	if (strlen(argv[1]) >= 255) {
501 		printf("dns error: hostname too long\n");
502 		return CMD_RET_FAILURE;
503 	}
504 
505 	net_dns_resolve = argv[1];
506 
507 	if (argc == 3)
508 		net_dns_env_var = argv[2];
509 	else
510 		net_dns_env_var = NULL;
511 
512 	if (net_loop(DNS) < 0) {
513 		printf("dns lookup of %s failed, check setup\n", argv[1]);
514 		return CMD_RET_FAILURE;
515 	}
516 
517 	return CMD_RET_SUCCESS;
518 }
519 
520 U_BOOT_CMD(
521 	dns,	3,	1,	do_dns,
522 	"lookup the IP of a hostname",
523 	"hostname [envvar]"
524 );
525 
526 #endif	/* CONFIG_CMD_DNS */
527 
528 #if defined(CONFIG_CMD_LINK_LOCAL)
do_link_local(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])529 static int do_link_local(cmd_tbl_t *cmdtp, int flag, int argc,
530 			char * const argv[])
531 {
532 	char tmp[22];
533 
534 	if (net_loop(LINKLOCAL) < 0)
535 		return CMD_RET_FAILURE;
536 
537 	net_gateway.s_addr = 0;
538 	ip_to_string(net_gateway, tmp);
539 	env_set("gatewayip", tmp);
540 
541 	ip_to_string(net_netmask, tmp);
542 	env_set("netmask", tmp);
543 
544 	ip_to_string(net_ip, tmp);
545 	env_set("ipaddr", tmp);
546 	env_set("llipaddr", tmp); /* store this for next time */
547 
548 	return CMD_RET_SUCCESS;
549 }
550 
551 U_BOOT_CMD(
552 	linklocal,	1,	1,	do_link_local,
553 	"acquire a network IP address using the link-local protocol",
554 	""
555 );
556 
557 #endif  /* CONFIG_CMD_LINK_LOCAL */
558