]> git.ipfire.org Git - thirdparty/u-boot.git/blob - cmd/net.c
Merge tag 'video-2021-08-05' of https://source.denx.de/u-boot/custodians/u-boot-video
[thirdparty/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