123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 |
- /**
- ******************************************************************************
- * @file LwIP/LwIP_IAP/Src/tftpserver.c
- * @author MCD Application Team
- * @brief basic tftp server implementation for IAP (only Write Req supported)
- ******************************************************************************
- * @attention
- *
- * <h2><center>© Copyright (c) 2017 STMicroelectronics International N.V.
- * All rights reserved.</center></h2>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted, provided that the following conditions are met:
- *
- * 1. Redistribution of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. Neither the name of STMicroelectronics nor the names of other
- * contributors to this software may be used to endorse or promote products
- * derived from this software without specific written permission.
- * 4. This software, including modifications and/or derivative works of this
- * software, must execute solely and exclusively on microcontroller or
- * microprocessor devices manufactured by or for STMicroelectronics.
- * 5. Redistribution and use of this software other than as permitted under
- * this license is void and will automatically terminate your rights under
- * this license.
- *
- * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
- * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
- * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
- * SHALL STMICROELECTRONICS OR 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.
- *
- ******************************************************************************
- */
- /* Includes ------------------------------------------------------------------*/
- #include "tftpserver.h"
- #include "flash_if.h"
- #include <string.h>
- #include <stdio.h>
- #include "main.h"
- #include "crc.h"
- /* Private variables ---------------------------------------------------------*/
- static uint32_t Flash_Write_Address;
- static struct udp_pcb *UDPpcb;
- static __IO uint32_t total_count=0;
- /* Private function prototypes -----------------------------------------------*/
- static void IAP_wrq_recv_callback(void *_args, struct udp_pcb *upcb, struct pbuf *pkt_buf,
- const ip_addr_t *addr, u16_t port);
- static int IAP_tftp_process_write(struct udp_pcb *upcb, const ip_addr_t *to, int to_port);
- static void IAP_tftp_recv_callback(void *arg, struct udp_pcb *Upcb, struct pbuf *pkt_buf,
- const ip_addr_t *addr, u16_t port);
- static void IAP_tftp_cleanup_wr(struct udp_pcb *upcb, tftp_connection_args *args);
- static tftp_opcode IAP_tftp_decode_op(char *buf);
- static u16_t IAP_tftp_extract_block(char *buf);
- static void IAP_tftp_set_opcode(char *buffer, tftp_opcode opcode);
- static void IAP_tftp_set_block(char* packet, u16_t block);
- static err_t IAP_tftp_send_ack_packet(struct udp_pcb *upcb, const ip_addr_t *to, int to_port, int block);
- /* Private functions ---------------------------------------------------------*/
- /**
- * @brief Returns the TFTP opcode
- * @param buf: pointer on the TFTP packet
- * @retval None
- */
- static tftp_opcode IAP_tftp_decode_op(char *buf)
- {
- return (tftp_opcode)(buf[1]);
- }
- /**
- * @brief Extracts the block number
- * @param buf: pointer on the TFTP packet
- * @retval block number
- */
- static u16_t IAP_tftp_extract_block(char *buf)
- {
- u16_t *b = (u16_t*)buf;
- return ntohs(b[1]);
- }
- /**
- * @brief Sets the TFTP opcode
- * @param buffer: pointer on the TFTP packet
- * @param opcode: TFTP opcode
- * @retval None
- */
- static void IAP_tftp_set_opcode(char *buffer, tftp_opcode opcode)
- {
- buffer[0] = 0;
- buffer[1] = (u8_t)opcode;
- }
- /**
- * @brief Sets the TFTP block number
- * @param packet: pointer on the TFTP packet
- * @param block: block number
- * @retval None
- */
- static void IAP_tftp_set_block(char* packet, u16_t block)
- {
- u16_t *p = (u16_t *)packet;
- p[1] = htons(block);
- }
- /**
- * @brief Sends TFTP ACK packet
- * @param upcb: pointer on udp_pcb structure
- * @param to: pointer on the receive IP address structure
- * @param to_port: receive port number
- * @param block: block number
- * @retval: err_t: error code
- */
- static err_t IAP_tftp_send_ack_packet(struct udp_pcb *upcb, const ip_addr_t *to, int to_port, int block)
- {
- err_t err;
- struct pbuf *pkt_buf; /* Chain of pbuf's to be sent */
- /* create the maximum possible size packet that a TFTP ACK packet can be */
- char packet[TFTP_ACK_PKT_LEN];
-
- memset(packet, 0, TFTP_ACK_PKT_LEN *sizeof(char));
- /* define the first two bytes of the packet */
- IAP_tftp_set_opcode(packet, TFTP_ACK);
- /* Specify the block number being ACK'd.
- * If we are ACK'ing a DATA pkt then the block number echoes that of the DATA pkt being ACK'd (duh)
- * If we are ACK'ing a WRQ pkt then the block number is always 0
- * RRQ packets are never sent ACK pkts by the server, instead the server sends DATA pkts to the
- * host which are, obviously, used as the "acknowledgement". This saves from having to sEndTransferboth
- * an ACK packet and a DATA packet for RRQs - see RFC1350 for more info. */
- IAP_tftp_set_block(packet, block);
- /* PBUF_TRANSPORT - specifies the transport layer */
- pkt_buf = pbuf_alloc(PBUF_TRANSPORT, TFTP_ACK_PKT_LEN, PBUF_POOL);
- if (!pkt_buf) /*if the packet pbuf == NULL exit and EndTransfertransmission */
- {
- DEBUG_ERROR("Can not allocate pbuf\r\n");
- return ERR_MEM;
- }
- /* Copy the original data buffer over to the packet buffer's payload */
- memcpy(pkt_buf->payload, packet, TFTP_ACK_PKT_LEN);
- /* Sending packet by UDP protocol */
- err = udp_sendto(upcb, pkt_buf, to, to_port);
- /* free the buffer pbuf */
- pbuf_free(pkt_buf);
- return err;
- }
- /**
- * @brief Processes data transfers after a TFTP write request
- * @param _args: used as pointer on TFTP connection args
- * @param upcb: pointer on udp_pcb structure
- * @param pkt_buf: pointer on a pbuf stucture
- * @param ip_addr: pointer on the receive IP_address structure
- * @param port: receive port address
- * @retval None
- */
- static void IAP_wrq_recv_callback(void *_args, struct udp_pcb *upcb, struct pbuf *pkt_buf, const ip_addr_t *addr, u16_t port)
- {
- tftp_connection_args *args = (tftp_connection_args *)_args;
- uint32_t data_buffer[128];
- uint16_t count=0;
- if (pkt_buf->len != pkt_buf->tot_len)
- {
- DEBUG_ERROR("Invalid data length\r\n");
- return;
- }
- /* Does this packet have any valid data to write? */
- if ((pkt_buf->len > TFTP_DATA_PKT_HDR_LEN) &&
- (IAP_tftp_extract_block(pkt_buf->payload) == (args->block + 1)))
- {
- /* copy packet payload to data_buffer */
- pbuf_copy_partial(pkt_buf, data_buffer, pkt_buf->len - TFTP_DATA_PKT_HDR_LEN,
- TFTP_DATA_PKT_HDR_LEN);
-
- total_count += pkt_buf->len - TFTP_DATA_PKT_HDR_LEN;
-
- count = (pkt_buf->len - TFTP_DATA_PKT_HDR_LEN)/4;
- if (((pkt_buf->len - TFTP_DATA_PKT_HDR_LEN)%4)!=0)
- count++;
-
- /* Write received data in Flash */
- FLASH_If_Write(Flash_Write_Address, data_buffer ,count);
- Flash_Write_Address += count*4;
- /* update our block number to match the block number just received */
- args->block++;
- /* update total bytes */
- (args->tot_bytes) += (pkt_buf->len - TFTP_DATA_PKT_HDR_LEN);
- /* This is a valid pkt but it has no data. This would occur if the file being
- written is an exact multiple of 512 bytes. In this case, the args->block
- value must still be updated, but we can skip everything else. */
- }
- else if (IAP_tftp_extract_block(pkt_buf->payload) == (args->block + 1))
- {
- /* update our block number to match the block number just received */
- args->block++;
- }
-
- /* Send the appropriate ACK pkt*/
- IAP_tftp_send_ack_packet(upcb, addr, port, args->block);
- /* If the last write returned less than the maximum TFTP data pkt length,
- * then we've received the whole file and so we can quit (this is how TFTP
- * signals the EndTransferof a transfer!)
- */
- if (pkt_buf->len < TFTP_DATA_PKT_LEN_MAX)
- {
- uint8_t endFlag[4]={0x55,0xaa,0x55,0xaa};
- IAP_tftp_cleanup_wr(upcb, args);
- pbuf_free(pkt_buf);
-
- DEBUG_INFO("Total bytes Received: %d byte\r\n", total_count);
- DEBUG_INFO("State: Prog Finished \r\n");
- DEBUG_INFO("Reset the board \r\n");
-
- Flash_Write_Address = NEW_CODE_ADDRESS;
- uint32_t checksum = HAL_CRC_Calculate(&hcrc, (uint32_t *)Flash_Write_Address, ((FLASH_AP_LENGTH-4)>>2));
- Flash_Write_Address = ((uint32_t)(NEW_CODE_ADDRESS+FLASH_AP_LENGTH-4));
- #if defined(DEBUG) || defined(RTOS_STAT)
- DEBUG_INFO("Firmware transfer end, AP CRC checksum, flash: 0x%x, 0x%x\r\n", checksum, *((uint32_t *)Flash_Write_Address) );
- #endif
-
- if(checksum == *((uint32_t *)Flash_Write_Address))
- {
- if (FLASH_If_Write(UPGRADE_REQ_ADDRESS, (uint32_t *)&endFlag[0], 1) == FLASHIF_OK)
- {
- #if defined(DEBUG) || defined(RTOS_STAT)
- DEBUG_INFO("Firmware Confirm Tag write ok..\n\r");
- #endif
- NVIC_SystemReset();
- }
- else
- {
- #if defined(DEBUG) || defined(RTOS_STAT)
- DEBUG_INFO("Firmware Confirm Tag write fail...\n\r");
- #endif
- }
- }
- }
- else
- {
- pbuf_free(pkt_buf);
- return;
- }
- }
- /**
- * @brief Processes TFTP write request
- * @param to: pointer on the receive IP address
- * @param to_port: receive port number
- * @retval None
- */
- static int IAP_tftp_process_write(struct udp_pcb *upcb, const ip_addr_t *to, int to_port)
- {
- tftp_connection_args *args = NULL;
- /* This function is called from a callback,
- * therefore interrupts are disabled,
- * therefore we can use regular malloc */
- args = mem_malloc(sizeof *args);
- if (!args)
- {
- DEBUG_ERROR("Memory error \r\n");
- IAP_tftp_cleanup_wr(upcb, args);
- return 0;
- }
- args->op = TFTP_WRQ;
- args->to_ip.addr = to->addr;
- args->to_port = to_port;
- /* the block # used as a positive response to a WRQ is _always_ 0!!! (see RFC1350) */
- args->block = 0;
- args->tot_bytes = 0;
- /* set callback for receives on this UDP PCB (Protocol Control Block) */
- udp_recv(upcb, IAP_wrq_recv_callback, args);
-
- total_count =0;
- /* init flash */
- FLASH_If_Init();
-
- /* erase user flash area */
- FLASH_If_Erase(NEW_CODE_ADDRESS, 3);
-
- Flash_Write_Address = NEW_CODE_ADDRESS;
- /* initiate the write transaction by sending the first ack */
- IAP_tftp_send_ack_packet(upcb, to, to_port, args->block);
- DEBUG_INFO("State: Programming... \r\n");
- return 0;
- }
- /**
- * @brief Processes traffic received on UDP port 69
- * @param args: pointer on tftp_connection arguments
- * @param upcb: pointer on udp_pcb structure
- * @param pbuf: pointer on packet buffer
- * @param addr: pointer on the receive IP address
- * @param port: receive port number
- * @retval None
- */
- static void IAP_tftp_recv_callback(void *arg, struct udp_pcb *upcb, struct pbuf *pkt_buf,
- const ip_addr_t *addr, u16_t port)
- {
- tftp_opcode op;
- struct udp_pcb *upcb_tftp_data;
- err_t err;
- uint32_t i;
- char filename[40],message[46], *ptr;
- /* create new UDP PCB structure */
- upcb_tftp_data = udp_new();
- if (!upcb_tftp_data)
- {
- /* Error creating PCB. Out of Memory */
- DEBUG_ERROR("Can not create pcb \r\n");
- return;
- }
- /* bind to port 0 to receive next available free port */
- /* NOTE: This is how TFTP works. There is a UDP PCB for the standard port
- * 69 which al transactions begin communication on, however, _all_ subsequent
- * transactions for a given "stream" occur on another port */
- err = udp_bind(upcb_tftp_data, IP_ADDR_ANY, 0);
- if (err != ERR_OK)
- {
- /* Unable to bind to port */
- DEBUG_ERROR("Can not create pcb \r\n");
- return;
- }
- op = IAP_tftp_decode_op(pkt_buf->payload);
- if (op != TFTP_WRQ)
- {
- /* remove PCB */
- DEBUG_ERROR("Bad TFTP opcode \r\n");
- udp_remove(upcb_tftp_data);
- }
- else
- {
- ptr = pkt_buf->payload;
- ptr = ptr +2;
- /*extract file name info */
- i= 0;
- while (*(ptr+i)!=0x0)
- {
- i++;
- }
- strncpy(filename, ptr, i+1);
- DEBUG_INFO("IAP using TFTP \r\n");
- sprintf(message, "File: %s",filename);
- DEBUG_INFO("%s\r\n", message);
- DEBUG_INFO("State: Erasing...\r\n");
- /* Start the TFTP write mode*/
- IAP_tftp_process_write(upcb_tftp_data, addr, port);
- }
- pbuf_free(pkt_buf);
- }
- /**
- * @brief disconnect and close the connection
- * @param upcb: pointer on udp_pcb structure
- * @param args: pointer on tftp_connection arguments
- * @retval None
- */
- static void IAP_tftp_cleanup_wr(struct udp_pcb *upcb, tftp_connection_args *args)
- {
- /* Free the tftp_connection_args structure */
- mem_free(args);
- /* Disconnect the udp_pcb */
- udp_disconnect(upcb);
-
- /* close the connection */
- udp_remove(upcb);
-
- /* reset the callback function */
- udp_recv(UDPpcb, IAP_tftp_recv_callback, NULL);
-
- }
- /* Global functions ---------------------------------------------------------*/
- /**
- * @brief Creates and initializes a UDP PCB for TFTP receive operation
- * @param None
- * @retval None
- */
- void IAP_tftpd_init(void)
- {
- err_t err;
- unsigned port = 69; /* 69 is the port used for TFTP protocol initial transaction */
- /* create a new UDP PCB structure */
- UDPpcb = udp_new();
- if (!UDPpcb)
- {
- /* Error creating PCB. Out of Memory */
- DEBUG_ERROR("Can not create pcb \r\n");
- return;
- }
- /* Bind this PCB to port 69 */
- err = udp_bind(UDPpcb, IP_ADDR_ANY, port);
- if (err == ERR_OK)
- {
- /* Initialize receive callback function */
- udp_recv(UDPpcb, IAP_tftp_recv_callback, NULL);
- }
- else
- {
- DEBUG_ERROR("Can not create pcb \r\n");
- }
- }
- /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
|