cmd_net.c 9.3 KB
Newer Older
wdenk's avatar
wdenk committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
/*
 * (C) Copyright 2000
 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

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

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

33
int do_bootp (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
wdenk's avatar
wdenk committed
34 35 36 37
{
	return netboot_common (BOOTP, cmdtp, argc, argv);
}

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

44
int do_tftpb (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
wdenk's avatar
wdenk committed
45
{
46 47 48 49 50 51
	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
52 53
}

54 55
U_BOOT_CMD(
	tftpboot,	3,	1,	do_tftpb,
Peter Tyser's avatar
Peter Tyser committed
56
	"boot image via network using TFTP protocol",
Wolfgang Denk's avatar
Wolfgang Denk committed
57
	"[loadAddress] [[hostIPaddr:]bootfilename]"
wdenk's avatar
wdenk committed
58 59
);

60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
#ifdef CONFIG_CMD_TFTPPUT
int do_tftpput(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	int ret;

	ret = netboot_common(TFTPPUT, cmdtp, argc, argv);
	return ret;
}

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

Luca Ceresoli's avatar
Luca Ceresoli committed
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
#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


93
#ifdef CONFIG_CMD_RARP
94
int do_rarpb (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
wdenk's avatar
wdenk committed
95 96 97 98
{
	return netboot_common (RARP, cmdtp, argc, argv);
}

99 100
U_BOOT_CMD(
	rarpboot,	3,	1,	do_rarpb,
Peter Tyser's avatar
Peter Tyser committed
101
	"boot image via network using RARP/TFTP protocol",
Wolfgang Denk's avatar
Wolfgang Denk committed
102
	"[loadAddress] [[hostIPaddr:]bootfilename]"
wdenk's avatar
wdenk committed
103
);
104
#endif
wdenk's avatar
wdenk committed
105

106
#if defined(CONFIG_CMD_DHCP)
107
int do_dhcp (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
wdenk's avatar
wdenk committed
108 109 110
{
	return netboot_common(DHCP, cmdtp, argc, argv);
}
wdenk's avatar
wdenk committed
111

112 113
U_BOOT_CMD(
	dhcp,	3,	1,	do_dhcp,
Peter Tyser's avatar
Peter Tyser committed
114
	"boot image via network using DHCP/TFTP protocol",
Wolfgang Denk's avatar
Wolfgang Denk committed
115
	"[loadAddress] [[hostIPaddr:]bootfilename]"
wdenk's avatar
wdenk committed
116
);
117
#endif
wdenk's avatar
wdenk committed
118

119
#if defined(CONFIG_CMD_NFS)
120
int do_nfs (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
wdenk's avatar
wdenk committed
121 122 123 124 125 126
{
	return netboot_common(NFS, cmdtp, argc, argv);
}

U_BOOT_CMD(
	nfs,	3,	1,	do_nfs,
Peter Tyser's avatar
Peter Tyser committed
127
	"boot image via network using NFS protocol",
Wolfgang Denk's avatar
Wolfgang Denk committed
128
	"[loadAddress] [[hostIPaddr:]bootfilename]"
wdenk's avatar
wdenk committed
129
);
130
#endif
wdenk's avatar
wdenk committed
131

wdenk's avatar
wdenk committed
132
static void netboot_update_env (void)
wdenk's avatar
wdenk committed
133
{
wdenk's avatar
wdenk committed
134
	char tmp[22];
wdenk's avatar
wdenk committed
135

wdenk's avatar
wdenk committed
136 137 138 139
	if (NetOurGatewayIP) {
		ip_to_string (NetOurGatewayIP, tmp);
		setenv ("gatewayip", tmp);
	}
wdenk's avatar
wdenk committed
140

wdenk's avatar
wdenk committed
141 142 143 144
	if (NetOurSubnetMask) {
		ip_to_string (NetOurSubnetMask, tmp);
		setenv ("netmask", tmp);
	}
wdenk's avatar
wdenk committed
145

wdenk's avatar
wdenk committed
146 147
	if (NetOurHostName[0])
		setenv ("hostname", NetOurHostName);
wdenk's avatar
wdenk committed
148

wdenk's avatar
wdenk committed
149 150
	if (NetOurRootPath[0])
		setenv ("rootpath", NetOurRootPath);
wdenk's avatar
wdenk committed
151

wdenk's avatar
wdenk committed
152 153 154 155
	if (NetOurIP) {
		ip_to_string (NetOurIP, tmp);
		setenv ("ipaddr", tmp);
	}
wdenk's avatar
wdenk committed
156

wdenk's avatar
wdenk committed
157 158 159 160
	if (NetServerIP) {
		ip_to_string (NetServerIP, tmp);
		setenv ("serverip", tmp);
	}
wdenk's avatar
wdenk committed
161

wdenk's avatar
wdenk committed
162 163 164 165
	if (NetOurDNSIP) {
		ip_to_string (NetOurDNSIP, tmp);
		setenv ("dnsip", tmp);
	}
166
#if defined(CONFIG_BOOTP_DNS2)
wdenk's avatar
wdenk committed
167 168 169 170
	if (NetOurDNS2IP) {
		ip_to_string (NetOurDNS2IP, tmp);
		setenv ("dnsip2", tmp);
	}
171
#endif
wdenk's avatar
wdenk committed
172 173
	if (NetOurNISDomain[0])
		setenv ("domain", NetOurNISDomain);
wdenk's avatar
wdenk committed
174

175
#if defined(CONFIG_CMD_SNTP) \
176
    && defined(CONFIG_BOOTP_TIMEOFFSET)
wdenk's avatar
wdenk committed
177 178 179 180 181
	if (NetTimeOffset) {
		sprintf (tmp, "%d", NetTimeOffset);
		setenv ("timeoffset", tmp);
	}
#endif
182
#if defined(CONFIG_CMD_SNTP) \
183
    && defined(CONFIG_BOOTP_NTPSERVER)
wdenk's avatar
wdenk committed
184 185 186 187 188
	if (NetNtpServerIP) {
		ip_to_string (NetNtpServerIP, tmp);
		setenv ("ntpserverip", tmp);
	}
#endif
wdenk's avatar
wdenk committed
189
}
wdenk's avatar
wdenk committed
190

191 192
static int netboot_common(enum proto_t proto, cmd_tbl_t *cmdtp, int argc,
		char * const argv[])
wdenk's avatar
wdenk committed
193 194
{
	char *s;
195
	char *end;
wdenk's avatar
wdenk committed
196 197
	int   rcode = 0;
	int   size;
198
	ulong addr;
wdenk's avatar
wdenk committed
199 200 201 202 203 204 205 206 207 208

	/* pre-set load_addr */
	if ((s = getenv("loadaddr")) != NULL) {
		load_addr = simple_strtoul(s, NULL, 16);
	}

	switch (argc) {
	case 1:
		break;

209 210 211 212 213
	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
214
		 */
215 216 217 218 219
		addr = simple_strtoul(argv[1], &end, 16);
		if (end == (argv[1] + strlen(argv[1])))
			load_addr = addr;
		else
			copy_filename(BootFile, argv[1], sizeof(BootFile));
wdenk's avatar
wdenk committed
220 221 222 223 224 225 226
		break;

	case 3:	load_addr = simple_strtoul(argv[1], NULL, 16);
		copy_filename (BootFile, argv[2], sizeof(BootFile));

		break;

227 228
#ifdef CONFIG_CMD_TFTPPUT
	case 4:
229 230 231 232 233
		if (strict_strtoul(argv[1], 16, &save_addr) < 0 ||
			strict_strtoul(argv[2], 16, &save_size) < 0) {
			printf("Invalid address/size\n");
			return cmd_usage(cmdtp);
		}
234 235 236
		copy_filename(BootFile, argv[3], sizeof(BootFile));
		break;
#endif
237
	default:
238
		bootstage_error(BOOTSTAGE_ID_NET_START);
239
		return CMD_RET_USAGE;
wdenk's avatar
wdenk committed
240
	}
241
	bootstage_mark(BOOTSTAGE_ID_NET_START);
wdenk's avatar
wdenk committed
242

243
	if ((size = NetLoop(proto)) < 0) {
244
		bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK);
wdenk's avatar
wdenk committed
245
		return 1;
246
	}
247
	bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK);
wdenk's avatar
wdenk committed
248 249 250 251

	/* NetLoop ok, update environment */
	netboot_update_env();

252
	/* done if no file was loaded (no errors though) */
253
	if (size == 0) {
254
		bootstage_error(BOOTSTAGE_ID_NET_LOADED);
255
		return 0;
256
	}
257

wdenk's avatar
wdenk committed
258 259 260
	/* flush cache */
	flush_cache(load_addr, size);

261
	bootstage_mark(BOOTSTAGE_ID_NET_LOADED);
262

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

265
	if (rcode < 0)
266
		bootstage_error(BOOTSTAGE_ID_NET_DONE_ERR);
267
	else
268
		bootstage_mark(BOOTSTAGE_ID_NET_DONE);
wdenk's avatar
wdenk committed
269 270 271
	return rcode;
}

272
#if defined(CONFIG_CMD_PING)
273
int do_ping (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
wdenk's avatar
wdenk committed
274 275 276 277 278
{
	if (argc < 2)
		return -1;

	NetPingIP = string_to_ip(argv[1]);
279
	if (NetPingIP == 0)
280
		return CMD_RET_USAGE;
wdenk's avatar
wdenk committed
281 282 283 284 285 286 287 288 289 290

	if (NetLoop(PING) < 0) {
		printf("ping failed; host %s is not alive\n", argv[1]);
		return 1;
	}

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

	return 0;
}
291 292 293

U_BOOT_CMD(
	ping,	2,	1,	do_ping,
Peter Tyser's avatar
Peter Tyser committed
294
	"send ICMP ECHO_REQUEST to network host",
Wolfgang Denk's avatar
Wolfgang Denk committed
295
	"pingAddress"
296
);
297
#endif
wdenk's avatar
wdenk committed
298

299
#if defined(CONFIG_CMD_CDP)
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320

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

	if (CDPApplianceVLAN != htons(-1)) {
		printf("CDP offered appliance VLAN %d\n", ntohs(CDPApplianceVLAN));
		VLAN_to_string(CDPApplianceVLAN, tmp);
		setenv("vlan", tmp);
		NetOurVLAN = CDPApplianceVLAN;
	}

	if (CDPNativeVLAN != htons(-1)) {
		printf("CDP offered native VLAN %d\n", ntohs(CDPNativeVLAN));
		VLAN_to_string(CDPNativeVLAN, tmp);
		setenv("nvlan", tmp);
		NetOurNativeVLAN = CDPNativeVLAN;
	}

}

321
int do_cdp (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
{
	int r;

	r = NetLoop(CDP);
	if (r < 0) {
		printf("cdp failed; perhaps not a CISCO switch?\n");
		return 1;
	}

	cdp_update_env();

	return 0;
}

U_BOOT_CMD(
	cdp,	1,	1,	do_cdp,
338
	"Perform CDP network configuration",
Wolfgang Denk's avatar
Wolfgang Denk committed
339
	"\n"
340
);
341
#endif
342

343
#if defined(CONFIG_CMD_SNTP)
344
int do_sntp (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
wdenk's avatar
wdenk committed
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
{
	char *toff;

	if (argc < 2) {
		NetNtpServerIP = getenv_IPaddr ("ntpserverip");
		if (NetNtpServerIP == 0) {
			printf ("ntpserverip not set\n");
			return (1);
		}
	} else {
		NetNtpServerIP = string_to_ip(argv[1]);
		if (NetNtpServerIP == 0) {
			printf ("Bad NTP server IP address\n");
			return (1);
		}
	}

	toff = getenv ("timeoffset");
	if (toff == NULL) NetTimeOffset = 0;
	else NetTimeOffset = simple_strtol (toff, NULL, 10);

	if (NetLoop(SNTP) < 0) {
367 368
		printf("SNTP failed: host %pI4 not responding\n",
			&NetNtpServerIP);
wdenk's avatar
wdenk committed
369 370 371 372 373 374 375 376
		return 1;
	}

	return 0;
}

U_BOOT_CMD(
	sntp,	2,	1,	do_sntp,
Peter Tyser's avatar
Peter Tyser committed
377
	"synchronize RTC via network",
wdenk's avatar
wdenk committed
378 379
	"[NTP server IP]\n"
);
380
#endif
Robin Getz's avatar
Robin Getz committed
381 382

#if defined(CONFIG_CMD_DNS)
383
int do_dns(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
Robin Getz's avatar
Robin Getz committed
384
{
385
	if (argc == 1)
386
		return CMD_RET_USAGE;
Robin Getz's avatar
Robin Getz committed
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426

	/*
	 * 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");
		return 1;
	}

	NetDNSResolve = argv[1];

	if (argc == 3)
		NetDNSenvvar = argv[2];
	else
		NetDNSenvvar = NULL;

	if (NetLoop(DNS) < 0) {
		printf("dns lookup of %s failed, check setup\n", argv[1]);
		return 1;
	}

	return 0;
}

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

#endif	/* CONFIG_CMD_DNS */