command: Remove the cmd_tbl_t typedef
[oweals/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 <env.h>
14 #include <image.h>
15 #include <net.h>
16
17 static int netboot_common(enum proto_t, struct cmd_tbl *, int, char * const []);
18
19 #ifdef CONFIG_CMD_BOOTP
20 static int do_bootp(struct cmd_tbl *cmdtp, int flag, int argc,
21                     char *const argv[])
22 {
23         return netboot_common(BOOTP, cmdtp, argc, argv);
24 }
25
26 U_BOOT_CMD(
27         bootp,  3,      1,      do_bootp,
28         "boot image via network using BOOTP/TFTP protocol",
29         "[loadAddress] [[hostIPaddr:]bootfilename]"
30 );
31 #endif
32
33 #ifdef CONFIG_CMD_TFTPBOOT
34 int do_tftpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
35 {
36         int ret;
37
38         bootstage_mark_name(BOOTSTAGE_KERNELREAD_START, "tftp_start");
39         ret = netboot_common(TFTPGET, cmdtp, argc, argv);
40         bootstage_mark_name(BOOTSTAGE_KERNELREAD_STOP, "tftp_done");
41         return ret;
42 }
43
44 U_BOOT_CMD(
45         tftpboot,       3,      1,      do_tftpb,
46         "boot image via network using TFTP protocol",
47         "[loadAddress] [[hostIPaddr:]bootfilename]"
48 );
49 #endif
50
51 #ifdef CONFIG_CMD_TFTPPUT
52 static int do_tftpput(struct cmd_tbl *cmdtp, int flag, int argc,
53                       char *const argv[])
54 {
55         return netboot_common(TFTPPUT, cmdtp, argc, argv);
56 }
57
58 U_BOOT_CMD(
59         tftpput,        4,      1,      do_tftpput,
60         "TFTP put command, for uploading files to a server",
61         "Address Size [[hostIPaddr:]filename]"
62 );
63 #endif
64
65 #ifdef CONFIG_CMD_TFTPSRV
66 static int do_tftpsrv(struct cmd_tbl *cmdtp, int flag, int argc,
67                       char *const argv[])
68 {
69         return netboot_common(TFTPSRV, cmdtp, argc, argv);
70 }
71
72 U_BOOT_CMD(
73         tftpsrv,        2,      1,      do_tftpsrv,
74         "act as a TFTP server and boot the first received file",
75         "[loadAddress]\n"
76         "Listen for an incoming TFTP transfer, receive a file and boot it.\n"
77         "The transfer is aborted if a transfer has not been started after\n"
78         "about 50 seconds or if Ctrl-C is pressed."
79 );
80 #endif
81
82
83 #ifdef CONFIG_CMD_RARP
84 int do_rarpb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
85 {
86         return netboot_common(RARP, cmdtp, argc, argv);
87 }
88
89 U_BOOT_CMD(
90         rarpboot,       3,      1,      do_rarpb,
91         "boot image via network using RARP/TFTP protocol",
92         "[loadAddress] [[hostIPaddr:]bootfilename]"
93 );
94 #endif
95
96 #if defined(CONFIG_CMD_DHCP)
97 static int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc,
98                    char *const argv[])
99 {
100         return netboot_common(DHCP, cmdtp, argc, argv);
101 }
102
103 U_BOOT_CMD(
104         dhcp,   3,      1,      do_dhcp,
105         "boot image via network using DHCP/TFTP protocol",
106         "[loadAddress] [[hostIPaddr:]bootfilename]"
107 );
108 #endif
109
110 #if defined(CONFIG_CMD_NFS)
111 static int do_nfs(struct cmd_tbl *cmdtp, int flag, int argc,
112                   char *const argv[])
113 {
114         return netboot_common(NFS, cmdtp, argc, argv);
115 }
116
117 U_BOOT_CMD(
118         nfs,    3,      1,      do_nfs,
119         "boot image via network using NFS protocol",
120         "[loadAddress] [[hostIPaddr:]bootfilename]"
121 );
122 #endif
123
124 static void netboot_update_env(void)
125 {
126         char tmp[22];
127
128         if (net_gateway.s_addr) {
129                 ip_to_string(net_gateway, tmp);
130                 env_set("gatewayip", tmp);
131         }
132
133         if (net_netmask.s_addr) {
134                 ip_to_string(net_netmask, tmp);
135                 env_set("netmask", tmp);
136         }
137
138         if (net_hostname[0])
139                 env_set("hostname", net_hostname);
140
141         if (net_root_path[0])
142                 env_set("rootpath", net_root_path);
143
144         if (net_ip.s_addr) {
145                 ip_to_string(net_ip, tmp);
146                 env_set("ipaddr", tmp);
147         }
148 #if !defined(CONFIG_BOOTP_SERVERIP)
149         /*
150          * Only attempt to change serverip if net/bootp.c:store_net_params()
151          * could have set it
152          */
153         if (net_server_ip.s_addr) {
154                 ip_to_string(net_server_ip, tmp);
155                 env_set("serverip", tmp);
156         }
157 #endif
158         if (net_dns_server.s_addr) {
159                 ip_to_string(net_dns_server, tmp);
160                 env_set("dnsip", tmp);
161         }
162 #if defined(CONFIG_BOOTP_DNS2)
163         if (net_dns_server2.s_addr) {
164                 ip_to_string(net_dns_server2, tmp);
165                 env_set("dnsip2", tmp);
166         }
167 #endif
168         if (net_nis_domain[0])
169                 env_set("domain", net_nis_domain);
170
171 #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET)
172         if (net_ntp_time_offset) {
173                 sprintf(tmp, "%d", net_ntp_time_offset);
174                 env_set("timeoffset", tmp);
175         }
176 #endif
177 #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER)
178         if (net_ntp_server.s_addr) {
179                 ip_to_string(net_ntp_server, tmp);
180                 env_set("ntpserverip", tmp);
181         }
182 #endif
183 }
184
185 static int netboot_common(enum proto_t proto, struct cmd_tbl *cmdtp, int argc,
186                           char *const argv[])
187 {
188         char *s;
189         char *end;
190         int   rcode = 0;
191         int   size;
192         ulong addr;
193
194         net_boot_file_name_explicit = false;
195
196         /* pre-set image_load_addr */
197         s = env_get("loadaddr");
198         if (s != NULL)
199                 image_load_addr = simple_strtoul(s, NULL, 16);
200
201         switch (argc) {
202         case 1:
203                 /* refresh bootfile name from env */
204                 copy_filename(net_boot_file_name, env_get("bootfile"),
205                               sizeof(net_boot_file_name));
206                 break;
207
208         case 2: /*
209                  * Only one arg - accept two forms:
210                  * Just load address, or just boot file name. The latter
211                  * form must be written in a format which can not be
212                  * mis-interpreted as a valid number.
213                  */
214                 addr = simple_strtoul(argv[1], &end, 16);
215                 if (end == (argv[1] + strlen(argv[1]))) {
216                         image_load_addr = addr;
217                         /* refresh bootfile name from env */
218                         copy_filename(net_boot_file_name, env_get("bootfile"),
219                                       sizeof(net_boot_file_name));
220                 } else {
221                         net_boot_file_name_explicit = true;
222                         copy_filename(net_boot_file_name, argv[1],
223                                       sizeof(net_boot_file_name));
224                 }
225                 break;
226
227         case 3:
228                 image_load_addr = simple_strtoul(argv[1], NULL, 16);
229                 net_boot_file_name_explicit = true;
230                 copy_filename(net_boot_file_name, argv[2],
231                               sizeof(net_boot_file_name));
232
233                 break;
234
235 #ifdef CONFIG_CMD_TFTPPUT
236         case 4:
237                 if (strict_strtoul(argv[1], 16, &image_save_addr) < 0 ||
238                     strict_strtoul(argv[2], 16, &image_save_size) < 0) {
239                         printf("Invalid address/size\n");
240                         return CMD_RET_USAGE;
241                 }
242                 net_boot_file_name_explicit = true;
243                 copy_filename(net_boot_file_name, argv[3],
244                               sizeof(net_boot_file_name));
245                 break;
246 #endif
247         default:
248                 bootstage_error(BOOTSTAGE_ID_NET_START);
249                 return CMD_RET_USAGE;
250         }
251         bootstage_mark(BOOTSTAGE_ID_NET_START);
252
253         size = net_loop(proto);
254         if (size < 0) {
255                 bootstage_error(BOOTSTAGE_ID_NET_NETLOOP_OK);
256                 return CMD_RET_FAILURE;
257         }
258         bootstage_mark(BOOTSTAGE_ID_NET_NETLOOP_OK);
259
260         /* net_loop ok, update environment */
261         netboot_update_env();
262
263         /* done if no file was loaded (no errors though) */
264         if (size == 0) {
265                 bootstage_error(BOOTSTAGE_ID_NET_LOADED);
266                 return CMD_RET_SUCCESS;
267         }
268
269         bootstage_mark(BOOTSTAGE_ID_NET_LOADED);
270
271         rcode = bootm_maybe_autostart(cmdtp, argv[0]);
272
273         if (rcode == CMD_RET_SUCCESS)
274                 bootstage_mark(BOOTSTAGE_ID_NET_DONE);
275         else
276                 bootstage_error(BOOTSTAGE_ID_NET_DONE_ERR);
277         return rcode;
278 }
279
280 #if defined(CONFIG_CMD_PING)
281 static int do_ping(struct cmd_tbl *cmdtp, int flag, int argc,
282                    char *const argv[])
283 {
284         if (argc < 2)
285                 return CMD_RET_USAGE;
286
287         net_ping_ip = string_to_ip(argv[1]);
288         if (net_ping_ip.s_addr == 0)
289                 return CMD_RET_USAGE;
290
291         if (net_loop(PING) < 0) {
292                 printf("ping failed; host %s is not alive\n", argv[1]);
293                 return CMD_RET_FAILURE;
294         }
295
296         printf("host %s is alive\n", argv[1]);
297
298         return CMD_RET_SUCCESS;
299 }
300
301 U_BOOT_CMD(
302         ping,   2,      1,      do_ping,
303         "send ICMP ECHO_REQUEST to network host",
304         "pingAddress"
305 );
306 #endif
307
308 #if defined(CONFIG_CMD_CDP)
309
310 static void cdp_update_env(void)
311 {
312         char tmp[16];
313
314         if (cdp_appliance_vlan != htons(-1)) {
315                 printf("CDP offered appliance VLAN %d\n",
316                        ntohs(cdp_appliance_vlan));
317                 vlan_to_string(cdp_appliance_vlan, tmp);
318                 env_set("vlan", tmp);
319                 net_our_vlan = cdp_appliance_vlan;
320         }
321
322         if (cdp_native_vlan != htons(-1)) {
323                 printf("CDP offered native VLAN %d\n", ntohs(cdp_native_vlan));
324                 vlan_to_string(cdp_native_vlan, tmp);
325                 env_set("nvlan", tmp);
326                 net_native_vlan = cdp_native_vlan;
327         }
328 }
329
330 int do_cdp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
331 {
332         int r;
333
334         r = net_loop(CDP);
335         if (r < 0) {
336                 printf("cdp failed; perhaps not a CISCO switch?\n");
337                 return CMD_RET_FAILURE;
338         }
339
340         cdp_update_env();
341
342         return CMD_RET_SUCCESS;
343 }
344
345 U_BOOT_CMD(
346         cdp,    1,      1,      do_cdp,
347         "Perform CDP network configuration",
348         "\n"
349 );
350 #endif
351
352 #if defined(CONFIG_CMD_SNTP)
353 int do_sntp(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
354 {
355         char *toff;
356
357         if (argc < 2) {
358                 net_ntp_server = env_get_ip("ntpserverip");
359                 if (net_ntp_server.s_addr == 0) {
360                         printf("ntpserverip not set\n");
361                         return CMD_RET_FAILURE;
362                 }
363         } else {
364                 net_ntp_server = string_to_ip(argv[1]);
365                 if (net_ntp_server.s_addr == 0) {
366                         printf("Bad NTP server IP address\n");
367                         return CMD_RET_FAILURE;
368                 }
369         }
370
371         toff = env_get("timeoffset");
372         if (toff == NULL)
373                 net_ntp_time_offset = 0;
374         else
375                 net_ntp_time_offset = simple_strtol(toff, NULL, 10);
376
377         if (net_loop(SNTP) < 0) {
378                 printf("SNTP failed: host %pI4 not responding\n",
379                        &net_ntp_server);
380                 return CMD_RET_FAILURE;
381         }
382
383         return CMD_RET_SUCCESS;
384 }
385
386 U_BOOT_CMD(
387         sntp,   2,      1,      do_sntp,
388         "synchronize RTC via network",
389         "[NTP server IP]\n"
390 );
391 #endif
392
393 #if defined(CONFIG_CMD_DNS)
394 int do_dns(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
395 {
396         if (argc == 1)
397                 return CMD_RET_USAGE;
398
399         /*
400          * We should check for a valid hostname:
401          * - Each label must be between 1 and 63 characters long
402          * - the entire hostname has a maximum of 255 characters
403          * - only the ASCII letters 'a' through 'z' (case-insensitive),
404          *   the digits '0' through '9', and the hyphen
405          * - cannot begin or end with a hyphen
406          * - no other symbols, punctuation characters, or blank spaces are
407          *   permitted
408          * but hey - this is a minimalist implmentation, so only check length
409          * and let the name server deal with things.
410          */
411         if (strlen(argv[1]) >= 255) {
412                 printf("dns error: hostname too long\n");
413                 return CMD_RET_FAILURE;
414         }
415
416         net_dns_resolve = argv[1];
417
418         if (argc == 3)
419                 net_dns_env_var = argv[2];
420         else
421                 net_dns_env_var = NULL;
422
423         if (net_loop(DNS) < 0) {
424                 printf("dns lookup of %s failed, check setup\n", argv[1]);
425                 return CMD_RET_FAILURE;
426         }
427
428         return CMD_RET_SUCCESS;
429 }
430
431 U_BOOT_CMD(
432         dns,    3,      1,      do_dns,
433         "lookup the IP of a hostname",
434         "hostname [envvar]"
435 );
436
437 #endif  /* CONFIG_CMD_DNS */
438
439 #if defined(CONFIG_CMD_LINK_LOCAL)
440 static int do_link_local(struct cmd_tbl *cmdtp, int flag, int argc,
441                          char *const argv[])
442 {
443         char tmp[22];
444
445         if (net_loop(LINKLOCAL) < 0)
446                 return CMD_RET_FAILURE;
447
448         net_gateway.s_addr = 0;
449         ip_to_string(net_gateway, tmp);
450         env_set("gatewayip", tmp);
451
452         ip_to_string(net_netmask, tmp);
453         env_set("netmask", tmp);
454
455         ip_to_string(net_ip, tmp);
456         env_set("ipaddr", tmp);
457         env_set("llipaddr", tmp); /* store this for next time */
458
459         return CMD_RET_SUCCESS;
460 }
461
462 U_BOOT_CMD(
463         linklocal,      1,      1,      do_link_local,
464         "acquire a network IP address using the link-local protocol",
465         ""
466 );
467
468 #endif  /* CONFIG_CMD_LINK_LOCAL */