ftp.c 20 KB

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