ftp.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  1. /*
  2. * lwftp.c : a lightweight FTP client using raw API of LWIP
  3. *
  4. * Copyright (c) 2014 GEZEDO
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without modification,
  8. * are permitted provided that the following conditions are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright notice,
  11. * this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright notice,
  13. * this list of conditions and the following disclaimer in the documentation
  14. * and/or other materials provided with the distribution.
  15. * 3. The name of the author may not be used to endorse or promote products
  16. * derived from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
  19. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  20. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
  21. * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  22. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
  23. * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  24. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  25. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  26. * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
  27. * OF SUCH DAMAGE.
  28. *
  29. * Author: Laurent GONZALEZ <lwip@gezedo.com>
  30. *
  31. */
  32. #pragma GCC diagnostic error "-Wall"
  33. #pragma GCC diagnostic error "-Wextra"
  34. #include "common_config.h"
  35. #ifdef FTP_ENABLE
  36. #include <string.h>
  37. #include <stdbool.h>
  38. #include "ftp.h"
  39. #include "lwip/tcp.h"
  40. #include "sockets.h"
  41. #include "stm32f4xx.h"
  42. #include "spi_flash.h"
  43. #include "web_params_api.h"
  44. #include "FreeRTOS.h"
  45. #include "task.h"
  46. #include "hal.h"
  47. /** Enable debugging for LWFTP */
  48. #ifndef LWFTP_DEBUG
  49. #define LWFTP_DEBUG LWIP_DBG_ON
  50. #endif
  51. #define LWFTP_TRACE (LWFTP_DEBUG|LWIP_DBG_TRACE)
  52. #define LWFTP_WARNING (LWFTP_DEBUG|LWIP_DBG_LEVEL_WARNING)
  53. #define LWFTP_SERIOUS (LWFTP_DEBUG|LWIP_DBG_LEVEL_SERIOUS)
  54. #define LWFTP_SEVERE (LWFTP_DEBUG|LWIP_DBG_LEVEL_SEVERE)
  55. #define PTRNLEN(s) s,(sizeof(s)-1)
  56. #define min(x,y) ((x)<(y)?(x):(y))
  57. lwftp_session_t ftpcfg;
  58. static unsigned received_bytes_count = 0;
  59. static char **error_ptr;
  60. /** Close control or data pcb
  61. * @param pointer to lwftp session data
  62. */
  63. static err_t lwftp_pcb_close(struct tcp_pcb *tpcb)
  64. {
  65. err_t error;
  66. tcp_err(tpcb, NULL);
  67. tcp_recv(tpcb, NULL);
  68. tcp_sent(tpcb, NULL);
  69. error = tcp_close(tpcb);
  70. if ( error != ERR_OK ) {
  71. LWIP_DEBUGF(LWFTP_SEVERE, ("lwftp:pcb close failure, not implemented\n"));
  72. }
  73. return ERR_OK;
  74. }
  75. /** Send data
  76. * @param pointer to lwftp session data
  77. * @param pointer to PCB
  78. * @param number of bytes sent
  79. */
  80. static err_t lwftp_send_next_data(lwftp_session_t *s)
  81. {
  82. const char *data;
  83. int len = 0;
  84. err_t error = ERR_OK;
  85. if (s->data_source) {
  86. len = s->data_source(s->data_handle, &data, s->data_pcb->mss);
  87. if (len) {
  88. LWIP_DEBUGF(LWFTP_TRACE, ("lwftp:sending %d bytes of data\n",len));
  89. error = tcp_write(s->data_pcb, data, len, 0);
  90. if (error!=ERR_OK) {
  91. LWIP_DEBUGF(LWFTP_SEVERE, ("lwftp:write failure (%s), not implemented\n",lwip_strerr(error)));
  92. }
  93. }
  94. }
  95. if (!len) {
  96. LWIP_DEBUGF(LWFTP_TRACE, ("lwftp:end of file\n"));
  97. lwftp_pcb_close(s->data_pcb);
  98. s->data_pcb = NULL;
  99. }
  100. return ERR_OK;
  101. }
  102. /** Handle data connection incoming data
  103. * @param pointer to lwftp session data
  104. * @param pointer to PCB
  105. * @param pointer to incoming pbuf
  106. * @param state of incoming process
  107. */
  108. static err_t lwftp_data_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
  109. {
  110. (void)err;
  111. lwftp_session_t *s = (lwftp_session_t*)arg;
  112. if (p) {
  113. if (s->data_sink) {
  114. struct pbuf *q;
  115. for (q=p; q; q=q->next) {
  116. s->data_sink(s->data_handle, q->payload, q->len);
  117. }
  118. } else {
  119. LWIP_DEBUGF(LWFTP_SEVERE, ("lwftp: sinking %d bytes\n",p->tot_len));
  120. }
  121. tcp_recved(tpcb, p->tot_len);
  122. pbuf_free(p);
  123. } else {
  124. if (s->data_sink) {
  125. s->data_sink(s->data_handle, NULL, 0);
  126. }
  127. // NULL pbuf shall lead to close the pcb.
  128. if (s->data_pcb) {
  129. lwftp_pcb_close(s->data_pcb);
  130. s->data_pcb = NULL;
  131. }
  132. }
  133. return ERR_OK;
  134. }
  135. /** Handle data connection acknowledge of sent data
  136. * @param pointer to lwftp session data
  137. * @param pointer to PCB
  138. * @param number of bytes sent
  139. */
  140. static err_t lwftp_data_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
  141. {
  142. (void)tpcb;
  143. lwftp_session_t *s = (lwftp_session_t*)arg;
  144. if ( s->data_source ) {
  145. s->data_source(s->data_handle, NULL, len);
  146. }
  147. return lwftp_send_next_data(s);
  148. }
  149. /** Handle data connection error
  150. * @param pointer to lwftp session data
  151. * @param state of connection
  152. */
  153. static void lwftp_data_err(void *arg, err_t err)
  154. {
  155. LWIP_UNUSED_ARG(err);
  156. if (arg != NULL) {
  157. lwftp_session_t *s = (lwftp_session_t*)arg;
  158. LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:failed/error connecting for data to server (%s)\n",lwip_strerr(err)));
  159. s->control_state = LWFTP_QUIT; // gracefully exit on data error
  160. s->data_pcb = NULL; // No need to de-allocate PCB
  161. }
  162. }
  163. /** Process newly connected PCB
  164. * @param pointer to lwftp session data
  165. * @param pointer to PCB
  166. * @param state of connection
  167. */
  168. static err_t lwftp_data_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
  169. {
  170. (void)tpcb;
  171. lwftp_session_t *s = (lwftp_session_t*)arg;
  172. if ( err == ERR_OK ) {
  173. LWIP_DEBUGF(LWFTP_TRACE, ("lwftp:connected for data to server\n"));
  174. s->data_state = LWFTP_CONNECTED;
  175. } else {
  176. LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:err in data_connected (%s)\n",lwip_strerr(err)));
  177. }
  178. return err;
  179. }
  180. /** Open data connection for passive transfer
  181. * @param pointer to lwftp session data
  182. * @param pointer to incoming PASV response
  183. */
  184. static err_t lwftp_data_open(lwftp_session_t *s, struct pbuf *p)
  185. {
  186. err_t error;
  187. char *ptr;
  188. ip_addr_t data_server;
  189. u16_t data_port;
  190. // Find server connection parameter
  191. ptr = strchr(p->payload, '(');
  192. if (!ptr) return ERR_BUF;
  193. do {
  194. unsigned int a = strtoul(ptr+1,&ptr,10);
  195. unsigned int b = strtoul(ptr+1,&ptr,10);
  196. unsigned int c = strtoul(ptr+1,&ptr,10);
  197. unsigned int d = strtoul(ptr+1,&ptr,10);
  198. IP4_ADDR(&data_server,a,b,c,d);
  199. } while(0);
  200. data_port = strtoul(ptr+1,&ptr,10) << 8;
  201. data_port |= strtoul(ptr+1,&ptr,10) & 255;
  202. if (*ptr!=')') return ERR_BUF;
  203. // Open data session
  204. tcp_arg(s->data_pcb, s);
  205. tcp_err(s->data_pcb, lwftp_data_err);
  206. tcp_recv(s->data_pcb, lwftp_data_recv);
  207. tcp_sent(s->data_pcb, lwftp_data_sent);
  208. error = tcp_connect(s->data_pcb, &data_server, data_port, lwftp_data_connected);
  209. return error;
  210. }
  211. /** Send a message to control connection
  212. * @param pointer to lwftp session data
  213. * @param pointer to message string
  214. */
  215. static err_t lwftp_send_msg(lwftp_session_t *s, const char* msg, size_t len)
  216. {
  217. err_t error;
  218. LWIP_DEBUGF(LWFTP_TRACE,("lwftp:sending %s",msg));
  219. error = tcp_write(s->control_pcb, msg, len, 0);
  220. if ( error != ERR_OK ) {
  221. LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:cannot write (%s)\n",lwip_strerr(error)));
  222. }
  223. return error;
  224. }
  225. /** Close control connection
  226. * @param pointer to lwftp session data
  227. * @param result to pass to callback fn (if called)
  228. */
  229. static void lwftp_control_close(lwftp_session_t *s, int result)
  230. {
  231. if (s->control_pcb) {
  232. lwftp_pcb_close(s->control_pcb);
  233. s->control_pcb = NULL;
  234. }
  235. s->control_state = LWFTP_CLOSED;
  236. if ( (result >= 0) && s->done_fn ) {
  237. s->done_fn(s->data_handle, result);
  238. }
  239. }
  240. static void set_timeout(struct tcp_pcb *tpcb, unsigned seconds)
  241. {
  242. struct timeval timeout;
  243. timeout.tv_sec = seconds;
  244. timeout.tv_usec = 0;
  245. setsockopt(tpcb, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout));
  246. }
  247. /** Main client state machine
  248. * @param pointer to lwftp session data
  249. * @param pointer to PCB
  250. * @param pointer to incoming data
  251. */
  252. static void lwftp_control_process(lwftp_session_t *s, struct tcp_pcb *tpcb, struct pbuf *p)
  253. {
  254. (void)tpcb;
  255. unsigned response = 0;
  256. int result = LWFTP_RESULT_ERR_SRVR_RESP;
  257. // Try to get response number
  258. if (p) {
  259. response = strtoul(p->payload, NULL, 10);
  260. LWIP_DEBUGF(LWFTP_TRACE, ("lwftp:got response %d\n",response));
  261. }
  262. switch (s->control_state) {
  263. case LWFTP_CONNECTED:
  264. if (response>0) {
  265. if (response==220) {
  266. lwftp_send_msg(s, PTRNLEN("USER "));
  267. lwftp_send_msg(s, s->settings->user, strlen(s->settings->user));
  268. lwftp_send_msg(s, PTRNLEN("\n"));
  269. s->control_state = LWFTP_USER_SENT;
  270. } else {
  271. s->error = "The server doesn't like us";
  272. s->control_state = LWFTP_QUIT;
  273. }
  274. } else {
  275. s->error = "The server doesn't greet us";
  276. s->control_state = LWFTP_QUIT;
  277. }
  278. break;
  279. case LWFTP_USER_SENT:
  280. if (response>0) {
  281. if (response==331) {
  282. lwftp_send_msg(s, PTRNLEN("PASS "));
  283. lwftp_send_msg(s, s->settings->pass, strlen(s->settings->pass));
  284. lwftp_send_msg(s, PTRNLEN("\n"));
  285. s->control_state = LWFTP_PASS_SENT;
  286. } else if (response==230) {
  287. goto anonymous;
  288. } else {
  289. s->error = "Wrong user name";
  290. s->control_state = LWFTP_QUIT;
  291. }
  292. }
  293. break;
  294. case LWFTP_PASS_SENT:
  295. if (response>0) {
  296. if (response==230) {
  297. anonymous:
  298. lwftp_send_msg(s, PTRNLEN("TYPE I\n"));
  299. s->control_state = LWFTP_TYPE_SENT;
  300. } else {
  301. s->error = "Wrong password";
  302. s->control_state = LWFTP_QUIT;
  303. }
  304. }
  305. break;
  306. case LWFTP_TYPE_SENT:
  307. if (response>0) {
  308. if (response==200) {
  309. lwftp_send_msg(s, PTRNLEN("PASV\n"));
  310. s->control_state = LWFTP_PASV_SENT;
  311. } else {
  312. s->error = "The server doesn't support binary files";
  313. s->control_state = LWFTP_QUIT;
  314. }
  315. }
  316. break;
  317. case LWFTP_PASV_SENT:
  318. if (response>0) {
  319. if (response==227) {
  320. lwftp_data_open(s,p);
  321. switch (s->target_state) {
  322. case LWFTP_STOR_SENT:
  323. lwftp_send_msg(s, PTRNLEN("STOR "));
  324. break;
  325. case LWFTP_RETR_SENT:
  326. lwftp_send_msg(s, PTRNLEN("RETR "));
  327. break;
  328. default:
  329. //LOG_ERROR("Unexpected internal state");
  330. s->target_state = LWFTP_QUIT;
  331. }
  332. lwftp_send_msg(s, s->settings->remote_path, strlen(s->settings->remote_path));
  333. lwftp_send_msg(s, PTRNLEN("\n"));
  334. s->control_state = s->target_state;
  335. } else {
  336. s->error = "The server doesn't support PASV";
  337. s->control_state = LWFTP_QUIT;
  338. }
  339. }
  340. break;
  341. case LWFTP_RETR_SENT:
  342. if (response>0) {
  343. if (response==150) {
  344. s->control_state = LWFTP_XFERING;
  345. set_timeout(s->control_pcb, 0);
  346. } else if (response==550) {
  347. s->control_state = LWFTP_QUIT;
  348. s->error = "Failed to open file";
  349. LWIP_DEBUGF(LWFTP_WARNING, ("lwftp: %s '%s'\n", error, s->settings->remote_path));
  350. }
  351. else {
  352. s->error = "The server doesn't start sending the file";
  353. s->control_state = LWFTP_QUIT;
  354. LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:expected 150, received %d\n",response));
  355. }
  356. }
  357. break;
  358. case LWFTP_STOR_SENT:
  359. if (response>0) {
  360. if (response==150) {
  361. s->control_state = LWFTP_XFERING;
  362. lwftp_data_sent(s,NULL,0);
  363. } else {
  364. s->control_state = LWFTP_QUIT;
  365. }
  366. }
  367. break;
  368. case LWFTP_XFERING:
  369. if (response>0) {
  370. if (response==226) {
  371. s->data_state = LWFTP_XFERING; // signal transfer OK
  372. } else {
  373. LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:expected 226, received %d\n",response));
  374. }
  375. // Quit anyway after any message received during STOR
  376. s->control_state = LWFTP_QUIT;
  377. }
  378. break;
  379. case LWFTP_QUIT_SENT:
  380. if (response>0) {
  381. if (response==221) {
  382. if (s->data_state == LWFTP_XFERING){ // check for transfer OK
  383. result = LWFTP_RESULT_OK;
  384. }
  385. } else {
  386. LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:expected 221, received %d\n",response));
  387. }
  388. s->control_state = LWFTP_CLOSING;
  389. }
  390. break;
  391. default:
  392. LWIP_DEBUGF(LWFTP_SEVERE, ("lwftp:unhandled state (%d)\n",s->control_state));
  393. }
  394. // Free receiving pbuf if any
  395. if (p) {
  396. pbuf_free(p);
  397. }
  398. // Handle second step in state machine
  399. switch ( s->control_state ) {
  400. case LWFTP_QUIT:
  401. lwftp_send_msg(s, PTRNLEN("QUIT\n"));
  402. s->control_state = LWFTP_QUIT_SENT;
  403. break;
  404. case LWFTP_CLOSING:
  405. // this function frees s, no use of s is allowed after
  406. return lwftp_control_close(s, result);
  407. default:;
  408. }
  409. }
  410. /** Handle control connection incoming data
  411. * @param pointer to lwftp session data
  412. * @param pointer to PCB
  413. * @param pointer to incoming pbuf
  414. * @param state of incoming process
  415. */
  416. static err_t lwftp_control_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
  417. {
  418. lwftp_session_t *s = (lwftp_session_t*)arg;
  419. if ( err == ERR_OK ) {
  420. if (p) {
  421. tcp_recved(tpcb, p->tot_len);
  422. lwftp_control_process(s, tpcb, p);
  423. } else {
  424. LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:connection closed by remote host\n"));
  425. lwftp_control_close(s, LWFTP_RESULT_ERR_CLOSED);
  426. }
  427. } else {
  428. LWIP_DEBUGF(LWFTP_SERIOUS, ("lwftp:failed to receive (%s)\n",lwip_strerr(err)));
  429. lwftp_control_close(s, LWFTP_RESULT_ERR_UNKNOWN);
  430. }
  431. return err;
  432. }
  433. /** Handle control connection acknowledge of sent data
  434. * @param pointer to lwftp session data
  435. * @param pointer to PCB
  436. * @param number of bytes sent
  437. */
  438. static err_t lwftp_control_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
  439. {
  440. (void)arg;
  441. (void)tpcb;
  442. (void)len;
  443. LWIP_DEBUGF(LWFTP_TRACE, ("lwftp:successfully sent %d bytes\n",len));
  444. return ERR_OK;
  445. }
  446. /** Handle control connection error
  447. * @param pointer to lwftp session data
  448. * @param state of connection
  449. */
  450. static void lwftp_control_err(void *arg, err_t err)
  451. {
  452. LWIP_UNUSED_ARG(err);
  453. if (arg != NULL) {
  454. lwftp_session_t *s = (lwftp_session_t*)arg;
  455. int result;
  456. if( s->control_state == LWFTP_CLOSED ) {
  457. s->error = "failed to connect to server";
  458. LWIP_DEBUGF(LWFTP_WARNING, ("lwftp: %s (%s)\n",lwip_strerr(err)));
  459. result = LWFTP_RESULT_ERR_CONNECT;
  460. } else {
  461. s->error = "connection closed by remote host";
  462. LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:connection closed by remote host\n"));
  463. result = LWFTP_RESULT_ERR_CLOSED;
  464. }
  465. s->control_pcb = NULL; // No need to de-allocate PCB
  466. lwftp_control_close(s, result);
  467. }
  468. }
  469. /** Process newly connected PCB
  470. * @param pointer to lwftp session data
  471. * @param pointer to PCB
  472. * @param state of connection
  473. */
  474. static err_t lwftp_control_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
  475. {
  476. (void)tpcb;
  477. lwftp_session_t *s = (lwftp_session_t*)arg;
  478. if ( err == ERR_OK ) {
  479. LWIP_DEBUGF(LWFTP_TRACE, ("lwftp:connected to server\n"));
  480. s->control_state = LWFTP_CONNECTED;
  481. } else {
  482. LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:err in control_connected (%s)\n",lwip_strerr(err)));
  483. }
  484. return err;
  485. }
  486. /** Store data to a remote file
  487. * @param Session structure
  488. */
  489. err_t lwftp_store(lwftp_session_t *s)
  490. {
  491. err_t error;
  492. // Check user supplied data
  493. if ( (s->control_state!=LWFTP_CLOSED) ||
  494. !s->settings->remote_path ||
  495. s->control_pcb ||
  496. s->data_pcb ||
  497. !s->settings->user ||
  498. !s->settings->pass )
  499. {
  500. LWIP_DEBUGF(LWFTP_WARNING, ("lwftp:invalid session data\n"));
  501. return ERR_ARG;
  502. }
  503. // Get sessions pcb
  504. s->control_pcb = tcp_new();
  505. if (!s->control_pcb) {
  506. LWIP_DEBUGF(LWFTP_SERIOUS, ("lwftp:cannot alloc control_pcb (low memory?)\n"));
  507. error = ERR_MEM;
  508. goto exit;
  509. }
  510. s->data_pcb = tcp_new();
  511. if (!s->data_pcb) {
  512. LWIP_DEBUGF(LWFTP_SERIOUS, ("lwftp:cannot alloc data_pcb (low memory?)\n"));
  513. error = ERR_MEM;
  514. goto close_pcb;
  515. }
  516. set_timeout(s->control_pcb, 5);
  517. set_timeout(s->data_pcb, 5);
  518. // Open control session
  519. tcp_arg(s->control_pcb, s);
  520. tcp_err(s->control_pcb, lwftp_control_err);
  521. tcp_recv(s->control_pcb, lwftp_control_recv);
  522. tcp_sent(s->control_pcb, lwftp_control_sent);
  523. error = tcp_connect(s->control_pcb, &s->settings->server_ip, s->settings->server_port, lwftp_control_connected);
  524. if ( error == ERR_OK ) goto exit;
  525. LWIP_DEBUGF(LWFTP_SERIOUS, ("lwftp:cannot connect control_pcb (%s)\n", lwip_strerr(error)));
  526. close_pcb:
  527. // Release pcbs in case of failure
  528. lwftp_control_close(s, -1);
  529. exit:
  530. return error;
  531. }
  532. err_t lwftp_retr(lwftp_session_t *s)
  533. {
  534. s->target_state = LWFTP_RETR_SENT;
  535. err_t error;
  536. // Check user supplied data
  537. if (!s->settings->remote_path) {
  538. s->error = "empty remote path";
  539. return ERR_ARG;
  540. }
  541. if (!s->settings->user) {
  542. s->error = "empty user name";
  543. return ERR_ARG;
  544. }
  545. if (!s->settings->pass) {
  546. s->error = "empty password";
  547. return ERR_ARG;
  548. }
  549. if (s->control_state != LWFTP_CLOSED || s->control_pcb) {
  550. // previous connection is incomplete
  551. lwftp_control_close(s, -1);
  552. }
  553. if (s->data_pcb) {
  554. lwftp_pcb_close(s->data_pcb);
  555. }
  556. // Get sessions pcb
  557. s->control_pcb = tcp_new();
  558. if (!s->control_pcb) {
  559. s->error = "cannot alloc control_pcb (low memory?)";
  560. error = ERR_MEM;
  561. goto exit;
  562. }
  563. s->data_pcb = tcp_new();
  564. if (!s->data_pcb) {
  565. s->error = "cannot alloc data_pcb (low memory?)";
  566. error = ERR_MEM;
  567. goto close_pcb;
  568. }
  569. // Open control session
  570. tcp_arg(s->control_pcb, s);
  571. tcp_err(s->control_pcb, lwftp_control_err);
  572. tcp_recv(s->control_pcb, lwftp_control_recv);
  573. tcp_sent(s->control_pcb, lwftp_control_sent);
  574. error = tcp_connect(s->control_pcb, &s->settings->server_ip, s->settings->server_port, lwftp_control_connected);
  575. if ( error == ERR_OK ) goto exit;
  576. LWIP_DEBUGF(LWFTP_SERIOUS, ("lwftp:cannot connect control_pcb (%s)\n", lwip_strerr(error)));
  577. s->error = "cannot connet control_pcb";
  578. close_pcb:
  579. // Release pcbs in case of failure
  580. lwftp_control_close(s, -1);
  581. exit:
  582. return error;
  583. }
  584. //static void ftp_retr_callback(void *arg, int result)
  585. //{
  586. // lwftp_session_t *s = (lwftp_session_t *)arg;
  587. //
  588. // if (result != LWFTP_RESULT_OK) {
  589. // //LOG_ERROR("retr failed (%d)", result);
  590. // return lwftp_close(s);
  591. // }
  592. // lwftp_close(s);
  593. //}
  594. static bool validate_spif_firmware(uint32_t fw_len)
  595. {
  596. const uint32_t spif_firmware_offset = SPI_FLASH_SECTOR_SIZE * FIRMWARE_UPDATE_SECTOR_OFFSET;
  597. // check the firmware revision id
  598. char rev[HW_REV_LEN];
  599. spi_flash_read(spif_firmware_offset + HW_REV_OFFSET, &rev, sizeof(rev), 0);
  600. if (strncmp(rev, HW_REV, sizeof(rev))) {
  601. printf("HW revision mismatch: expected %s, found %s\r\n", HW_REV, rev);
  602. return false;
  603. }
  604. // check if the firmware length is correct
  605. if (fw_len != MAIN_FW_SIZE) {
  606. printf("ftp: firmware size mismatch: expected %d, got %ld\r\n", MAIN_FW_SIZE, fw_len);
  607. return false;
  608. }
  609. uint32_t expected_crc;
  610. const uint32_t crc_offset = USER_FLASH_CRC_ADDRESS - USER_FLASH_FIRST_PAGE_ADDRESS;
  611. spi_flash_read(spif_firmware_offset + crc_offset, &expected_crc, sizeof(expected_crc), 0);
  612. // calculate CRC
  613. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE);
  614. CRC->CR = 1;
  615. for (uint32_t offset = 0; offset < crc_offset; offset += 4) {
  616. uint32_t data;
  617. spi_flash_read(spif_firmware_offset + offset, &data, sizeof(data), 0);
  618. CRC->DR = data;
  619. }
  620. uint32_t calculated_crc = CRC->DR;
  621. if (expected_crc != calculated_crc) {
  622. printf("ftp: calculated CRC (%lx) doesn't match the expected CRC (%lx)!\r\n", calculated_crc, expected_crc);
  623. return false;
  624. }
  625. return true;
  626. }
  627. static void erase_spif_firmware()
  628. {
  629. printf("ftp: erasing SPI firmware partition...\r\n");
  630. for (int sec = 0; sec < FIRMWARE_UPDATE_SECTOR_COUNT; ++sec) {
  631. spi_flash_erase_sector(SPI_FLASH_SECTOR_SIZE * (FIRMWARE_UPDATE_SECTOR_OFFSET + sec), 0);
  632. }
  633. }
  634. static unsigned data_sink(void *arg, const char* ptr, unsigned len)
  635. {
  636. (void)arg;
  637. if (ptr && len) {
  638. // we received some data from the FTP server
  639. if (received_bytes_count == 0) {
  640. // we need to erase the flash before we can write it
  641. erase_spif_firmware();
  642. }
  643. if (received_bytes_count + len > MAIN_FW_SIZE) {
  644. printf("ftp: the firmware is too big! aborting the download\r\n");
  645. return 0;
  646. }
  647. spi_flash_write(SPI_FLASH_SECTOR_SIZE * FIRMWARE_UPDATE_SECTOR_OFFSET + received_bytes_count, ptr, len, 0);
  648. received_bytes_count += len;
  649. } else {
  650. printf("ftp: the firmware is downloaded, verifying...\r\n");
  651. uint32_t fw_size = received_bytes_count;
  652. bool good_firmware = validate_spif_firmware(fw_size);
  653. if (good_firmware) {
  654. printf("ftp: the firmware is valid, rebooting...\r\n");
  655. set_act_source(FTP_ACT);
  656. HTTP_StartResetTask(true);
  657. } else {
  658. // erase it so the bootloader won't try to verify it every time
  659. erase_spif_firmware();
  660. }
  661. }
  662. return len;
  663. }
  664. void start_ftp_client(lwftp_session_t *s)
  665. {
  666. received_bytes_count = 0;
  667. s->error = NULL;
  668. error_ptr = &s->error;
  669. s->data_sink = data_sink;
  670. //s->done_fn = ftp_retr_callback;
  671. lwftp_retr(s);
  672. // FTP session will continue with the connection callback
  673. }
  674. char *get_ftp_progress()
  675. {
  676. if (*error_ptr) {
  677. return *error_ptr;
  678. } else {
  679. unsigned progress = received_bytes_count * 100 / MAIN_FW_SIZE;
  680. static char progress_str_buf[4];
  681. snprintf(progress_str_buf, sizeof(progress_str_buf), "%u", progress);
  682. return progress_str_buf;
  683. }
  684. }
  685. #endif // FTP_ENABLE