Merge tag 'for-v2022.10' of https://source.denx.de/u-boot/custodians/u-boot-i2c
[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         /*
156          * Only attempt to change serverip if net/bootp.c:store_net_params()
157          * could have set it
158          */
159         if (!IS_ENABLED(CONFIG_BOOTP_SERVERIP) && net_server_ip.s_addr) {
160                 ip_to_string(net_server_ip, tmp);
161                 env_set("serverip", tmp);
162         }
163         if (net_dns_server.s_addr) {
164                 ip_to_string(net_dns_server, tmp);
165                 env_set("dnsip", tmp);
166         }
167 #if defined(CONFIG_BOOTP_DNS2)
168         if (net_dns_server2.s_addr) {
169                 ip_to_string(net_dns_server2, tmp);
170                 env_set("dnsip2", tmp);
171         }
172 #endif
173 #ifdef CONFIG_CMD_BOOTP
174         if (net_nis_domain[0])
175                 env_set("domain", net_nis_domain);
176 #endif
177
178 #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
179         if (net_ntp_time_offset) {
180                 sprintf(tmp, "%d", net_ntp_time_offset);
181                 env_set("timeoffset", tmp);
182         }
183 #endif
184 #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
185         if (net_ntp_server.s_addr) {
186                 ip_to_string(net_ntp_server, tmp);
187                 env_set("ntpserverip", tmp);
188         }
189 #endif
190 }
191
192 static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc,
193                           char *const argv[])
194 {
195         char *s;
196         char *end;
197         int   rcode = 0;
198         int   size;
199         ulong addr;
200
201         net_boot_file_name_explicit = false;
202
203         /* pre-set image_load_addr */
204         s = env_get("loadaddr");
205         if (s != NULL)
206                 image_load_addr = hextoul(s, NULL);
207
208         switch (argc) {
209         case 1:
210                 /* refresh bootfile name from env */
211                 copy_filename(net_boot_file_name, env_get("bootfile"),
212                               sizeof(net_boot_file_name));
213                 break;
214
215         case 2: /*
216                  * Only one arg - accept two forms:
217                  * Just load address, or just boot file name. The latter
218                  * form must be written in a format which can not be
219                  * mis-interpreted as a valid number.
220                  */
221                 addr = hextoul(argv[1], &end);
222                 if (end == (argv[1] + strlen(argv[1]))) {
223                         image_load_addr = addr;
224                         /* refresh bootfile name from env */
225                         copy_filename(net_boot_file_name, env_get("bootfile"),
226                                       sizeof(net_boot_file_name));
227                 } else {
228                         net_boot_file_name_explicit = true;
229                         copy_filename(net_boot_file_name, argv[1],
230                                       sizeof(net_boot_file_name));
231                 }
232                 break;
233
234         case 3:
235                 image_load_addr = hextoul(argv[1], NULL);
236                 net_boot_file_name_explicit = true;
237                 copy_filename(net_boot_file_name, argv[2],
238                               sizeof(net_boot_file_name));
239
240                 break;
241
242 #ifdef CONFIG_CMD_TFTPPUT
243         case 4:
244                 if (strict_strtoul(argv[1], 16, &image_save_addr) < 0 ||
245                     strict_strtoul(argv[2], 16, &image_save_size) < 0) {
246                         printf("Invalid address/size\n");
247                         return CMD_RET_USAGE;
248                 }
249                 net_boot_file_name_explicit = true;
250                 copy_filename(net_boot_file_name, argv[3],
251                               sizeof(net_boot_file_name));
252                 break;
253 #endif
254         default:
255                 bootstage_error(BOOTSTAGE_ID_NET_START);
256                 return CMD_RET_USAGE;
257         }
258         bootstage_mark(BOOTSTAGE_ID_NET_START);
259
260         size = net_loop(proto);
261         if (size < 0) {
262                 bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK);
263                 return CMD_RET_FAILURE;
264         }
265         bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK);
266
267         /* net_loop ok, update environment */
268         netboot_update_env();
269
270         /* done if no file was loaded (no errors though) */
271         if (size == 0) {
272                 bootstage_error(BOOTSTAGE_ID_NET_LOADED);
273                 return CMD_RET_SUCCESS;
274         }
275
276         bootstage_mark(BOOTSTAGE_ID_NET_LOADED);
277
278         rcode = bootm_maybe_autostart(cmdtp, argv[0]);
279
280         if (rcode == CMD_RET_SUCCESS)
281                 bootstage_mark(BOOTSTAGE_ID_NET_DONE);
282         else
283                 bootstage_error(BOOTSTAGE_ID_NET_DONE_ERR);
284         return rcode;
285 }
286
287 #if defined(CONFIG_CMD_PING)
288 static int do_ping(struct cmd_tbl *cmdtp, int flag, int argc,
289                    char *const argv[])
290 {
291         if (argc < 2)
292                 return CMD_RET_USAGE;
293
294         net_ping_ip = string_to_ip(argv[1]);
295         if (net_ping_ip.s_addr == 0)
296                 return CMD_RET_USAGE;
297
298         if (net_loop(PING) < 0) {
299                 printf("ping failed; host %s is not alive\n", argv[1]);
300                 return CMD_RET_FAILURE;
301         }
302
303         printf("host %s is alive\n", argv[1]);
304
305         return CMD_RET_SUCCESS;
306 }
307
308 U_BOOT_CMD(
309         ping,   2,      1,      do_ping,
310         "send ICMP ECHO_REQUEST to network host",
311         "pingAddress"
312 );
313 #endif
314
315 #if defined(CONFIG_CMD_CDP)
316
317 static void cdp_update_env(void)
318 {
319         char tmp[16];
320
321         if (cdp_appliance_vlan != htons(-1)) {
322                 printf("CDP offered appliance VLAN %d\n",
323                        ntohs(cdp_appliance_vlan));
324                 vlan_to_string(cdp_appliance_vlan, tmp);
325                 env_set("vlan", tmp);
326                 net_our_vlan = cdp_appliance_vlan;
327         }
328
329         if (cdp_native_vlan != htons(-1)) {
330                 printf("CDP offered native VLAN %d\n", ntohs(cdp_native_vlan));
331                 vlan_to_string(cdp_native_vlan, tmp);
332                 env_set("nvlan", tmp);
333                 net_native_vlan = cdp_native_vlan;
334         }
335 }
336
337 int do_cdp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
338 {
339         int r;
340
341         r = net_loop(CDP);
342         if (r < 0) {
343                 printf("cdp failed; perhaps not a CISCO switch?\n");
344                 return CMD_RET_FAILURE;
345         }
346
347         cdp_update_env();
348
349         return CMD_RET_SUCCESS;
350 }
351
352 U_BOOT_CMD(
353         cdp,    1,      1,      do_cdp,
354         "Perform CDP network configuration",
355         "\n"
356 );
357 #endif
358
359 #if defined(CONFIG_CMD_SNTP)
360 static struct udp_ops sntp_ops = {
361         .prereq = sntp_prereq,
362         .start = sntp_start,
363         .data = NULL,
364 };
365
366 int do_sntp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
367 {
368         char *toff;
369
370         if (argc < 2) {
371                 net_ntp_server = env_get_ip("ntpserverip");
372                 if (net_ntp_server.s_addr == 0) {
373                         printf("ntpserverip not set\n");
374                         return CMD_RET_FAILURE;
375                 }
376         } else {
377                 net_ntp_server = string_to_ip(argv[1]);
378                 if (net_ntp_server.s_addr == 0) {
379                         printf("Bad NTP server IP address\n");
380                         return CMD_RET_FAILURE;
381                 }
382         }
383
384         toff = env_get("timeoffset");
385         if (toff == NULL)
386                 net_ntp_time_offset = 0;
387         else
388                 net_ntp_time_offset = simple_strtol(toff, NULL, 10);
389
390         if (udp_loop(&sntp_ops) < 0) {
391                 printf("SNTP failed: host %pI4 not responding\n",
392                        &net_ntp_server);
393                 return CMD_RET_FAILURE;
394         }
395
396         return CMD_RET_SUCCESS;
397 }
398
399 U_BOOT_CMD(
400         sntp,   2,      1,      do_sntp,
401         "synchronize RTC via network",
402         "[NTP server IP]\n"
403 );
404 #endif
405
406 #if defined(CONFIG_CMD_DNS)
407 int do_dns(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
408 {
409         if (argc == 1)
410                 return CMD_RET_USAGE;
411
412         /*
413          * We should check for a valid hostname:
414          * - Each label must be between 1 and 63 characters long
415          * - the entire hostname has a maximum of 255 characters
416          * - only the ASCII letters 'a' through 'z' (case-insensitive),
417          *   the digits '0' through '9', and the hyphen
418          * - cannot begin or end with a hyphen
419          * - no other symbols, punctuation characters, or blank spaces are
420          *   permitted
421          * but hey - this is a minimalist implmentation, so only check length
422          * and let the name server deal with things.
423          */
424         if (strlen(argv[1]) >= 255) {
425                 printf("dns error: hostname too long\n");
426                 return CMD_RET_FAILURE;
427         }
428
429         net_dns_resolve = argv[1];
430
431         if (argc == 3)
432                 net_dns_env_var = argv[2];
433         else
434                 net_dns_env_var = NULL;
435
436         if (net_loop(DNS) < 0) {
437                 printf("dns lookup of %s failed, check setup\n", argv[1]);
438                 return CMD_RET_FAILURE;
439         }
440
441         return CMD_RET_SUCCESS;
442 }
443
444 U_BOOT_CMD(
445         dns,    3,      1,      do_dns,
446         "lookup the IP of a hostname",
447         "hostname [envvar]"
448 );
449
450 #endif  /* CONFIG_CMD_DNS */
451
452 #if defined(CONFIG_CMD_LINK_LOCAL)
453 static int do_link_local(struct cmd_tbl *cmdtp, int flag, int argc,
454                          char *const argv[])
455 {
456         char tmp[22];
457
458         if (net_loop(LINKLOCAL) < 0)
459                 return CMD_RET_FAILURE;
460
461         net_gateway.s_addr = 0;
462         ip_to_string(net_gateway, tmp);
463         env_set("gatewayip", tmp);
464
465         ip_to_string(net_netmask, tmp);
466         env_set("netmask", tmp);
467
468         ip_to_string(net_ip, tmp);
469         env_set("ipaddr", tmp);
470         env_set("llipaddr", tmp); /* store this for next time */
471
472         return CMD_RET_SUCCESS;
473 }
474
475 U_BOOT_CMD(
476         linklocal,      1,      1,      do_link_local,
477         "acquire a network IP address using the link-local protocol",
478         ""
479 );
480
481 #endif  /* CONFIG_CMD_LINK_LOCAL */
482
483 #ifdef CONFIG_DM_ETH
484 static int do_net_list(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
485 {
486         const struct udevice *current = eth_get_dev();
487         unsigned char env_enetaddr[ARP_HLEN];
488         const struct udevice *dev;
489         struct uclass *uc;
490
491         uclass_id_foreach_dev(UCLASS_ETH, dev, uc) {
492                 eth_env_get_enetaddr_by_index("eth", dev_seq(dev), env_enetaddr);
493                 printf("eth%d : %s %pM %s\n", dev_seq(dev), dev->name, env_enetaddr,
494                        current == dev ? "active" : "");
495         }
496         return CMD_RET_SUCCESS;
497 }
498
499 static struct cmd_tbl cmd_net[] = {
500         U_BOOT_CMD_MKENT(list, 1, 0, do_net_list, "", ""),
501 };
502
503 static int do_net(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
504 {
505         struct cmd_tbl *cp;
506
507         cp = find_cmd_tbl(argv[1], cmd_net, ARRAY_SIZE(cmd_net));
508
509         /* Drop the net command */
510         argc--;
511         argv++;
512
513         if (!cp || argc > cp->maxargs)
514                 return CMD_RET_USAGE;
515         if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
516                 return CMD_RET_SUCCESS;
517
518         return cp->cmd(cmdtp, flag, argc, argv);
519 }
520
521 U_BOOT_CMD(
522         net, 2, 1, do_net,
523         "NET sub-system",
524         "list - list available devices\n"
525 );
526 #endif // CONFIG_DM_ETH