1 /* *********************************************************************
2 * Broadcom Common Firmware Environment (CFE)
4 * TFTP Client File: net_tftp.c
6 * This module contains a TFTP client.
8 * Author: Mitch Lichtenberg (mpl@broadcom.com)
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"
60 #include "net_ether.h"
64 #include "cfe_loader.h"
68 #include "bsp_config.h"
71 /* *********************************************************************
73 ********************************************************************* */
75 #define UDP_PROTO_TFTP 69
77 #define TFTP_BLOCKSIZE 512
81 #define TFTP_OP_DATA 3
83 #define TFTP_OP_ERROR 5
85 #define TFTP_ERR_DISKFULL 3
87 #ifndef TFTP_MAX_RETRIES
88 #define TFTP_MAX_RETRIES 8
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 */
96 unsigned char tftpipfrom
[4] = { 0xc0, 0xa8, 0x01, 0x01 };
97 unsigned char tftpipto
[4] = { 0xc0, 0xa8, 0x01, 0x01 };
98 uint16_t ackport
= 7777;
101 /* *********************************************************************
103 ********************************************************************* */
105 typedef struct tftp_fsctx_s
{
109 typedef struct tftp_info_s
{
111 uint8_t tftp_data
[TFTP_BLOCKSIZE
];
115 uint16_t tftp_blknum
;
116 uint8_t tftp_ipaddr
[IP_ADDR_LEN
];
123 /* *********************************************************************
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
);
135 extern int send_rescueack(unsigned short no
, unsigned short lo
);
138 /* *********************************************************************
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
= {
152 LOADFLG_NOBB
| FSYS_TYPE_NETWORK
,
163 #define ip_addriszero(a) (((a)[0]|(a)[1]|(a)[2]|(a)[3]) == 0)
164 static void ui_myshowifconfig(void)
169 devname
= (char *) net_getparam(NET_DEVNAME
);
170 if (devname
== NULL
) {
171 xprintf("Network interface has not been configured\n");
174 xprintf("Device %s: ",devname
);
175 addr
= net_getparam(NET_HWADDR
);
177 xprintf(" hwaddr %a",addr
);
178 addr
= net_getparam(NET_IPADDR
);
180 if (ip_addriszero(addr
))
181 xprintf(", ipaddr not set");
183 xprintf(", ipaddr %I",addr
);
185 addr
= net_getparam(NET_NETMASK
);
187 if (ip_addriszero(addr
))
188 xprintf(", mask not set");
190 xprintf(", mask %I",addr
);
194 addr
= net_getparam(NET_GATEWAY
);
196 if (ip_addriszero(addr
))
197 xprintf("gateway not set");
199 xprintf("gateway %I",addr
);
201 addr
= net_getparam(NET_NAMESERVER
);
203 if (ip_addriszero(addr
))
204 xprintf(", nameserver not set");
206 xprintf(", nameserver %I",addr
);
208 addr
= net_getparam(NET_DOMAIN
);
210 xprintf(", domain %s",addr
);
216 /* *********************************************************************
217 * _tftp_open(info,hostname,filename,mode)
219 * Open a file on a remote host, using the TFTP protocol.
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
230 ********************************************************************* */
232 static int _tftp_open(tftp_info_t
*info
,char *hostname
,char *filename
,int mode
)
235 const char *datamode
= "octet";
236 uint16_t type
,error
,block
;
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
++) {
265 if (info
->tftp_filemode
== FILE_MODE_READ
) {
266 ebuf_append_u16_be(buf
,TFTP_OP_RRQ
); /* read file */
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
);
281 * If we got no response, bail now.
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
);
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;
315 * we aren't expecting any of these messages
318 udp_close(info
->tftp_socket
);
319 info
->tftp_socket
= -1;
320 return CFE_ERR_PROTOCOLERR
;
323 ebuf_get_u16_be(buf
,error
);
324 xprintf("TFTP error %d: %s\n",error
,ebuf_ptr(buf
));
326 udp_close(info
->tftp_socket
);
327 info
->tftp_socket
= -1;
328 return CFE_ERR_PROTOCOLERR
;
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
));
340 if (info
->tftp_blklen
< TFTP_BLOCKSIZE
) {
341 info
->tftp_lastblock
= 1; /* EOF */
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.
358 * info - TFTP information
363 ********************************************************************* */
365 static int _tftp_readmore(tftp_info_t
*info
)
372 * If we've already read the last block, there is no more
376 if (info
->tftp_lastblock
) {
377 xprintf("- Last block -\n");
380 if (info
->tftp_error
) {
381 xprintf("break !! tftp_error !!\n");
382 return CFE_ERR_TIMEOUT
;
385 if (info
->tftp_lastblock
) return 1;
386 if (info
->tftp_error
) return CFE_ERR_TIMEOUT
;
390 * Otherwise, ack the current block so another one will come
393 for (retries
= 0; retries
< tftp_max_retries
; retries
++) {
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
);
414 xprintf("break! no netctx or timer expired ! \n");
418 if (buf
== NULL
) continue;
422 * Got a response, make sure it's right
425 ebuf_get_u16_be(buf
,cmd
);
426 if (cmd
!= TFTP_OP_DATA
) {
431 ebuf_get_u16_be(buf
,block
);
432 if (block
!= (info
->tftp_blknum
+1)) {
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
));
449 * If the block is less than 512 bytes long, it's the EOF block.
452 if (retries
== tftp_max_retries
) {
454 xprintf("break!! reach max retry!!\n");
456 info
->tftp_error
= 1;
457 return CFE_ERR_TIMEOUT
;
460 if (info
->tftp_blklen
< TFTP_BLOCKSIZE
) {
462 xprintf("- last blk -\n");
464 info
->tftp_lastblock
= 1; /* EOF */
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.
478 * info - TFTP information
483 ********************************************************************* */
485 static int _tftp_writemore(tftp_info_t
*info
)
488 uint16_t cmd
,block
,error
;
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
++) {
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;
534 return CFE_ERR_IOERR
;
537 if (cmd
!= TFTP_OP_ACK
) {
542 ebuf_get_u16_be(buf
,block
);
543 if (block
!= (info
->tftp_blknum
)) {
549 * It's the correct response. Update the block #
553 if (info
->tftp_blklen
!= TFTP_BLOCKSIZE
) info
->tftp_lastblock
= 1;
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
;
571 static int _tftpd_open(tftp_info_t
*info
,char *hostname
,char *filename
,int mode
)
579 uint8_t asuslink
[13] = "ASUSSPACELINK";
580 uint8_t maclink
[13]="snxxxxxxxxxxx";
581 unsigned char tftpmask
[4] = { 0xff, 0xff, 0xff, 0x00 };
584 uint8_t ipaddr
[4] = { 0xc0, 0xa8, 0x01, 0x0c };
585 uint8_t hwaddr
[6] = { 0x00, 0xe0, 0x18, 0x00, 0x3e, 0xc4 };
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()) {
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
);
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
])
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
);
653 ipaddr
[i
]=tftpipto
[i
];
655 hwaddr
[i
]=buf
->eb_data
[6+i
];
658 res
= CFE_ERR_TIMEOUT
;
661 ebuf_append_u16_be(buf
, 3);
662 ebuf_append_u16_be(buf
, 1);
663 ebuf_append_bytes(buf
,&tftpnull
, 0);
665 arp_add(ipaddr
,hwaddr
);
666 udp_send(info
->tftp_socket
, buf
, tftpipto
);
669 for (i
=0; i
<13; i
++) {
670 if (buf
->eb_ptr
[i
] != maclink
[i
])
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
);
688 ipaddr
[i
]=tftpipto
[i
];
690 hwaddr
[i
]=buf
->eb_data
[6+i
];
693 res
= CFE_ERR_TIMEOUT
;
696 ebuf_append_u16_be(buf
, 3);
697 ebuf_append_u16_be(buf
, 1);
698 ebuf_append_bytes(buf
,&tftpnull
, 0);
700 arp_add(ipaddr
,hwaddr
);
701 udp_send(info
->tftp_socket
, buf
, tftpipto
);
704 res
= CFE_ERR_TIMEOUT
;
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;
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
);
723 * we aren't expecting any of these messages
725 res
= CFE_ERR_PROTOCOLERR
;
734 udp_close(info
->tftp_socket
);
735 info
->tftp_socket
= -1;
742 /* *********************************************************************
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
755 * 0 if ok, else error code
756 ********************************************************************* */
758 static int _tftp_close(tftp_info_t
*info
)
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
) {
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
);
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
);
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;
793 /* *********************************************************************
794 * tftp_fileop_init(fsctx,device)
796 * Create a file system device context for the TFTP service
799 * fsctx - location to place context information
800 * device - underlying device (unused)
805 ********************************************************************* */
807 static int tftp_fileop_init(void **fsctx
,void *dev
)
811 ref
= KMALLOC(sizeof(tftp_fsctx_t
),0);
813 if (!ref
) return CFE_ERR_NOMEM
;
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
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
834 ********************************************************************* */
836 static int tftp_fileop_open(void **ref
,void *fsctx
,char *filename
,int mode
)
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);
852 return CFE_ERR_NOMEM
;
856 info
->tftp_filename
= lib_strdup(filename
);
857 if (!info
->tftp_filename
) {
859 return CFE_ERR_NOMEM
;
862 lib_chop_filename(info
->tftp_filename
,&host
,&file
);
866 if (!*host
&& !*file
) {
867 /* TFTP server if hostname and filename are not specified */
869 xprintf("TFTP Server.\n");
871 res
= _tftpd_open(info
,host
,file
,mode
);
873 /* TFTP client otherwise */
875 xprintf("TFTP Client.\n");
877 res
= _tftp_open(info
,host
,file
,mode
);
881 info
->tftp_blkoffset
= 0;
882 info
->tftp_fileoffset
= 0;
886 KFREE(info
->tftp_filename
);
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.
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
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
;
917 if (info
->tftp_error
) return CFE_ERR_IOERR
;
918 if (info
->tftp_filemode
== FILE_MODE_WRITE
) return CFE_ERR_UNSUPPORTED
;
922 if (info
->tftp_blkoffset
>= info
->tftp_blklen
) break;
925 if (amtcopy
> (info
->tftp_blklen
-info
->tftp_blkoffset
)) {
926 amtcopy
= (info
->tftp_blklen
-info
->tftp_blkoffset
);
930 memcpy(buf
,&(info
->tftp_data
[info
->tftp_blkoffset
]),amtcopy
);
934 info
->tftp_blkoffset
+= amtcopy
;
936 info
->tftp_fileoffset
+= amtcopy
;
939 if (info
->tftp_blkoffset
>= info
->tftp_blklen
) {
940 res
= _tftp_readmore(info
);
942 info
->tftp_blkoffset
= 0;
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.
957 * ref - tftp_info structure
958 * buf - source buffer address
959 * len - number of bytes to write
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
;
972 if (info
->tftp_error
) return CFE_ERR_IOERR
;
973 if (info
->tftp_filemode
== FILE_MODE_READ
) return CFE_ERR_UNSUPPORTED
;
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
);
985 info
->tftp_blklen
+= amtcopy
;
987 info
->tftp_fileoffset
+= amtcopy
;
990 if (info
->tftp_blklen
== TFTP_BLOCKSIZE
) {
991 res
= _tftp_writemore(info
);
995 info
->tftp_blklen
= 0;
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.
1011 * ref - our tftp information
1012 * offset - distance to move
1013 * how - how to move, (FILE_SEEK_*)
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
;
1026 if (info
->tftp_filemode
== FILE_MODE_WRITE
) return CFE_ERR_UNSUPPORTED
;
1029 case FILE_SEEK_BEGINNING
:
1030 startloc
= info
->tftp_fileoffset
;
1032 case FILE_SEEK_CURRENT
:
1040 delta
= offset
- startloc
;
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.
1058 * ref - our TFTP info
1062 ********************************************************************* */
1064 static void tftp_fileop_close(void *ref
)
1066 tftp_info_t
*info
= (tftp_info_t
*) ref
;
1070 KFREE(info
->tftp_filename
);
1075 /* *********************************************************************
1076 * tftp_fileop_uninit(fsctx)
1078 * Uninitialize the filesystem context, freeing allocated
1082 * fsctx - our context
1086 ********************************************************************* */
1088 static void tftp_fileop_uninit(void *fsctx
)
1094 extern int send_rescueack(unsigned short no
, unsigned short lo
)
1102 * Open a UDP socket to the TFTP server
1104 acksocket
= udp_socket(UDP_PROTO_TFTP
);
1105 res
= udp_bind(acksocket
, 69);
1109 udp_connect(acksocket
, ackport
);
1110 for (i
= 0; i
< 1; i
++) {
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
);
1124 udp_close(acksocket
);