blob: 847ca458e126b853ab96b125a82292273c35785b [file] [log] [blame]
wdenkfe8c2802002-11-03 00:38:21 +00001/*
Luca Ceresoli2f094132011-05-14 05:49:56 +00002 * Copyright 1994, 1995, 2000 Neil Russell.
3 * (See License)
4 * Copyright 2000, 2001 DENX Software Engineering, Wolfgang Denk, wd@denx.de
Luca Ceresolie59e3562011-05-17 00:03:39 +00005 * Copyright 2011 Comelit Group SpA,
6 * Luca Ceresoli <luca.ceresoli@comelit.it>
wdenkfe8c2802002-11-03 00:38:21 +00007 */
8
9#include <common.h>
10#include <command.h>
Joe Hershberger55d5fd92015-03-22 17:09:08 -050011#include <mapmem.h>
wdenkfe8c2802002-11-03 00:38:21 +000012#include <net.h>
Lukasz Majewski34696952015-08-24 00:21:43 +020013#include <net/tftp.h>
wdenkfe8c2802002-11-03 00:38:21 +000014#include "bootp.h"
Joe Hershberger13dfe942012-05-15 08:59:12 +000015#ifdef CONFIG_SYS_DIRECT_FLASH_TFTP
16#include <flash.h>
17#endif
wdenkfe8c2802002-11-03 00:38:21 +000018
Luca Ceresoli2f094132011-05-14 05:49:56 +000019/* Well known TFTP port # */
20#define WELL_KNOWN_PORT 69
21/* Millisecs to timeout for lost pkt */
Bin Mengaf2ca592015-08-27 22:25:51 -070022#define TIMEOUT 5000UL
wdenkfe8c2802002-11-03 00:38:21 +000023#ifndef CONFIG_NET_RETRY_COUNT
Luca Ceresoli2f094132011-05-14 05:49:56 +000024/* # of timeouts before giving up */
Bin Mengaf2ca592015-08-27 22:25:51 -070025# define TIMEOUT_COUNT 10
wdenkfe8c2802002-11-03 00:38:21 +000026#else
27# define TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT * 2)
28#endif
Luca Ceresoli2f094132011-05-14 05:49:56 +000029/* Number of "loading" hashes per line (for checking the image size) */
30#define HASHES_PER_LINE 65
wdenkfe8c2802002-11-03 00:38:21 +000031
32/*
33 * TFTP operations.
34 */
35#define TFTP_RRQ 1
36#define TFTP_WRQ 2
37#define TFTP_DATA 3
38#define TFTP_ACK 4
39#define TFTP_ERROR 5
wdenkfbe4b5c2003-10-06 21:55:32 +000040#define TFTP_OACK 6
wdenkfe8c2802002-11-03 00:38:21 +000041
Sanjeev N9908fc32017-09-05 15:18:54 +053042DECLARE_GLOBAL_DATA_PTR;
Joe Hershberger8885c5f2015-04-08 01:41:07 -050043static ulong timeout_ms = TIMEOUT;
44static int timeout_count_max = TIMEOUT_COUNT;
Simon Glass85b19802012-10-11 13:57:36 +000045static ulong time_start; /* Record time we started tftp */
Bartlomiej Siekae83cc062008-10-01 15:26:29 +020046
47/*
48 * These globals govern the timeout behavior when attempting a connection to a
Joe Hershberger8885c5f2015-04-08 01:41:07 -050049 * TFTP server. tftp_timeout_ms specifies the number of milliseconds to
Bartlomiej Siekae83cc062008-10-01 15:26:29 +020050 * wait for the server to respond to initial connection. Second global,
Joe Hershberger8885c5f2015-04-08 01:41:07 -050051 * tftp_timeout_count_max, gives the number of such connection retries.
52 * tftp_timeout_count_max must be non-negative and tftp_timeout_ms must be
Bartlomiej Siekae83cc062008-10-01 15:26:29 +020053 * positive. The globals are meant to be set (and restored) by code needing
54 * non-standard timeout behavior when initiating a TFTP transfer.
55 */
Joe Hershberger8885c5f2015-04-08 01:41:07 -050056ulong tftp_timeout_ms = TIMEOUT;
57int tftp_timeout_count_max = TIMEOUT_COUNT;
Bartlomiej Siekae83cc062008-10-01 15:26:29 +020058
Remy Bohmeraafda382009-10-28 22:13:40 +010059enum {
60 TFTP_ERR_UNDEFINED = 0,
61 TFTP_ERR_FILE_NOT_FOUND = 1,
62 TFTP_ERR_ACCESS_DENIED = 2,
63 TFTP_ERR_DISK_FULL = 3,
64 TFTP_ERR_UNEXPECTED_OPCODE = 4,
65 TFTP_ERR_UNKNOWN_TRANSFER_ID = 5,
66 TFTP_ERR_FILE_ALREADY_EXISTS = 6,
67};
68
Joe Hershberger049a95a2015-04-08 01:41:01 -050069static struct in_addr tftp_remote_ip;
Luca Ceresoli2f094132011-05-14 05:49:56 +000070/* The UDP port at their end */
Joe Hershberger8885c5f2015-04-08 01:41:07 -050071static int tftp_remote_port;
Luca Ceresoli2f094132011-05-14 05:49:56 +000072/* The UDP port at our end */
Joe Hershberger8885c5f2015-04-08 01:41:07 -050073static int tftp_our_port;
74static int timeout_count;
Luca Ceresoli2f094132011-05-14 05:49:56 +000075/* packet sequence number */
Joe Hershberger8885c5f2015-04-08 01:41:07 -050076static ulong tftp_cur_block;
Luca Ceresoli2f094132011-05-14 05:49:56 +000077/* last packet sequence number received */
Joe Hershberger8885c5f2015-04-08 01:41:07 -050078static ulong tftp_prev_block;
Luca Ceresoli2f094132011-05-14 05:49:56 +000079/* count of sequence number wraparounds */
Joe Hershberger8885c5f2015-04-08 01:41:07 -050080static ulong tftp_block_wrap;
Luca Ceresoli2f094132011-05-14 05:49:56 +000081/* memory offset due to wrapping */
Joe Hershberger8885c5f2015-04-08 01:41:07 -050082static ulong tftp_block_wrap_offset;
83static int tftp_state;
Robin Getz4fccb812009-08-20 10:50:20 -040084#ifdef CONFIG_TFTP_TSIZE
Luca Ceresoli2f094132011-05-14 05:49:56 +000085/* The file size reported by the server */
Joe Hershberger8885c5f2015-04-08 01:41:07 -050086static int tftp_tsize;
Luca Ceresoli2f094132011-05-14 05:49:56 +000087/* The number of hashes we printed */
Joe Hershberger8885c5f2015-04-08 01:41:07 -050088static short tftp_tsize_num_hash;
Robin Getz4fccb812009-08-20 10:50:20 -040089#endif
Simon Glass1fb7cd42011-10-24 18:00:07 +000090#ifdef CONFIG_CMD_TFTPPUT
Joe Hershberger8885c5f2015-04-08 01:41:07 -050091/* 1 if writing, else 0 */
92static int tftp_put_active;
93/* 1 if we have sent the last block */
94static int tftp_put_final_block_sent;
Simon Glass1fb7cd42011-10-24 18:00:07 +000095#else
Joe Hershberger8885c5f2015-04-08 01:41:07 -050096#define tftp_put_active 0
Simon Glass1fb7cd42011-10-24 18:00:07 +000097#endif
wdenk3f85ce22004-02-23 16:11:30 +000098
Luca Ceresolie3fb0ab2011-05-17 00:03:38 +000099#define STATE_SEND_RRQ 1
wdenkfe8c2802002-11-03 00:38:21 +0000100#define STATE_DATA 2
101#define STATE_TOO_LARGE 3
102#define STATE_BAD_MAGIC 4
wdenkfbe4b5c2003-10-06 21:55:32 +0000103#define STATE_OACK 5
Luca Ceresolie59e3562011-05-17 00:03:39 +0000104#define STATE_RECV_WRQ 6
Simon Glass1fb7cd42011-10-24 18:00:07 +0000105#define STATE_SEND_WRQ 7
wdenkfe8c2802002-11-03 00:38:21 +0000106
Luca Ceresoli2f094132011-05-14 05:49:56 +0000107/* default TFTP block size */
108#define TFTP_BLOCK_SIZE 512
109/* sequence number is 16 bit */
110#define TFTP_SEQUENCE_SIZE ((ulong)(1<<16))
wdenk3f85ce22004-02-23 16:11:30 +0000111
wdenkfe8c2802002-11-03 00:38:21 +0000112#define DEFAULT_NAME_LEN (8 + 4 + 1)
113static char default_filename[DEFAULT_NAME_LEN];
Jean-Christophe PLAGNIOL-VILLARDa93907c2008-01-18 01:14:03 +0100114
115#ifndef CONFIG_TFTP_FILE_NAME_MAX_LEN
116#define MAX_LEN 128
117#else
118#define MAX_LEN CONFIG_TFTP_FILE_NAME_MAX_LEN
119#endif
120
121static char tftp_filename[MAX_LEN];
wdenkfe8c2802002-11-03 00:38:21 +0000122
Wolfgang Denk85eb5ca2007-08-14 09:47:27 +0200123/* 512 is poor choice for ethernet, MTU is typically 1500.
124 * Minus eth.hdrs thats 1468. Can get 2x better throughput with
David Updegraff53a5c422007-06-11 10:41:07 -0500125 * almost-MTU block sizes. At least try... fall back to 512 if need be.
Alessandro Rubini89ba81d2009-08-07 13:59:06 +0200126 * (but those using CONFIG_IP_DEFRAG may want to set a larger block in cfg file)
David Updegraff53a5c422007-06-11 10:41:07 -0500127 */
Alessandro Rubini89ba81d2009-08-07 13:59:06 +0200128#ifdef CONFIG_TFTP_BLOCKSIZE
129#define TFTP_MTU_BLOCKSIZE CONFIG_TFTP_BLOCKSIZE
130#else
David Updegraff53a5c422007-06-11 10:41:07 -0500131#define TFTP_MTU_BLOCKSIZE 1468
Alessandro Rubini89ba81d2009-08-07 13:59:06 +0200132#endif
133
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500134static unsigned short tftp_block_size = TFTP_BLOCK_SIZE;
135static unsigned short tftp_block_size_option = TFTP_MTU_BLOCKSIZE;
David Updegraff53a5c422007-06-11 10:41:07 -0500136
137#ifdef CONFIG_MCAST_TFTP
138#include <malloc.h>
139#define MTFTP_BITMAPSIZE 0x1000
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500140static unsigned *tftp_mcast_bitmap;
141static int tftp_mcast_prev_hole;
142static int tftp_mcast_bitmap_size = MTFTP_BITMAPSIZE;
143static int tftp_mcast_disabled;
144static int tftp_mcast_master_client;
145static int tftp_mcast_active;
146static int tftp_mcast_port;
147/* can get 'last' block before done..*/
148static ulong tftp_mcast_ending_block;
David Updegraff53a5c422007-06-11 10:41:07 -0500149
Luca Ceresolic718b142011-05-14 05:49:57 +0000150static void parse_multicast_oack(char *pkt, int len);
David Updegraff53a5c422007-06-11 10:41:07 -0500151
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500152static void mcast_cleanup(void)
David Updegraff53a5c422007-06-11 10:41:07 -0500153{
Joe Hershberger049a95a2015-04-08 01:41:01 -0500154 if (net_mcast_addr)
155 eth_mcast_join(net_mcast_addr, 0);
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500156 if (tftp_mcast_bitmap)
157 free(tftp_mcast_bitmap);
158 tftp_mcast_bitmap = NULL;
Joe Hershberger049a95a2015-04-08 01:41:01 -0500159 net_mcast_addr.s_addr = 0;
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500160 tftp_mcast_active = 0;
161 tftp_mcast_port = 0;
162 tftp_mcast_ending_block = -1;
David Updegraff53a5c422007-06-11 10:41:07 -0500163}
164
165#endif /* CONFIG_MCAST_TFTP */
166
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500167static inline void store_block(int block, uchar *src, unsigned len)
wdenkfe8c2802002-11-03 00:38:21 +0000168{
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500169 ulong offset = block * tftp_block_size + tftp_block_wrap_offset;
wdenk3f85ce22004-02-23 16:11:30 +0000170 ulong newsize = offset + len;
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200171#ifdef CONFIG_SYS_DIRECT_FLASH_TFTP
wdenkfe8c2802002-11-03 00:38:21 +0000172 int i, rc = 0;
173
Luca Ceresolic718b142011-05-14 05:49:57 +0000174 for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
wdenkfe8c2802002-11-03 00:38:21 +0000175 /* start address in flash? */
Jochen Friedrichbe1b0d22008-09-02 11:24:59 +0200176 if (flash_info[i].flash_id == FLASH_UNKNOWN)
177 continue;
wdenkfe8c2802002-11-03 00:38:21 +0000178 if (load_addr + offset >= flash_info[i].start[0]) {
179 rc = 1;
180 break;
181 }
182 }
183
184 if (rc) { /* Flash is destination for this packet */
Luca Ceresolic718b142011-05-14 05:49:57 +0000185 rc = flash_write((char *)src, (ulong)(load_addr+offset), len);
wdenkfe8c2802002-11-03 00:38:21 +0000186 if (rc) {
Luca Ceresolic718b142011-05-14 05:49:57 +0000187 flash_perror(rc);
Joe Hershberger22f6e992012-05-23 07:59:14 +0000188 net_set_state(NETLOOP_FAIL);
wdenkfe8c2802002-11-03 00:38:21 +0000189 return;
190 }
Joe Hershberger13dfe942012-05-15 08:59:12 +0000191 } else
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200192#endif /* CONFIG_SYS_DIRECT_FLASH_TFTP */
wdenkfe8c2802002-11-03 00:38:21 +0000193 {
Sanjeev N9908fc32017-09-05 15:18:54 +0530194 /*
195 * The file to be tftp'ed should not overwrite the
196 * code/stack area.
197 */
198 if (((load_addr + newsize) >= CONFIG_SYS_SDRAM_END) ||
199 (((load_addr + newsize) >= CONFIG_IPQ_FDT_HIGH) &&
200 ((load_addr + newsize) < CONFIG_TZ_END_ADDR))) {
201 puts("\nError file size too large\n");
202 net_set_state(NETLOOP_FAIL);
203 return;
204 }
Joe Hershberger55d5fd92015-03-22 17:09:08 -0500205 void *ptr = map_sysmem(load_addr + offset, len);
206
207 memcpy(ptr, src, len);
208 unmap_sysmem(ptr);
wdenkfe8c2802002-11-03 00:38:21 +0000209 }
David Updegraff53a5c422007-06-11 10:41:07 -0500210#ifdef CONFIG_MCAST_TFTP
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500211 if (tftp_mcast_active)
212 ext2_set_bit(block, tftp_mcast_bitmap);
David Updegraff53a5c422007-06-11 10:41:07 -0500213#endif
wdenkfe8c2802002-11-03 00:38:21 +0000214
Joe Hershberger14111572015-04-08 01:41:02 -0500215 if (net_boot_file_size < newsize)
216 net_boot_file_size = newsize;
wdenkfe8c2802002-11-03 00:38:21 +0000217}
218
Simon Glasse4cde2f2011-10-24 18:00:04 +0000219/* Clear our state ready for a new transfer */
Simon Glass165099e2011-10-27 06:24:28 +0000220static void new_transfer(void)
Simon Glasse4cde2f2011-10-24 18:00:04 +0000221{
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500222 tftp_prev_block = 0;
223 tftp_block_wrap = 0;
224 tftp_block_wrap_offset = 0;
Simon Glasse4cde2f2011-10-24 18:00:04 +0000225#ifdef CONFIG_CMD_TFTPPUT
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500226 tftp_put_final_block_sent = 0;
Simon Glasse4cde2f2011-10-24 18:00:04 +0000227#endif
228}
229
Simon Glass1fb7cd42011-10-24 18:00:07 +0000230#ifdef CONFIG_CMD_TFTPPUT
231/**
232 * Load the next block from memory to be sent over tftp.
233 *
234 * @param block Block number to send
235 * @param dst Destination buffer for data
236 * @param len Number of bytes in block (this one and every other)
237 * @return number of bytes loaded
238 */
239static int load_block(unsigned block, uchar *dst, unsigned len)
240{
241 /* We may want to get the final block from the previous set */
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500242 ulong offset = ((int)block - 1) * len + tftp_block_wrap_offset;
Simon Glass1fb7cd42011-10-24 18:00:07 +0000243 ulong tosend = len;
244
Joe Hershberger14111572015-04-08 01:41:02 -0500245 tosend = min(net_boot_file_size - offset, tosend);
Simon Glass1fb7cd42011-10-24 18:00:07 +0000246 (void)memcpy(dst, (void *)(save_addr + offset), tosend);
247 debug("%s: block=%d, offset=%ld, len=%d, tosend=%ld\n", __func__,
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500248 block, offset, len, tosend);
Simon Glass1fb7cd42011-10-24 18:00:07 +0000249 return tosend;
250}
251#endif
252
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500253static void tftp_send(void);
254static void tftp_timeout_handler(void);
wdenkfe8c2802002-11-03 00:38:21 +0000255
256/**********************************************************************/
257
Simon Glassf5329bb2011-10-24 18:00:03 +0000258static void show_block_marker(void)
259{
260#ifdef CONFIG_TFTP_TSIZE
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500261 if (tftp_tsize) {
262 ulong pos = tftp_cur_block * tftp_block_size +
263 tftp_block_wrap_offset;
Max Krummenacher7628afe2015-08-05 17:17:05 +0200264 if (pos > tftp_tsize)
265 pos = tftp_tsize;
Simon Glassf5329bb2011-10-24 18:00:03 +0000266
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500267 while (tftp_tsize_num_hash < pos * 50 / tftp_tsize) {
Simon Glassf5329bb2011-10-24 18:00:03 +0000268 putc('#');
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500269 tftp_tsize_num_hash++;
Simon Glassf5329bb2011-10-24 18:00:03 +0000270 }
Simon Glass1fb7cd42011-10-24 18:00:07 +0000271 } else
Simon Glassf5329bb2011-10-24 18:00:03 +0000272#endif
Simon Glass1fb7cd42011-10-24 18:00:07 +0000273 {
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500274 if (((tftp_cur_block - 1) % 10) == 0)
Simon Glassf5329bb2011-10-24 18:00:03 +0000275 putc('#');
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500276 else if ((tftp_cur_block % (10 * HASHES_PER_LINE)) == 0)
Simon Glassf5329bb2011-10-24 18:00:03 +0000277 puts("\n\t ");
278 }
279}
280
Simon Glasse4cde2f2011-10-24 18:00:04 +0000281/**
282 * restart the current transfer due to an error
283 *
284 * @param msg Message to print for user
285 */
286static void restart(const char *msg)
287{
288 printf("\n%s; starting again\n", msg);
289#ifdef CONFIG_MCAST_TFTP
290 mcast_cleanup();
291#endif
Joe Hershbergerbc0571f2015-04-08 01:41:21 -0500292 net_start_again();
Simon Glasse4cde2f2011-10-24 18:00:04 +0000293}
294
295/*
296 * Check if the block number has wrapped, and update progress
297 *
298 * TODO: The egregious use of global variables in this file should be tidied.
299 */
300static void update_block_number(void)
301{
302 /*
303 * RFC1350 specifies that the first data packet will
304 * have sequence number 1. If we receive a sequence
305 * number of 0 this means that there was a wrap
306 * around of the (16 bit) counter.
307 */
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500308 if (tftp_cur_block == 0 && tftp_prev_block != 0) {
309 tftp_block_wrap++;
310 tftp_block_wrap_offset += tftp_block_size * TFTP_SEQUENCE_SIZE;
311 timeout_count = 0; /* we've done well, reset the timeout */
Simon Glasse4cde2f2011-10-24 18:00:04 +0000312 } else {
313 show_block_marker();
314 }
315}
316
Simon Glassf5329bb2011-10-24 18:00:03 +0000317/* The TFTP get or put is complete */
318static void tftp_complete(void)
319{
320#ifdef CONFIG_TFTP_TSIZE
321 /* Print hash marks for the last packet received */
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500322 while (tftp_tsize && tftp_tsize_num_hash < 49) {
Simon Glassf5329bb2011-10-24 18:00:03 +0000323 putc('#');
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500324 tftp_tsize_num_hash++;
Simon Glassf5329bb2011-10-24 18:00:03 +0000325 }
Simon Glass8104f542014-10-10 07:30:21 -0600326 puts(" ");
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500327 print_size(tftp_tsize, "");
Simon Glassf5329bb2011-10-24 18:00:03 +0000328#endif
Simon Glass85b19802012-10-11 13:57:36 +0000329 time_start = get_timer(time_start);
330 if (time_start > 0) {
331 puts("\n\t "); /* Line up with "Loading: " */
Joe Hershberger14111572015-04-08 01:41:02 -0500332 print_size(net_boot_file_size /
Simon Glass85b19802012-10-11 13:57:36 +0000333 time_start * 1000, "/s");
334 }
Simon Glassf5329bb2011-10-24 18:00:03 +0000335 puts("\ndone\n");
Joe Hershberger22f6e992012-05-23 07:59:14 +0000336 net_set_state(NETLOOP_SUCCESS);
Simon Glassf5329bb2011-10-24 18:00:03 +0000337}
338
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500339static void tftp_send(void)
wdenkfe8c2802002-11-03 00:38:21 +0000340{
Simon Glass1fb7cd42011-10-24 18:00:07 +0000341 uchar *pkt;
Joe Hershbergerdb288a92012-05-15 08:59:04 +0000342 uchar *xp;
343 int len = 0;
344 ushort *s;
wdenkfe8c2802002-11-03 00:38:21 +0000345
Wolfgang Denk85eb5ca2007-08-14 09:47:27 +0200346#ifdef CONFIG_MCAST_TFTP
David Updegraff53a5c422007-06-11 10:41:07 -0500347 /* Multicast TFTP.. non-MasterClients do not ACK data. */
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500348 if (tftp_mcast_active && tftp_state == STATE_DATA &&
349 tftp_mcast_master_client == 0)
David Updegraff53a5c422007-06-11 10:41:07 -0500350 return;
351#endif
wdenkfe8c2802002-11-03 00:38:21 +0000352 /*
353 * We will always be sending some sort of packet, so
354 * cobble together the packet headers now.
355 */
Joe Hershberger1203fcc2015-04-08 01:41:05 -0500356 pkt = net_tx_packet + net_eth_hdr_size() + IP_UDP_HDR_SIZE;
wdenkfe8c2802002-11-03 00:38:21 +0000357
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500358 switch (tftp_state) {
Luca Ceresolie3fb0ab2011-05-17 00:03:38 +0000359 case STATE_SEND_RRQ:
Simon Glass1fb7cd42011-10-24 18:00:07 +0000360 case STATE_SEND_WRQ:
wdenkfe8c2802002-11-03 00:38:21 +0000361 xp = pkt;
Wolfgang Denk7bc5ee02005-08-26 01:36:03 +0200362 s = (ushort *)pkt;
Simon Glass8c6914f2011-10-27 06:24:29 +0000363#ifdef CONFIG_CMD_TFTPPUT
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500364 *s++ = htons(tftp_state == STATE_SEND_RRQ ? TFTP_RRQ :
Simon Glass1fb7cd42011-10-24 18:00:07 +0000365 TFTP_WRQ);
Simon Glass8c6914f2011-10-27 06:24:29 +0000366#else
367 *s++ = htons(TFTP_RRQ);
368#endif
Wolfgang Denk7bc5ee02005-08-26 01:36:03 +0200369 pkt = (uchar *)s;
Luca Ceresolic718b142011-05-14 05:49:57 +0000370 strcpy((char *)pkt, tftp_filename);
wdenkfe8c2802002-11-03 00:38:21 +0000371 pkt += strlen(tftp_filename) + 1;
Luca Ceresolic718b142011-05-14 05:49:57 +0000372 strcpy((char *)pkt, "octet");
wdenkfe8c2802002-11-03 00:38:21 +0000373 pkt += 5 /*strlen("octet")*/ + 1;
Luca Ceresolic718b142011-05-14 05:49:57 +0000374 strcpy((char *)pkt, "timeout");
wdenkfbe4b5c2003-10-06 21:55:32 +0000375 pkt += 7 /*strlen("timeout")*/ + 1;
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500376 sprintf((char *)pkt, "%lu", timeout_ms / 1000);
Robin Getz0ebf04c2009-07-23 03:01:03 -0400377 debug("send option \"timeout %s\"\n", (char *)pkt);
wdenkfbe4b5c2003-10-06 21:55:32 +0000378 pkt += strlen((char *)pkt) + 1;
Robin Getz4fccb812009-08-20 10:50:20 -0400379#ifdef CONFIG_TFTP_TSIZE
Joe Hershberger14111572015-04-08 01:41:02 -0500380 pkt += sprintf((char *)pkt, "tsize%c%u%c",
381 0, net_boot_file_size, 0);
Robin Getz4fccb812009-08-20 10:50:20 -0400382#endif
David Updegraff53a5c422007-06-11 10:41:07 -0500383 /* try for more effic. blk size */
Luca Ceresolic718b142011-05-14 05:49:57 +0000384 pkt += sprintf((char *)pkt, "blksize%c%d%c",
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500385 0, tftp_block_size_option, 0);
Wolfgang Denk85eb5ca2007-08-14 09:47:27 +0200386#ifdef CONFIG_MCAST_TFTP
David Updegraff53a5c422007-06-11 10:41:07 -0500387 /* Check all preconditions before even trying the option */
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500388 if (!tftp_mcast_disabled) {
389 tftp_mcast_bitmap = malloc(tftp_mcast_bitmap_size);
390 if (tftp_mcast_bitmap && eth_get_dev()->mcast) {
391 free(tftp_mcast_bitmap);
392 tftp_mcast_bitmap = NULL;
Joe Hershberger13dfe942012-05-15 08:59:12 +0000393 pkt += sprintf((char *)pkt, "multicast%c%c",
394 0, 0);
395 }
David Updegraff53a5c422007-06-11 10:41:07 -0500396 }
397#endif /* CONFIG_MCAST_TFTP */
wdenkfe8c2802002-11-03 00:38:21 +0000398 len = pkt - xp;
399 break;
400
wdenkfbe4b5c2003-10-06 21:55:32 +0000401 case STATE_OACK:
David Updegraff53a5c422007-06-11 10:41:07 -0500402#ifdef CONFIG_MCAST_TFTP
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500403 /* My turn! Start at where I need blocks I missed. */
404 if (tftp_mcast_active)
405 tftp_cur_block = ext2_find_next_zero_bit(
406 tftp_mcast_bitmap,
407 tftp_mcast_bitmap_size * 8, 0);
408 /* fall through */
David Updegraff53a5c422007-06-11 10:41:07 -0500409#endif
Luca Ceresolie59e3562011-05-17 00:03:39 +0000410
411 case STATE_RECV_WRQ:
David Updegraff53a5c422007-06-11 10:41:07 -0500412 case STATE_DATA:
wdenkfe8c2802002-11-03 00:38:21 +0000413 xp = pkt;
Wolfgang Denk7bc5ee02005-08-26 01:36:03 +0200414 s = (ushort *)pkt;
Simon Glass1fb7cd42011-10-24 18:00:07 +0000415 s[0] = htons(TFTP_ACK);
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500416 s[1] = htons(tftp_cur_block);
Simon Glass1fb7cd42011-10-24 18:00:07 +0000417 pkt = (uchar *)(s + 2);
418#ifdef CONFIG_CMD_TFTPPUT
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500419 if (tftp_put_active) {
420 int toload = tftp_block_size;
421 int loaded = load_block(tftp_cur_block, pkt, toload);
Simon Glass1fb7cd42011-10-24 18:00:07 +0000422
423 s[0] = htons(TFTP_DATA);
424 pkt += loaded;
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500425 tftp_put_final_block_sent = (loaded < toload);
Simon Glass1fb7cd42011-10-24 18:00:07 +0000426 }
427#endif
wdenkfe8c2802002-11-03 00:38:21 +0000428 len = pkt - xp;
429 break;
430
431 case STATE_TOO_LARGE:
432 xp = pkt;
Wolfgang Denk7bc5ee02005-08-26 01:36:03 +0200433 s = (ushort *)pkt;
434 *s++ = htons(TFTP_ERROR);
Simon Glass1fb7cd42011-10-24 18:00:07 +0000435 *s++ = htons(3);
436
Wolfgang Denk7bc5ee02005-08-26 01:36:03 +0200437 pkt = (uchar *)s;
Luca Ceresolic718b142011-05-14 05:49:57 +0000438 strcpy((char *)pkt, "File too large");
wdenkfe8c2802002-11-03 00:38:21 +0000439 pkt += 14 /*strlen("File too large")*/ + 1;
440 len = pkt - xp;
441 break;
442
443 case STATE_BAD_MAGIC:
444 xp = pkt;
Wolfgang Denk7bc5ee02005-08-26 01:36:03 +0200445 s = (ushort *)pkt;
446 *s++ = htons(TFTP_ERROR);
447 *s++ = htons(2);
448 pkt = (uchar *)s;
Luca Ceresolic718b142011-05-14 05:49:57 +0000449 strcpy((char *)pkt, "File has bad magic");
wdenkfe8c2802002-11-03 00:38:21 +0000450 pkt += 18 /*strlen("File has bad magic")*/ + 1;
451 len = pkt - xp;
452 break;
453 }
454
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500455 net_send_udp_packet(net_server_ethaddr, tftp_remote_ip,
456 tftp_remote_port, tftp_our_port, len);
wdenkfe8c2802002-11-03 00:38:21 +0000457}
458
Simon Glass39bccd22011-10-26 14:18:38 +0000459#ifdef CONFIG_CMD_TFTPPUT
Simon Glass1fb7cd42011-10-24 18:00:07 +0000460static void icmp_handler(unsigned type, unsigned code, unsigned dest,
Joe Hershberger049a95a2015-04-08 01:41:01 -0500461 struct in_addr sip, unsigned src, uchar *pkt,
462 unsigned len)
Simon Glass1fb7cd42011-10-24 18:00:07 +0000463{
464 if (type == ICMP_NOT_REACH && code == ICMP_NOT_REACH_PORT) {
465 /* Oh dear the other end has gone away */
466 restart("TFTP server died");
467 }
468}
Simon Glass39bccd22011-10-26 14:18:38 +0000469#endif
Simon Glass1fb7cd42011-10-24 18:00:07 +0000470
Joe Hershberger049a95a2015-04-08 01:41:01 -0500471static void tftp_handler(uchar *pkt, unsigned dest, struct in_addr sip,
472 unsigned src, unsigned len)
wdenkfe8c2802002-11-03 00:38:21 +0000473{
Kim Phillips61fdd4f2013-01-16 18:09:19 -0600474 __be16 proto;
475 __be16 *s;
Wolfgang Denkff13ac82007-08-30 14:42:15 +0200476 int i;
wdenkfe8c2802002-11-03 00:38:21 +0000477
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500478 if (dest != tftp_our_port) {
David Updegraff53a5c422007-06-11 10:41:07 -0500479#ifdef CONFIG_MCAST_TFTP
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500480 if (tftp_mcast_active &&
481 (!tftp_mcast_port || dest != tftp_mcast_port))
David Updegraff53a5c422007-06-11 10:41:07 -0500482#endif
Luca Ceresoli0bdd8ac2011-05-14 05:50:02 +0000483 return;
wdenkfe8c2802002-11-03 00:38:21 +0000484 }
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500485 if (tftp_state != STATE_SEND_RRQ && src != tftp_remote_port &&
486 tftp_state != STATE_RECV_WRQ && tftp_state != STATE_SEND_WRQ)
wdenkfe8c2802002-11-03 00:38:21 +0000487 return;
wdenkfe8c2802002-11-03 00:38:21 +0000488
Luca Ceresoli7bc325a2011-05-14 05:50:00 +0000489 if (len < 2)
wdenkfe8c2802002-11-03 00:38:21 +0000490 return;
wdenkfe8c2802002-11-03 00:38:21 +0000491 len -= 2;
492 /* warning: don't use increment (++) in ntohs() macros!! */
Kim Phillips61fdd4f2013-01-16 18:09:19 -0600493 s = (__be16 *)pkt;
Wolfgang Denk7bc5ee02005-08-26 01:36:03 +0200494 proto = *s++;
495 pkt = (uchar *)s;
wdenkfe8c2802002-11-03 00:38:21 +0000496 switch (ntohs(proto)) {
wdenkfe8c2802002-11-03 00:38:21 +0000497 case TFTP_RRQ:
wdenkfe8c2802002-11-03 00:38:21 +0000498 break;
Simon Glass1fb7cd42011-10-24 18:00:07 +0000499
500 case TFTP_ACK:
501#ifdef CONFIG_CMD_TFTPPUT
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500502 if (tftp_put_active) {
503 if (tftp_put_final_block_sent) {
Simon Glass1fb7cd42011-10-24 18:00:07 +0000504 tftp_complete();
505 } else {
506 /*
507 * Move to the next block. We want our block
508 * count to wrap just like the other end!
509 */
510 int block = ntohs(*s);
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500511 int ack_ok = (tftp_cur_block == block);
Simon Glass1fb7cd42011-10-24 18:00:07 +0000512
Ajay Kishore3491df22016-09-15 15:29:02 +0530513 tftp_prev_block = tftp_cur_block;
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500514 tftp_cur_block = (unsigned short)(block + 1);
Simon Glass1fb7cd42011-10-24 18:00:07 +0000515 update_block_number();
516 if (ack_ok)
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500517 tftp_send(); /* Send next data block */
Simon Glass1fb7cd42011-10-24 18:00:07 +0000518 }
519 }
520#endif
521 break;
522
wdenkfe8c2802002-11-03 00:38:21 +0000523 default:
524 break;
525
Luca Ceresolie59e3562011-05-17 00:03:39 +0000526#ifdef CONFIG_CMD_TFTPSRV
527 case TFTP_WRQ:
528 debug("Got WRQ\n");
Joe Hershberger049a95a2015-04-08 01:41:01 -0500529 tftp_remote_ip = sip;
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500530 tftp_remote_port = src;
531 tftp_our_port = 1024 + (get_timer(0) % 3072);
Simon Glasse4cde2f2011-10-24 18:00:04 +0000532 new_transfer();
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500533 tftp_send(); /* Send ACK(0) */
Luca Ceresolie59e3562011-05-17 00:03:39 +0000534 break;
535#endif
536
wdenkfbe4b5c2003-10-06 21:55:32 +0000537 case TFTP_OACK:
Wolfgang Denkd3717082009-08-10 09:59:10 +0200538 debug("Got OACK: %s %s\n",
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500539 pkt, pkt + strlen((char *)pkt) + 1);
540 tftp_state = STATE_OACK;
541 tftp_remote_port = src;
Wolfgang Denk60174742007-08-31 10:01:51 +0200542 /*
543 * Check for 'blksize' option.
544 * Careful: "i" is signed, "len" is unsigned, thus
545 * something like "len-8" may give a *huge* number
546 */
Luca Ceresolic718b142011-05-14 05:49:57 +0000547 for (i = 0; i+8 < len; i++) {
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500548 if (strcmp((char *)pkt + i, "blksize") == 0) {
549 tftp_block_size = (unsigned short)
550 simple_strtoul((char *)pkt + i + 8,
551 NULL, 10);
Robin Getz0ebf04c2009-07-23 03:01:03 -0400552 debug("Blocksize ack: %s, %d\n",
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500553 (char *)pkt + i + 8, tftp_block_size);
Wolfgang Denkff13ac82007-08-30 14:42:15 +0200554 }
Robin Getz4fccb812009-08-20 10:50:20 -0400555#ifdef CONFIG_TFTP_TSIZE
Luca Ceresoli2e320252011-05-14 05:49:58 +0000556 if (strcmp((char *)pkt+i, "tsize") == 0) {
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500557 tftp_tsize = simple_strtoul((char *)pkt + i + 6,
Luca Ceresoli2f094132011-05-14 05:49:56 +0000558 NULL, 10);
Robin Getz4fccb812009-08-20 10:50:20 -0400559 debug("size = %s, %d\n",
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500560 (char *)pkt + i + 6, tftp_tsize);
Robin Getz4fccb812009-08-20 10:50:20 -0400561 }
562#endif
David Updegraff53a5c422007-06-11 10:41:07 -0500563 }
564#ifdef CONFIG_MCAST_TFTP
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500565 parse_multicast_oack((char *)pkt, len - 1);
566 if ((tftp_mcast_active) && (!tftp_mcast_master_client))
567 tftp_state = STATE_DATA; /* passive.. */
David Updegraff53a5c422007-06-11 10:41:07 -0500568 else
569#endif
Simon Glass1fb7cd42011-10-24 18:00:07 +0000570#ifdef CONFIG_CMD_TFTPPUT
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500571 if (tftp_put_active) {
Simon Glass1fb7cd42011-10-24 18:00:07 +0000572 /* Get ready to send the first block */
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500573 tftp_state = STATE_DATA;
574 tftp_cur_block++;
Simon Glass1fb7cd42011-10-24 18:00:07 +0000575 }
576#endif
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500577 tftp_send(); /* Send ACK or first data block */
wdenkfbe4b5c2003-10-06 21:55:32 +0000578 break;
wdenkfe8c2802002-11-03 00:38:21 +0000579 case TFTP_DATA:
580 if (len < 2)
581 return;
582 len -= 2;
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500583 tftp_cur_block = ntohs(*(__be16 *)pkt);
wdenk3f85ce22004-02-23 16:11:30 +0000584
Simon Glasse4cde2f2011-10-24 18:00:04 +0000585 update_block_number();
wdenkfe8c2802002-11-03 00:38:21 +0000586
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500587 if (tftp_state == STATE_SEND_RRQ)
Robin Getz0ebf04c2009-07-23 03:01:03 -0400588 debug("Server did not acknowledge timeout option!\n");
wdenkfbe4b5c2003-10-06 21:55:32 +0000589
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500590 if (tftp_state == STATE_SEND_RRQ || tftp_state == STATE_OACK ||
591 tftp_state == STATE_RECV_WRQ) {
wdenk3f85ce22004-02-23 16:11:30 +0000592 /* first block received */
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500593 tftp_state = STATE_DATA;
594 tftp_remote_port = src;
Simon Glasse4cde2f2011-10-24 18:00:04 +0000595 new_transfer();
wdenkfe8c2802002-11-03 00:38:21 +0000596
David Updegraff53a5c422007-06-11 10:41:07 -0500597#ifdef CONFIG_MCAST_TFTP
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500598 if (tftp_mcast_active) { /* start!=1 common if mcast */
599 tftp_prev_block = tftp_cur_block - 1;
David Updegraff53a5c422007-06-11 10:41:07 -0500600 } else
601#endif
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500602 if (tftp_cur_block != 1) { /* Assertion */
603 puts("\nTFTP error: ");
604 printf("First block is not block 1 (%ld)\n",
605 tftp_cur_block);
606 puts("Starting again\n\n");
Joe Hershbergerbc0571f2015-04-08 01:41:21 -0500607 net_start_again();
wdenkfe8c2802002-11-03 00:38:21 +0000608 break;
609 }
610 }
611
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500612 if (tftp_cur_block == tftp_prev_block) {
613 /* Same block again; ignore it. */
wdenkfe8c2802002-11-03 00:38:21 +0000614 break;
615 }
616
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500617 tftp_prev_block = tftp_cur_block;
Albert ARIBAUD \(3ADEV\)f5fb7342015-10-12 00:02:57 +0200618 timeout_count_max = tftp_timeout_count_max;
Joe Hershbergerbc0571f2015-04-08 01:41:21 -0500619 net_set_timeout_handler(timeout_ms, tftp_timeout_handler);
wdenkfe8c2802002-11-03 00:38:21 +0000620
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500621 store_block(tftp_cur_block - 1, pkt + 2, len);
wdenkfe8c2802002-11-03 00:38:21 +0000622
623 /*
Luca Ceresoli4d69e982011-05-17 00:03:41 +0000624 * Acknowledge the block just received, which will prompt
Luca Ceresoli20478ce2011-05-17 00:03:37 +0000625 * the remote for the next one.
wdenkfe8c2802002-11-03 00:38:21 +0000626 */
David Updegraff53a5c422007-06-11 10:41:07 -0500627#ifdef CONFIG_MCAST_TFTP
Wolfgang Denk85eb5ca2007-08-14 09:47:27 +0200628 /* if I am the MasterClient, actively calculate what my next
629 * needed block is; else I'm passive; not ACKING
Jean-Christophe PLAGNIOL-VILLARDa93907c2008-01-18 01:14:03 +0100630 */
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500631 if (tftp_mcast_active) {
632 if (len < tftp_block_size) {
633 tftp_mcast_ending_block = tftp_cur_block;
634 } else if (tftp_mcast_master_client) {
635 tftp_mcast_prev_hole = ext2_find_next_zero_bit(
636 tftp_mcast_bitmap,
637 tftp_mcast_bitmap_size * 8,
638 tftp_mcast_prev_hole);
639 tftp_cur_block = tftp_mcast_prev_hole;
640 if (tftp_cur_block >
641 ((tftp_mcast_bitmap_size * 8) - 1)) {
642 debug("tftpfile too big\n");
David Updegraff53a5c422007-06-11 10:41:07 -0500643 /* try to double it and retry */
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500644 tftp_mcast_bitmap_size <<= 1;
David Updegraff53a5c422007-06-11 10:41:07 -0500645 mcast_cleanup();
Joe Hershbergerbc0571f2015-04-08 01:41:21 -0500646 net_start_again();
David Updegraff53a5c422007-06-11 10:41:07 -0500647 return;
648 }
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500649 tftp_prev_block = tftp_cur_block;
David Updegraff53a5c422007-06-11 10:41:07 -0500650 }
651 }
652#endif
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500653 tftp_send();
wdenkfe8c2802002-11-03 00:38:21 +0000654
David Updegraff53a5c422007-06-11 10:41:07 -0500655#ifdef CONFIG_MCAST_TFTP
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500656 if (tftp_mcast_active) {
657 if (tftp_mcast_master_client &&
658 (tftp_cur_block >= tftp_mcast_ending_block)) {
Luca Ceresolic718b142011-05-14 05:49:57 +0000659 puts("\nMulticast tftp done\n");
David Updegraff53a5c422007-06-11 10:41:07 -0500660 mcast_cleanup();
Joe Hershberger22f6e992012-05-23 07:59:14 +0000661 net_set_state(NETLOOP_SUCCESS);
Wolfgang Denk85eb5ca2007-08-14 09:47:27 +0200662 }
Joe Hershberger13dfe942012-05-15 08:59:12 +0000663 } else
David Updegraff53a5c422007-06-11 10:41:07 -0500664#endif
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500665 if (len < tftp_block_size)
Simon Glassf5329bb2011-10-24 18:00:03 +0000666 tftp_complete();
wdenkfe8c2802002-11-03 00:38:21 +0000667 break;
668
669 case TFTP_ERROR:
Luca Ceresolic718b142011-05-14 05:49:57 +0000670 printf("\nTFTP error: '%s' (%d)\n",
Kim Phillips61fdd4f2013-01-16 18:09:19 -0600671 pkt + 2, ntohs(*(__be16 *)pkt));
Remy Bohmeraafda382009-10-28 22:13:40 +0100672
Kim Phillips61fdd4f2013-01-16 18:09:19 -0600673 switch (ntohs(*(__be16 *)pkt)) {
Remy Bohmeraafda382009-10-28 22:13:40 +0100674 case TFTP_ERR_FILE_NOT_FOUND:
675 case TFTP_ERR_ACCESS_DENIED:
676 puts("Not retrying...\n");
677 eth_halt();
Joe Hershberger22f6e992012-05-23 07:59:14 +0000678 net_set_state(NETLOOP_FAIL);
Remy Bohmeraafda382009-10-28 22:13:40 +0100679 break;
680 case TFTP_ERR_UNDEFINED:
681 case TFTP_ERR_DISK_FULL:
682 case TFTP_ERR_UNEXPECTED_OPCODE:
683 case TFTP_ERR_UNKNOWN_TRANSFER_ID:
684 case TFTP_ERR_FILE_ALREADY_EXISTS:
685 default:
686 puts("Starting again\n\n");
David Updegraff53a5c422007-06-11 10:41:07 -0500687#ifdef CONFIG_MCAST_TFTP
Remy Bohmeraafda382009-10-28 22:13:40 +0100688 mcast_cleanup();
David Updegraff53a5c422007-06-11 10:41:07 -0500689#endif
Joe Hershbergerbc0571f2015-04-08 01:41:21 -0500690 net_start_again();
Remy Bohmeraafda382009-10-28 22:13:40 +0100691 break;
692 }
wdenkfe8c2802002-11-03 00:38:21 +0000693 break;
694 }
695}
696
697
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500698static void tftp_timeout_handler(void)
wdenkfe8c2802002-11-03 00:38:21 +0000699{
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500700 if (++timeout_count > timeout_count_max) {
Simon Glasse4cde2f2011-10-24 18:00:04 +0000701 restart("Retry count exceeded");
wdenkfe8c2802002-11-03 00:38:21 +0000702 } else {
Luca Ceresolic718b142011-05-14 05:49:57 +0000703 puts("T ");
Joe Hershbergerbc0571f2015-04-08 01:41:21 -0500704 net_set_timeout_handler(timeout_ms, tftp_timeout_handler);
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500705 if (tftp_state != STATE_RECV_WRQ)
706 tftp_send();
wdenkfe8c2802002-11-03 00:38:21 +0000707 }
708}
709
710
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500711void tftp_start(enum proto_t protocol)
wdenkfe8c2802002-11-03 00:38:21 +0000712{
Albert ARIBAUD \(3ADEV\)f5fb7342015-10-12 00:02:57 +0200713#if CONFIG_NET_TFTP_VARS
Wolfgang Denkecb0ccd2005-09-24 22:37:32 +0200714 char *ep; /* Environment pointer */
Alessandro Rubini89ba81d2009-08-07 13:59:06 +0200715
Wolfgang Denkc96f86e2010-01-17 23:55:53 +0100716 /*
717 * Allow the user to choose TFTP blocksize and timeout.
718 * TFTP protocol has a minimal timeout of 1 second.
719 */
Albert ARIBAUD \(3ADEV\)f5fb7342015-10-12 00:02:57 +0200720
Luca Ceresoli2cb53602011-05-14 05:49:59 +0000721 ep = getenv("tftpblocksize");
722 if (ep != NULL)
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500723 tftp_block_size_option = simple_strtol(ep, NULL, 10);
Wolfgang Denkc96f86e2010-01-17 23:55:53 +0100724
Luca Ceresoli2cb53602011-05-14 05:49:59 +0000725 ep = getenv("tftptimeout");
726 if (ep != NULL)
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500727 timeout_ms = simple_strtol(ep, NULL, 10);
Wolfgang Denkc96f86e2010-01-17 23:55:53 +0100728
Bin Mengaf2ca592015-08-27 22:25:51 -0700729 if (timeout_ms < 1000) {
730 printf("TFTP timeout (%ld ms) too low, set min = 1000 ms\n",
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500731 timeout_ms);
Bin Mengaf2ca592015-08-27 22:25:51 -0700732 timeout_ms = 1000;
Wolfgang Denkc96f86e2010-01-17 23:55:53 +0100733 }
734
Albert ARIBAUD \(3ADEV\)f5fb7342015-10-12 00:02:57 +0200735 ep = getenv("tftptimeoutcountmax");
736 if (ep != NULL)
737 tftp_timeout_count_max = simple_strtol(ep, NULL, 10);
738
739 if (tftp_timeout_count_max < 0) {
740 printf("TFTP timeout count max (%d ms) negative, set to 0\n",
741 tftp_timeout_count_max);
742 tftp_timeout_count_max = 0;
743 }
744#endif
745
Wolfgang Denkc96f86e2010-01-17 23:55:53 +0100746 debug("TFTP blocksize = %i, timeout = %ld ms\n",
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500747 tftp_block_size_option, timeout_ms);
Wolfgang Denkecb0ccd2005-09-24 22:37:32 +0200748
Joe Hershberger049a95a2015-04-08 01:41:01 -0500749 tftp_remote_ip = net_server_ip;
Joe Hershberger14111572015-04-08 01:41:02 -0500750 if (net_boot_file_name[0] == '\0') {
Matthias Weisserea45cb02011-12-03 03:29:44 +0000751 sprintf(default_filename, "%02X%02X%02X%02X.img",
Joe Hershberger049a95a2015-04-08 01:41:01 -0500752 net_ip.s_addr & 0xFF,
753 (net_ip.s_addr >> 8) & 0xFF,
754 (net_ip.s_addr >> 16) & 0xFF,
755 (net_ip.s_addr >> 24) & 0xFF);
Jean-Christophe PLAGNIOL-VILLARDa93907c2008-01-18 01:14:03 +0100756
757 strncpy(tftp_filename, default_filename, MAX_LEN);
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500758 tftp_filename[MAX_LEN - 1] = 0;
wdenkfe8c2802002-11-03 00:38:21 +0000759
Luca Ceresolic718b142011-05-14 05:49:57 +0000760 printf("*** Warning: no boot file name; using '%s'\n",
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500761 tftp_filename);
wdenkfe8c2802002-11-03 00:38:21 +0000762 } else {
Joe Hershberger14111572015-04-08 01:41:02 -0500763 char *p = strchr(net_boot_file_name, ':');
Jean-Christophe PLAGNIOL-VILLARDa93907c2008-01-18 01:14:03 +0100764
765 if (p == NULL) {
Joe Hershberger14111572015-04-08 01:41:02 -0500766 strncpy(tftp_filename, net_boot_file_name, MAX_LEN);
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500767 tftp_filename[MAX_LEN - 1] = 0;
Jean-Christophe PLAGNIOL-VILLARDa93907c2008-01-18 01:14:03 +0100768 } else {
Joe Hershberger14111572015-04-08 01:41:02 -0500769 tftp_remote_ip = string_to_ip(net_boot_file_name);
Peter Tyser6a86bb62008-12-01 16:29:38 -0600770 strncpy(tftp_filename, p + 1, MAX_LEN);
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500771 tftp_filename[MAX_LEN - 1] = 0;
Jean-Christophe PLAGNIOL-VILLARDa93907c2008-01-18 01:14:03 +0100772 }
wdenkfe8c2802002-11-03 00:38:21 +0000773 }
774
Luca Ceresolic718b142011-05-14 05:49:57 +0000775 printf("Using %s device\n", eth_get_name());
Simon Glass1fb7cd42011-10-24 18:00:07 +0000776 printf("TFTP %s server %pI4; our IP address is %pI4",
Simon Glass8c6914f2011-10-27 06:24:29 +0000777#ifdef CONFIG_CMD_TFTPPUT
778 protocol == TFTPPUT ? "to" : "from",
779#else
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500780 "from",
Simon Glass8c6914f2011-10-27 06:24:29 +0000781#endif
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500782 &tftp_remote_ip, &net_ip);
wdenkfe8c2802002-11-03 00:38:21 +0000783
784 /* Check if we need to send across this subnet */
Joe Hershberger049a95a2015-04-08 01:41:01 -0500785 if (net_gateway.s_addr && net_netmask.s_addr) {
786 struct in_addr our_net;
787 struct in_addr remote_net;
wdenkfe8c2802002-11-03 00:38:21 +0000788
Joe Hershberger049a95a2015-04-08 01:41:01 -0500789 our_net.s_addr = net_ip.s_addr & net_netmask.s_addr;
790 remote_net.s_addr = tftp_remote_ip.s_addr & net_netmask.s_addr;
791 if (our_net.s_addr != remote_net.s_addr)
792 printf("; sending through gateway %pI4", &net_gateway);
wdenkfe8c2802002-11-03 00:38:21 +0000793 }
Luca Ceresolic718b142011-05-14 05:49:57 +0000794 putc('\n');
wdenkfe8c2802002-11-03 00:38:21 +0000795
Luca Ceresolic718b142011-05-14 05:49:57 +0000796 printf("Filename '%s'.", tftp_filename);
wdenkfe8c2802002-11-03 00:38:21 +0000797
Joe Hershberger14111572015-04-08 01:41:02 -0500798 if (net_boot_file_expected_size_in_blocks) {
799 printf(" Size is 0x%x Bytes = ",
800 net_boot_file_expected_size_in_blocks << 9);
801 print_size(net_boot_file_expected_size_in_blocks << 9, "");
wdenkfe8c2802002-11-03 00:38:21 +0000802 }
803
Luca Ceresolic718b142011-05-14 05:49:57 +0000804 putc('\n');
Simon Glass1fb7cd42011-10-24 18:00:07 +0000805#ifdef CONFIG_CMD_TFTPPUT
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500806 tftp_put_active = (protocol == TFTPPUT);
807 if (tftp_put_active) {
Simon Glass1fb7cd42011-10-24 18:00:07 +0000808 printf("Save address: 0x%lx\n", save_addr);
809 printf("Save size: 0x%lx\n", save_size);
Joe Hershberger14111572015-04-08 01:41:02 -0500810 net_boot_file_size = save_size;
Simon Glass1fb7cd42011-10-24 18:00:07 +0000811 puts("Saving: *\b");
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500812 tftp_state = STATE_SEND_WRQ;
Simon Glass1fb7cd42011-10-24 18:00:07 +0000813 new_transfer();
814 } else
815#endif
816 {
817 printf("Load address: 0x%lx\n", load_addr);
Sanjeev N9908fc32017-09-05 15:18:54 +0530818 /*
819 * Do not load files to the reserved region or the
820 * region where linux is executed.
821 */
822 if ((load_addr < IPQ_TFTP_MIN_ADDR) ||
823 (load_addr >= CONFIG_SYS_SDRAM_END) ||
824 ((load_addr >= CONFIG_IPQ_FDT_HIGH) &&
825 (load_addr < CONFIG_TZ_END_ADDR))) {
826 puts("\nError specified load address not allowed\n");
827 net_set_state(NETLOOP_FAIL);
828 return;
829 }
Simon Glass1fb7cd42011-10-24 18:00:07 +0000830 puts("Loading: *\b");
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500831 tftp_state = STATE_SEND_RRQ;
Simon Glass1fb7cd42011-10-24 18:00:07 +0000832 }
wdenkfe8c2802002-11-03 00:38:21 +0000833
Simon Glass85b19802012-10-11 13:57:36 +0000834 time_start = get_timer(0);
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500835 timeout_count_max = tftp_timeout_count_max;
Bartlomiej Siekae83cc062008-10-01 15:26:29 +0200836
Joe Hershbergerbc0571f2015-04-08 01:41:21 -0500837 net_set_timeout_handler(timeout_ms, tftp_timeout_handler);
Joe Hershberger049a95a2015-04-08 01:41:01 -0500838 net_set_udp_handler(tftp_handler);
Simon Glass39bccd22011-10-26 14:18:38 +0000839#ifdef CONFIG_CMD_TFTPPUT
Simon Glass1fb7cd42011-10-24 18:00:07 +0000840 net_set_icmp_handler(icmp_handler);
Simon Glass39bccd22011-10-26 14:18:38 +0000841#endif
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500842 tftp_remote_port = WELL_KNOWN_PORT;
843 timeout_count = 0;
Wolfgang Denkecb0ccd2005-09-24 22:37:32 +0200844 /* Use a pseudo-random port unless a specific port is set */
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500845 tftp_our_port = 1024 + (get_timer(0) % 3072);
David Updegraff53a5c422007-06-11 10:41:07 -0500846
Wolfgang Denkecb0ccd2005-09-24 22:37:32 +0200847#ifdef CONFIG_TFTP_PORT
Luca Ceresoli2cb53602011-05-14 05:49:59 +0000848 ep = getenv("tftpdstp");
Luca Ceresoli7bc325a2011-05-14 05:50:00 +0000849 if (ep != NULL)
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500850 tftp_remote_port = simple_strtol(ep, NULL, 10);
Luca Ceresoli2cb53602011-05-14 05:49:59 +0000851 ep = getenv("tftpsrcp");
Luca Ceresoli7bc325a2011-05-14 05:50:00 +0000852 if (ep != NULL)
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500853 tftp_our_port = simple_strtol(ep, NULL, 10);
Wolfgang Denkecb0ccd2005-09-24 22:37:32 +0200854#endif
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500855 tftp_cur_block = 0;
wdenkfe8c2802002-11-03 00:38:21 +0000856
wdenk73a8b272003-06-05 19:27:42 +0000857 /* zero out server ether in case the server ip has changed */
Joe Hershberger0adb5b72015-04-08 01:41:04 -0500858 memset(net_server_ethaddr, 0, 6);
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500859 /* Revert tftp_block_size to dflt */
860 tftp_block_size = TFTP_BLOCK_SIZE;
David Updegraff53a5c422007-06-11 10:41:07 -0500861#ifdef CONFIG_MCAST_TFTP
Jean-Christophe PLAGNIOL-VILLARDa93907c2008-01-18 01:14:03 +0100862 mcast_cleanup();
David Updegraff53a5c422007-06-11 10:41:07 -0500863#endif
Robin Getz4fccb812009-08-20 10:50:20 -0400864#ifdef CONFIG_TFTP_TSIZE
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500865 tftp_tsize = 0;
866 tftp_tsize_num_hash = 0;
Robin Getz4fccb812009-08-20 10:50:20 -0400867#endif
wdenk73a8b272003-06-05 19:27:42 +0000868
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500869 tftp_send();
wdenkfe8c2802002-11-03 00:38:21 +0000870}
871
Luca Ceresolie59e3562011-05-17 00:03:39 +0000872#ifdef CONFIG_CMD_TFTPSRV
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500873void tftp_start_server(void)
Luca Ceresolie59e3562011-05-17 00:03:39 +0000874{
875 tftp_filename[0] = 0;
876
Luca Ceresolie59e3562011-05-17 00:03:39 +0000877 printf("Using %s device\n", eth_get_name());
Joe Hershberger049a95a2015-04-08 01:41:01 -0500878 printf("Listening for TFTP transfer on %pI4\n", &net_ip);
Luca Ceresolie59e3562011-05-17 00:03:39 +0000879 printf("Load address: 0x%lx\n", load_addr);
880
881 puts("Loading: *\b");
882
Albert ARIBAUD \(3ADEV\)f5fb7342015-10-12 00:02:57 +0200883 timeout_count_max = tftp_timeout_count_max;
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500884 timeout_count = 0;
885 timeout_ms = TIMEOUT;
Joe Hershbergerbc0571f2015-04-08 01:41:21 -0500886 net_set_timeout_handler(timeout_ms, tftp_timeout_handler);
Luca Ceresolie59e3562011-05-17 00:03:39 +0000887
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500888 /* Revert tftp_block_size to dflt */
889 tftp_block_size = TFTP_BLOCK_SIZE;
890 tftp_cur_block = 0;
891 tftp_our_port = WELL_KNOWN_PORT;
Luca Ceresolie59e3562011-05-17 00:03:39 +0000892
893#ifdef CONFIG_TFTP_TSIZE
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500894 tftp_tsize = 0;
895 tftp_tsize_num_hash = 0;
Luca Ceresolie59e3562011-05-17 00:03:39 +0000896#endif
897
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500898 tftp_state = STATE_RECV_WRQ;
Joe Hershberger049a95a2015-04-08 01:41:01 -0500899 net_set_udp_handler(tftp_handler);
Andrew Ruder8e525332013-10-22 19:10:28 -0500900
901 /* zero out server ether in case the server ip has changed */
Joe Hershberger0adb5b72015-04-08 01:41:04 -0500902 memset(net_server_ethaddr, 0, 6);
Luca Ceresolie59e3562011-05-17 00:03:39 +0000903}
904#endif /* CONFIG_CMD_TFTPSRV */
905
David Updegraff53a5c422007-06-11 10:41:07 -0500906#ifdef CONFIG_MCAST_TFTP
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500907/*
908 * Credits: atftp project.
David Updegraff53a5c422007-06-11 10:41:07 -0500909 */
910
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500911/*
912 * Pick up BcastAddr, Port, and whether I am [now] the master-client.
David Updegraff53a5c422007-06-11 10:41:07 -0500913 * Frame:
914 * +-------+-----------+---+-------~~-------+---+
915 * | opc | multicast | 0 | addr, port, mc | 0 |
916 * +-------+-----------+---+-------~~-------+---+
917 * The multicast addr/port becomes what I listen to, and if 'mc' is '1' then
918 * I am the new master-client so must send ACKs to DataBlocks. If I am not
919 * master-client, I'm a passive client, gathering what DataBlocks I may and
920 * making note of which ones I got in my bitmask.
921 * In theory, I never go from master->passive..
922 * .. this comes in with pkt already pointing just past opc
923 */
924static void parse_multicast_oack(char *pkt, int len)
925{
Luca Ceresolic718b142011-05-14 05:49:57 +0000926 int i;
Joe Hershberger049a95a2015-04-08 01:41:01 -0500927 struct in_addr addr;
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500928 char *mc_adr;
929 char *port;
930 char *mc;
David Updegraff53a5c422007-06-11 10:41:07 -0500931
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500932 mc_adr = NULL;
933 port = NULL;
934 mc = NULL;
David Updegraff53a5c422007-06-11 10:41:07 -0500935 /* march along looking for 'multicast\0', which has to start at least
936 * 14 bytes back from the end.
937 */
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500938 for (i = 0; i < len - 14; i++)
939 if (strcmp(pkt + i, "multicast") == 0)
David Updegraff53a5c422007-06-11 10:41:07 -0500940 break;
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500941 if (i >= (len - 14)) /* non-Multicast OACK, ign. */
David Updegraff53a5c422007-06-11 10:41:07 -0500942 return;
Wolfgang Denk85eb5ca2007-08-14 09:47:27 +0200943
Luca Ceresolic718b142011-05-14 05:49:57 +0000944 i += 10; /* strlen multicast */
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500945 mc_adr = pkt + i;
Luca Ceresolic718b142011-05-14 05:49:57 +0000946 for (; i < len; i++) {
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500947 if (*(pkt + i) == ',') {
948 *(pkt + i) = '\0';
David Updegraff53a5c422007-06-11 10:41:07 -0500949 if (port) {
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500950 mc = pkt + i + 1;
David Updegraff53a5c422007-06-11 10:41:07 -0500951 break;
952 } else {
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500953 port = pkt + i + 1;
David Updegraff53a5c422007-06-11 10:41:07 -0500954 }
955 }
956 }
Luca Ceresoli6d2231e2011-05-14 05:50:01 +0000957 if (!port || !mc_adr || !mc)
958 return;
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500959 if (tftp_mcast_active && tftp_mcast_master_client) {
Luca Ceresolic718b142011-05-14 05:49:57 +0000960 printf("I got a OACK as master Client, WRONG!\n");
David Updegraff53a5c422007-06-11 10:41:07 -0500961 return;
962 }
963 /* ..I now accept packets destined for this MCAST addr, port */
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500964 if (!tftp_mcast_active) {
965 if (tftp_mcast_bitmap) {
Luca Ceresolic718b142011-05-14 05:49:57 +0000966 printf("Internal failure! no mcast.\n");
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500967 free(tftp_mcast_bitmap);
968 tftp_mcast_bitmap = NULL;
969 tftp_mcast_disabled = 1;
970 return;
David Updegraff53a5c422007-06-11 10:41:07 -0500971 }
972 /* I malloc instead of pre-declare; so that if the file ends
Wolfgang Denk85eb5ca2007-08-14 09:47:27 +0200973 * up being too big for this bitmap I can retry
974 */
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500975 tftp_mcast_bitmap = malloc(tftp_mcast_bitmap_size);
976 if (!tftp_mcast_bitmap) {
977 printf("No bitmap, no multicast. Sorry.\n");
978 tftp_mcast_disabled = 1;
David Updegraff53a5c422007-06-11 10:41:07 -0500979 return;
980 }
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500981 memset(tftp_mcast_bitmap, 0, tftp_mcast_bitmap_size);
982 tftp_mcast_prev_hole = 0;
983 tftp_mcast_active = 1;
David Updegraff53a5c422007-06-11 10:41:07 -0500984 }
985 addr = string_to_ip(mc_adr);
Joe Hershberger049a95a2015-04-08 01:41:01 -0500986 if (net_mcast_addr.s_addr != addr.s_addr) {
987 if (net_mcast_addr.s_addr)
988 eth_mcast_join(net_mcast_addr, 0);
989 net_mcast_addr = addr;
990 if (eth_mcast_join(net_mcast_addr, 1)) {
Luca Ceresolic718b142011-05-14 05:49:57 +0000991 printf("Fail to set mcast, revert to TFTP\n");
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500992 tftp_mcast_disabled = 1;
David Updegraff53a5c422007-06-11 10:41:07 -0500993 mcast_cleanup();
Joe Hershbergerbc0571f2015-04-08 01:41:21 -0500994 net_start_again();
David Updegraff53a5c422007-06-11 10:41:07 -0500995 }
996 }
Joe Hershberger8885c5f2015-04-08 01:41:07 -0500997 tftp_mcast_master_client = simple_strtoul((char *)mc, NULL, 10);
998 tftp_mcast_port = (unsigned short)simple_strtoul(port, NULL, 10);
999 printf("Multicast: %s:%d [%d]\n", mc_adr, tftp_mcast_port,
1000 tftp_mcast_master_client);
David Updegraff53a5c422007-06-11 10:41:07 -05001001 return;
1002}
1003
1004#endif /* Multicast TFTP */