0
mirror of https://github.com/Indemsys/Frequency_Inverter.git synced 2026-05-12 22:33:25 +00:00
Files
2022-01-04 12:22:53 +02:00

361 lines
10 KiB
C

/**HEADER********************************************************************
*
* Copyright (c) 2008 Freescale Semiconductor;
* All Rights Reserved
*
* Copyright (c) 2004-2008 Embedded Access Inc.;
* All Rights Reserved
*
* Copyright (c) 1989-2008 ARC International;
* All Rights Reserved
*
***************************************************************************
*
* THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY EXPRESSED OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL FREESCALE OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
**************************************************************************
*
* $FileName: tftp.c$
* $Version : 3.8.13.0$
* $Date : Jun-14-2012$
*
* Comments:
*
* This file contains the TFTP client implementation for
* the Exec function of the RTCS Communication Library.
*
*END************************************************************************/
#include <rtcs.h>
#if RTCSCFG_ENABLE_UDP
#include <fio.h>
#include "tftp.h"
/* The File Transfer client information to pass to RTCS_load() */
uint_32 TFTP_open (pointer ft_data);
uchar_ptr TFTP_read (uint_32_ptr size);
boolean TFTP_eof (void);
uint_32 TFTP_close (void);
static FT_CALL_STRUCT ft_tftp = {
TFTP_open,
TFTP_read,
TFTP_eof,
TFTP_close
};
const FT_CALL_STRUCT_PTR FT_TFTP = &ft_tftp;
/* TFTP state information */
static struct {
TFTP_PACKET PACKET;
TFTP_HEADER ACK;
sockaddr_in SADDR;
uchar_ptr RRQ_PTR;
uint_32 RRQ_LEN;
TFTP_TO_STRUCT TIMEOUT;
uint_32 SOCK;
boolean LAST;
} TFTP_config;
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : TFTP_open
* Returned Value : socket handle or RTCS_ERROR
* Comments : Routine to initiate a TFTP session.
*
*END*-----------------------------------------------------------------*/
uint_32 TFTP_open
(
pointer ft_data
/* [IN] the address and filename of the bootimage */
)
{ /* Body */
TFTP_DATA_STRUCT_PTR tftp;
sockaddr_in local_addr;
char_ptr str_ptr;
uchar_ptr packet;
uint_32 sock;
uint_32 error;
uint_32 fn_len, fm_len;
uint_32 pkt_len;
tftp = (TFTP_DATA_STRUCT_PTR) ft_data;
/* Get a socket */
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == RTCS_SOCKET_ERROR) {
return RTCSERR_TFTP_SOCKET;
} /* Endif */
/* Must be initialized in order for TFTP_close to be able to release socket and memory */
TFTP_config.SOCK = sock;
TFTP_config.RRQ_PTR = NULL;
/* Bind it */
local_addr.sin_family = AF_INET;
local_addr.sin_port = 0;
local_addr.sin_addr.s_addr = INADDR_ANY;
error = bind(sock, (const sockaddr *)&local_addr, sizeof(local_addr));
if (error != RTCS_OK) {
TFTP_close();
return error;
} /* Endif */
if ( (tftp->FILENAME == NULL) || (tftp->FILEMODE == NULL) ){
TFTP_close();
return TFTPERR_FILE_NOT_FOUND;
} /* Endif */
/* Prepare a read request (RRQ) */
str_ptr = tftp->FILENAME;
while (*str_ptr++) {};
fn_len = str_ptr - tftp->FILENAME;
str_ptr = tftp->FILEMODE;
while (*str_ptr++) {};
fm_len = str_ptr - tftp->FILEMODE;
pkt_len = 2 + fn_len + fm_len;
packet = RTCS_mem_alloc(pkt_len);
if (packet == NULL) {
TFTP_close();
return RTCSERR_TFTP_RRQ_ALLOC;
} /* Endif */
_mem_set_type(packet, MEM_TYPE_TFTP_PACKET);
TFTP_config.RRQ_PTR = packet;
htons(packet, TFTPOP_RRQ);
_mem_copy(tftp->FILENAME, &packet[ 2], fn_len);
_mem_copy(tftp->FILEMODE, &packet[fn_len+2], fm_len);
/* Send the RRQ */
TFTP_config.SOCK = sock;
TFTP_config.SADDR.sin_family = AF_INET;
TFTP_config.SADDR.sin_port = IPPORT_TFTP;
TFTP_config.SADDR.sin_addr.s_addr = tftp->SERVER;
TFTP_timeout_init(&TFTP_config.TIMEOUT);
error = sendto(sock, packet, pkt_len, 0,
(sockaddr *)(&TFTP_config.SADDR), sizeof(TFTP_config.SADDR));
if (error != pkt_len) {
TFTP_close();
return RTCSERR_TFTP_RRQ_SEND;
} /* Endif */
/* Initialize the TFTP client */
TFTP_config.RRQ_PTR = packet;
TFTP_config.RRQ_LEN = pkt_len;
TFTP_config.LAST = FALSE;
htons(TFTP_config.ACK.OP, TFTPOP_ACK);
htons(TFTP_config.ACK.BLOCK, 0);
return RTCS_OK;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : TFTP_read
* Returned Value : pointer to read data, or NULL on error
* Comments : Routine to retrieve one file block via TFTP.
*
*END*-----------------------------------------------------------------*/
uchar_ptr TFTP_read
(
uint_32_ptr size
/* [OUT] number of bytes read, or error code */
)
{ /* Body */
uint_32 sock;
sockaddr_in remote_addr;
uint_16 remote_size;
uint_16 ack_block;
uint_16 pkt_op, pkt_block;
uint_32 pkt_size;
uint_32 time_left;
boolean expired;
#if TFTP_TIMEOUT_RETRIES
uint_32 retries = 0;
#endif
ack_block = ntohs(TFTP_config.ACK.BLOCK);
TFTP_timeout_restart(&TFTP_config.TIMEOUT);
for (;;) {
/* Check for timeout */
time_left = TFTP_timeout_left(&TFTP_config.TIMEOUT, &expired);
if (expired) {
#if TFTP_TIMEOUT_RETRIES
retries++;
if (retries > TFTP_TIMEOUT_RETRIES) {
*size = RTCSERR_TFTP_TIMEOUT;
TFTP_close();
return NULL;
} /* Endif */
#endif
/* Retransmit the last packet */
TFTP_RESEND();
} /* Endif */
/* Wait for a packet */
sock = TFTP_WAIT(time_left);
/* Timeout -- retransmit last packet */
if (sock != TFTP_config.SOCK) {
continue;
} /* Endif */
remote_size = sizeof(remote_addr);
pkt_size = TFTP_RECV(TFTP_config.PACKET);
pkt_op = ntohs(TFTP_config.PACKET.HEAD.OP);
pkt_block = ntohs(TFTP_config.PACKET.HEAD.BLOCK);
/* Check source address of received packet */
if (remote_addr.sin_addr.s_addr != TFTP_config.SADDR.sin_addr.s_addr) {
continue;
} /* Endif */
/* Validate source port */
if (ack_block && remote_addr.sin_port != TFTP_config.SADDR.sin_port) {
TFTP_SEND(TFTP_config.SOCK, _tftp_error_tid, remote_addr);
continue;
} /* Endif */
/* Check size of received packet */
if (pkt_size < sizeof(TFTP_HEADER)) {
TFTP_SEND(TFTP_config.SOCK, _tftp_error_op, remote_addr);
*size = RTCSERR_TFTP_ERROR + TFTPERR_ILLEGAL_OP;
TFTP_close();
return NULL;
} /* Endif */
/* Check for error packet */
if (pkt_op == TFTPOP_ERROR) {
*size = RTCSERR_TFTP_ERROR + pkt_block;
TFTP_close();
return NULL;
} /* Endif */
/* Check for data packet */
if ((pkt_op != TFTPOP_DATA)
|| (pkt_size > sizeof(TFTP_PACKET))) {
TFTP_SEND(TFTP_config.SOCK, _tftp_error_op, remote_addr);
*size = RTCSERR_TFTP_ERROR + TFTPERR_ILLEGAL_OP;
TFTP_close();
return NULL;
} /* Endif */
/* Check for retransmitted packet */
if (pkt_block == ack_block) {
TFTP_timeout_restart(&TFTP_config.TIMEOUT);
TFTP_SEND(TFTP_config.SOCK, TFTP_config.ACK, TFTP_config.SADDR);
continue;
} /* Endif */
/* Aknowledge also packets with lower id, some servers do retransmit them until they get an ack */
if (pkt_block < ack_block) {
TFTP_timeout_restart(&TFTP_config.TIMEOUT);
htons(TFTP_config.ACK.BLOCK, pkt_block);
TFTP_SEND(TFTP_config.SOCK, TFTP_config.ACK, TFTP_config.SADDR);
htons(TFTP_config.ACK.BLOCK, ack_block); /* Restore id of last acknowledged packet */
continue;
} /* Endif */
/* Drop unexpected packets */
if (pkt_block > ack_block+1) {
/* Some server do send more than one packet at a time, these will eventually retransmitted */
continue;
}
/* We have the next packet */
break;
} /* Endfor */
/* Update the adaptive timeout */
TFTP_timeout_update(&TFTP_config.TIMEOUT);
/* Free the original RRQ */
if (!ack_block) {
TFTP_config.SADDR.sin_port = remote_addr.sin_port;
_mem_free(TFTP_config.RRQ_PTR);
TFTP_config.RRQ_PTR = NULL;
} /* Endif */
/* ACK it */
ack_block++;
htons(TFTP_config.ACK.BLOCK, ack_block);
TFTP_SEND(TFTP_config.SOCK, TFTP_config.ACK, TFTP_config.SADDR);
TFTP_config.LAST = (pkt_size < sizeof(TFTP_PACKET));
/* Return the data */
*size = pkt_size - sizeof(TFTP_HEADER);
return TFTP_config.PACKET.DATA;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : TFTP_eof
* Returned Value : TRUE or FALSE
* Comments : Routine to determine whether the file transfer is complete.
*
*END*-----------------------------------------------------------------*/
boolean TFTP_eof
(
void
)
{ /* Body */
return TFTP_config.LAST;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : TFTP_close
* Returned Value : error code
* Comments : Routine to close a TFTP session.
*
*END*-----------------------------------------------------------------*/
uint_32 TFTP_close
(
void
)
{ /* Body */
uint_32 result = RTCSERR_SOCK_INVALID;
if (TFTP_config.RRQ_PTR != NULL) {
_mem_free(TFTP_config.RRQ_PTR);
TFTP_config.RRQ_PTR = NULL;
}
if (TFTP_config.SOCK != RTCS_SOCKET_ERROR) {
result = shutdown(TFTP_config.SOCK, 0);
TFTP_config.SOCK = RTCS_SOCKET_ERROR;
TFTP_config.LAST = TRUE;
}
return result;
} /* Endbody */
#endif
/* EOF */