123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752 |
- /*
- * lwftp.c : a lightweight FTP client using raw API of LWIP
- *
- * Copyright (c) 2014 GEZEDO
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions 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. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 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 THE AUTHOR 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.
- *
- * Author: Laurent GONZALEZ <lwip@gezedo.com>
- *
- */
- #pragma GCC diagnostic error "-Wall"
- #pragma GCC diagnostic error "-Wextra"
- #include "common_config.h"
- #ifdef FTP_ENABLE
- #include <string.h>
- #include <stdbool.h>
- #include "ftp.h"
- #include "lwip/tcp.h"
- #include "sockets.h"
- #include "stm32f4xx.h"
- #include "spi_flash.h"
- #include "web_params_api.h"
- #include "FreeRTOS.h"
- #include "task.h"
- #include "hal.h"
- #include "syslog.h"
- #include "log.h"
- /** Enable debugging for LWFTP */
- #ifndef LWFTP_DEBUG
- #define LWFTP_DEBUG LWIP_DBG_ON
- #endif
- #define LWFTP_TRACE (LWFTP_DEBUG|LWIP_DBG_TRACE)
- #define LWFTP_WARNING (LWFTP_DEBUG|LWIP_DBG_LEVEL_WARNING)
- #define LWFTP_SERIOUS (LWFTP_DEBUG|LWIP_DBG_LEVEL_SERIOUS)
- #define LWFTP_SEVERE (LWFTP_DEBUG|LWIP_DBG_LEVEL_SEVERE)
- #define PTRNLEN(s) s,(sizeof(s)-1)
- #define min(x,y) ((x)<(y)?(x):(y))
- lwftp_session_t ftpcfg;
- static unsigned received_bytes_count = 0;
- static char **error_ptr;
- /** Close control or data pcb
- * @param pointer to lwftp session data
- */
- static err_t lwftp_pcb_close(struct tcp_pcb *tpcb)
- {
- err_t error;
- tcp_err(tpcb, NULL);
- tcp_recv(tpcb, NULL);
- tcp_sent(tpcb, NULL);
- error = tcp_close(tpcb);
- if ( error != ERR_OK ) {
- LWIP_DEBUGF(LWFTP_SEVERE, ("lwftp:pcb close failure, not implemented\n"));
- }
- return ERR_OK;
- }
- /** Send data
- * @param pointer to lwftp session data
- * @param pointer to PCB
- * @param number of bytes sent
- */
- static err_t lwftp_send_next_data(lwftp_session_t *s)
- {
- const char *data;
- int len = 0;
- err_t error = ERR_OK;
- if (s->data_source) {
- len = s->data_source(s->data_handle, &data, s->data_pcb->mss);
- if (len) {
- LWIP_DEBUGF(LWFTP_TRACE, ("lwftp:sending %d bytes of data\n",len));
- error = tcp_write(s->data_pcb, data, len, 0);
- if (error!=ERR_OK) {
- LWIP_DEBUGF(LWFTP_SEVERE, ("lwftp:write failure (%s), not implemented\n",lwip_strerr(error)));
- }
- }
- }
- if (!len) {
- LWIP_DEBUGF(LWFTP_TRACE, ("lwftp:end of file\n"));
- lwftp_pcb_close(s->data_pcb);
- s->data_pcb = NULL;
- }
- return ERR_OK;
- }
- /** Handle data connection incoming data
- * @param pointer to lwftp session data
- * @param pointer to PCB
- * @param pointer to incoming pbuf
- * @param state of incoming process
- */
- static err_t lwftp_data_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
- {
- (void)err;
- lwftp_session_t *s = (lwftp_session_t*)arg;
- if (p) {
- if (s->data_sink) {
- struct pbuf *q;
- for (q=p; q; q=q->next) {
- s->data_sink(s->data_handle, q->payload, q->len);
- }
- } else {
- LWIP_DEBUGF(LWFTP_SEVERE, ("lwftp: sinking %d bytes\n",p->tot_len));
- }
- tcp_recved(tpcb, p->tot_len);
- pbuf_free(p);
- } else {
- if (s->data_sink) {
- s->data_sink(s->data_handle, NULL, 0);
- }
- // NULL pbuf shall lead to close the pcb.
- if (s->data_pcb) {
- lwftp_pcb_close(s->data_pcb);
- s->data_pcb = NULL;
- }
- }
- return ERR_OK;
- }
- /** Handle data connection acknowledge of sent data
- * @param pointer to lwftp session data
- * @param pointer to PCB
- * @param number of bytes sent
- */
- static err_t lwftp_data_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
- {
- (void)tpcb;
- lwftp_session_t *s = (lwftp_session_t*)arg;
- if ( s->data_source ) {
- s->data_source(s->data_handle, NULL, len);
- }
- return lwftp_send_next_data(s);
- }
- /** Handle data connection error
- * @param pointer to lwftp session data
- * @param state of connection
- */
- static void lwftp_data_err(void *arg, err_t err)
- {
- LWIP_UNUSED_ARG(err);
- if (arg != NULL) {
- lwftp_session_t *s = (lwftp_session_t*)arg;
- LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:failed/error connecting for data to server (%s)\n",lwip_strerr(err)));
- s->control_state = LWFTP_QUIT; // gracefully exit on data error
- s->data_pcb = NULL; // No need to de-allocate PCB
- }
- }
- /** Process newly connected PCB
- * @param pointer to lwftp session data
- * @param pointer to PCB
- * @param state of connection
- */
- static err_t lwftp_data_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
- {
- (void)tpcb;
- lwftp_session_t *s = (lwftp_session_t*)arg;
- if ( err == ERR_OK ) {
- LWIP_DEBUGF(LWFTP_TRACE, ("lwftp:connected for data to server\n"));
- s->data_state = LWFTP_CONNECTED;
- } else {
- LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:err in data_connected (%s)\n",lwip_strerr(err)));
- }
- return err;
- }
- /** Open data connection for passive transfer
- * @param pointer to lwftp session data
- * @param pointer to incoming PASV response
- */
- static err_t lwftp_data_open(lwftp_session_t *s, struct pbuf *p)
- {
- err_t error;
- char *ptr;
- ip_addr_t data_server;
- u16_t data_port;
- // Find server connection parameter
- ptr = strchr(p->payload, '(');
- if (!ptr) return ERR_BUF;
- do {
- unsigned int a = strtoul(ptr+1,&ptr,10);
- unsigned int b = strtoul(ptr+1,&ptr,10);
- unsigned int c = strtoul(ptr+1,&ptr,10);
- unsigned int d = strtoul(ptr+1,&ptr,10);
- IP4_ADDR(&data_server,a,b,c,d);
- } while(0);
- data_port = strtoul(ptr+1,&ptr,10) << 8;
- data_port |= strtoul(ptr+1,&ptr,10) & 255;
- if (*ptr!=')') return ERR_BUF;
- // Open data session
- tcp_arg(s->data_pcb, s);
- tcp_err(s->data_pcb, lwftp_data_err);
- tcp_recv(s->data_pcb, lwftp_data_recv);
- tcp_sent(s->data_pcb, lwftp_data_sent);
- error = tcp_connect(s->data_pcb, &data_server, data_port, lwftp_data_connected);
- return error;
- }
- /** Send a message to control connection
- * @param pointer to lwftp session data
- * @param pointer to message string
- */
- static err_t lwftp_send_msg(lwftp_session_t *s, const char* msg, size_t len)
- {
- err_t error;
- LWIP_DEBUGF(LWFTP_TRACE,("lwftp:sending %s",msg));
- error = tcp_write(s->control_pcb, msg, len, 0);
- if ( error != ERR_OK ) {
- LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:cannot write (%s)\n",lwip_strerr(error)));
- }
- return error;
- }
- /** Close control connection
- * @param pointer to lwftp session data
- * @param result to pass to callback fn (if called)
- */
- static void lwftp_control_close(lwftp_session_t *s, int result)
- {
- if (s->control_pcb) {
- lwftp_pcb_close(s->control_pcb);
- s->control_pcb = NULL;
- }
- s->control_state = LWFTP_CLOSED;
- if ( (result >= 0) && s->done_fn ) {
- s->done_fn(s->data_handle, result);
- }
- }
- static void set_timeout(struct tcp_pcb *tpcb, unsigned seconds)
- {
- struct timeval timeout;
- timeout.tv_sec = seconds;
- timeout.tv_usec = 0;
- setsockopt(tpcb, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout));
- }
- /** Main client state machine
- * @param pointer to lwftp session data
- * @param pointer to PCB
- * @param pointer to incoming data
- */
- static void lwftp_control_process(lwftp_session_t *s, struct tcp_pcb *tpcb, struct pbuf *p)
- {
- (void)tpcb;
- unsigned response = 0;
- int result = LWFTP_RESULT_ERR_SRVR_RESP;
- // Try to get response number
- if (p) {
- response = strtoul(p->payload, NULL, 10);
- LWIP_DEBUGF(LWFTP_TRACE, ("lwftp:got response %d\n",response));
- }
- switch (s->control_state) {
- case LWFTP_CONNECTED:
- if (response>0) {
- if (response==220) {
- lwftp_send_msg(s, PTRNLEN("USER "));
- lwftp_send_msg(s, s->settings->user, strlen(s->settings->user));
- lwftp_send_msg(s, PTRNLEN("\r\n"));
- s->control_state = LWFTP_USER_SENT;
- } else {
- s->error = "The server doesn't like us";
- s->control_state = LWFTP_QUIT;
- }
- } else {
- s->error = "The server doesn't greet us";
- s->control_state = LWFTP_QUIT;
- }
- break;
- case LWFTP_USER_SENT:
- if (response>0) {
- if (response==331) {
- lwftp_send_msg(s, PTRNLEN("PASS "));
- lwftp_send_msg(s, s->settings->pass, strlen(s->settings->pass));
- lwftp_send_msg(s, PTRNLEN("\r\n"));
- s->control_state = LWFTP_PASS_SENT;
- } else if (response==230) {
- goto anonymous;
- } else {
- s->error = "Wrong user name";
- s->control_state = LWFTP_QUIT;
- }
- }
- break;
- case LWFTP_PASS_SENT:
- if (response>0) {
- if (response==230) {
- anonymous:
- lwftp_send_msg(s, PTRNLEN("TYPE I\r\n"));
- s->control_state = LWFTP_TYPE_SENT;
- } else {
- s->error = "Wrong password";
- s->control_state = LWFTP_QUIT;
- }
- }
- break;
- case LWFTP_TYPE_SENT:
- if (response>0) {
- if (response==200) {
- lwftp_send_msg(s, PTRNLEN("PASV\r\n"));
- s->control_state = LWFTP_PASV_SENT;
- } else {
- s->error = "The server doesn't support binary files";
- s->control_state = LWFTP_QUIT;
- }
- }
- break;
- case LWFTP_PASV_SENT:
- if (response>0) {
- if (response==227) {
- lwftp_data_open(s,p);
- switch (s->target_state) {
- case LWFTP_STOR_SENT:
- lwftp_send_msg(s, PTRNLEN("STOR "));
- break;
- case LWFTP_RETR_SENT:
- lwftp_send_msg(s, PTRNLEN("RETR "));
- break;
- default:
- //LOG_ERROR("Unexpected internal state");
- s->target_state = LWFTP_QUIT;
- }
- lwftp_send_msg(s, s->settings->remote_path, strlen(s->settings->remote_path));
- lwftp_send_msg(s, PTRNLEN("\r\n"));
- s->control_state = s->target_state;
- } else {
- s->error = "The server doesn't support PASV";
- s->control_state = LWFTP_QUIT;
- }
- }
- break;
- case LWFTP_RETR_SENT:
- if (response>0) {
- if (response==150) {
- s->control_state = LWFTP_XFERING;
- set_timeout(s->control_pcb, 0);
- } else if (response==550) {
- s->control_state = LWFTP_QUIT;
- s->error = "Failed to open file";
- LWIP_DEBUGF(LWFTP_WARNING, ("lwftp: %s '%s'\n", s->error, s->settings->remote_path));
- }
- else {
- s->error = "The server doesn't start sending the file";
- s->control_state = LWFTP_QUIT;
- LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:expected 150, received %d\n",response));
- }
- }
- break;
- case LWFTP_STOR_SENT:
- if (response>0) {
- if (response==150) {
- s->control_state = LWFTP_XFERING;
- lwftp_data_sent(s,NULL,0);
- } else {
- s->control_state = LWFTP_QUIT;
- }
- }
- break;
- case LWFTP_XFERING:
- if (response>0) {
- if (response==226) {
- s->data_state = LWFTP_XFERING; // signal transfer OK
- } else {
- LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:expected 226, received %d\n",response));
- }
- // Quit anyway after any message received during STOR
- s->control_state = LWFTP_QUIT;
- }
- break;
- case LWFTP_QUIT_SENT:
- if (response>0) {
- if (response==221) {
- if (s->data_state == LWFTP_XFERING){ // check for transfer OK
- result = LWFTP_RESULT_OK;
- }
- } else {
- LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:expected 221, received %d\n",response));
- }
- s->control_state = LWFTP_CLOSING;
- }
- break;
- default:
- LWIP_DEBUGF(LWFTP_SEVERE, ("lwftp:unhandled state (%d)\n",s->control_state));
- }
- // Free receiving pbuf if any
- if (p) {
- pbuf_free(p);
- }
- // Handle second step in state machine
- switch ( s->control_state ) {
- case LWFTP_QUIT:
- lwftp_send_msg(s, PTRNLEN("QUIT\r\n"));
- s->control_state = LWFTP_QUIT_SENT;
- break;
- case LWFTP_CLOSING:
- // this function frees s, no use of s is allowed after
- return lwftp_control_close(s, result);
- default:;
- }
- }
- /** Handle control connection incoming data
- * @param pointer to lwftp session data
- * @param pointer to PCB
- * @param pointer to incoming pbuf
- * @param state of incoming process
- */
- static err_t lwftp_control_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
- {
- lwftp_session_t *s = (lwftp_session_t*)arg;
- if ( err == ERR_OK ) {
- if (p) {
- tcp_recved(tpcb, p->tot_len);
- lwftp_control_process(s, tpcb, p);
- } else {
- LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:connection closed by remote host\n"));
- lwftp_control_close(s, LWFTP_RESULT_ERR_CLOSED);
- }
- } else {
- LWIP_DEBUGF(LWFTP_SERIOUS, ("lwftp:failed to receive (%s)\n",lwip_strerr(err)));
- lwftp_control_close(s, LWFTP_RESULT_ERR_UNKNOWN);
- }
- return err;
- }
- /** Handle control connection acknowledge of sent data
- * @param pointer to lwftp session data
- * @param pointer to PCB
- * @param number of bytes sent
- */
- static err_t lwftp_control_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
- {
- (void)arg;
- (void)tpcb;
- (void)len;
- LWIP_DEBUGF(LWFTP_TRACE, ("lwftp:successfully sent %d bytes\n",len));
- return ERR_OK;
- }
- /** Handle control connection error
- * @param pointer to lwftp session data
- * @param state of connection
- */
- static void lwftp_control_err(void *arg, err_t err)
- {
- LWIP_UNUSED_ARG(err);
- if (arg != NULL) {
- lwftp_session_t *s = (lwftp_session_t*)arg;
- int result;
- if( s->control_state == LWFTP_CLOSED ) {
- s->error = "failed to connect to server";
- LWIP_DEBUGF(LWFTP_WARNING, ("lwftp: %s (%s)\n",lwip_strerr(err)));
- result = LWFTP_RESULT_ERR_CONNECT;
- } else {
- s->error = "connection closed by remote host";
- LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:connection closed by remote host\n"));
- result = LWFTP_RESULT_ERR_CLOSED;
- }
- s->control_pcb = NULL; // No need to de-allocate PCB
- lwftp_control_close(s, result);
- }
- }
- /** Process newly connected PCB
- * @param pointer to lwftp session data
- * @param pointer to PCB
- * @param state of connection
- */
- static err_t lwftp_control_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
- {
- (void)tpcb;
- lwftp_session_t *s = (lwftp_session_t*)arg;
- if ( err == ERR_OK ) {
- LWIP_DEBUGF(LWFTP_TRACE, ("lwftp:connected to server\n"));
- s->control_state = LWFTP_CONNECTED;
- } else {
- LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:err in control_connected (%s)\n",lwip_strerr(err)));
- }
- return err;
- }
- /** Store data to a remote file
- * @param Session structure
- */
- err_t lwftp_store(lwftp_session_t *s)
- {
- err_t error;
- // Check user supplied data
- if ( (s->control_state!=LWFTP_CLOSED) ||
- !s->settings->remote_path ||
- s->control_pcb ||
- s->data_pcb ||
- !s->settings->user ||
- !s->settings->pass )
- {
- LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:invalid session data\n"));
- return ERR_ARG;
- }
- // Get sessions pcb
- s->control_pcb = tcp_new();
- if (!s->control_pcb) {
- LWIP_DEBUGF(LWFTP_SERIOUS, ("lwftp:cannot alloc control_pcb (low memory?)\n"));
- error = ERR_MEM;
- goto exit;
- }
- s->data_pcb = tcp_new();
- if (!s->data_pcb) {
- LWIP_DEBUGF(LWFTP_SERIOUS, ("lwftp:cannot alloc data_pcb (low memory?)\n"));
- error = ERR_MEM;
- goto close_pcb;
- }
- set_timeout(s->control_pcb, 5);
- set_timeout(s->data_pcb, 5);
- // Open control session
- tcp_arg(s->control_pcb, s);
- tcp_err(s->control_pcb, lwftp_control_err);
- tcp_recv(s->control_pcb, lwftp_control_recv);
- tcp_sent(s->control_pcb, lwftp_control_sent);
- error = tcp_connect(s->control_pcb, &s->settings->server_ip, s->settings->server_port, lwftp_control_connected);
- if ( error == ERR_OK ) goto exit;
- LWIP_DEBUGF(LWFTP_SERIOUS, ("lwftp:cannot connect control_pcb (%s)\n", lwip_strerr(error)));
- close_pcb:
- // Release pcbs in case of failure
- lwftp_control_close(s, -1);
- exit:
- return error;
- }
- err_t lwftp_retr(lwftp_session_t *s)
- {
- s->target_state = LWFTP_RETR_SENT;
- err_t error;
- // Check user supplied data
- if (!s->settings->remote_path) {
- s->error = "empty remote path";
- return ERR_ARG;
- }
- if (!s->settings->user) {
- s->error = "empty user name";
- return ERR_ARG;
- }
- if (!s->settings->pass) {
- s->error = "empty password";
- return ERR_ARG;
- }
- if (s->control_state != LWFTP_CLOSED || s->control_pcb) {
- // previous connection is incomplete
- lwftp_control_close(s, -1);
- }
- if (s->data_pcb) {
- lwftp_pcb_close(s->data_pcb);
- }
- // Get sessions pcb
- s->control_pcb = tcp_new();
- if (!s->control_pcb) {
- s->error = "cannot alloc control_pcb (low memory?)";
- error = ERR_MEM;
- goto exit;
- }
- s->data_pcb = tcp_new();
- if (!s->data_pcb) {
- s->error = "cannot alloc data_pcb (low memory?)";
- error = ERR_MEM;
- goto close_pcb;
- }
- // Open control session
- tcp_arg(s->control_pcb, s);
- tcp_err(s->control_pcb, lwftp_control_err);
- tcp_recv(s->control_pcb, lwftp_control_recv);
- tcp_sent(s->control_pcb, lwftp_control_sent);
- error = tcp_connect(s->control_pcb, &s->settings->server_ip, s->settings->server_port, lwftp_control_connected);
- if ( error == ERR_OK ) goto exit;
- LWIP_DEBUGF(LWFTP_SERIOUS, ("lwftp:cannot connect control_pcb (%s)\n", lwip_strerr(error)));
- s->error = "cannot connet control_pcb";
- close_pcb:
- // Release pcbs in case of failure
- lwftp_control_close(s, -1);
- exit:
- return error;
- }
- //static void ftp_retr_callback(void *arg, int result)
- //{
- // lwftp_session_t *s = (lwftp_session_t *)arg;
- //
- // if (result != LWFTP_RESULT_OK) {
- // //LOG_ERROR("retr failed (%d)", result);
- // return lwftp_close(s);
- // }
- // lwftp_close(s);
- //}
- static bool validate_spif_firmware(uint32_t fw_len)
- {
- const uint32_t spif_firmware_offset = SPI_FLASH_SECTOR_SIZE * FIRMWARE_UPDATE_SECTOR_OFFSET;
- // check the firmware revision id
- char rev[HW_REV_LEN];
- spi_flash_read(spif_firmware_offset + HW_REV_OFFSET, &rev, sizeof(rev), 0);
- if (strncmp(rev, HW_REV, sizeof(rev))) {
- printf("HW revision mismatch: expected %s, found %s\r\n", HW_REV, rev);
- return false;
- }
- // check if the firmware length is correct
- if (fw_len != MAIN_FW_SIZE) {
- printf("ftp: firmware size mismatch: expected %d, got %ld\r\n", MAIN_FW_SIZE, fw_len);
- return false;
- }
- uint32_t expected_crc;
- const uint32_t crc_offset = USER_FLASH_CRC_ADDRESS - USER_FLASH_FIRST_PAGE_ADDRESS;
- spi_flash_read(spif_firmware_offset + crc_offset, &expected_crc, sizeof(expected_crc), 0);
- // calculate CRC
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE);
- CRC->CR = 1;
- for (uint32_t offset = 0; offset < crc_offset; offset += 4) {
- uint32_t data;
- spi_flash_read(spif_firmware_offset + offset, &data, sizeof(data), 0);
- CRC->DR = data;
- }
- uint32_t calculated_crc = CRC->DR;
- if (expected_crc != calculated_crc) {
- printf("ftp: calculated CRC (%lx) doesn't match the expected CRC (%lx)!\r\n", calculated_crc, expected_crc);
- return false;
- }
- return true;
- }
- static void erase_spif_firmware()
- {
- printf("ftp: erasing SPI firmware partition...\r\n");
- for (int sec = 0; sec < FIRMWARE_UPDATE_SECTOR_COUNT; ++sec) {
- spi_flash_erase_sector(SPI_FLASH_SECTOR_SIZE * (FIRMWARE_UPDATE_SECTOR_OFFSET + sec), 0);
- }
- }
- static unsigned data_sink(void *arg, const char* ptr, unsigned len)
- {
- (void)arg;
- if (ptr && len) {
- // we received some data from the FTP server
- if (received_bytes_count == 0) {
- // we need to erase the flash before we can write it
- erase_spif_firmware();
- }
- if (received_bytes_count + len > MAIN_FW_SIZE) {
- syslog_str(SYSLOG_ERROR, "Некорректный размер файла ПО");
- log_event_data(LOG_UPDATE_SOFT, "Некорр. размер файла");
- return 0;
- }
- spi_flash_write(SPI_FLASH_SECTOR_SIZE * FIRMWARE_UPDATE_SECTOR_OFFSET + received_bytes_count, ptr, len, 0);
- received_bytes_count += len;
- } else {
- printf("ftp: the firmware is downloaded, verifying...\r\n");
- uint32_t fw_size = received_bytes_count;
- bool good_firmware = validate_spif_firmware(fw_size);
- if (good_firmware) {
- printf("ftp: the firmware is valid, rebooting...\r\n");
- set_act_source(FTP_ACT);
- HTTP_StartResetTask(true);
- } else {
- syslog_str(SYSLOG_ERROR, "Некорректный файл ПО");
- log_event_data(LOG_UPDATE_SOFT, "Некорректный файл");
- // erase it so the bootloader won't try to verify it every time
- erase_spif_firmware();
- }
- }
- return len;
- }
- void start_ftp_client(lwftp_session_t *s)
- {
- received_bytes_count = 0;
- s->error = NULL;
- error_ptr = &s->error;
- s->data_sink = data_sink;
- //s->done_fn = ftp_retr_callback;
- lwftp_retr(s);
- // FTP session will continue with the connection callback
- }
- char *get_ftp_progress()
- {
- if (*error_ptr) {
- return *error_ptr;
- } else {
- unsigned progress = received_bytes_count * 100 / MAIN_FW_SIZE;
- static char progress_str_buf[4];
- snprintf(progress_str_buf, sizeof(progress_str_buf), "%u", progress);
- return progress_str_buf;
- }
- }
- #endif // FTP_ENABLE
|