common: Move do_tftpb() to net.h
[oweals/u-boot.git] / cmd / pxe.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2010-2011 Calxeda, Inc.
4  * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
5  */
6
7 #include <common.h>
8 #include <command.h>
9 #include <net.h>
10
11 #include "pxe_utils.h"
12
13 #ifdef CONFIG_CMD_NET
14 const char *pxe_default_paths[] = {
15 #ifdef CONFIG_SYS_SOC
16 #ifdef CONFIG_SYS_BOARD
17         "default-" CONFIG_SYS_ARCH "-" CONFIG_SYS_SOC "-" CONFIG_SYS_BOARD,
18 #endif
19         "default-" CONFIG_SYS_ARCH "-" CONFIG_SYS_SOC,
20 #endif
21         "default-" CONFIG_SYS_ARCH,
22         "default",
23         NULL
24 };
25
26 static int do_get_tftp(cmd_tbl_t *cmdtp, const char *file_path, char *file_addr)
27 {
28         char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
29
30         tftp_argv[1] = file_addr;
31         tftp_argv[2] = (void *)file_path;
32
33         if (do_tftpb(cmdtp, 0, 3, tftp_argv))
34                 return -ENOENT;
35
36         return 1;
37 }
38
39 /*
40  * Looks for a pxe file with a name based on the pxeuuid environment variable.
41  *
42  * Returns 1 on success or < 0 on error.
43  */
44 static int pxe_uuid_path(cmd_tbl_t *cmdtp, unsigned long pxefile_addr_r)
45 {
46         char *uuid_str;
47
48         uuid_str = from_env("pxeuuid");
49
50         if (!uuid_str)
51                 return -ENOENT;
52
53         return get_pxelinux_path(cmdtp, uuid_str, pxefile_addr_r);
54 }
55
56 /*
57  * Looks for a pxe file with a name based on the 'ethaddr' environment
58  * variable.
59  *
60  * Returns 1 on success or < 0 on error.
61  */
62 static int pxe_mac_path(cmd_tbl_t *cmdtp, unsigned long pxefile_addr_r)
63 {
64         char mac_str[21];
65         int err;
66
67         err = format_mac_pxe(mac_str, sizeof(mac_str));
68
69         if (err < 0)
70                 return err;
71
72         return get_pxelinux_path(cmdtp, mac_str, pxefile_addr_r);
73 }
74
75 /*
76  * Looks for pxe files with names based on our IP address. See pxelinux
77  * documentation for details on what these file names look like.  We match
78  * that exactly.
79  *
80  * Returns 1 on success or < 0 on error.
81  */
82 static int pxe_ipaddr_paths(cmd_tbl_t *cmdtp, unsigned long pxefile_addr_r)
83 {
84         char ip_addr[9];
85         int mask_pos, err;
86
87         sprintf(ip_addr, "%08X", ntohl(net_ip.s_addr));
88
89         for (mask_pos = 7; mask_pos >= 0;  mask_pos--) {
90                 err = get_pxelinux_path(cmdtp, ip_addr, pxefile_addr_r);
91
92                 if (err > 0)
93                         return err;
94
95                 ip_addr[mask_pos] = '\0';
96         }
97
98         return -ENOENT;
99 }
100 /*
101  * Entry point for the 'pxe get' command.
102  * This Follows pxelinux's rules to download a config file from a tftp server.
103  * The file is stored at the location given by the pxefile_addr_r environment
104  * variable, which must be set.
105  *
106  * UUID comes from pxeuuid env variable, if defined
107  * MAC addr comes from ethaddr env variable, if defined
108  * IP
109  *
110  * see http://syslinux.zytor.com/wiki/index.php/PXELINUX
111  *
112  * Returns 0 on success or 1 on error.
113  */
114 static int
115 do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
116 {
117         char *pxefile_addr_str;
118         unsigned long pxefile_addr_r;
119         int err, i = 0;
120
121         do_getfile = do_get_tftp;
122
123         if (argc != 1)
124                 return CMD_RET_USAGE;
125
126         pxefile_addr_str = from_env("pxefile_addr_r");
127
128         if (!pxefile_addr_str)
129                 return 1;
130
131         err = strict_strtoul(pxefile_addr_str, 16,
132                              (unsigned long *)&pxefile_addr_r);
133         if (err < 0)
134                 return 1;
135
136         /*
137          * Keep trying paths until we successfully get a file we're looking
138          * for.
139          */
140         if (pxe_uuid_path(cmdtp, pxefile_addr_r) > 0 ||
141             pxe_mac_path(cmdtp, pxefile_addr_r) > 0 ||
142             pxe_ipaddr_paths(cmdtp, pxefile_addr_r) > 0) {
143                 printf("Config file found\n");
144
145                 return 0;
146         }
147
148         while (pxe_default_paths[i]) {
149                 if (get_pxelinux_path(cmdtp, pxe_default_paths[i],
150                                       pxefile_addr_r) > 0) {
151                         printf("Config file found\n");
152                         return 0;
153                 }
154                 i++;
155         }
156
157         printf("Config file not found\n");
158
159         return 1;
160 }
161
162 /*
163  * Boots a system using a pxe file
164  *
165  * Returns 0 on success, 1 on error.
166  */
167 static int
168 do_pxe_boot(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
169 {
170         unsigned long pxefile_addr_r;
171         struct pxe_menu *cfg;
172         char *pxefile_addr_str;
173
174         do_getfile = do_get_tftp;
175
176         if (argc == 1) {
177                 pxefile_addr_str = from_env("pxefile_addr_r");
178                 if (!pxefile_addr_str)
179                         return 1;
180
181         } else if (argc == 2) {
182                 pxefile_addr_str = argv[1];
183         } else {
184                 return CMD_RET_USAGE;
185         }
186
187         if (strict_strtoul(pxefile_addr_str, 16, &pxefile_addr_r) < 0) {
188                 printf("Invalid pxefile address: %s\n", pxefile_addr_str);
189                 return 1;
190         }
191
192         cfg = parse_pxefile(cmdtp, pxefile_addr_r);
193
194         if (!cfg) {
195                 printf("Error parsing config file\n");
196                 return 1;
197         }
198
199         handle_pxe_menu(cmdtp, cfg);
200
201         destroy_pxe_menu(cfg);
202
203         copy_filename(net_boot_file_name, "", sizeof(net_boot_file_name));
204
205         return 0;
206 }
207
208 static cmd_tbl_t cmd_pxe_sub[] = {
209         U_BOOT_CMD_MKENT(get, 1, 1, do_pxe_get, "", ""),
210         U_BOOT_CMD_MKENT(boot, 2, 1, do_pxe_boot, "", "")
211 };
212
213 static int do_pxe(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
214 {
215         cmd_tbl_t *cp;
216
217         if (argc < 2)
218                 return CMD_RET_USAGE;
219
220         is_pxe = true;
221
222         /* drop initial "pxe" arg */
223         argc--;
224         argv++;
225
226         cp = find_cmd_tbl(argv[0], cmd_pxe_sub, ARRAY_SIZE(cmd_pxe_sub));
227
228         if (cp)
229                 return cp->cmd(cmdtp, flag, argc, argv);
230
231         return CMD_RET_USAGE;
232 }
233
234 U_BOOT_CMD(pxe, 3, 1, do_pxe,
235            "commands to get and boot from pxe files",
236            "get - try to retrieve a pxe file using tftp\n"
237            "pxe boot [pxefile_addr_r] - boot from the pxe file at pxefile_addr_r\n"
238 );
239 #endif