1 //==========================================================================
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) 2003 Andrew.Lunn@ascom.ch
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, andrew.lunn@ascom.ch
51 //####DESCRIPTIONEND####
53 //==========================================================================
55 // TFTP client support
58 #include <arpa/tftp.h>
59 #include <tftp_support.h>
61 #define min(x,y) (x<y ? x : y)
64 // Read a file from a host into a local buffer. Returns the
65 // number of bytes actually read, or (-1) if an error occurs.
66 // On error, *err will hold the reason.
67 // This version uses the server name. This can be a name for DNS lookup
68 // or a dotty or colony number format for IPv4 or IPv6.
69 int tftp_client_get(char *filename,
79 int actual_len, data_len;
80 socklen_t from_len, recv_len;
81 static int get_port = 7700;
82 struct addrinfo * addrinfo;
83 struct addrinfo * res;
84 struct addrinfo hints;
87 struct sockaddr local_addr, from_addr;
88 char data[SEGSIZE+sizeof(struct tftphdr)];
89 struct tftphdr *hdr = (struct tftphdr *)data;
91 struct timeval timeout;
92 unsigned short last_good_block = 0;
94 int total_timeouts = 0;
96 *err = 0; // Just in case
98 // Create initial request
99 hdr->th_opcode = htons(RRQ); // Read file
100 cp = (char *)&hdr->th_stuff;
102 while (*fp) *cp++ = *fp++;
104 if (mode == TFTP_NETASCII) {
106 } else if (mode == TFTP_OCTET) {
112 while (*fp) *cp++ = *fp++;
115 memset(&hints,0,sizeof(hints));
116 hints.ai_family = PF_UNSPEC;
117 error = getaddrinfo(server, "tftp", &hints, &res);
125 s = socket(addrinfo->ai_family, addrinfo->ai_socktype,
126 addrinfo->ai_protocol);
128 memcpy(&local_addr,addrinfo->ai_addr,addrinfo->ai_addrlen);
129 switch(addrinfo->ai_addr->sa_family) {
131 struct sockaddr_in * saddr =
132 (struct sockaddr_in *) addrinfo->ai_addr;
133 struct sockaddr_in * laddr =
134 (struct sockaddr_in *) &local_addr;
136 saddr->sin_port = htons(port);
138 laddr->sin_port = htons(get_port++);
139 laddr->sin_addr.s_addr = INADDR_ANY;
142 #ifdef CYGPKG_NET_INET6
144 struct sockaddr_in6 * saddr =
145 (struct sockaddr_in6 *) addrinfo->ai_addr;
146 struct sockaddr_in6 * laddr =
147 (struct sockaddr_in6 *) &local_addr;
149 saddr->sin6_port = htons(port);
151 laddr->sin6_port = htons(get_port++);
152 laddr->sin6_addr = in6addr_any;
161 if (bind(s,&local_addr,addrinfo->ai_addrlen) < 0) {
167 if (sendto(s, data, (int)(cp-data), 0,
169 addrinfo->ai_addrlen) < 0) {
170 // Problem sending request
178 timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
182 if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
184 if ((last_good_block == 0) && (total_timeouts > TFTP_RETRIES_MAX)) {
185 // Timeout - no data received. Probably no server.
189 if (total_timeouts > TFTP_TIMEOUT_MAX) {
190 // Timeout - have received data. Network problem?
195 if (last_good_block == 0 ) {
197 if (sendto(s, data, (int)(cp-data), 0,
199 addrinfo->ai_addrlen) < 0) {
200 // Problem sending request
205 // Try resending last ACK
206 hdr->th_opcode = htons(ACK);
207 hdr->th_block = htons(last_good_block);
208 if (sendto(s, data, 4 /* FIXME */, 0,
209 &from_addr, from_len) < 0) {
210 // Problem sending request
216 recv_len = sizeof(data);
217 from_len = sizeof(from_addr);
218 if ((data_len = recvfrom(s, &data, recv_len, 0,
219 &from_addr, &from_len)) < 0) {
224 if (ntohs(hdr->th_opcode) == DATA) {
226 if (ntohs(hdr->th_block) == (last_good_block+1)) {
229 data_len -= 4; /* Sizeof TFTP header */
230 actual_len = data_len;
231 result += actual_len;
232 while (data_len-- > 0) {
237 *err = TFTP_TOOLARGE;
243 // To prevent an out-of-sequence packet from
244 // terminating transmission prematurely, set
245 // actual_len to a full size packet.
246 actual_len = SEGSIZE;
249 hdr->th_opcode = htons(ACK);
250 hdr->th_block = htons(last_good_block);
251 if (sendto(s, data, 4 /* FIXME */, 0,
252 &from_addr, from_len) < 0) {
253 // Problem sending request
257 // A short packet marks the end of the file.
258 if ((actual_len >= 0) && (actual_len < SEGSIZE)) {
265 if (ntohs(hdr->th_opcode) == ERROR) {
266 *err = ntohs(hdr->th_code);
269 // What kind of packet is this?
270 *err = TFTP_PROTOCOL;
276 // If we got here, it means there was a problem connecting to the
277 // server. Try the next address returned by getaddrinfo
282 addrinfo=addrinfo->ai_next;
284 // We ran into problems. Cleanup
293 // Read a file from a host into a local buffer. Returns the
294 // number of bytes actually read, or (-1) if an error occurs.
295 // On error, *err will hold the reason.
297 // Depreciated. Use tftp_client_get instead.
299 tftp_get(char *filename,
300 struct sockaddr_in *server,
306 char server_name[20];
310 ret = inet_ntop(AF_INET, (void *)&server->sin_addr,
311 server_name, sizeof(server_name));
316 port = server->sin_port;
318 return tftp_client_get(filename, server_name, port, buf, len, mode, err);
322 // Send data to a file on a server via TFTP.
325 tftp_put(char *filename,
326 struct sockaddr_in *server,
332 char server_name[20];
336 ret = inet_ntop(AF_INET, (void *)&server->sin_addr,
337 server_name, sizeof(server_name));
342 port = server->sin_port;
344 return tftp_client_put(filename, server_name, port, buf, len, mode, err);
348 // Put a file to a host from a local buffer. Returns the
349 // number of bytes actually writen, or (-1) if an error occurs.
350 // On error, *err will hold the reason.
351 // This version uses the server name. This can be a name for DNS lookup
352 // or a dotty or colony number format for IPv4 or IPv6.
353 int tftp_client_put(char *filename,
362 int s = -1, actual_len, data_len;
363 socklen_t recv_len, from_len;
364 static int put_port = 7800;
365 struct sockaddr local_addr, from_addr;
366 char data[SEGSIZE+sizeof(struct tftphdr)];
367 struct tftphdr *hdr = (struct tftphdr *)data;
369 struct timeval timeout;
370 unsigned short last_good_block = 0;
372 int total_timeouts = 0;
373 struct addrinfo hints;
374 struct addrinfo * addrinfo;
375 struct addrinfo * res;
378 *err = 0; // Just in case
380 memset(&hints,0,sizeof(hints));
381 hints.ai_family = PF_UNSPEC;
382 error = getaddrinfo(server, "tftp", &hints, &res);
390 s = socket(addrinfo->ai_family, addrinfo->ai_socktype,
391 addrinfo->ai_protocol);
393 memcpy(&local_addr,addrinfo->ai_addr,addrinfo->ai_addrlen);
394 switch(addrinfo->ai_addr->sa_family) {
396 struct sockaddr_in * saddr =
397 (struct sockaddr_in *) addrinfo->ai_addr;
398 struct sockaddr_in * laddr =
399 (struct sockaddr_in *) &local_addr;
401 saddr->sin_port = htons(port);
403 laddr->sin_port = htons(put_port++);
404 laddr->sin_addr.s_addr = INADDR_ANY;
407 #ifdef CYGPKG_NET_INET6
409 struct sockaddr_in6 * saddr =
410 (struct sockaddr_in6 *) addrinfo->ai_addr;
411 struct sockaddr_in6 * laddr =
412 (struct sockaddr_in6 *) &local_addr;
414 saddr->sin6_port = htons(port);
416 laddr->sin6_port = htons(put_port++);
417 laddr->sin6_addr = in6addr_any;
426 (struct sockaddr *)&local_addr,
427 addrinfo->ai_addrlen) < 0) {
428 // Problem setting up my end
434 // Create initial request
435 hdr->th_opcode = htons(WRQ); // Create/write file
436 cp = (char *)&hdr->th_stuff;
438 while (*fp) *cp++ = *fp++;
440 if (mode == TFTP_NETASCII) {
442 } else if (mode == TFTP_OCTET) {
448 while (*fp) *cp++ = *fp++;
451 if (sendto(s, data, (int)(cp-data), 0,
453 addrinfo->ai_addrlen) < 0) {
454 // Problem sending request
459 timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
463 if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
464 if (++total_timeouts > TFTP_RETRIES_MAX) {
465 // Timeout - no ACK received
470 recv_len = sizeof(data);
471 from_len = sizeof(from_addr);
472 if ((data_len = recvfrom(s, &data, recv_len, 0,
473 &from_addr, &from_len)) < 0) {
478 if (ntohs(hdr->th_opcode) == ACK) {
479 // Write request accepted - start sending data
482 if (ntohs(hdr->th_opcode) == ERROR) {
483 *err = ntohs(hdr->th_code);
486 // What kind of packet is this?
495 while (result < len) {
496 // Build packet of data to send
497 data_len = min(SEGSIZE, len-result);
498 hdr->th_opcode = htons(DATA);
499 hdr->th_block = htons(last_good_block);
502 actual_len = data_len + 4;
503 // FIXME - what about "netascii" data?
504 while (data_len-- > 0) *cp++ = *fp++;
506 if (sendto(s, data, actual_len, 0,
507 &from_addr, from_len) < 0) {
508 // Problem sending request
513 timeout.tv_sec = TFTP_TIMEOUT_PERIOD;
517 if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
518 if (++total_timeouts > TFTP_TIMEOUT_MAX) {
519 // Timeout - no data received
524 recv_len = sizeof(data);
525 from_len = sizeof(from_addr);
526 if ((data_len = recvfrom(s, &data, recv_len, 0,
527 &from_addr, &from_len)) < 0) {
532 if (ntohs(hdr->th_opcode) == ACK) {
533 if (ntohs(hdr->th_block) == last_good_block) {
534 // Advance pointers, etc
536 result += (actual_len - 4);
539 diag_printf("Send block #%d, got ACK for #%d\n",
540 last_good_block, ntohs(hdr->th_block));
543 if (ntohs(hdr->th_opcode) == ERROR) {
544 *err = ntohs(hdr->th_code);
547 // What kind of packet is this?
548 *err = TFTP_PROTOCOL;
557 // If we got here, it means there was a problem connecting to the
558 // server. Try the next address returned by getaddrinfo
563 addrinfo=addrinfo->ai_next;
565 // We ran into problems. Cleanup