root/ar5315_microredboot/microredboot/ecos/packages/redboot/current/src/net/tftp_client.c

Revision 12407, 8.2 kB (checked in by BrainSlayer, 5 months ago)

fixes firmware check

Line 
1 //==========================================================================
2 //
3 //      net/tftp_client.c
4 //
5 //      Stand-alone TFTP support for RedBoot
6 //
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
13 //
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.
17 //
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
21 // for more details.
22 //
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.
26 //
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.
33 //
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.
36 //
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####
43 //
44 // Author(s):    gthomas
45 // Contributors: gthomas
46 // Date:         2000-07-14
47 // Purpose:     
48 // Description: 
49 //             
50 // This code is part of RedBoot (tm).
51 //
52 //####DESCRIPTIONEND####
53 //
54 //==========================================================================
55
56 // TFTP client support
57
58 #include <redboot.h>            // have_net
59 #include <net/net.h>
60 #include <net/tftp.h>
61 #include <net/tftp_support.h>
62
63 // So we remember which ports have been used
64 static int get_port = 7700;
65
66 static struct {
67         bool open;
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)];
73         char *bufp;
74 } tftp_stream;
75
76 int tftp_stream_open(connection_info_t * info, int *err)
77 {
78         struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data;
79         char *cp, *fp;
80         char test_buf;
81
82         if (!have_net || tftp_stream.open) {
83                 *err = TFTP_INVALID;    // Already open
84                 return -1;
85         }
86         // Create initial request
87         hdr->th_opcode = htons(RRQ);    // Read file
88         cp = (char *)&hdr->th_stuff;
89         fp = info->filename;
90         while (*fp)
91                 *cp++ = *fp++;
92         *cp++ = '\0';
93         // Since this is used for downloading data, OCTET (binary) is the
94         // only mode that makes sense.
95         fp = "OCTET";
96         while (*fp)
97                 *cp++ = *fp++;
98         *cp++ = '\0';
99
100         memset((char *)&tftp_stream.local_addr, 0,
101                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++);
105
106         if (info->server->sin_port == 0) {
107                 info->server->sin_port = htons(TFTP_PORT);
108         } else {
109                 info->server->sin_port = htons(info->server->sin_port);
110         }
111
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
118                 *err = TFTP_NETERR;
119                 return -1;
120         }
121
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;
129
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
134                 tftp_stream.bufp--;
135                 tftp_stream.avail++;
136                 return 0;       // Open and first read successful
137         } else {
138                 tftp_stream.open = false;
139                 return -1;      // Couldn't read
140         }
141 }
142
143 static int tftp_ack(int *err)
144 {
145         struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data;
146         // ACK last packet so server can shut down
147         if (tftp_stream.packets_received > 0) {
148                 hdr->th_opcode = htons(ACK);
149                 hdr->th_block =
150                     htons((cyg_uint16) tftp_stream.last_good_block & 0xFFFF);
151                 if (__udp_sendto(tftp_stream.data, 4 /* FIXME */ ,
152                                  &tftp_stream.from_addr,
153                                  &tftp_stream.local_addr) < 0) {
154                         // Problem sending ACK
155                         *err = TFTP_NETERR;
156                         return -1;
157                 }
158         }
159         return 0;
160 }
161
162 void tftp_stream_close(int *err)
163 {
164         tftp_ack(err);
165         tftp_stream.open = false;
166 }
167
168 int tftp_stream_read(char *buf, int len, int *err)
169 {
170         int total_bytes = 0;
171         int size, recv_len, data_len;
172         struct timeval timeout;
173         struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data;
174
175         while (total_bytes < len) {
176                 // Move any bytes which we've already read/buffered
177                 if (tftp_stream.avail > 0) {
178                         size = tftp_stream.avail;
179                         if (size > (len - total_bytes))
180                                 size = len - total_bytes;
181                         memcpy(buf, tftp_stream.bufp, size);
182                         buf += size;
183                         tftp_stream.bufp += size;
184                         tftp_stream.avail -= size;
185                         total_bytes += size;
186                 } else {
187                         if (tftp_ack(err) < 0) {
188                                 return -1;
189                         }
190                         if ((tftp_stream.actual_len >= 0)
191                             && (tftp_stream.actual_len < SEGSIZE)) {
192                                 // Out of data
193                                 break;
194                         }
195                         timeout.tv_sec =
196                             (tftp_stream.last_good_block ==
197                              0) ? 10 *
198                             TFTP_TIMEOUT_PERIOD : TFTP_TIMEOUT_PERIOD;
199                         timeout.tv_usec = 0;
200                         recv_len = sizeof(tftp_stream.data);
201                         if ((data_len =
202                              __udp_recvfrom(&tftp_stream.data[0], recv_len,
203                                             &tftp_stream.from_addr,
204                                             &tftp_stream.local_addr,
205                                             &timeout)) < 0) {
206                                 // No data, try again
207                                 diag_printf("TFTP timed out %d/%d\n",
208                                             tftp_stream.total_timeouts + 1,
209                                             TFTP_TIMEOUT_MAX);
210                                 if ((++tftp_stream.total_timeouts >
211                                      TFTP_TIMEOUT_MAX)
212                                     || (tftp_stream.last_good_block == 0)) {
213                                         // Timeout - no data received
214                                         *err = TFTP_TIMEOUT;
215                                         return -1;
216                                 }
217                                 // Send out the ACK for the last block - maybe server will retry
218                                 if (tftp_ack(err) < 0) {
219                                         return -1;
220                                 }
221                         } else {
222                                 tftp_stream.packets_received++;
223                                 if (ntohs(hdr->th_opcode) == DATA) {
224                                         if (ntohs(hdr->th_block) ==
225                                             (cyg_uint16) ((tftp_stream.last_good_block + 1) & 0xFFFF)) {
226                                                 // Consume this data
227                                                 data_len -= 4;  /* Sizeof TFTP header */
228                                                 tftp_stream.avail =
229                                                     tftp_stream.actual_len =
230                                                     data_len;
231                                                 tftp_stream.bufp = hdr->th_data;
232                                                 tftp_stream.last_good_block++;
233                                         }
234                                 } else {
235                                         if (ntohs(hdr->th_opcode) == ERROR) {
236                                                 *err = ntohs(hdr->th_code);
237                                                 return -1;
238                                         } else {
239                                                 // What kind of packet is this?
240                                                 *err = TFTP_PROTOCOL;
241                                                 return -1;
242                                         }
243                                 }
244                         }
245                 }
246         }
247         return total_bytes;
248 }
249
250 char *tftp_error(int err)
251 {
252         char *errmsg = "Unknown error";
253
254         switch (err) {
255         case TFTP_ENOTFOUND:
256                 return "file not found";
257         case TFTP_EACCESS:
258                 return "access violation";
259         case TFTP_ENOSPACE:
260                 return "disk full or allocation exceeded";
261         case TFTP_EBADOP:
262                 return "illegal TFTP operation";
263         case TFTP_EBADID:
264                 return "unknown transfer ID";
265         case TFTP_EEXISTS:
266                 return "file already exists";
267         case TFTP_ENOUSER:
268                 return "no such user";
269         case TFTP_TIMEOUT:
270                 return "operation timed out";
271         case TFTP_NETERR:
272                 return "some sort of network error";
273         case TFTP_INVALID:
274                 return "invalid parameter";
275         case TFTP_PROTOCOL:
276                 return "protocol violation";
277         case TFTP_TOOLARGE:
278                 return "file is larger than buffer";
279         }
280         return errmsg;
281 }
282
283 //
284 // RedBoot interface
285 //
286 GETC_IO_FUNCS(tftp_io, tftp_stream_open, tftp_stream_close,
287               0, tftp_stream_read, tftp_error);
288 RedBoot_load(tftp, tftp_io, true, true, 0);
Note: See TracBrowser for help on using the browser.