net.c 9.7 KB
Newer Older
wdenk's avatar
wdenk committed
1 2 3 4
/*
 * (C) Copyright 2000
 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 *
5
 * SPDX-License-Identifier:	GPL-2.0+
wdenk's avatar
wdenk committed
6 7 8 9 10 11 12 13 14
 */

/*
 * Boot support
 */
#include <common.h>
#include <command.h>
#include <net.h>

15
static int netboot_common(enum proto_t, cmd_tbl_t *, int, char * const []);
wdenk's avatar
wdenk committed
16

17
static int do_bootp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
wdenk's avatar
wdenk committed
18
{
19
	return netboot_common(BOOTP, cmdtp, argc, argv);
wdenk's avatar
wdenk committed
20 21
}

22 23
U_BOOT_CMD(
	bootp,	3,	1,	do_bootp,
Peter Tyser's avatar
Peter Tyser committed
24
	"boot image via network using BOOTP/TFTP protocol",
25
	"[loadAddress] [[hostIPaddr:]bootfilename]"
wdenk's avatar
wdenk committed
26 27
);

28
int do_tftpb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
wdenk's avatar
wdenk committed
29
{
30 31 32 33 34 35
	int ret;

	bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start");
	ret = netboot_common(TFTPGET, cmdtp, argc, argv);
	bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done");
	return ret;
wdenk's avatar
wdenk committed
36 37
}

38 39
U_BOOT_CMD(
	tftpboot,	3,	1,	do_tftpb,
Peter Tyser's avatar
Peter Tyser committed
40
	"boot image via network using TFTP protocol",
41
	"[loadAddress] [[hostIPaddr:]bootfilename]"
wdenk's avatar
wdenk committed
42 43
);

44 45 46
#ifdef CONFIG_CMD_TFTPPUT
int do_tftpput(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
47
	return netboot_common(TFTPPUT, cmdtp, argc, argv);
48 49 50 51 52 53 54 55 56
}

U_BOOT_CMD(
	tftpput,	4,	1,	do_tftpput,
	"TFTP put command, for uploading files to a server",
	"Address Size [[hostIPaddr:]filename]"
);
#endif

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
#ifdef CONFIG_CMD_TFTPSRV
static int do_tftpsrv(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
	return netboot_common(TFTPSRV, cmdtp, argc, argv);
}

U_BOOT_CMD(
	tftpsrv,	2,	1,	do_tftpsrv,
	"act as a TFTP server and boot the first received file",
	"[loadAddress]\n"
	"Listen for an incoming TFTP transfer, receive a file and boot it.\n"
	"The transfer is aborted if a transfer has not been started after\n"
	"about 50 seconds or if Ctrl-C is pressed."
);
#endif


74
#ifdef CONFIG_CMD_RARP
75
int do_rarpb(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
wdenk's avatar
wdenk committed
76
{
77
	return netboot_common(RARP, cmdtp, argc, argv);
wdenk's avatar
wdenk committed
78 79
}

80 81
U_BOOT_CMD(
	rarpboot,	3,	1,	do_rarpb,
Peter Tyser's avatar
Peter Tyser committed
82
	"boot image via network using RARP/TFTP protocol",
83
	"[loadAddress] [[hostIPaddr:]bootfilename]"
wdenk's avatar
wdenk committed
84
);
85
#endif
wdenk's avatar
wdenk committed
86

87
#if defined(CONFIG_CMD_DHCP)
88
static int do_dhcp(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
wdenk's avatar
wdenk committed
89 90 91
{
	return netboot_common(DHCP, cmdtp, argc, argv);
}
wdenk's avatar
wdenk committed
92

93 94
U_BOOT_CMD(
	dhcp,	3,	1,	do_dhcp,
Peter Tyser's avatar
Peter Tyser committed
95
	"boot image via network using DHCP/TFTP protocol",
96
	"[loadAddress] [[hostIPaddr:]bootfilename]"
wdenk's avatar
wdenk committed
97
);
98
#endif
wdenk's avatar
wdenk committed
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 104 105 106 107
{
	return netboot_common(NFS, cmdtp, argc, argv);
}

U_BOOT_CMD(
	nfs,	3,	1,	do_nfs,
Peter Tyser's avatar
Peter Tyser committed
108
	"boot image via network using NFS protocol",
109
	"[loadAddress] [[hostIPaddr:]bootfilename]"
110
);
111
#endif
112

113
static void netboot_update_env(void)
wdenk's avatar
wdenk committed
114
{
wdenk's avatar
wdenk committed
115
	char tmp[22];
wdenk's avatar
wdenk committed
116

117 118
	if (net_gateway.s_addr) {
		ip_to_string(net_gateway, tmp);
119
		setenv("gatewayip", tmp);
wdenk's avatar
wdenk committed
120
	}
wdenk's avatar
wdenk committed
121

122 123
	if (net_netmask.s_addr) {
		ip_to_string(net_netmask, tmp);
124
		setenv("netmask", tmp);
wdenk's avatar
wdenk committed
125
	}
wdenk's avatar
wdenk committed
126

127 128
	if (net_hostname[0])
		setenv("hostname", net_hostname);
wdenk's avatar
wdenk committed
129

130 131
	if (net_root_path[0])
		setenv("rootpath", net_root_path);
wdenk's avatar
wdenk committed
132

133 134
	if (net_ip.s_addr) {
		ip_to_string(net_ip, tmp);
135
		setenv("ipaddr", tmp);
wdenk's avatar
wdenk committed
136
	}
137 138 139 140 141
#if !defined(CONFIG_BOOTP_SERVERIP)
	/*
	 * Only attempt to change serverip if net/bootp.c:BootpCopyNetParams()
	 * could have set it
	 */
142 143
	if (net_server_ip.s_addr) {
		ip_to_string(net_server_ip, tmp);
144
		setenv("serverip", tmp);
wdenk's avatar
wdenk committed
145
	}
146
#endif
147 148
	if (net_dns_server.s_addr) {
		ip_to_string(net_dns_server, tmp);
149
		setenv("dnsip", tmp);
wdenk's avatar
wdenk committed
150
	}
151
#if defined(CONFIG_BOOTP_DNS2)
152 153
	if (net_dns_server2.s_addr) {
		ip_to_string(net_dns_server2, tmp);
154
		setenv("dnsip2", tmp);
wdenk's avatar
wdenk committed
155
	}
156
#endif
157 158
	if (net_nis_domain[0])
		setenv("domain", net_nis_domain);
159

160
#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
161 162
	if (net_ntp_time_offset) {
		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 168
	if (net_ntp_server.s_addr) {
		ip_to_string(net_ntp_server, tmp);
169
		setenv("ntpserverip", tmp);
170 171
	}
#endif
wdenk's avatar
wdenk committed
172
}
wdenk's avatar
wdenk committed
173

174 175
static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc,
		char * const argv[])
wdenk's avatar
wdenk committed
176 177
{
	char *s;
178
	char *end;
wdenk's avatar
wdenk committed
179 180
	int   rcode = 0;
	int   size;
181
	ulong addr;
wdenk's avatar
wdenk committed
182 183

	/* pre-set load_addr */
184 185
	s = getenv("loadaddr");
	if (s != NULL)
wdenk's avatar
wdenk committed
186 187 188 189 190 191
		load_addr = simple_strtoul(s, NULL, 16);

	switch (argc) {
	case 1:
		break;

192 193 194 195 196
	case 2:	/*
		 * Only one arg - accept two forms:
		 * Just load address, or just boot file name. The latter
		 * form must be written in a format which can not be
		 * mis-interpreted as a valid number.
wdenk's avatar
wdenk committed
197
		 */
198 199 200 201
		addr = simple_strtoul(argv[1], &end, 16);
		if (end == (argv[1] + strlen(argv[1])))
			load_addr = addr;
		else
202 203
			copy_filename(net_boot_file_name, argv[1],
				      sizeof(net_boot_file_name));
wdenk's avatar
wdenk committed
204 205
		break;

206 207
	case 3:
		load_addr = simple_strtoul(argv[1], NULL, 16);
208 209
		copy_filename(net_boot_file_name, argv[2],
			      sizeof(net_boot_file_name));
wdenk's avatar
wdenk committed
210 211 212

		break;

213 214
#ifdef CONFIG_CMD_TFTPPUT
	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 221
		copy_filename(net_boot_file_name, argv[3],
			      sizeof(net_boot_file_name));
222 223
		break;
#endif
224
	default:
225
		bootstage_error(BOOTSTAGE_ID_NET_START);
226
		return CMD_RET_USAGE;
wdenk's avatar
wdenk committed
227
	}
228
	bootstage_mark(BOOTSTAGE_ID_NET_START);
wdenk's avatar
wdenk committed
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);
wdenk's avatar
wdenk committed
236

237
	/* net_loop ok, update environment */
wdenk's avatar
wdenk committed
238 239
	netboot_update_env();

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

wdenk's avatar
wdenk committed
246 247 248
	/* flush cache */
	flush_cache(load_addr, size);

249
	bootstage_mark(BOOTSTAGE_ID_NET_LOADED);
250

251
	rcode = bootm_maybe_autostart(cmdtp, argv[0]);
wdenk's avatar
wdenk committed
252

253
	if (rcode == CMD_RET_SUCCESS)
254
		bootstage_mark(BOOTSTAGE_ID_NET_DONE);
255 256
	else
		bootstage_error(BOOTSTAGE_ID_NET_DONE_ERR);
wdenk's avatar
wdenk committed
257 258 259
	return rcode;
}

260
#if defined(CONFIG_CMD_PING)
261
static int do_ping(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
wdenk's avatar
wdenk committed
262 263
{
	if (argc < 2)
264
		return CMD_RET_USAGE;
wdenk's avatar
wdenk committed
265

266 267
	net_ping_ip = string_to_ip(argv[1]);
	if (net_ping_ip.s_addr == 0)
268
		return CMD_RET_USAGE;
wdenk's avatar
wdenk committed
269

270
	if (net_loop(PING) < 0) {
wdenk's avatar
wdenk committed
271
		printf("ping failed; host %s is not alive\n", argv[1]);
272
		return CMD_RET_FAILURE;
wdenk's avatar
wdenk committed
273 274 275 276
	}

	printf("host %s is alive\n", argv[1]);

277
	return CMD_RET_SUCCESS;
wdenk's avatar
wdenk committed
278
}
279 280 281

U_BOOT_CMD(
	ping,	2,	1,	do_ping,
Peter Tyser's avatar
Peter Tyser committed
282
	"send ICMP ECHO_REQUEST to network host",
283
	"pingAddress"
284
);
285
#endif
wdenk's avatar
wdenk committed
286

287
#if defined(CONFIG_CMD_CDP)
288 289 290 291 292

static void cdp_update_env(void)
{
	char tmp[16];

293 294 295
	if (cdp_appliance_vlan != htons(-1)) {
		printf("CDP offered appliance VLAN %d\n",
		       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 302
	if (cdp_native_vlan != htons(-1)) {
		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 312
{
	int r;

313
	r = net_loop(CDP);
314 315
	if (r < 0) {
		printf("cdp failed; perhaps not a CISCO switch?\n");
316
		return CMD_RET_FAILURE;
317 318 319 320
	}

	cdp_update_env();

321
	return CMD_RET_SUCCESS;
322 323 324 325
}

U_BOOT_CMD(
	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 335 336
{
	char *toff;

	if (argc < 2) {
337 338
		net_ntp_server = getenv_ip("ntpserverip");
		if (net_ntp_server.s_addr == 0) {
339
			printf("ntpserverip not set\n");
340
			return CMD_RET_FAILURE;
341 342
		}
	} else {
343 344
		net_ntp_server = string_to_ip(argv[1]);
		if (net_ntp_server.s_addr == 0) {
345
			printf("Bad NTP server IP address\n");
346
			return CMD_RET_FAILURE;
347 348 349
		}
	}

350 351
	toff = getenv("timeoffset");
	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 366
}

U_BOOT_CMD(
	sntp,	2,	1,	do_sntp,
Peter Tyser's avatar
Peter Tyser committed
367
	"synchronize RTC via network",
368 369
	"[NTP server IP]\n"
);
370
#endif
Robin Getz's avatar
Robin Getz committed
371 372

#if defined(CONFIG_CMD_DNS)
373
int do_dns(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
Robin Getz's avatar
Robin Getz committed
374
{
375
	if (argc == 1)
376
		return CMD_RET_USAGE;
Robin Getz's avatar
Robin Getz committed
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391

	/*
	 * We should check for a valid hostname:
	 * - Each label must be between 1 and 63 characters long
	 * - the entire hostname has a maximum of 255 characters
	 * - only the ASCII letters 'a' through 'z' (case-insensitive),
	 *   the digits '0' through '9', and the hyphen
	 * - cannot begin or end with a hyphen
	 * - no other symbols, punctuation characters, or blank spaces are
	 *   permitted
	 * but hey - this is a minimalist implmentation, so only check length
	 * and let the name server deal with things.
	 */
	if (strlen(argv[1]) >= 255) {
		printf("dns error: hostname too long\n");
392
		return CMD_RET_FAILURE;
Robin Getz's avatar
Robin Getz committed
393 394
	}

395
	net_dns_resolve = argv[1];
Robin Getz's avatar
Robin Getz committed
396 397

	if (argc == 3)
398
		net_dns_env_var = argv[2];
Robin Getz's avatar
Robin Getz committed
399
	else
400
		net_dns_env_var = NULL;
Robin Getz's avatar
Robin Getz committed
401

402
	if (net_loop(DNS) < 0) {
Robin Getz's avatar
Robin Getz committed
403
		printf("dns lookup of %s failed, check setup\n", argv[1]);
404
		return CMD_RET_FAILURE;
Robin Getz's avatar
Robin Getz committed
405 406
	}

407
	return CMD_RET_SUCCESS;
Robin Getz's avatar
Robin Getz committed
408 409 410 411 412 413 414 415 416
}

U_BOOT_CMD(
	dns,	3,	1,	do_dns,
	"lookup the IP of a hostname",
	"hostname [envvar]"
);

#endif	/* CONFIG_CMD_DNS */
417 418 419 420 421 422 423

#if defined(CONFIG_CMD_LINK_LOCAL)
static int do_link_local(cmd_tbl_t *cmdtp, int flag, int argc,
			char * const argv[])
{
	char tmp[22];

424
	if (net_loop(LINKLOCAL) < 0)
425
		return CMD_RET_FAILURE;
426

427 428
	net_gateway.s_addr = 0;
	ip_to_string(net_gateway, tmp);
429 430
	setenv("gatewayip", tmp);

431
	ip_to_string(net_netmask, tmp);
432 433
	setenv("netmask", tmp);

434
	ip_to_string(net_ip, tmp);
435 436 437
	setenv("ipaddr", tmp);
	setenv("llipaddr", tmp); /* store this for next time */

438
	return CMD_RET_SUCCESS;
439 440 441 442 443 444 445 446 447
}

U_BOOT_CMD(
	linklocal,	1,	1,	do_link_local,
	"acquire a network IP address using the link-local protocol",
	""
);

#endif  /* CONFIG_CMD_LINK_LOCAL */