1
2
3
4
5
6
7
8
9
10#include <common.h>
11#include <bootstage.h>
12#include <command.h>
13#include <dm.h>
14#include <env.h>
15#include <image.h>
16#include <net.h>
17#include <net/udp.h>
18#include <net/sntp.h>
19
20static int netboot_common(enum proto_t, struct cmd_tbl *, int, char * const []);
21
22#ifdef CONFIG_CMD_BOOTP
23static int do_bootp(struct cmd_tbl *cmdtp, int flag, int argc,
24 char *const argv[])
25{
26 return netboot_common(BOOTP, cmdtp, argc, argv);
27}
28
29U_BOOT_CMD(
30 bootp, 3, 1, do_bootp,
31 "boot image via network using BOOTP/TFTP protocol",
32 "[loadAddress] [[hostIPaddr:]bootfilename]"
33);
34#endif
35
36#ifdef CONFIG_CMD_TFTPBOOT
37int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
38{
39 int ret;
40
41 bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start");
42 ret = netboot_common(TFTPGET, cmdtp, argc, argv);
43 bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done");
44 return ret;
45}
46
47U_BOOT_CMD(
48 tftpboot, 3, 1, do_tftpb,
49 "boot image via network using TFTP protocol",
50 "[loadAddress] [[hostIPaddr:]bootfilename]"
51);
52#endif
53
54#ifdef CONFIG_CMD_TFTPPUT
55static int do_tftpput(struct cmd_tbl *cmdtp, int flag, int argc,
56 char *const argv[])
57{
58 return netboot_common(TFTPPUT, cmdtp, argc, argv);
59}
60
61U_BOOT_CMD(
62 tftpput, 4, 1, do_tftpput,
63 "TFTP put command, for uploading files to a server",
64 "Address Size [[hostIPaddr:]filename]"
65);
66#endif
67
68#ifdef CONFIG_CMD_TFTPSRV
69static int do_tftpsrv(struct cmd_tbl *cmdtp, int flag, int argc,
70 char *const argv[])
71{
72 return netboot_common(TFTPSRV, cmdtp, argc, argv);
73}
74
75U_BOOT_CMD(
76 tftpsrv, 2, 1, do_tftpsrv,
77 "act as a TFTP server and boot the first received file",
78 "[loadAddress]\n"
79 "Listen for an incoming TFTP transfer, receive a file and boot it.\n"
80 "The transfer is aborted if a transfer has not been started after\n"
81 "about 50 seconds or if Ctrl-C is pressed."
82);
83#endif
84
85
86#ifdef CONFIG_CMD_RARP
87int do_rarpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
88{
89 return netboot_common(RARP, cmdtp, argc, argv);
90}
91
92U_BOOT_CMD(
93 rarpboot, 3, 1, do_rarpb,
94 "boot image via network using RARP/TFTP protocol",
95 "[loadAddress] [[hostIPaddr:]bootfilename]"
96);
97#endif
98
99#if defined(CONFIG_CMD_DHCP)
100static int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc,
101 char *const argv[])
102{
103 return netboot_common(DHCP, cmdtp, argc, argv);
104}
105
106U_BOOT_CMD(
107 dhcp, 3, 1, do_dhcp,
108 "boot image via network using DHCP/TFTP protocol",
109 "[loadAddress] [[hostIPaddr:]bootfilename]"
110);
111#endif
112
113#if defined(CONFIG_CMD_NFS)
114static int do_nfs(struct cmd_tbl *cmdtp, int flag, int argc,
115 char *const argv[])
116{
117 return netboot_common(NFS, cmdtp, argc, argv);
118}
119
120U_BOOT_CMD(
121 nfs, 3, 1, do_nfs,
122 "boot image via network using NFS protocol",
123 "[loadAddress] [[hostIPaddr:]bootfilename]"
124);
125#endif
126
127static void netboot_update_env(void)
128{
129 char tmp[22];
130
131 if (net_gateway.s_addr) {
132 ip_to_string(net_gateway, tmp);
133 env_set("gatewayip", tmp);
134 }
135
136 if (net_netmask.s_addr) {
137 ip_to_string(net_netmask, tmp);
138 env_set("netmask", tmp);
139 }
140
141#ifdef CONFIG_CMD_BOOTP
142 if (net_hostname[0])
143 env_set("hostname", net_hostname);
144#endif
145
146#ifdef CONFIG_CMD_BOOTP
147 if (net_root_path[0])
148 env_set("rootpath", net_root_path);
149#endif
150
151 if (net_ip.s_addr) {
152 ip_to_string(net_ip, tmp);
153 env_set("ipaddr", tmp);
154 }
155#if !defined(CONFIG_BOOTP_SERVERIP)
156
157
158
159
160 if (net_server_ip.s_addr) {
161 ip_to_string(net_server_ip, tmp);
162 env_set("serverip", tmp);
163 }
164#endif
165 if (net_dns_server.s_addr) {
166 ip_to_string(net_dns_server, tmp);
167 env_set("dnsip", tmp);
168 }
169#if defined(CONFIG_BOOTP_DNS2)
170 if (net_dns_server2.s_addr) {
171 ip_to_string(net_dns_server2, tmp);
172 env_set("dnsip2", tmp);
173 }
174#endif
175#ifdef CONFIG_CMD_BOOTP
176 if (net_nis_domain[0])
177 env_set("domain", net_nis_domain);
178#endif
179
180#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
181 if (net_ntp_time_offset) {
182 sprintf(tmp, "%d", net_ntp_time_offset);
183 env_set("timeoffset", tmp);
184 }
185#endif
186#if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
187 if (net_ntp_server.s_addr) {
188 ip_to_string(net_ntp_server, tmp);
189 env_set("ntpserverip", tmp);
190 }
191#endif
192}
193
194static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc,
195 char *const argv[])
196{
197 char *s;
198 char *end;
199 int rcode = 0;
200 int size;
201 ulong addr;
202
203 net_boot_file_name_explicit = false;
204
205
206 s = env_get("loadaddr");
207 if (s != NULL)
208 image_load_addr = hextoul(s, NULL);
209
210 switch (argc) {
211 case 1:
212
213 copy_filename(net_boot_file_name, env_get("bootfile"),
214 sizeof(net_boot_file_name));
215 break;
216
217 case 2:
218
219
220
221
222
223 addr = hextoul(argv[1], &end);
224 if (end == (argv[1] + strlen(argv[1]))) {
225 image_load_addr = addr;
226
227 copy_filename(net_boot_file_name, env_get("bootfile"),
228 sizeof(net_boot_file_name));
229 } else {
230 net_boot_file_name_explicit = true;
231 copy_filename(net_boot_file_name, argv[1],
232 sizeof(net_boot_file_name));
233 }
234 break;
235
236 case 3:
237 image_load_addr = hextoul(argv[1], NULL);
238 net_boot_file_name_explicit = true;
239 copy_filename(net_boot_file_name, argv[2],
240 sizeof(net_boot_file_name));
241
242 break;
243
244#ifdef CONFIG_CMD_TFTPPUT
245 case 4:
246 if (strict_strtoul(argv[1], 16, &image_save_addr) < 0 ||
247 strict_strtoul(argv[2], 16, &image_save_size) < 0) {
248 printf("Invalid address/size\n");
249 return CMD_RET_USAGE;
250 }
251 net_boot_file_name_explicit = true;
252 copy_filename(net_boot_file_name, argv[3],
253 sizeof(net_boot_file_name));
254 break;
255#endif
256 default:
257 bootstage_error(BOOTSTAGE_ID_NET_START);
258 return CMD_RET_USAGE;
259 }
260 bootstage_mark(BOOTSTAGE_ID_NET_START);
261
262 size = net_loop(proto);
263 if (size < 0) {
264 bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK);
265 return CMD_RET_FAILURE;
266 }
267 bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK);
268
269
270 netboot_update_env();
271
272
273 if (size == 0) {
274 bootstage_error(BOOTSTAGE_ID_NET_LOADED);
275 return CMD_RET_SUCCESS;
276 }
277
278 bootstage_mark(BOOTSTAGE_ID_NET_LOADED);
279
280 rcode = bootm_maybe_autostart(cmdtp, argv[0]);
281
282 if (rcode == CMD_RET_SUCCESS)
283 bootstage_mark(BOOTSTAGE_ID_NET_DONE);
284 else
285 bootstage_error(BOOTSTAGE_ID_NET_DONE_ERR);
286 return rcode;
287}
288
289#if defined(CONFIG_CMD_PING)
290static int do_ping(struct cmd_tbl *cmdtp, int flag, int argc,
291 char *const argv[])
292{
293 if (argc < 2)
294 return CMD_RET_USAGE;
295
296 net_ping_ip = string_to_ip(argv[1]);
297 if (net_ping_ip.s_addr == 0)
298 return CMD_RET_USAGE;
299
300 if (net_loop(PING) < 0) {
301 printf("ping failed; host %s is not alive\n", argv[1]);
302 return CMD_RET_FAILURE;
303 }
304
305 printf("host %s is alive\n", argv[1]);
306
307 return CMD_RET_SUCCESS;
308}
309
310U_BOOT_CMD(
311 ping, 2, 1, do_ping,
312 "send ICMP ECHO_REQUEST to network host",
313 "pingAddress"
314);
315#endif
316
317#if defined(CONFIG_CMD_CDP)
318
319static void cdp_update_env(void)
320{
321 char tmp[16];
322
323 if (cdp_appliance_vlan != htons(-1)) {
324 printf("CDP offered appliance VLAN %d\n",
325 ntohs(cdp_appliance_vlan));
326 vlan_to_string(cdp_appliance_vlan, tmp);
327 env_set("vlan", tmp);
328 net_our_vlan = cdp_appliance_vlan;
329 }
330
331 if (cdp_native_vlan != htons(-1)) {
332 printf("CDP offered native VLAN %d\n", ntohs(cdp_native_vlan));
333 vlan_to_string(cdp_native_vlan, tmp);
334 env_set("nvlan", tmp);
335 net_native_vlan = cdp_native_vlan;
336 }
337}
338
339int do_cdp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
340{
341 int r;
342
343 r = net_loop(CDP);
344 if (r < 0) {
345 printf("cdp failed; perhaps not a CISCO switch?\n");
346 return CMD_RET_FAILURE;
347 }
348
349 cdp_update_env();
350
351 return CMD_RET_SUCCESS;
352}
353
354U_BOOT_CMD(
355 cdp, 1, 1, do_cdp,
356 "Perform CDP network configuration",
357 "\n"
358);
359#endif
360
361#if defined(CONFIG_CMD_SNTP)
362static struct udp_ops sntp_ops = {
363 .prereq = sntp_prereq,
364 .start = sntp_start,
365 .data = NULL,
366};
367
368int do_sntp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
369{
370 char *toff;
371
372 if (argc < 2) {
373 net_ntp_server = env_get_ip("ntpserverip");
374 if (net_ntp_server.s_addr == 0) {
375 printf("ntpserverip not set\n");
376 return CMD_RET_FAILURE;
377 }
378 } else {
379 net_ntp_server = string_to_ip(argv[1]);
380 if (net_ntp_server.s_addr == 0) {
381 printf("Bad NTP server IP address\n");
382 return CMD_RET_FAILURE;
383 }
384 }
385
386 toff = env_get("timeoffset");
387 if (toff == NULL)
388 net_ntp_time_offset = 0;
389 else
390 net_ntp_time_offset = simple_strtol(toff, NULL, 10);
391
392 if (udp_loop(&sntp_ops) < 0) {
393 printf("SNTP failed: host %pI4 not responding\n",
394 &net_ntp_server);
395 return CMD_RET_FAILURE;
396 }
397
398 return CMD_RET_SUCCESS;
399}
400
401U_BOOT_CMD(
402 sntp, 2, 1, do_sntp,
403 "synchronize RTC via network",
404 "[NTP server IP]\n"
405);
406#endif
407
408#if defined(CONFIG_CMD_DNS)
409int do_dns(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
410{
411 if (argc == 1)
412 return CMD_RET_USAGE;
413
414
415
416
417
418
419
420
421
422
423
424
425
426 if (strlen(argv[1]) >= 255) {
427 printf("dns error: hostname too long\n");
428 return CMD_RET_FAILURE;
429 }
430
431 net_dns_resolve = argv[1];
432
433 if (argc == 3)
434 net_dns_env_var = argv[2];
435 else
436 net_dns_env_var = NULL;
437
438 if (net_loop(DNS) < 0) {
439 printf("dns lookup of %s failed, check setup\n", argv[1]);
440 return CMD_RET_FAILURE;
441 }
442
443 return CMD_RET_SUCCESS;
444}
445
446U_BOOT_CMD(
447 dns, 3, 1, do_dns,
448 "lookup the IP of a hostname",
449 "hostname [envvar]"
450);
451
452#endif
453
454#if defined(CONFIG_CMD_LINK_LOCAL)
455static int do_link_local(struct cmd_tbl *cmdtp, int flag, int argc,
456 char *const argv[])
457{
458 char tmp[22];
459
460 if (net_loop(LINKLOCAL) < 0)
461 return CMD_RET_FAILURE;
462
463 net_gateway.s_addr = 0;
464 ip_to_string(net_gateway, tmp);
465 env_set("gatewayip", tmp);
466
467 ip_to_string(net_netmask, tmp);
468 env_set("netmask", tmp);
469
470 ip_to_string(net_ip, tmp);
471 env_set("ipaddr", tmp);
472 env_set("llipaddr", tmp);
473
474 return CMD_RET_SUCCESS;
475}
476
477U_BOOT_CMD(
478 linklocal, 1, 1, do_link_local,
479 "acquire a network IP address using the link-local protocol",
480 ""
481);
482
483#endif
484
485#ifdef CONFIG_DM_ETH
486static int do_net_list(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
487{
488 const struct udevice *current = eth_get_dev();
489 unsigned char env_enetaddr[ARP_HLEN];
490 const struct udevice *dev;
491 struct uclass *uc;
492
493 uclass_id_foreach_dev(UCLASS_ETH, dev, uc) {
494 eth_env_get_enetaddr_by_index("eth", dev_seq(dev), env_enetaddr);
495 printf("eth%d : %s %pM %s\n", dev_seq(dev), dev->name, env_enetaddr,
496 current == dev ? "active" : "");
497 }
498 return CMD_RET_SUCCESS;
499}
500
501static struct cmd_tbl cmd_net[] = {
502 U_BOOT_CMD_MKENT(list, 1, 0, do_net_list, "", ""),
503};
504
505static int do_net(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
506{
507 struct cmd_tbl *cp;
508
509 cp = find_cmd_tbl(argv[1], cmd_net, ARRAY_SIZE(cmd_net));
510
511
512 argc--;
513 argv++;
514
515 if (!cp || argc > cp->maxargs)
516 return CMD_RET_USAGE;
517 if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
518 return CMD_RET_SUCCESS;
519
520 return cp->cmd(cmdtp, flag, argc, argv);
521}
522
523U_BOOT_CMD(
524 net, 2, 1, do_net,
525 "NET sub-system",
526 "list - list available devices\n"
527);
528#endif
529