GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / cfe / cfe / net / net_tftp.c
blob49eae5de0ad02390312f6580d9f4cacfbe3e2141
1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
3 *
4 * TFTP Client File: net_tftp.c
5 *
6 * This module contains a TFTP client.
7 *
8 * Author: Mitch Lichtenberg (mpl@broadcom.com)
9 *
10 *********************************************************************
12 * Copyright 2000,2001,2002,2003
13 * Broadcom Corporation. All rights reserved.
15 * This software is furnished under license and may be used and
16 * copied only in accordance with the following terms and
17 * conditions. Subject to these conditions, you may download,
18 * copy, install, use, modify and distribute modified or unmodified
19 * copies of this software in source and/or binary form. No title
20 * or ownership is transferred hereby.
22 * 1) Any source code used, modified or distributed must reproduce
23 * and retain this copyright notice and list of conditions
24 * as they appear in the source file.
26 * 2) No right is granted to use any trade name, trademark, or
27 * logo of Broadcom Corporation. The "Broadcom Corporation"
28 * name may not be used to endorse or promote products derived
29 * from this software without the prior written permission of
30 * Broadcom Corporation.
32 * 3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
33 * IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
34 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
35 * PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT
36 * SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN
37 * PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
38 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
39 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
40 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
41 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
42 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
43 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF
44 * THE POSSIBILITY OF SUCH DAMAGE.
45 ********************************************************************* */
48 #include "lib_types.h"
49 #include "lib_string.h"
50 #include "lib_queue.h"
51 #include "lib_malloc.h"
52 #include "lib_printf.h"
54 #include "cfe_error.h"
55 #include "cfe_fileops.h"
56 #include "cfe_console.h"
57 #include "cfe_timer.h"
59 #include "net_ebuf.h"
60 #include "net_ether.h"
62 #include "cfe.h"
64 #include "cfe_loader.h"
66 #include "net_api.h"
68 #include "bsp_config.h"
71 /* *********************************************************************
72 * TFTP protocol
73 ********************************************************************* */
75 #define UDP_PROTO_TFTP 69
77 #define TFTP_BLOCKSIZE 512
79 #define TFTP_OP_RRQ 1
80 #define TFTP_OP_WRQ 2
81 #define TFTP_OP_DATA 3
82 #define TFTP_OP_ACK 4
83 #define TFTP_OP_ERROR 5
85 #define TFTP_ERR_DISKFULL 3
87 #ifndef TFTP_MAX_RETRIES
88 #define TFTP_MAX_RETRIES 8
89 #endif
91 #define TFTP_RRQ_TIMEOUT CFE_HZ*5 /* ticks */
92 //#define TFTP_RECV_TIMEOUT CFE_HZ*5 /* ticks */
93 #define TFTP_RECV_TIMEOUT CFE_HZ*1 /* ticks */
95 #ifdef RESCUE_MODE
96 unsigned char tftpipfrom[4] = { 0xc0, 0xa8, 0x01, 0x01 };
97 unsigned char tftpipto[4] = { 0xc0, 0xa8, 0x01, 0x01 };
98 uint16_t ackport = 7777;
99 #endif
101 /* *********************************************************************
102 * TFTP context
103 ********************************************************************* */
105 typedef struct tftp_fsctx_s {
106 int dummy;
107 } tftp_fsctx_t;
109 typedef struct tftp_info_s {
110 int tftp_socket;
111 uint8_t tftp_data[TFTP_BLOCKSIZE];
112 int tftp_blklen;
113 int tftp_blkoffset;
114 int tftp_fileoffset;
115 uint16_t tftp_blknum;
116 uint8_t tftp_ipaddr[IP_ADDR_LEN];
117 int tftp_lastblock;
118 int tftp_error;
119 int tftp_filemode;
120 char *tftp_filename;
121 } tftp_info_t;
123 /* *********************************************************************
124 * Prototypes
125 ********************************************************************* */
127 static int tftp_fileop_init(void **fsctx,void *devicename);
128 static int tftp_fileop_open(void **ref,void *fsctx,char *filename,int mode);
129 static int tftp_fileop_read(void *ref,uint8_t *buf,int len);
130 static int tftp_fileop_write(void *ref,uint8_t *buf,int len);
131 static int tftp_fileop_seek(void *ref,int offset,int how);
132 static void tftp_fileop_close(void *ref);
133 static void tftp_fileop_uninit(void *fsctx);
134 #ifdef RESCUE_MODE
135 extern int send_rescueack(unsigned short no, unsigned short lo);
136 #endif
138 /* *********************************************************************
139 * Globals
140 ********************************************************************* */
142 int tftp_max_retries = TFTP_MAX_RETRIES;
143 int tftp_rrq_timeout = TFTP_RRQ_TIMEOUT;
144 int tftp_recv_timeout = TFTP_RECV_TIMEOUT;
146 /* *********************************************************************
147 * TFTP fileio dispatch table
148 ********************************************************************* */
150 const fileio_dispatch_t tftp_fileops = {
151 "tftp",
152 LOADFLG_NOBB | FSYS_TYPE_NETWORK,
153 tftp_fileop_init,
154 tftp_fileop_open,
155 tftp_fileop_read,
156 tftp_fileop_write,
157 tftp_fileop_seek,
158 tftp_fileop_close,
159 tftp_fileop_uninit
162 #ifdef RESCUE_MODE
163 #define ip_addriszero(a) (((a)[0]|(a)[1]|(a)[2]|(a)[3]) == 0)
164 static void ui_myshowifconfig(void)
166 char *devname;
167 uint8_t *addr;
169 devname = (char *) net_getparam(NET_DEVNAME);
170 if (devname == NULL) {
171 xprintf("Network interface has not been configured\n");
172 return;
174 xprintf("Device %s: ",devname);
175 addr = net_getparam(NET_HWADDR);
176 if (addr)
177 xprintf(" hwaddr %a",addr);
178 addr = net_getparam(NET_IPADDR);
179 if (addr) {
180 if (ip_addriszero(addr))
181 xprintf(", ipaddr not set");
182 else
183 xprintf(", ipaddr %I",addr);
185 addr = net_getparam(NET_NETMASK);
186 if (addr) {
187 if (ip_addriszero(addr))
188 xprintf(", mask not set");
189 else
190 xprintf(", mask %I",addr);
192 xprintf("\n");
193 xprintf(" ");
194 addr = net_getparam(NET_GATEWAY);
195 if (addr) {
196 if (ip_addriszero(addr))
197 xprintf("gateway not set");
198 else
199 xprintf("gateway %I",addr);
201 addr = net_getparam(NET_NAMESERVER);
202 if (addr) {
203 if (ip_addriszero(addr))
204 xprintf(", nameserver not set");
205 else
206 xprintf(", nameserver %I",addr);
208 addr = net_getparam(NET_DOMAIN);
209 if (addr) {
210 xprintf(", domain %s",addr);
212 xprintf("\n");
214 #endif
216 /* *********************************************************************
217 * _tftp_open(info,hostname,filename,mode)
219 * Open a file on a remote host, using the TFTP protocol.
221 * Input parameters:
222 * info - TFTP information
223 * hostname - host name or IP address of remote host
224 * filename - name of file on remote system
225 * mode - file open mode, read or write
227 * Return value:
228 * 0 if ok
229 * else error code
230 ********************************************************************* */
232 static int _tftp_open(tftp_info_t *info,char *hostname,char *filename,int mode)
234 ebuf_t *buf = NULL;
235 const char *datamode = "octet";
236 uint16_t type,error,block;
237 int res;
238 int retries;
241 * Look up the remote host's IP address
244 res = dns_lookup(hostname,info->tftp_ipaddr);
245 if (res < 0) return res;
248 * Open a UDP socket to the TFTP server
251 info->tftp_socket = udp_socket(UDP_PROTO_TFTP);
252 info->tftp_lastblock = 0;
253 info->tftp_error = 0;
254 info->tftp_filemode = mode;
257 * Try to send the RRQ packet to open the file
260 for (retries = 0; retries < tftp_max_retries; retries++) {
262 buf = udp_alloc();
263 if (!buf) break;
265 if (info->tftp_filemode == FILE_MODE_READ) {
266 ebuf_append_u16_be(buf,TFTP_OP_RRQ); /* read file */
268 else {
269 ebuf_append_u16_be(buf,TFTP_OP_WRQ); /* write file */
271 ebuf_append_bytes(buf,filename,strlen(filename)+1);
272 ebuf_append_bytes(buf,datamode,strlen(datamode)+1);
274 udp_send(info->tftp_socket,buf,info->tftp_ipaddr);
276 buf = udp_recv_with_timeout(info->tftp_socket,tftp_rrq_timeout);
277 if (buf) break;
281 * If we got no response, bail now.
284 if (!buf) {
285 udp_close(info->tftp_socket);
286 info->tftp_socket = -1;
287 return CFE_ERR_TIMEOUT;
291 * Otherwise, process the response.
294 ebuf_get_u16_be(buf,type);
296 switch (type) {
297 case TFTP_OP_ACK:
299 * Acks are what we get back on a WRQ command,
300 * but are otherwise unexpected.
302 if (info->tftp_filemode == FILE_MODE_WRITE) {
303 udp_connect(info->tftp_socket,(uint16_t) buf->eb_usrdata);
304 info->tftp_blknum = 1;
305 info->tftp_blklen = 0;
306 udp_free(buf);
307 return 0;
308 break;
310 /* fall through */
311 case TFTP_OP_RRQ:
312 case TFTP_OP_WRQ:
313 default:
315 * we aren't expecting any of these messages
317 udp_free(buf);
318 udp_close(info->tftp_socket);
319 info->tftp_socket = -1;
320 return CFE_ERR_PROTOCOLERR;
322 case TFTP_OP_ERROR:
323 ebuf_get_u16_be(buf,error);
324 xprintf("TFTP error %d: %s\n",error,ebuf_ptr(buf));
325 udp_free(buf);
326 udp_close(info->tftp_socket);
327 info->tftp_socket = -1;
328 return CFE_ERR_PROTOCOLERR;
330 case TFTP_OP_DATA:
332 * Yay, we've got data! Store the first block.
334 ebuf_get_u16_be(buf,block);
335 udp_connect(info->tftp_socket,(uint16_t) buf->eb_usrdata);
336 info->tftp_blknum = block;
337 info->tftp_blklen = ebuf_length(buf);
338 ebuf_get_bytes(buf,info->tftp_data,ebuf_length(buf));
339 udp_free(buf);
340 if (info->tftp_blklen < TFTP_BLOCKSIZE) {
341 info->tftp_lastblock = 1; /* EOF */
343 return 0;
344 break;
350 /* *********************************************************************
351 * _tftp_readmore(info)
353 * Read the next block of the file. We do this by acking the
354 * previous block. Once that block is acked, the TFTP server
355 * should send the next block to us.
357 * Input parameters:
358 * info - TFTP information
360 * Return value:
361 * 0 if ok
362 * else error code
363 ********************************************************************* */
365 static int _tftp_readmore(tftp_info_t *info)
367 ebuf_t *buf;
368 uint16_t cmd,block;
369 int retries;
372 * If we've already read the last block, there is no more
375 #ifdef RESCUE_MODE
376 if (info->tftp_lastblock) {
377 xprintf("- Last block -\n");
378 return 1;
380 if (info->tftp_error) {
381 xprintf("break !! tftp_error !!\n");
382 return CFE_ERR_TIMEOUT;
384 #else
385 if (info->tftp_lastblock) return 1;
386 if (info->tftp_error) return CFE_ERR_TIMEOUT;
387 #endif
390 * Otherwise, ack the current block so another one will come
393 for (retries = 0; retries < tftp_max_retries; retries++) {
395 buf = udp_alloc();
396 if (!buf) return -1;
399 * Send the ack
402 ebuf_append_u16_be(buf,TFTP_OP_ACK);
403 ebuf_append_u16_be(buf,info->tftp_blknum);
404 udp_send(info->tftp_socket,buf,info->tftp_ipaddr);
407 * Wait for some response, retransmitting as necessary
410 buf = udp_recv_with_timeout(info->tftp_socket,tftp_recv_timeout);
411 #ifdef RESCUE_MODE
412 if (!buf)
414 xprintf("break! no netctx or timer expired ! \n");
415 continue;
417 #else
418 if (buf == NULL) continue;
419 #endif
422 * Got a response, make sure it's right
425 ebuf_get_u16_be(buf,cmd);
426 if (cmd != TFTP_OP_DATA) {
427 udp_free(buf);
428 continue;
431 ebuf_get_u16_be(buf,block);
432 if (block != (info->tftp_blknum+1)) {
433 udp_free(buf);
434 continue;
438 * It's the correct response. Copy the user data
441 info->tftp_blknum = block;
442 info->tftp_blklen = ebuf_length(buf);
443 ebuf_get_bytes(buf,info->tftp_data,ebuf_length(buf));
444 udp_free(buf);
445 break;
449 * If the block is less than 512 bytes long, it's the EOF block.
452 if (retries == tftp_max_retries) {
453 #ifdef RESCUE_MODE
454 xprintf("break!! reach max retry!!\n");
455 #endif
456 info->tftp_error = 1;
457 return CFE_ERR_TIMEOUT;
460 if (info->tftp_blklen < TFTP_BLOCKSIZE) {
461 #ifdef RESCUE_MODE
462 xprintf("- last blk -\n");
463 #endif
464 info->tftp_lastblock = 1; /* EOF */
467 return 0;
470 /* *********************************************************************
471 * _tftp_writemore(info)
473 * Write the next block of the file, sending the data from our
474 * holding buffer. Note that the holding buffer must be full
475 * or else we consider this to be an EOF.
477 * Input parameters:
478 * info - TFTP information
480 * Return value:
481 * 0 if ok
482 * else error code
483 ********************************************************************* */
485 static int _tftp_writemore(tftp_info_t *info)
487 ebuf_t *buf;
488 uint16_t cmd,block,error;
489 int retries;
492 * If we've already written the last block, there is no more
495 if (info->tftp_lastblock) return 1;
496 if (info->tftp_error) return CFE_ERR_TIMEOUT;
499 * Otherwise, send a block
501 for (retries = 0; retries < tftp_max_retries; retries++) {
503 buf = udp_alloc();
504 if (!buf) return -1;
507 * Send the data
510 ebuf_append_u16_be(buf,TFTP_OP_DATA);
511 ebuf_append_u16_be(buf,info->tftp_blknum);
512 ebuf_append_bytes(buf,info->tftp_data,info->tftp_blklen);
513 udp_send(info->tftp_socket,buf,info->tftp_ipaddr);
516 * Wait for some response, retransmitting as necessary
519 buf = udp_recv_with_timeout(info->tftp_socket,tftp_recv_timeout);
520 if (buf == NULL) continue;
523 * Got a response, make sure it's right
526 ebuf_get_u16_be(buf,cmd);
528 if (cmd == TFTP_OP_ERROR) {
529 ebuf_get_u16_be(buf,error);
530 xprintf("TFTP write error %d: %s\n",error,ebuf_ptr(buf));
531 info->tftp_error = 1;
532 info->tftp_lastblock = 1;
533 udp_free(buf);
534 return CFE_ERR_IOERR;
537 if (cmd != TFTP_OP_ACK) {
538 udp_free(buf);
539 continue;
542 ebuf_get_u16_be(buf,block);
543 if (block != (info->tftp_blknum)) {
544 udp_free(buf);
545 continue;
549 * It's the correct response. Update the block #
552 info->tftp_blknum++;
553 if (info->tftp_blklen != TFTP_BLOCKSIZE) info->tftp_lastblock = 1;
554 udp_free(buf);
555 break;
559 * If we had some failure, mark the stream with an error
562 if (retries == tftp_max_retries) {
563 info->tftp_error = 1;
564 return CFE_ERR_TIMEOUT;
567 return 0;
571 static int _tftpd_open(tftp_info_t *info,char *hostname,char *filename,int mode)
573 ebuf_t *buf = NULL;
574 uint16_t type;
575 int res;
576 int retries;
577 char ch = 0;
578 #ifdef RESCUE_MODE
579 uint8_t asuslink[13] = "ASUSSPACELINK";
580 uint8_t maclink[13]="snxxxxxxxxxxx";
581 unsigned char tftpmask[4] = { 0xff, 0xff, 0xff, 0x00 };
582 int i;
583 char tftpnull;
584 uint8_t ipaddr[4] = { 0xc0, 0xa8, 0x01, 0x0c };
585 uint8_t hwaddr[6] = { 0x00, 0xe0, 0x18, 0x00, 0x3e, 0xc4 };
586 #endif
589 * Open a UDP socket
592 info->tftp_socket = udp_socket(UDP_PROTO_TFTP);
593 info->tftp_lastblock = 0;
594 info->tftp_error = 0;
595 info->tftp_filemode = mode;
598 * Listen for requests
601 res = udp_bind(info->tftp_socket,UDP_PROTO_TFTP);
602 if (res < 0) return res;
604 res = CFE_ERR_TIMEOUT;
606 for (retries = 0; retries < tftp_max_retries; retries++) { // go load wait
607 printf("..tftp retry wait %d\n", retries);
608 while (console_status()) {
609 console_read(&ch,1);
610 if (ch == 3) break;
612 if (ch == 3) {
613 res = CFE_ERR_INTR;
614 break;
617 buf = udp_recv_with_timeout(info->tftp_socket,tftp_recv_timeout);
618 if (buf == NULL) continue;
621 * Process the request
624 ebuf_get_u16_be(buf,type);
626 switch (type) {
627 case TFTP_OP_RRQ:
628 #ifdef RESCUE_MODE
629 udp_connect(info->tftp_socket,(uint16_t) buf->eb_usrdata);
630 ackport = buf->eb_usrdata;
631 memcpy(info->tftp_ipaddr,buf->eb_usrptr,IP_ADDR_LEN);
632 info->tftp_blknum = 1;
633 info->tftp_blklen = 0;
634 for (i=0; i<13; i++) {
635 if (buf->eb_ptr[i] != asuslink[i])
636 break;
638 if (i==13) {
639 tftpipfrom[0]=buf->eb_ptr[16];
640 tftpipfrom[1]=buf->eb_ptr[15];
641 tftpipfrom[2]=buf->eb_ptr[14];
642 tftpipfrom[3]=buf->eb_ptr[13];
643 tftpipto[0]=buf->eb_usrptr[0];
644 tftpipto[1]=buf->eb_usrptr[1];
645 tftpipto[2]=buf->eb_usrptr[2];
646 tftpipto[3]=buf->eb_usrptr[3];
647 net_setparam(NET_IPADDR,tftpipfrom);
648 net_setparam(NET_NETMASK,tftpmask);
649 net_setparam(NET_GATEWAY,tftpipfrom);
650 ui_myshowifconfig();
651 net_setnetvars();
652 for (i=0; i<4; i++)
653 ipaddr[i]=tftpipto[i];
654 for (i=0; i<6; i++)
655 hwaddr[i]=buf->eb_data[6+i];
656 buf = udp_alloc();
657 if (!buf) {
658 res = CFE_ERR_TIMEOUT;
659 break;
661 ebuf_append_u16_be(buf, 3);
662 ebuf_append_u16_be(buf, 1);
663 ebuf_append_bytes(buf,&tftpnull, 0);
664 arp_delete(ipaddr);
665 arp_add(ipaddr,hwaddr);
666 udp_send(info->tftp_socket, buf, tftpipto);
668 else {
669 for (i=0; i<13; i++) {
670 if (buf->eb_ptr[i] != maclink[i])
671 break;
673 if (i==13) {
674 tftpipfrom[0]=buf->eb_ptr[16];
675 tftpipfrom[1]=buf->eb_ptr[15];
676 tftpipfrom[2]=buf->eb_ptr[14];
677 tftpipfrom[3]=buf->eb_ptr[13];
678 tftpipto[0]=buf->eb_usrptr[0];
679 tftpipto[1]=buf->eb_usrptr[1];
680 tftpipto[2]=buf->eb_usrptr[2];
681 tftpipto[3]=buf->eb_usrptr[3];
682 net_setparam(NET_IPADDR,tftpipfrom);
683 net_setparam(NET_NETMASK,tftpmask);
684 net_setparam(NET_GATEWAY,tftpipfrom);
685 ui_myshowifconfig();
686 net_setnetvars();
687 for (i=0; i<4; i++)
688 ipaddr[i]=tftpipto[i];
689 for (i=0; i<6; i++)
690 hwaddr[i]=buf->eb_data[6+i];
691 buf = udp_alloc();
692 if (!buf) {
693 res = CFE_ERR_TIMEOUT;
694 break;
696 ebuf_append_u16_be(buf, 3);
697 ebuf_append_u16_be(buf, 1);
698 ebuf_append_bytes(buf,&tftpnull, 0);
699 arp_delete(ipaddr);
700 arp_add(ipaddr,hwaddr);
701 udp_send(info->tftp_socket, buf, tftpipto);
704 res = CFE_ERR_TIMEOUT;
705 #else
706 udp_connect(info->tftp_socket,(uint16_t) buf->eb_usrdata);
707 memcpy(info->tftp_ipaddr,buf->eb_usrptr,IP_ADDR_LEN);
708 info->tftp_blknum = 1;
709 info->tftp_blklen = 0;
710 res = 0;
711 #endif
712 break;
714 case TFTP_OP_WRQ:
715 udp_connect(info->tftp_socket,(uint16_t) buf->eb_usrdata);
716 memcpy(info->tftp_ipaddr,buf->eb_usrptr,IP_ADDR_LEN);
717 info->tftp_blknum = 0;
718 res = _tftp_readmore(info);
719 break;
721 default:
723 * we aren't expecting any of these messages
725 res = CFE_ERR_PROTOCOLERR;
726 break;
729 udp_free(buf);
730 break;
733 if (res) {
734 udp_close(info->tftp_socket);
735 info->tftp_socket = -1;
738 return res;
742 /* *********************************************************************
743 * _tftp_close(info)
745 * Close a TFTP file. There are two cases for what we do
746 * here. If we're closing the file mid-stream, send an error
747 * packet to tell the host we're getting out early. Otherwise,
748 * just ack the final packet and the connection will close
749 * gracefully.
751 * Input parameters:
752 * info - TFTP info
754 * Return value:
755 * 0 if ok, else error code
756 ********************************************************************* */
758 static int _tftp_close(tftp_info_t *info)
760 ebuf_t *buf;
761 const char *emsg = "transfer cancelled"; /* some error message */
763 if (info->tftp_socket == -1) return 0;
765 if (info->tftp_filemode == FILE_MODE_READ) {
766 buf = udp_alloc();
767 if (buf) {
768 /* If we're on the EOF packet, just send an ack */
769 if (info->tftp_lastblock) {
770 ebuf_append_u16_be(buf,TFTP_OP_ACK);
771 ebuf_append_u16_be(buf,info->tftp_blknum);
773 else {
774 ebuf_append_u16_be(buf,TFTP_OP_ERROR);
775 ebuf_append_u16_be(buf,TFTP_ERR_DISKFULL);
776 ebuf_append_bytes(buf,emsg,strlen(emsg)+1);
778 udp_send(info->tftp_socket,buf,info->tftp_ipaddr);
781 else {
782 /* Just flush out the remaining write data, if any */
783 _tftp_writemore(info);
786 udp_close(info->tftp_socket);
787 info->tftp_socket = -1;
788 return 0;
793 /* *********************************************************************
794 * tftp_fileop_init(fsctx,device)
796 * Create a file system device context for the TFTP service
798 * Input parameters:
799 * fsctx - location to place context information
800 * device - underlying device (unused)
802 * Return value:
803 * 0 if ok
804 * else error code
805 ********************************************************************* */
807 static int tftp_fileop_init(void **fsctx,void *dev)
809 void *ref;
811 ref = KMALLOC(sizeof(tftp_fsctx_t),0);
813 if (!ref) return CFE_ERR_NOMEM;
814 *fsctx = ref;
815 return 0;
818 /* *********************************************************************
819 * tftp_fileop_open(ref,fsctx,filename,mode)
821 * This is the filesystem entry point for opening a TFTP file.
822 * Allocate a tftp_info structure, open the TFTP file, and
823 * return a handle.
825 * Input parameters:
826 * ref - location to place reference data (the TFTP structure)
827 * fsctx - filesystem context
828 * filename - name of remote file to open
829 * mode - FILE_MODE_READ or FILE_MODE_WRITE
831 * Return value:
832 * 0 if ok
833 * else error code
834 ********************************************************************* */
836 static int tftp_fileop_open(void **ref,void *fsctx,char *filename,int mode)
838 tftp_info_t *info;
839 char *host;
840 char *file;
841 int res;
843 if ((mode != FILE_MODE_READ) && (mode != FILE_MODE_WRITE)) {
844 /* must be either read or write, not both */
845 return CFE_ERR_UNSUPPORTED;
848 /* Allocate the tftp info structure */
850 info = KMALLOC(sizeof(tftp_info_t),0);
851 if (!info) {
852 return CFE_ERR_NOMEM;
856 info->tftp_filename = lib_strdup(filename);
857 if (!info->tftp_filename) {
858 KFREE(info);
859 return CFE_ERR_NOMEM;
862 lib_chop_filename(info->tftp_filename,&host,&file);
864 /* Open the file */
866 if (!*host && !*file) {
867 /* TFTP server if hostname and filename are not specified */
868 #ifdef RESCUE_MODE
869 xprintf("TFTP Server.\n");
870 #endif
871 res = _tftpd_open(info,host,file,mode);
872 } else {
873 /* TFTP client otherwise */
874 #ifdef RESCUE_MODE
875 xprintf("TFTP Client.\n");
876 #endif
877 res = _tftp_open(info,host,file,mode);
880 if (res == 0) {
881 info->tftp_blkoffset = 0;
882 info->tftp_fileoffset = 0;
883 *ref = info;
885 else {
886 KFREE(info->tftp_filename);
887 KFREE(info);
888 *ref = NULL;
890 return res;
893 /* *********************************************************************
894 * tftp_fileop_read(ref,buf,len)
896 * Read some bytes from the remote TFTP file. Do this by copying
897 * data from the block buffer, and reading more data from the
898 * remote file as necessary.
900 * Input parameters:
901 * ref - tftp_info structure
902 * buf - destination buffer address (NULL to read data and
903 * not copy it anywhere)
904 * len - number of bytes to read
906 * Return value:
907 * number of bytes read, 0 for EOF, <0 if an error occured.
908 ********************************************************************* */
910 static int tftp_fileop_read(void *ref,uint8_t *buf,int len)
912 tftp_info_t *info = (tftp_info_t *) ref;
913 int copied = 0;
914 int amtcopy;
915 int res;
917 if (info->tftp_error) return CFE_ERR_IOERR;
918 if (info->tftp_filemode == FILE_MODE_WRITE) return CFE_ERR_UNSUPPORTED;
920 while (len) {
922 if (info->tftp_blkoffset >= info->tftp_blklen) break;
923 amtcopy = len;
925 if (amtcopy > (info->tftp_blklen-info->tftp_blkoffset)) {
926 amtcopy = (info->tftp_blklen-info->tftp_blkoffset);
929 if (buf) {
930 memcpy(buf,&(info->tftp_data[info->tftp_blkoffset]),amtcopy);
931 buf += amtcopy;
934 info->tftp_blkoffset += amtcopy;
935 len -= amtcopy;
936 info->tftp_fileoffset += amtcopy;
937 copied += amtcopy;
939 if (info->tftp_blkoffset >= info->tftp_blklen) {
940 res = _tftp_readmore(info);
941 if (res != 0) break;
942 info->tftp_blkoffset = 0;
946 return copied;
949 /* *********************************************************************
950 * tftp_fileop_write(ref,buf,len)
952 * Write some bytes to the remote TFTP file. Do this by copying
953 * data to the block buffer, and writing data to the
954 * remote file as necessary.
956 * Input parameters:
957 * ref - tftp_info structure
958 * buf - source buffer address
959 * len - number of bytes to write
961 * Return value:
962 * number of bytes written, 0 for EOF, <0 if an error occured.
963 ********************************************************************* */
965 static int tftp_fileop_write(void *ref,uint8_t *buf,int len)
967 tftp_info_t *info = (tftp_info_t *) ref;
968 int copied = 0;
969 int amtcopy;
970 int res;
972 if (info->tftp_error) return CFE_ERR_IOERR;
973 if (info->tftp_filemode == FILE_MODE_READ) return CFE_ERR_UNSUPPORTED;
975 while (len) {
977 amtcopy = len;
978 if (amtcopy > (TFTP_BLOCKSIZE - info->tftp_blklen)) {
979 amtcopy = (TFTP_BLOCKSIZE - info->tftp_blklen);
982 memcpy(&(info->tftp_data[info->tftp_blklen]),buf,amtcopy);
983 buf += amtcopy;
985 info->tftp_blklen += amtcopy;
986 len -= amtcopy;
987 info->tftp_fileoffset += amtcopy;
988 copied += amtcopy;
990 if (info->tftp_blklen == TFTP_BLOCKSIZE) {
991 res = _tftp_writemore(info);
992 if (res != 0) {
993 break;
995 info->tftp_blklen = 0;
999 return copied;
1002 /* *********************************************************************
1003 * tftp_fileop_seek(ref,offset,how)
1005 * Seek within a TFTP file. Note that you can only seek *forward*,
1006 * as TFTP doesn't really let you go backwards. (I suppose you
1007 * could reopen the file, but thus far nobody needs to go
1008 * backwards). You can only seek in a file in read mode.
1010 * Input parameters:
1011 * ref - our tftp information
1012 * offset - distance to move
1013 * how - how to move, (FILE_SEEK_*)
1015 * Return value:
1016 * new offset, or <0 if an error occured.
1017 ********************************************************************* */
1019 static int tftp_fileop_seek(void *ref,int offset,int how)
1021 tftp_info_t *info = (tftp_info_t *) ref;
1022 int delta;
1023 int startloc;
1024 int res;
1026 if (info->tftp_filemode == FILE_MODE_WRITE) return CFE_ERR_UNSUPPORTED;
1028 switch (how) {
1029 case FILE_SEEK_BEGINNING:
1030 startloc = info->tftp_fileoffset;
1031 break;
1032 case FILE_SEEK_CURRENT:
1033 startloc = 0;
1034 break;
1035 default:
1036 startloc = 0;
1037 break;
1040 delta = offset - startloc;
1041 if (delta < 0) {
1042 xprintf("Warning: negative seek on tftp file attempted\n");
1043 return CFE_ERR_UNSUPPORTED;
1045 res = tftp_fileop_read(ref,NULL,delta);
1046 if (res < 0) return res;
1048 return info->tftp_fileoffset;
1052 /* *********************************************************************
1053 * tftp_fileop_close(ref)
1055 * Close the TFTP file.
1057 * Input parameters:
1058 * ref - our TFTP info
1060 * Return value:
1061 * nothing
1062 ********************************************************************* */
1064 static void tftp_fileop_close(void *ref)
1066 tftp_info_t *info = (tftp_info_t *) ref;
1068 _tftp_close(info);
1070 KFREE(info->tftp_filename);
1071 KFREE(info);
1075 /* *********************************************************************
1076 * tftp_fileop_uninit(fsctx)
1078 * Uninitialize the filesystem context, freeing allocated
1079 * resources.
1081 * Input parameters:
1082 * fsctx - our context
1084 * Return value:
1085 * nothing
1086 ********************************************************************* */
1088 static void tftp_fileop_uninit(void *fsctx)
1090 KFREE(fsctx);
1093 #ifdef RESCUE_MODE
1094 extern int send_rescueack(unsigned short no, unsigned short lo)
1096 ebuf_t *buf = NULL;
1097 int acksocket;
1098 char tftpnull;
1099 int res, i;
1102 * Open a UDP socket to the TFTP server
1104 acksocket = udp_socket(UDP_PROTO_TFTP);
1105 res = udp_bind(acksocket, 69);
1106 if (res < 0) {
1107 return res;
1109 udp_connect(acksocket, ackport);
1110 for (i = 0; i < 1; i++) {
1111 buf = udp_alloc();
1112 if (!buf)
1113 return -1;
1115 * Send the data
1117 ebuf_append_u16_be(buf, no);
1118 ebuf_append_u16_be(buf, lo);
1119 ebuf_append_bytes(buf,&tftpnull, 0);
1120 udp_send(acksocket ,buf, tftpipto);
1122 if (buf)
1123 udp_free(buf);
1124 udp_close(acksocket);
1125 return 0;
1127 #endif