1 /*
2  * (C) Copyright 2000
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23 
24 /*
25  * Boot support
26  */
27 #include <common.h>
28 #include <command.h>
29 #include <net.h>
30 
31 extern int do_bootm (cmd_tbl_t *, int, int, char *[]);
32 
33 static int netboot_common (proto_t, cmd_tbl_t *, int , char *[]);
34 
do_bootp(cmd_tbl_t * cmdtp,int flag,int argc,char * argv[])35 int do_bootp (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
36 {
37 	return netboot_common (BOOTP, cmdtp, argc, argv);
38 }
39 
40 U_BOOT_CMD(
41 	bootp,	3,	1,	do_bootp,
42 	"boot image via network using BOOTP/TFTP protocol",
43 	"[loadAddress] [[hostIPaddr:]bootfilename]"
44 );
45 
do_tftpb(cmd_tbl_t * cmdtp,int flag,int argc,char * argv[])46 int do_tftpb (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
47 {
48 	return netboot_common (TFTP, cmdtp, argc, argv);
49 }
50 
51 U_BOOT_CMD(
52 	tftpboot,	3,	1,	do_tftpb,
53 	"boot image via network using TFTP protocol",
54 	"[loadAddress] [[hostIPaddr:]bootfilename]"
55 );
56 
do_rarpb(cmd_tbl_t * cmdtp,int flag,int argc,char * argv[])57 int do_rarpb (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
58 {
59 	return netboot_common (RARP, cmdtp, argc, argv);
60 }
61 
62 U_BOOT_CMD(
63 	rarpboot,	3,	1,	do_rarpb,
64 	"boot image via network using RARP/TFTP protocol",
65 	"[loadAddress] [[hostIPaddr:]bootfilename]"
66 );
67 
68 #if defined(CONFIG_CMD_DHCP)
do_dhcp(cmd_tbl_t * cmdtp,int flag,int argc,char * argv[])69 int do_dhcp (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
70 {
71 	return netboot_common(DHCP, cmdtp, argc, argv);
72 }
73 
74 U_BOOT_CMD(
75 	dhcp,	3,	1,	do_dhcp,
76 	"boot image via network using DHCP/TFTP protocol",
77 	"[loadAddress] [[hostIPaddr:]bootfilename]"
78 );
79 #endif
80 
81 #if defined(CONFIG_CMD_NFS)
do_nfs(cmd_tbl_t * cmdtp,int flag,int argc,char * argv[])82 int do_nfs (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
83 {
84 	return netboot_common(NFS, cmdtp, argc, argv);
85 }
86 
87 U_BOOT_CMD(
88 	nfs,	3,	1,	do_nfs,
89 	"boot image via network using NFS protocol",
90 	"[loadAddress] [[hostIPaddr:]bootfilename]"
91 );
92 #endif
93 
netboot_update_env(void)94 static void netboot_update_env (void)
95 {
96 	char tmp[22];
97 
98 	if (NetOurGatewayIP) {
99 		ip_to_string (NetOurGatewayIP, tmp);
100 		setenv ("gatewayip", tmp);
101 	}
102 
103 	if (NetOurSubnetMask) {
104 		ip_to_string (NetOurSubnetMask, tmp);
105 		setenv ("netmask", tmp);
106 	}
107 
108 	if (NetOurHostName[0])
109 		setenv ("hostname", NetOurHostName);
110 
111 	if (NetOurRootPath[0])
112 		setenv ("rootpath", NetOurRootPath);
113 
114 	if (NetOurIP) {
115 		ip_to_string (NetOurIP, tmp);
116 		setenv ("ipaddr", tmp);
117 	}
118 
119 	if (NetServerIP) {
120 		ip_to_string (NetServerIP, tmp);
121 		setenv ("serverip", tmp);
122 	}
123 
124 	if (NetOurDNSIP) {
125 		ip_to_string (NetOurDNSIP, tmp);
126 		setenv ("dnsip", tmp);
127 	}
128 #if defined(CONFIG_BOOTP_DNS2)
129 	if (NetOurDNS2IP) {
130 		ip_to_string (NetOurDNS2IP, tmp);
131 		setenv ("dnsip2", tmp);
132 	}
133 #endif
134 	if (NetOurNISDomain[0])
135 		setenv ("domain", NetOurNISDomain);
136 
137 #if defined(CONFIG_CMD_SNTP) \
138     && defined(CONFIG_BOOTP_TIMEOFFSET)
139 	if (NetTimeOffset) {
140 		sprintf (tmp, "%d", NetTimeOffset);
141 		setenv ("timeoffset", tmp);
142 	}
143 #endif
144 #if defined(CONFIG_CMD_SNTP) \
145     && defined(CONFIG_BOOTP_NTPSERVER)
146 	if (NetNtpServerIP) {
147 		ip_to_string (NetNtpServerIP, tmp);
148 		setenv ("ntpserverip", tmp);
149 	}
150 #endif
151 }
152 
153 static int
netboot_common(proto_t proto,cmd_tbl_t * cmdtp,int argc,char * argv[])154 netboot_common (proto_t proto, cmd_tbl_t *cmdtp, int argc, char *argv[])
155 {
156 	char *s;
157 	char *end;
158 	int   rcode = 0;
159 	int   size;
160 	ulong addr;
161 
162 	/* pre-set load_addr */
163 	if ((s = getenv("loadaddr")) != NULL) {
164 		load_addr = simple_strtoul(s, NULL, 16);
165 	}
166 
167 	switch (argc) {
168 	case 1:
169 		break;
170 
171 	case 2:	/*
172 		 * Only one arg - accept two forms:
173 		 * Just load address, or just boot file name. The latter
174 		 * form must be written in a format which can not be
175 		 * mis-interpreted as a valid number.
176 		 */
177 		addr = simple_strtoul(argv[1], &end, 16);
178 		if (end == (argv[1] + strlen(argv[1])))
179 			load_addr = addr;
180 		else
181 			copy_filename(BootFile, argv[1], sizeof(BootFile));
182 		break;
183 
184 	case 3:	load_addr = simple_strtoul(argv[1], NULL, 16);
185 		copy_filename (BootFile, argv[2], sizeof(BootFile));
186 
187 		break;
188 
189 	default: cmd_usage(cmdtp);
190 		show_boot_progress (-80);
191 		return 1;
192 	}
193 
194 	show_boot_progress (80);
195 	if ((size = NetLoop(proto)) < 0) {
196 		show_boot_progress (-81);
197 		return 1;
198 	}
199 
200 	show_boot_progress (81);
201 	/* NetLoop ok, update environment */
202 	netboot_update_env();
203 
204 	/* done if no file was loaded (no errors though) */
205 	if (size == 0) {
206 		show_boot_progress (-82);
207 		return 0;
208 	}
209 
210 	/* flush cache */
211 	flush_cache(load_addr, size);
212 
213 	/* Loading ok, check if we should attempt an auto-start */
214 	if (((s = getenv("autostart")) != NULL) && (strcmp(s,"yes") == 0)) {
215 		char *local_args[2];
216 		local_args[0] = argv[0];
217 		local_args[1] = NULL;
218 
219 		printf ("Automatic boot of image at addr 0x%08lX ...\n",
220 			load_addr);
221 		show_boot_progress (82);
222 		rcode = do_bootm (cmdtp, 0, 1, local_args);
223 	}
224 
225 	if (rcode < 0)
226 		show_boot_progress (-83);
227 	else
228 		show_boot_progress (84);
229 	return rcode;
230 }
231 
232 #if defined(CONFIG_CMD_PING)
do_ping(cmd_tbl_t * cmdtp,int flag,int argc,char * argv[])233 int do_ping (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
234 {
235 	if (argc < 2)
236 		return -1;
237 
238 	NetPingIP = string_to_ip(argv[1]);
239 	if (NetPingIP == 0) {
240 		cmd_usage(cmdtp);
241 		return -1;
242 	}
243 
244 	if (NetLoop(PING) < 0) {
245 		printf("ping failed; host %s is not alive\n", argv[1]);
246 		return 1;
247 	}
248 
249 	printf("host %s is alive\n", argv[1]);
250 
251 	return 0;
252 }
253 
254 U_BOOT_CMD(
255 	ping,	2,	1,	do_ping,
256 	"send ICMP ECHO_REQUEST to network host",
257 	"pingAddress"
258 );
259 #endif
260 
261 #if defined(CONFIG_CMD_CDP)
262 
cdp_update_env(void)263 static void cdp_update_env(void)
264 {
265 	char tmp[16];
266 
267 	if (CDPApplianceVLAN != htons(-1)) {
268 		printf("CDP offered appliance VLAN %d\n", ntohs(CDPApplianceVLAN));
269 		VLAN_to_string(CDPApplianceVLAN, tmp);
270 		setenv("vlan", tmp);
271 		NetOurVLAN = CDPApplianceVLAN;
272 	}
273 
274 	if (CDPNativeVLAN != htons(-1)) {
275 		printf("CDP offered native VLAN %d\n", ntohs(CDPNativeVLAN));
276 		VLAN_to_string(CDPNativeVLAN, tmp);
277 		setenv("nvlan", tmp);
278 		NetOurNativeVLAN = CDPNativeVLAN;
279 	}
280 
281 }
282 
do_cdp(cmd_tbl_t * cmdtp,int flag,int argc,char * argv[])283 int do_cdp (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
284 {
285 	int r;
286 
287 	r = NetLoop(CDP);
288 	if (r < 0) {
289 		printf("cdp failed; perhaps not a CISCO switch?\n");
290 		return 1;
291 	}
292 
293 	cdp_update_env();
294 
295 	return 0;
296 }
297 
298 U_BOOT_CMD(
299 	cdp,	1,	1,	do_cdp,
300 	"Perform CDP network configuration",
301 );
302 #endif
303 
304 #if defined(CONFIG_CMD_SNTP)
do_sntp(cmd_tbl_t * cmdtp,int flag,int argc,char * argv[])305 int do_sntp (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
306 {
307 	char *toff;
308 
309 	if (argc < 2) {
310 		NetNtpServerIP = getenv_IPaddr ("ntpserverip");
311 		if (NetNtpServerIP == 0) {
312 			printf ("ntpserverip not set\n");
313 			return (1);
314 		}
315 	} else {
316 		NetNtpServerIP = string_to_ip(argv[1]);
317 		if (NetNtpServerIP == 0) {
318 			printf ("Bad NTP server IP address\n");
319 			return (1);
320 		}
321 	}
322 
323 	toff = getenv ("timeoffset");
324 	if (toff == NULL) NetTimeOffset = 0;
325 	else NetTimeOffset = simple_strtol (toff, NULL, 10);
326 
327 	if (NetLoop(SNTP) < 0) {
328 		printf("SNTP failed: host %s not responding\n", argv[1]);
329 		return 1;
330 	}
331 
332 	return 0;
333 }
334 
335 U_BOOT_CMD(
336 	sntp,	2,	1,	do_sntp,
337 	"synchronize RTC via network",
338 	"[NTP server IP]\n"
339 );
340 #endif
341 
342 #if defined(CONFIG_CMD_DNS)
do_dns(cmd_tbl_t * cmdtp,int flag,int argc,char * argv[])343 int do_dns(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
344 {
345 	if (argc == 1) {
346 		cmd_usage(cmdtp);
347 		return -1;
348 	}
349 
350 	/*
351 	 * We should check for a valid hostname:
352 	 * - Each label must be between 1 and 63 characters long
353 	 * - the entire hostname has a maximum of 255 characters
354 	 * - only the ASCII letters 'a' through 'z' (case-insensitive),
355 	 *   the digits '0' through '9', and the hyphen
356 	 * - cannot begin or end with a hyphen
357 	 * - no other symbols, punctuation characters, or blank spaces are
358 	 *   permitted
359 	 * but hey - this is a minimalist implmentation, so only check length
360 	 * and let the name server deal with things.
361 	 */
362 	if (strlen(argv[1]) >= 255) {
363 		printf("dns error: hostname too long\n");
364 		return 1;
365 	}
366 
367 	NetDNSResolve = argv[1];
368 
369 	if (argc == 3)
370 		NetDNSenvvar = argv[2];
371 	else
372 		NetDNSenvvar = NULL;
373 
374 	if (NetLoop(DNS) < 0) {
375 		printf("dns lookup of %s failed, check setup\n", argv[1]);
376 		return 1;
377 	}
378 
379 	return 0;
380 }
381 
382 U_BOOT_CMD(
383 	dns,	3,	1,	do_dns,
384 	"lookup the IP of a hostname",
385 	"hostname [envvar]"
386 );
387 
388 #endif	/* CONFIG_CMD_DNS */
389