Add basic support for mini2440 board to barebox.
[barebox-mini2440.git] / net / tftp.c
blob6345a7220de0643cbec826a1bad3ff2f3e0e787b
1 /*
2 * Copyright 1994, 1995, 2000 Neil Russell.
3 * (See License)
4 * Copyright 2000, 2001 DENX Software Engineering, Wolfgang Denk, wd@denx.de
5 */
7 #include <common.h>
8 #include <command.h>
9 #include <net.h>
10 #include <driver.h>
11 #include <clock.h>
12 #include <fs.h>
13 #include <errno.h>
14 #include <libgen.h>
15 #include <fcntl.h>
16 #include <progress.h>
17 #include <getopt.h>
18 #include <fs.h>
19 #include <linux/stat.h>
20 #include <linux/err.h>
22 #define TFTP_PORT 69 /* Well known TFTP port # */
23 #define TIMEOUT 5 /* Seconds to timeout for a lost pkt */
26 * TFTP operations.
28 #define TFTP_RRQ 1
29 #define TFTP_WRQ 2
30 #define TFTP_DATA 3
31 #define TFTP_ACK 4
32 #define TFTP_ERROR 5
33 #define TFTP_OACK 6
36 static int tftp_server_port; /* The UDP port at their end */
37 static unsigned int tftp_block; /* packet sequence number */
38 static unsigned int tftp_last_block; /* last packet sequence number received */
39 static int tftp_state;
40 static uint64_t tftp_timer_start;
41 static int tftp_err;
43 #define STATE_RRQ 1
44 #define STATE_WRQ 2
45 #define STATE_RDATA 3
46 #define STATE_WDATA 4
47 #define STATE_OACK 5
48 #define STATE_LAST 6
49 #define STATE_DONE 7
51 #define TFTP_BLOCK_SIZE 512 /* default TFTP block size */
53 static char *tftp_filename;
54 static struct net_connection *tftp_con;
55 static int tftp_fd;
56 static int tftp_size;
58 #ifdef CONFIG_NET_TFTP_PUSH
59 static int tftp_push;
61 static inline void do_tftp_push(int push)
63 tftp_push = push;
66 #else
68 #define tftp_push 0
70 static inline void do_tftp_push(int push)
73 #endif
75 static int tftp_send(void)
77 unsigned char *xp;
78 int len = 0;
79 uint16_t *s;
80 unsigned char *pkt = net_udp_get_payload(tftp_con);
81 int ret;
82 static int last_len;
84 switch (tftp_state) {
85 case STATE_RRQ:
86 case STATE_WRQ:
87 xp = pkt;
88 s = (uint16_t *)pkt;
89 if (tftp_state == STATE_RRQ)
90 *s++ = htons(TFTP_RRQ);
91 else
92 *s++ = htons(TFTP_WRQ);
93 pkt = (unsigned char *)s;
94 pkt += sprintf((unsigned char *)pkt, "%s%coctet%ctimeout%c%d",
95 tftp_filename, 0, 0, 0, TIMEOUT) + 1;
96 len = pkt - xp;
97 break;
99 case STATE_WDATA:
100 if (!tftp_push)
101 break;
103 if (tftp_last_block == tftp_block) {
104 len = last_len;
105 break;
108 tftp_last_block = tftp_block;
109 s = (uint16_t *)pkt;
110 *s++ = htons(TFTP_DATA);
111 *s++ = htons(tftp_block);
112 len = read(tftp_fd, s, 512);
113 if (len < 0) {
114 perror("read");
115 tftp_err = -errno;
116 tftp_state = STATE_DONE;
117 return tftp_err;
119 tftp_size += len;
120 if (len < 512)
121 tftp_state = STATE_LAST;
122 len += 4;
123 last_len = len;
124 break;
126 case STATE_RDATA:
127 case STATE_OACK:
128 xp = pkt;
129 s = (uint16_t *)pkt;
130 *s++ = htons(TFTP_ACK);
131 *s++ = htons(tftp_block);
132 pkt = (unsigned char *)s;
133 len = pkt - xp;
134 break;
137 tftp_timer_start = get_time_ns();
138 show_progress(tftp_size);
139 ret = net_udp_send(tftp_con, len);
141 return ret;
144 static void tftp_handler(char *packet, unsigned len)
146 uint16_t proto;
147 uint16_t *s;
148 char *pkt = net_eth_to_udp_payload(packet);
149 struct udphdr *udp = net_eth_to_udphdr(packet);
150 int ret;
152 len = net_eth_to_udplen(packet);
153 if (len < 2)
154 return;
156 len -= 2;
158 s = (uint16_t *)pkt;
159 proto = *s++;
160 pkt = (unsigned char *)s;
162 switch (ntohs(proto)) {
163 case TFTP_RRQ:
164 case TFTP_WRQ:
165 default:
166 break;
167 case TFTP_ACK:
168 if (!tftp_push)
169 break;
171 tftp_block = ntohs(*(uint16_t *)pkt);
172 if (tftp_block != tftp_last_block) {
173 debug("ack %d != %d\n", tftp_block, tftp_last_block);
174 break;
176 tftp_block++;
177 if (tftp_state == STATE_LAST) {
178 tftp_state = STATE_DONE;
179 break;
181 tftp_con->udp->uh_dport = udp->uh_sport;
182 tftp_state = STATE_WDATA;
183 tftp_send();
184 break;
186 case TFTP_OACK:
187 debug("Got OACK: %s %s\n", pkt, pkt + strlen(pkt) + 1);
188 tftp_server_port = ntohs(udp->uh_sport);
189 tftp_con->udp->uh_dport = udp->uh_sport;
191 if (tftp_push) {
192 /* send first block */
193 tftp_state = STATE_WDATA;
194 tftp_block = 1;
195 } else {
196 /* send ACK */
197 tftp_state = STATE_OACK;
198 tftp_block = 0;
201 tftp_send();
203 break;
204 case TFTP_DATA:
205 if (len < 2)
206 return;
207 len -= 2;
208 tftp_block = ntohs(*(uint16_t *)pkt);
210 if (tftp_state == STATE_RRQ)
211 debug("Server did not acknowledge timeout option!\n");
213 if (tftp_state == STATE_RRQ || tftp_state == STATE_OACK) {
214 /* first block received */
215 tftp_state = STATE_RDATA;
216 tftp_con->udp->uh_dport = udp->uh_sport;
217 tftp_server_port = ntohs(udp->uh_sport);
218 tftp_last_block = 0;
220 if (tftp_block != 1) { /* Assertion */
221 printf("error: First block is not block 1 (%ld)\n",
222 tftp_block);
223 tftp_err = -EINVAL;
224 tftp_state = STATE_DONE;
225 break;
229 if (tftp_block == tftp_last_block)
230 /* Same block again; ignore it. */
231 break;
233 tftp_last_block = tftp_block;
235 if (!(tftp_block % 10))
236 tftp_size++;
238 ret = write(tftp_fd, pkt + 2, len);
239 if (ret < 0) {
240 perror("write");
241 tftp_err = -errno;
242 tftp_state = STATE_DONE;
243 return;
247 * Acknowledge the block just received, which will prompt
248 * the server for the next one.
250 tftp_send();
252 if (len < TFTP_BLOCK_SIZE)
253 tftp_state = STATE_DONE;
255 break;
257 case TFTP_ERROR:
258 debug("\nTFTP error: '%s' (%d)\n",
259 pkt + 2, ntohs(*(uint16_t *)pkt));
260 switch (ntohs(*(uint16_t *)pkt)) {
261 case 1: tftp_err = -ENOENT; break;
262 case 2: tftp_err = -EACCES; break;
263 default: tftp_err = -EINVAL; break;
265 tftp_state = STATE_DONE;
266 break;
270 static int do_tftpb(struct command *cmdtp, int argc, char *argv[])
272 char *localfile, *remotefile, *file1, *file2;
273 char ip1[16];
274 int opt;
275 struct stat s;
276 unsigned long flags;
278 do_tftp_push(0);
279 tftp_last_block = 0;
280 tftp_size = 0;
282 while((opt = getopt(argc, argv, "p")) > 0) {
283 switch(opt) {
284 case 'p':
285 do_tftp_push(1);
286 break;
290 if (argc <= optind)
291 return COMMAND_ERROR_USAGE;
293 file1 = argv[optind++];
295 if (argc == optind)
296 file2 = basename(file1);
297 else
298 file2 = argv[optind];
300 if (tftp_push) {
301 localfile = file1;
302 remotefile = file2;
303 stat(localfile, &s);
304 flags = O_RDONLY;
305 } else {
306 localfile = file2;
307 remotefile = file1;
308 flags = O_WRONLY | O_CREAT;
311 tftp_fd = open(localfile, flags);
312 if (tftp_fd < 0) {
313 perror("open");
314 return 1;
317 tftp_con = net_udp_new(net_get_serverip(), TFTP_PORT, tftp_handler);
318 if (IS_ERR(tftp_con)) {
319 tftp_err = PTR_ERR(tftp_con);
320 goto out_close;
323 tftp_filename = remotefile;
325 printf("TFTP %s server %s ('%s' -> '%s')\n",
326 tftp_push ? "to" : "from",
327 ip_to_string(net_get_serverip(), ip1),
328 file1, file2);
330 init_progression_bar(tftp_push ? s.st_size : 0);
332 tftp_timer_start = get_time_ns();
333 tftp_state = tftp_push ? STATE_WRQ : STATE_RRQ;
334 tftp_block = 1;
336 tftp_err = tftp_send();
337 if (tftp_err)
338 goto out_unreg;
340 while (tftp_state != STATE_DONE) {
341 if (ctrlc()) {
342 tftp_err = -EINTR;
343 break;
345 net_poll();
346 if (is_timeout(tftp_timer_start, SECOND)) {
347 show_progress(-1);
348 tftp_send();
351 out_unreg:
352 net_unregister(tftp_con);
353 out_close:
354 close(tftp_fd);
356 if (tftp_err) {
357 printf("\ntftp failed: %s\n", strerror(-tftp_err));
358 if (!tftp_push)
359 unlink(localfile);
362 printf("\n");
364 return tftp_err == 0 ? 0 : 1;
367 static const __maybe_unused char cmd_tftp_help[] =
368 "Usage: tftp <remotefile> [localfile]\n"
369 "Load a file from a TFTP server.\n"
370 #ifdef CONFIG_NET_TFTP_PUSH
371 "or\n"
372 " tftp -p <localfile> [remotefile]\n"
373 "Upload a file to a TFTP server\n"
374 #endif
377 BAREBOX_CMD_START(tftp)
378 .cmd = do_tftpb,
379 .usage =
380 #ifdef CONFIG_NET_TFTP_PUSH
381 "(up-)"
382 #endif
383 "Load file using tftp protocol",
384 BAREBOX_CMD_HELP(cmd_tftp_help)
385 BAREBOX_CMD_END
388 * @page tftp_command tftp
390 * Usage:
391 * tftp \<remotefilename\> [\<localfilename\>]
393 * or
395 * tftp -p \<localfilename\> [\<remotefilename\>]
397 * Load a file from a tftp server or upload a file to a tftp server if
398 * the -p option is given. The second file argument can be skipped in
399 * which case the first filename is used (without the directory part).
401 * \<localfile> can be the local filename or a device file under /dev.
402 * This also works for flash memory. Refer to \b erase, \b unprotect for
403 * flash preparation.
405 * Note: This command is available only if enabled in menuconfig.