1 //==========================================================================
5 // Stand-alone TFTP support for RedBoot
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2002, 2003 Gary Thomas
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
45 // Contributors: gthomas
50 // This code is part of RedBoot (tm).
52 //####DESCRIPTIONEND####
54 //==========================================================================
56 // TFTP client support
58 #include <redboot.h> // have_net
61 #include <net/tftp_support.h>
63 // So we remember which ports have been used
64 static int get_port = 7700;
68 int total_timeouts, packets_received;
69 unsigned long last_good_block;
70 int avail, actual_len;
71 struct sockaddr_in local_addr, from_addr;
72 char data[SEGSIZE+sizeof(struct tftphdr)];
77 tftp_stream_open(connection_info_t *info,
80 struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data;
84 if (!have_net || tftp_stream.open) {
85 *err = TFTP_INVALID; // Already open
89 // Create initial request
90 hdr->th_opcode = htons(RRQ); // Read file
91 cp = (char *)&hdr->th_stuff;
93 while (*fp) *cp++ = *fp++;
95 // Since this is used for downloading data, OCTET (binary) is the
96 // only mode that makes sense.
98 while (*fp) *cp++ = *fp++;
101 memset((char *)&tftp_stream.local_addr, 0, sizeof(tftp_stream.local_addr));
102 tftp_stream.local_addr.sin_family = AF_INET;
103 tftp_stream.local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
104 tftp_stream.local_addr.sin_port = htons(get_port++);
106 if (info->server->sin_port == 0) {
107 info->server->sin_port = htons(TFTP_PORT);
109 info->server->sin_port = htons(info->server->sin_port);
112 // Send request - note: RFC 1350 (TFTP rev 2) indicates that this should be
113 // only as long as required to hold the request, with the nul terminator.
114 // Some servers silently go to lunch if the request is not the correct size.
115 if (__udp_sendto(tftp_stream.data, cp-(char *)hdr,
116 info->server, &tftp_stream.local_addr) < 0) {
117 // Problem sending request
122 tftp_stream.open = true;
123 tftp_stream.avail = 0;
124 tftp_stream.actual_len = -1;
125 tftp_stream.last_good_block = 0;
126 tftp_stream.total_timeouts = 0;
127 tftp_stream.from_addr.sin_port = 0;
128 tftp_stream.packets_received = 0;
130 // Try and read the first byte [block] since no errors are
131 // reported until then.
132 if (tftp_stream_read(&test_buf, 1, err) == 1) {
133 // Back up [rewind] over this datum
136 return 0; // Open and first read successful
138 tftp_stream.open = false;
139 return -1; // Couldn't read
146 struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data;
147 // ACK last packet so server can shut down
148 if (tftp_stream.packets_received > 0) {
149 hdr->th_opcode = htons(ACK);
150 hdr->th_block = htons((cyg_uint16)tftp_stream.last_good_block & 0xFFFF);
151 if (__udp_sendto(tftp_stream.data, 4 /* FIXME */,
152 &tftp_stream.from_addr, &tftp_stream.local_addr) < 0) {
153 // Problem sending ACK
162 tftp_error_ack(int *err, short code, char *msg)
164 struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data;
166 if (strlen(msg) > (SEGSIZE-1)) {
167 *(msg + SEGSIZE) = '\0';
170 if (tftp_stream.packets_received > 0) {
171 hdr->th_opcode = htons(ERROR);
173 strcpy((char*)&hdr->th_data, msg);
174 if (__udp_sendto(tftp_stream.data, (5 + strlen(msg)),
175 &tftp_stream.from_addr, &tftp_stream.local_addr) < 0) {
176 // Problem sending ACK
185 tftp_stream_close(int *err)
187 if (tftp_stream.open == true) {
189 tftp_stream.open = false;
194 tftp_stream_terminate(bool abort,
200 tftp_error_ack(&err, EUNDEF, "redboot tftp_stream_terminate");
204 tftp_stream.open = false;
208 tftp_stream_read(char *buf,
213 int size, recv_len, data_len;
214 struct timeval timeout;
215 struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data;
217 while (total_bytes < len) {
218 // Move any bytes which we've already read/buffered
219 if (tftp_stream.avail > 0) {
220 size = tftp_stream.avail;
221 if (size > (len - total_bytes)) size = len - total_bytes;
222 memcpy(buf, tftp_stream.bufp, size);
224 tftp_stream.bufp += size;
225 tftp_stream.avail -= size;
228 if (tftp_ack(err) < 0) {
231 if ((tftp_stream.actual_len >= 0) && (tftp_stream.actual_len < SEGSIZE)) {
235 timeout.tv_sec = (tftp_stream.last_good_block == 0) ? 10*TFTP_TIMEOUT_PERIOD : TFTP_TIMEOUT_PERIOD;
237 recv_len = sizeof(tftp_stream.data);
238 if ((data_len = __udp_recvfrom(&tftp_stream.data[0], recv_len, &tftp_stream.from_addr,
239 &tftp_stream.local_addr, &timeout)) < 0) {
240 // No data, try again
241 diag_printf("TFTP timed out %d/%d\n", tftp_stream.total_timeouts+1, TFTP_TIMEOUT_MAX);
242 if ((++tftp_stream.total_timeouts > TFTP_TIMEOUT_MAX) ||
243 (tftp_stream.last_good_block == 0)) {
244 // Timeout - no data received
248 // Send out the ACK for the last block - maybe server will retry
249 if (tftp_ack(err) < 0) {
253 tftp_stream.packets_received++;
254 if (ntohs(hdr->th_opcode) == DATA) {
255 if (ntohs(hdr->th_block) == (cyg_uint16)((tftp_stream.last_good_block+1) & 0xFFFF)) {
257 data_len -= 4; /* Sizeof TFTP header */
258 tftp_stream.avail = tftp_stream.actual_len = data_len;
259 tftp_stream.bufp = hdr->th_data;
260 tftp_stream.last_good_block++;
263 if (ntohs(hdr->th_opcode) == ERROR) {
264 *err = ntohs(hdr->th_code);
267 // What kind of packet is this?
268 *err = TFTP_PROTOCOL;
281 char *errmsg = "Unknown error";
285 return "file not found";
287 return "access violation";
289 return "disk full or allocation exceeded";
291 return "illegal TFTP operation";
293 return "unknown transfer ID";
295 return "file already exists";
297 return "no such user";
299 return "operation timed out";
301 return "some sort of network error";
303 return "invalid parameter";
305 return "protocol violation";
307 return "file is larger than buffer";
315 GETC_IO_FUNCS(tftp_io, tftp_stream_open, tftp_stream_close,
316 tftp_stream_terminate, tftp_stream_read, tftp_error);
317 RedBoot_load(tftp, tftp_io, true, true, 0);