Merge tag 'u-boot-amlogic-20220107' of https://source.denx.de/u-boot/custodians/u...
[platform/kernel/u-boot.git] / cmd / net.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2000
4  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5  */
6
7 /*
8  * Boot support
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
20 static int netboot_common(enum proto_t, struct cmd_tbl *, int, char * const []);
21
22 #ifdef CONFIG_CMD_BOOTP
23 static 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
29 U_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
37 int 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
47 U_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
55 static 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
61 U_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
69 static 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
75 U_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
87 int do_rarpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
88 {
89         return netboot_common(RARP, cmdtp, argc, argv);
90 }
91
92 U_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)
100 static 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
106 U_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)
114 static 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
120 U_BOOT_CMD(
121         nfs,    3,      1,      do_nfs,
122         "boot image via network using NFS protocol",
123         "[loadAddress] [[hostIPaddr:]bootfilename]"
124 );
125 #endif
126
127 static 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          * Only attempt to change serverip if net/bootp.c:store_net_params()
158          * could have set it
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
194 static 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         /* pre-set image_load_addr */
206         s = env_get("loadaddr");
207         if (s != NULL)
208                 image_load_addr = hextoul(s, NULL);
209
210         switch (argc) {
211         case 1:
212                 /* refresh bootfile name from env */
213                 copy_filename(net_boot_file_name, env_get("bootfile"),
214                               sizeof(net_boot_file_name));
215                 break;
216
217         case 2: /*
218                  * Only one arg - accept two forms:
219                  * Just load address, or just boot file name. The latter
220                  * form must be written in a format which can not be
221                  * mis-interpreted as a valid number.
222                  */
223                 addr = hextoul(argv[1], &end);
224                 if (end == (argv[1] + strlen(argv[1]))) {
225                         image_load_addr = addr;
226                         /* refresh bootfile name from env */
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         /* net_loop ok, update environment */
270         netboot_update_env();
271
272         /* done if no file was loaded (no errors though) */
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)
290 static 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
310 U_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
319 static 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
339 int 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
354 U_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)
362 static struct udp_ops sntp_ops = {
363         .prereq = sntp_prereq,
364         .start = sntp_start,
365         .data = NULL,
366 };
367
368 int 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
401 U_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)
409 int 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          * We should check for a valid hostname:
416          * - Each label must be between 1 and 63 characters long
417          * - the entire hostname has a maximum of 255 characters
418          * - only the ASCII letters 'a' through 'z' (case-insensitive),
419          *   the digits '0' through '9', and the hyphen
420          * - cannot begin or end with a hyphen
421          * - no other symbols, punctuation characters, or blank spaces are
422          *   permitted
423          * but hey - this is a minimalist implmentation, so only check length
424          * and let the name server deal with things.
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
446 U_BOOT_CMD(
447         dns,    3,      1,      do_dns,
448         "lookup the IP of a hostname",
449         "hostname [envvar]"
450 );
451
452 #endif  /* CONFIG_CMD_DNS */
453
454 #if defined(CONFIG_CMD_LINK_LOCAL)
455 static 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); /* store this for next time */
473
474         return CMD_RET_SUCCESS;
475 }
476
477 U_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  /* CONFIG_CMD_LINK_LOCAL */
484
485 #ifdef CONFIG_DM_ETH
486 static 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
501 static struct cmd_tbl cmd_net[] = {
502         U_BOOT_CMD_MKENT(list, 1, 0, do_net_list, "", ""),
503 };
504
505 static 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         /* Drop the net command */
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
523 U_BOOT_CMD(
524         net, 2, 1, do_net,
525         "NET sub-system",
526         "list - list available devices\n"
527 );
528 #endif // CONFIG_DM_ETH