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;
73 char buf[SEGSIZE + sizeof(struct tftphdr)];
80 tftp_stream_open(connection_info_t *info,
83 struct tftphdr *hdr = &tftp_stream.data.hdr;
87 if (!have_net || tftp_stream.open) {
88 *err = TFTP_INVALID; // Already open
92 // Create initial request
93 hdr->th_opcode = htons(RRQ); // Read file
94 cp = (char *)&hdr->th_stuff;
96 while (*fp) *cp++ = *fp++;
98 // Since this is used for downloading data, OCTET (binary) is the
99 // only mode that makes sense.
101 while (*fp) *cp++ = *fp++;
104 memset(&tftp_stream.local_addr, 0, sizeof(tftp_stream.local_addr));
105 tftp_stream.local_addr.sin_family = AF_INET;
106 tftp_stream.local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
107 tftp_stream.local_addr.sin_port = htons(get_port++);
109 if (info->server->sin_port == 0) {
110 info->server->sin_port = htons(TFTP_PORT);
112 info->server->sin_port = htons(info->server->sin_port);
115 // Send request - note: RFC 1350 (TFTP rev 2) indicates that this should be
116 // only as long as required to hold the request, with the nul terminator.
117 // Some servers silently go to lunch if the request is not the correct size.
118 if (__udp_sendto(tftp_stream.data.buf, cp-(char *)hdr,
119 info->server, &tftp_stream.local_addr) < 0) {
120 // Problem sending request
125 tftp_stream.open = true;
126 tftp_stream.avail = 0;
127 tftp_stream.actual_len = -1;
128 tftp_stream.last_good_block = 0;
129 tftp_stream.total_timeouts = 0;
130 tftp_stream.from_addr.sin_port = 0;
131 tftp_stream.packets_received = 0;
133 // Try and read the first byte [block] since no errors are
134 // reported until then.
135 if (tftp_stream_read(&test_buf, 1, err) == 1) {
136 // Back up [rewind] over this datum
139 return 0; // Open and first read successful
141 tftp_stream.open = false;
142 return -1; // Couldn't read
149 struct tftphdr *hdr = &tftp_stream.data.hdr;
150 // ACK last packet so server can shut down
151 if (tftp_stream.packets_received > 0) {
152 hdr->th_opcode = htons(ACK);
153 hdr->th_block = htons((cyg_uint16)tftp_stream.last_good_block & 0xFFFF);
154 if (__udp_sendto(tftp_stream.data.buf, 4 /* FIXME */,
155 &tftp_stream.from_addr, &tftp_stream.local_addr) < 0) {
156 // Problem sending ACK
165 tftp_error_ack(int *err, short code, char *msg)
167 struct tftphdr *hdr = &tftp_stream.data.hdr;
169 if (strlen(msg) > (SEGSIZE - 1)) {
170 *(msg + SEGSIZE) = '\0';
173 if (tftp_stream.packets_received > 0) {
174 hdr->th_opcode = htons(ERROR);
176 strcpy((char *)&hdr->th_data, msg);
177 if (__udp_sendto(tftp_stream.data.buf, (5 + strlen(msg)),
178 &tftp_stream.from_addr, &tftp_stream.local_addr) < 0) {
179 // Problem sending ACK
188 tftp_stream_close(int *err)
190 if (tftp_stream.open == true) {
192 tftp_stream.open = false;
197 tftp_stream_terminate(bool abort,
203 tftp_error_ack(&err, EUNDEF, "redboot tftp_stream_terminate");
207 tftp_stream.open = false;
211 tftp_stream_read(void *buf,
216 int size, recv_len, data_len;
217 struct timeval timeout;
218 struct tftphdr *hdr = &tftp_stream.data.hdr;
220 while (total_bytes < len) {
221 // Move any bytes which we've already read/buffered
222 if (tftp_stream.avail > 0) {
223 size = tftp_stream.avail;
224 if (size > (len - total_bytes)) size = len - total_bytes;
225 memcpy(buf, tftp_stream.bufp, size);
226 buf = (char *)buf + size;
227 tftp_stream.bufp += size;
228 tftp_stream.avail -= size;
231 if (tftp_ack(err) < 0) {
234 if ((tftp_stream.actual_len >= 0) && (tftp_stream.actual_len < SEGSIZE)) {
238 timeout.tv_sec = (tftp_stream.last_good_block == 0) ? 10*TFTP_TIMEOUT_PERIOD : TFTP_TIMEOUT_PERIOD;
240 recv_len = sizeof(tftp_stream.data.buf);
241 if ((data_len = __udp_recvfrom(&tftp_stream.data.buf[0], recv_len, &tftp_stream.from_addr,
242 &tftp_stream.local_addr, &timeout)) < 0) {
243 // No data, try again
244 diag_printf("TFTP timed out %d/%d\n", tftp_stream.total_timeouts+1, TFTP_TIMEOUT_MAX);
245 if ((++tftp_stream.total_timeouts > TFTP_TIMEOUT_MAX) ||
246 (tftp_stream.last_good_block == 0)) {
247 // Timeout - no data received
251 // Send out the ACK for the last block - maybe server will retry
252 if (tftp_ack(err) < 0) {
256 tftp_stream.packets_received++;
257 if (ntohs(hdr->th_opcode) == DATA) {
258 if (ntohs(hdr->th_block) == (cyg_uint16)((tftp_stream.last_good_block+1) & 0xFFFF)) {
260 data_len -= 4; /* Sizeof TFTP header */
261 tftp_stream.avail = tftp_stream.actual_len = data_len;
262 tftp_stream.bufp = hdr->th_data;
263 tftp_stream.last_good_block++;
266 if (ntohs(hdr->th_opcode) == ERROR) {
267 *err = ntohs(hdr->th_code);
270 // What kind of packet is this?
271 *err = TFTP_PROTOCOL;
284 char *errmsg = "Unknown error";
288 return "file not found";
290 return "access violation";
292 return "disk full or allocation exceeded";
294 return "illegal TFTP operation";
296 return "unknown transfer ID";
298 return "file already exists";
300 return "no such user";
302 return "operation timed out";
304 return "some sort of network error";
306 return "invalid parameter";
308 return "protocol violation";
310 return "file is larger than buffer";
318 GETC_IO_FUNCS(tftp_io, tftp_stream_open, tftp_stream_close,
319 tftp_stream_terminate, tftp_stream_read, tftp_error);
320 RedBoot_load(tftp, tftp_io, true, true, 0);