OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [redboot/] [current/] [src/] [net/] [tftp_client.c] - Blame information for rev 786

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
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, 2003 Free Software Foundation, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under    
14
// the terms of the GNU General Public License as published by the Free     
15
// Software Foundation; either version 2 or (at your option) any later      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY 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        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):    gthomas
43
// Contributors: gthomas
44
// Date:         2000-07-14
45
// Purpose:      
46
// Description:  
47
//              
48
// This code is part of RedBoot (tm).
49
//
50
//####DESCRIPTIONEND####
51
//
52
//==========================================================================
53
 
54
// TFTP client support
55
 
56
#include <redboot.h>     // have_net
57
#include <net/net.h>
58
#include <net/tftp.h>
59
#include <net/tftp_support.h>
60
 
61
// So we remember which ports have been used
62
static int get_port = 7700;
63
 
64
static struct {
65
    bool open;
66
    int  total_timeouts, packets_received;
67
    unsigned long last_good_block;
68
    int  avail, actual_len;
69
    struct sockaddr_in local_addr, from_addr;
70
    char data[SEGSIZE+sizeof(struct tftphdr)];
71
    char *bufp;
72
} tftp_stream;
73
 
74
int
75
tftp_stream_open(connection_info_t *info,
76
                 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
 
87
    // Create initial request
88
    hdr->th_opcode = htons(RRQ);  // Read file
89
    cp = (char *)&hdr->th_stuff;
90
    fp = info->filename;
91
    while (*fp) *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) *cp++ = *fp++;
97
    *cp++ = '\0';
98
 
99
    memset((char *)&tftp_stream.local_addr, 0, sizeof(tftp_stream.local_addr));
100
    tftp_stream.local_addr.sin_family = AF_INET;
101
    tftp_stream.local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
102
    tftp_stream.local_addr.sin_port = htons(get_port++);
103
 
104
    if (info->server->sin_port == 0) {
105
        info->server->sin_port = htons(TFTP_PORT);
106
    } else {
107
        info->server->sin_port = htons(info->server->sin_port);
108
    }
109
 
110
    // Send request - note: RFC 1350 (TFTP rev 2) indicates that this should be
111
    // only as long as required to hold the request, with the nul terminator.
112
    // Some servers silently go to lunch if the request is not the correct size.
113
    if (__udp_sendto(tftp_stream.data, cp-(char *)hdr,
114
                     info->server, &tftp_stream.local_addr) < 0) {
115
        // Problem sending request
116
        *err = TFTP_NETERR;
117
        return -1;
118
    }
119
 
120
    tftp_stream.open = true;
121
    tftp_stream.avail = 0;
122
    tftp_stream.actual_len = -1;
123
    tftp_stream.last_good_block = 0;
124
    tftp_stream.total_timeouts = 0;
125
    tftp_stream.from_addr.sin_port = 0;
126
    tftp_stream.packets_received = 0;
127
 
128
    // Try and read the first byte [block] since no errors are
129
    // reported until then.
130
    if (tftp_stream_read(&test_buf, 1, err) == 1) {
131
        // Back up [rewind] over this datum
132
        tftp_stream.bufp--;
133
        tftp_stream.avail++;
134
        return 0;  // Open and first read successful
135
    } else {
136
        tftp_stream.open = false;
137
        return -1; // Couldn't read
138
    }
139
}
140
 
141
static int
142
tftp_ack(int *err)
143
{
144
    struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data;
145
    // ACK last packet so server can shut down
146
    if (tftp_stream.packets_received > 0) {
147
        hdr->th_opcode = htons(ACK);
148
        hdr->th_block = htons((cyg_uint16)tftp_stream.last_good_block & 0xFFFF);
149
        if (__udp_sendto(tftp_stream.data, 4 /* FIXME */,
150
                         &tftp_stream.from_addr, &tftp_stream.local_addr) < 0) {
151
            // Problem sending ACK
152
            *err = TFTP_NETERR;
153
            return -1;
154
        }
155
    }
156
    return 0;
157
}
158
 
159
static int
160
tftp_error_ack(int *err, short code, char *msg)
161
{
162
    struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data;
163
 
164
    if (strlen(msg) > (SEGSIZE-1)) {
165
      *(msg + SEGSIZE) = 0;
166
    }
167
 
168
    if (tftp_stream.packets_received > 0) {
169
        hdr->th_opcode = htons(ERROR);
170
        hdr->th_code = code;
171
        strcpy((char *)&hdr->th_data, msg);
172
        if (__udp_sendto(tftp_stream.data, (5 + strlen(msg)),
173
                         &tftp_stream.from_addr, &tftp_stream.local_addr) < 0) {
174
            // Problem sending ACK
175
            *err = TFTP_NETERR;
176
            return -1;
177
        }
178
    }
179
    return 0;
180
}
181
 
182
void
183
tftp_stream_close(int *err)
184
{
185
    if (tftp_stream.open == true) {
186
        tftp_ack(err);
187
        tftp_stream.open = false;
188
    }
189
}
190
 
191
void
192
tftp_stream_terminate(bool abort,
193
                      int (*getc)(void))
194
{
195
    int err;
196
 
197
    if (abort)
198
        tftp_error_ack(&err, EUNDEF, "redboot tftp_stream_terminate");
199
    else
200
        tftp_ack(&err);
201
 
202
    tftp_stream.open = false;
203
}
204
 
205
int
206
tftp_stream_read(char *buf,
207
                 int len,
208
                 int *err)
209
{
210
    int total_bytes = 0;
211
    int size, recv_len, data_len;
212
    struct timeval timeout;
213
    struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data;
214
 
215
    while (total_bytes < len) {
216
        // Move any bytes which we've already read/buffered
217
        if (tftp_stream.avail > 0) {
218
            size = tftp_stream.avail;
219
            if (size > (len - total_bytes)) size = len - total_bytes;
220
            memcpy(buf, tftp_stream.bufp, size);
221
            buf += size;
222
            tftp_stream.bufp += size;
223
            tftp_stream.avail -= size;
224
            total_bytes += size;
225
        } else {
226
            if (tftp_ack(err) < 0) {
227
                return -1;
228
            }
229
            if ((tftp_stream.actual_len >= 0) && (tftp_stream.actual_len < SEGSIZE)) {
230
                // Out of data
231
                break;
232
            }
233
            timeout.tv_sec = (tftp_stream.last_good_block == 0) ? 10*TFTP_TIMEOUT_PERIOD : TFTP_TIMEOUT_PERIOD;
234
            timeout.tv_usec = 0;
235
            recv_len = sizeof(tftp_stream.data);
236
            if ((data_len = __udp_recvfrom(&tftp_stream.data[0], recv_len, &tftp_stream.from_addr,
237
                                           &tftp_stream.local_addr,  &timeout)) < 0) {
238
                // No data, try again
239
                diag_printf("TFTP timed out %d/%d\n", tftp_stream.total_timeouts+1, TFTP_TIMEOUT_MAX);
240
                if ((++tftp_stream.total_timeouts > TFTP_TIMEOUT_MAX) ||
241
                    (tftp_stream.last_good_block == 0)) {
242
                    // Timeout - no data received
243
                    *err = TFTP_TIMEOUT;
244
                    return -1;
245
                }
246
                // Send out the ACK for the last block - maybe server will retry
247
                if (tftp_ack(err) < 0) {
248
                    return -1;
249
                }
250
            } else {
251
                tftp_stream.packets_received++;
252
                if (ntohs(hdr->th_opcode) == DATA) {
253
                    if (ntohs(hdr->th_block) == (cyg_uint16)((tftp_stream.last_good_block+1) & 0xFFFF)) {
254
                        // Consume this data
255
                        data_len -= 4;  /* Sizeof TFTP header */
256
                        tftp_stream.avail = tftp_stream.actual_len = data_len;
257
                        tftp_stream.bufp = hdr->th_data;
258
                        tftp_stream.last_good_block++;
259
                    }
260
                } else {
261
                    if (ntohs(hdr->th_opcode) == ERROR) {
262
                        *err = ntohs(hdr->th_code);
263
                        return -1;
264
                    } else {
265
                        // What kind of packet is this?
266
                        *err = TFTP_PROTOCOL;
267
                        return -1;
268
                    }
269
                }
270
            }
271
        }
272
    }
273
    return total_bytes;
274
}
275
 
276
char *
277
tftp_error(int err)
278
{
279
    char *errmsg = "Unknown error";
280
 
281
    switch (err) {
282
    case TFTP_ENOTFOUND:
283
        return "file not found";
284
    case TFTP_EACCESS:
285
        return "access violation";
286
    case TFTP_ENOSPACE:
287
        return "disk full or allocation exceeded";
288
    case TFTP_EBADOP:
289
        return "illegal TFTP operation";
290
    case TFTP_EBADID:
291
        return "unknown transfer ID";
292
    case TFTP_EEXISTS:
293
        return "file already exists";
294
    case TFTP_ENOUSER:
295
        return "no such user";
296
    case TFTP_TIMEOUT:
297
        return "operation timed out";
298
    case TFTP_NETERR:
299
        return "some sort of network error";
300
    case TFTP_INVALID:
301
        return "invalid parameter";
302
    case TFTP_PROTOCOL:
303
        return "protocol violation";
304
    case TFTP_TOOLARGE:
305
        return "file is larger than buffer";
306
    }
307
    return errmsg;
308
}
309
 
310
//
311
// RedBoot interface
312
//
313
GETC_IO_FUNCS(tftp_io, tftp_stream_open, tftp_stream_close,
314
              tftp_stream_terminate, tftp_stream_read, tftp_error);
315
RedBoot_load(tftp, tftp_io, true, true, 0);
316
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.