tftpserver.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. /**
  2. ******************************************************************************
  3. * @file LwIP/LwIP_IAP/Src/tftpserver.c
  4. * @author MCD Application Team
  5. * @brief basic tftp server implementation for IAP (only Write Req supported)
  6. ******************************************************************************
  7. * @attention
  8. *
  9. * <h2><center>&copy; Copyright (c) 2017 STMicroelectronics International N.V.
  10. * All rights reserved.</center></h2>
  11. *
  12. * Redistribution and use in source and binary forms, with or without
  13. * modification, are permitted, provided that the following conditions are met:
  14. *
  15. * 1. Redistribution of source code must retain the above copyright notice,
  16. * this list of conditions and the following disclaimer.
  17. * 2. Redistributions in binary form must reproduce the above copyright notice,
  18. * this list of conditions and the following disclaimer in the documentation
  19. * and/or other materials provided with the distribution.
  20. * 3. Neither the name of STMicroelectronics nor the names of other
  21. * contributors to this software may be used to endorse or promote products
  22. * derived from this software without specific written permission.
  23. * 4. This software, including modifications and/or derivative works of this
  24. * software, must execute solely and exclusively on microcontroller or
  25. * microprocessor devices manufactured by or for STMicroelectronics.
  26. * 5. Redistribution and use of this software other than as permitted under
  27. * this license is void and will automatically terminate your rights under
  28. * this license.
  29. *
  30. * THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
  31. * AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
  32. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  33. * PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
  34. * RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
  35. * SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  36. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  37. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
  38. * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  39. * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  40. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  41. * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  42. *
  43. ******************************************************************************
  44. */
  45. /* Includes ------------------------------------------------------------------*/
  46. #include "tftpserver.h"
  47. #include "flash_if.h"
  48. #include <string.h>
  49. #include <stdio.h>
  50. #include "main.h"
  51. #include "crc.h"
  52. /* Private variables ---------------------------------------------------------*/
  53. static uint32_t Flash_Write_Address;
  54. static struct udp_pcb *UDPpcb;
  55. static __IO uint32_t total_count=0;
  56. /* Private function prototypes -----------------------------------------------*/
  57. static void IAP_wrq_recv_callback(void *_args, struct udp_pcb *upcb, struct pbuf *pkt_buf,
  58. const ip_addr_t *addr, u16_t port);
  59. static int IAP_tftp_process_write(struct udp_pcb *upcb, const ip_addr_t *to, int to_port);
  60. static void IAP_tftp_recv_callback(void *arg, struct udp_pcb *Upcb, struct pbuf *pkt_buf,
  61. const ip_addr_t *addr, u16_t port);
  62. static void IAP_tftp_cleanup_wr(struct udp_pcb *upcb, tftp_connection_args *args);
  63. static tftp_opcode IAP_tftp_decode_op(char *buf);
  64. static u16_t IAP_tftp_extract_block(char *buf);
  65. static void IAP_tftp_set_opcode(char *buffer, tftp_opcode opcode);
  66. static void IAP_tftp_set_block(char* packet, u16_t block);
  67. static err_t IAP_tftp_send_ack_packet(struct udp_pcb *upcb, const ip_addr_t *to, int to_port, int block);
  68. /* Private functions ---------------------------------------------------------*/
  69. /**
  70. * @brief Returns the TFTP opcode
  71. * @param buf: pointer on the TFTP packet
  72. * @retval None
  73. */
  74. static tftp_opcode IAP_tftp_decode_op(char *buf)
  75. {
  76. return (tftp_opcode)(buf[1]);
  77. }
  78. /**
  79. * @brief Extracts the block number
  80. * @param buf: pointer on the TFTP packet
  81. * @retval block number
  82. */
  83. static u16_t IAP_tftp_extract_block(char *buf)
  84. {
  85. u16_t *b = (u16_t*)buf;
  86. return ntohs(b[1]);
  87. }
  88. /**
  89. * @brief Sets the TFTP opcode
  90. * @param buffer: pointer on the TFTP packet
  91. * @param opcode: TFTP opcode
  92. * @retval None
  93. */
  94. static void IAP_tftp_set_opcode(char *buffer, tftp_opcode opcode)
  95. {
  96. buffer[0] = 0;
  97. buffer[1] = (u8_t)opcode;
  98. }
  99. /**
  100. * @brief Sets the TFTP block number
  101. * @param packet: pointer on the TFTP packet
  102. * @param block: block number
  103. * @retval None
  104. */
  105. static void IAP_tftp_set_block(char* packet, u16_t block)
  106. {
  107. u16_t *p = (u16_t *)packet;
  108. p[1] = htons(block);
  109. }
  110. /**
  111. * @brief Sends TFTP ACK packet
  112. * @param upcb: pointer on udp_pcb structure
  113. * @param to: pointer on the receive IP address structure
  114. * @param to_port: receive port number
  115. * @param block: block number
  116. * @retval: err_t: error code
  117. */
  118. static err_t IAP_tftp_send_ack_packet(struct udp_pcb *upcb, const ip_addr_t *to, int to_port, int block)
  119. {
  120. err_t err;
  121. struct pbuf *pkt_buf; /* Chain of pbuf's to be sent */
  122. /* create the maximum possible size packet that a TFTP ACK packet can be */
  123. char packet[TFTP_ACK_PKT_LEN];
  124. memset(packet, 0, TFTP_ACK_PKT_LEN *sizeof(char));
  125. /* define the first two bytes of the packet */
  126. IAP_tftp_set_opcode(packet, TFTP_ACK);
  127. /* Specify the block number being ACK'd.
  128. * If we are ACK'ing a DATA pkt then the block number echoes that of the DATA pkt being ACK'd (duh)
  129. * If we are ACK'ing a WRQ pkt then the block number is always 0
  130. * RRQ packets are never sent ACK pkts by the server, instead the server sends DATA pkts to the
  131. * host which are, obviously, used as the "acknowledgement". This saves from having to sEndTransferboth
  132. * an ACK packet and a DATA packet for RRQs - see RFC1350 for more info. */
  133. IAP_tftp_set_block(packet, block);
  134. /* PBUF_TRANSPORT - specifies the transport layer */
  135. pkt_buf = pbuf_alloc(PBUF_TRANSPORT, TFTP_ACK_PKT_LEN, PBUF_POOL);
  136. if (!pkt_buf) /*if the packet pbuf == NULL exit and EndTransfertransmission */
  137. {
  138. DEBUG_ERROR("Can not allocate pbuf\r\n");
  139. return ERR_MEM;
  140. }
  141. /* Copy the original data buffer over to the packet buffer's payload */
  142. memcpy(pkt_buf->payload, packet, TFTP_ACK_PKT_LEN);
  143. /* Sending packet by UDP protocol */
  144. err = udp_sendto(upcb, pkt_buf, to, to_port);
  145. /* free the buffer pbuf */
  146. pbuf_free(pkt_buf);
  147. return err;
  148. }
  149. /**
  150. * @brief Processes data transfers after a TFTP write request
  151. * @param _args: used as pointer on TFTP connection args
  152. * @param upcb: pointer on udp_pcb structure
  153. * @param pkt_buf: pointer on a pbuf stucture
  154. * @param ip_addr: pointer on the receive IP_address structure
  155. * @param port: receive port address
  156. * @retval None
  157. */
  158. static void IAP_wrq_recv_callback(void *_args, struct udp_pcb *upcb, struct pbuf *pkt_buf, const ip_addr_t *addr, u16_t port)
  159. {
  160. tftp_connection_args *args = (tftp_connection_args *)_args;
  161. uint32_t data_buffer[128];
  162. uint16_t count=0;
  163. if (pkt_buf->len != pkt_buf->tot_len)
  164. {
  165. DEBUG_ERROR("Invalid data length\r\n");
  166. return;
  167. }
  168. /* Does this packet have any valid data to write? */
  169. if ((pkt_buf->len > TFTP_DATA_PKT_HDR_LEN) &&
  170. (IAP_tftp_extract_block(pkt_buf->payload) == (args->block + 1)))
  171. {
  172. /* copy packet payload to data_buffer */
  173. pbuf_copy_partial(pkt_buf, data_buffer, pkt_buf->len - TFTP_DATA_PKT_HDR_LEN,
  174. TFTP_DATA_PKT_HDR_LEN);
  175. total_count += pkt_buf->len - TFTP_DATA_PKT_HDR_LEN;
  176. count = (pkt_buf->len - TFTP_DATA_PKT_HDR_LEN)/4;
  177. if (((pkt_buf->len - TFTP_DATA_PKT_HDR_LEN)%4)!=0)
  178. count++;
  179. /* Write received data in Flash */
  180. FLASH_If_Write(Flash_Write_Address, data_buffer ,count);
  181. Flash_Write_Address += count*4;
  182. /* update our block number to match the block number just received */
  183. args->block++;
  184. /* update total bytes */
  185. (args->tot_bytes) += (pkt_buf->len - TFTP_DATA_PKT_HDR_LEN);
  186. /* This is a valid pkt but it has no data. This would occur if the file being
  187. written is an exact multiple of 512 bytes. In this case, the args->block
  188. value must still be updated, but we can skip everything else. */
  189. }
  190. else if (IAP_tftp_extract_block(pkt_buf->payload) == (args->block + 1))
  191. {
  192. /* update our block number to match the block number just received */
  193. args->block++;
  194. }
  195. /* Send the appropriate ACK pkt*/
  196. IAP_tftp_send_ack_packet(upcb, addr, port, args->block);
  197. /* If the last write returned less than the maximum TFTP data pkt length,
  198. * then we've received the whole file and so we can quit (this is how TFTP
  199. * signals the EndTransferof a transfer!)
  200. */
  201. if (pkt_buf->len < TFTP_DATA_PKT_LEN_MAX)
  202. {
  203. uint8_t endFlag[4]={0x55,0xaa,0x55,0xaa};
  204. IAP_tftp_cleanup_wr(upcb, args);
  205. pbuf_free(pkt_buf);
  206. DEBUG_INFO("Total bytes Received: %d byte\r\n", total_count);
  207. DEBUG_INFO("State: Prog Finished \r\n");
  208. DEBUG_INFO("Reset the board \r\n");
  209. Flash_Write_Address = NEW_CODE_ADDRESS;
  210. uint32_t checksum = HAL_CRC_Calculate(&hcrc, (uint32_t *)Flash_Write_Address, ((FLASH_AP_LENGTH-4)>>2));
  211. Flash_Write_Address = ((uint32_t)(NEW_CODE_ADDRESS+FLASH_AP_LENGTH-4));
  212. #if defined(DEBUG) || defined(RTOS_STAT)
  213. DEBUG_INFO("Firmware transfer end, AP CRC checksum, flash: 0x%x, 0x%x\r\n", checksum, *((uint32_t *)Flash_Write_Address) );
  214. #endif
  215. if(checksum == *((uint32_t *)Flash_Write_Address))
  216. {
  217. if (FLASH_If_Write(UPGRADE_REQ_ADDRESS, (uint32_t *)&endFlag[0], 1) == FLASHIF_OK)
  218. {
  219. #if defined(DEBUG) || defined(RTOS_STAT)
  220. DEBUG_INFO("Firmware Confirm Tag write ok..\n\r");
  221. #endif
  222. NVIC_SystemReset();
  223. }
  224. else
  225. {
  226. #if defined(DEBUG) || defined(RTOS_STAT)
  227. DEBUG_INFO("Firmware Confirm Tag write fail...\n\r");
  228. #endif
  229. }
  230. }
  231. }
  232. else
  233. {
  234. pbuf_free(pkt_buf);
  235. return;
  236. }
  237. }
  238. /**
  239. * @brief Processes TFTP write request
  240. * @param to: pointer on the receive IP address
  241. * @param to_port: receive port number
  242. * @retval None
  243. */
  244. static int IAP_tftp_process_write(struct udp_pcb *upcb, const ip_addr_t *to, int to_port)
  245. {
  246. tftp_connection_args *args = NULL;
  247. /* This function is called from a callback,
  248. * therefore interrupts are disabled,
  249. * therefore we can use regular malloc */
  250. args = mem_malloc(sizeof *args);
  251. if (!args)
  252. {
  253. DEBUG_ERROR("Memory error \r\n");
  254. IAP_tftp_cleanup_wr(upcb, args);
  255. return 0;
  256. }
  257. args->op = TFTP_WRQ;
  258. args->to_ip.addr = to->addr;
  259. args->to_port = to_port;
  260. /* the block # used as a positive response to a WRQ is _always_ 0!!! (see RFC1350) */
  261. args->block = 0;
  262. args->tot_bytes = 0;
  263. /* set callback for receives on this UDP PCB (Protocol Control Block) */
  264. udp_recv(upcb, IAP_wrq_recv_callback, args);
  265. total_count =0;
  266. /* init flash */
  267. FLASH_If_Init();
  268. /* erase user flash area */
  269. FLASH_If_Erase(NEW_CODE_ADDRESS, 3);
  270. Flash_Write_Address = NEW_CODE_ADDRESS;
  271. /* initiate the write transaction by sending the first ack */
  272. IAP_tftp_send_ack_packet(upcb, to, to_port, args->block);
  273. DEBUG_INFO("State: Programming... \r\n");
  274. return 0;
  275. }
  276. /**
  277. * @brief Processes traffic received on UDP port 69
  278. * @param args: pointer on tftp_connection arguments
  279. * @param upcb: pointer on udp_pcb structure
  280. * @param pbuf: pointer on packet buffer
  281. * @param addr: pointer on the receive IP address
  282. * @param port: receive port number
  283. * @retval None
  284. */
  285. static void IAP_tftp_recv_callback(void *arg, struct udp_pcb *upcb, struct pbuf *pkt_buf,
  286. const ip_addr_t *addr, u16_t port)
  287. {
  288. tftp_opcode op;
  289. struct udp_pcb *upcb_tftp_data;
  290. err_t err;
  291. uint32_t i;
  292. char filename[40],message[46], *ptr;
  293. /* create new UDP PCB structure */
  294. upcb_tftp_data = udp_new();
  295. if (!upcb_tftp_data)
  296. {
  297. /* Error creating PCB. Out of Memory */
  298. DEBUG_ERROR("Can not create pcb \r\n");
  299. return;
  300. }
  301. /* bind to port 0 to receive next available free port */
  302. /* NOTE: This is how TFTP works. There is a UDP PCB for the standard port
  303. * 69 which al transactions begin communication on, however, _all_ subsequent
  304. * transactions for a given "stream" occur on another port */
  305. err = udp_bind(upcb_tftp_data, IP_ADDR_ANY, 0);
  306. if (err != ERR_OK)
  307. {
  308. /* Unable to bind to port */
  309. DEBUG_ERROR("Can not create pcb \r\n");
  310. return;
  311. }
  312. op = IAP_tftp_decode_op(pkt_buf->payload);
  313. if (op != TFTP_WRQ)
  314. {
  315. /* remove PCB */
  316. DEBUG_ERROR("Bad TFTP opcode \r\n");
  317. udp_remove(upcb_tftp_data);
  318. }
  319. else
  320. {
  321. ptr = pkt_buf->payload;
  322. ptr = ptr +2;
  323. /*extract file name info */
  324. i= 0;
  325. while (*(ptr+i)!=0x0)
  326. {
  327. i++;
  328. }
  329. strncpy(filename, ptr, i+1);
  330. DEBUG_INFO("IAP using TFTP \r\n");
  331. sprintf(message, "File: %s",filename);
  332. DEBUG_INFO("%s\r\n", message);
  333. DEBUG_INFO("State: Erasing...\r\n");
  334. /* Start the TFTP write mode*/
  335. IAP_tftp_process_write(upcb_tftp_data, addr, port);
  336. }
  337. pbuf_free(pkt_buf);
  338. }
  339. /**
  340. * @brief disconnect and close the connection
  341. * @param upcb: pointer on udp_pcb structure
  342. * @param args: pointer on tftp_connection arguments
  343. * @retval None
  344. */
  345. static void IAP_tftp_cleanup_wr(struct udp_pcb *upcb, tftp_connection_args *args)
  346. {
  347. /* Free the tftp_connection_args structure */
  348. mem_free(args);
  349. /* Disconnect the udp_pcb */
  350. udp_disconnect(upcb);
  351. /* close the connection */
  352. udp_remove(upcb);
  353. /* reset the callback function */
  354. udp_recv(UDPpcb, IAP_tftp_recv_callback, NULL);
  355. }
  356. /* Global functions ---------------------------------------------------------*/
  357. /**
  358. * @brief Creates and initializes a UDP PCB for TFTP receive operation
  359. * @param None
  360. * @retval None
  361. */
  362. void IAP_tftpd_init(void)
  363. {
  364. err_t err;
  365. unsigned port = 69; /* 69 is the port used for TFTP protocol initial transaction */
  366. /* create a new UDP PCB structure */
  367. UDPpcb = udp_new();
  368. if (!UDPpcb)
  369. {
  370. /* Error creating PCB. Out of Memory */
  371. DEBUG_ERROR("Can not create pcb \r\n");
  372. return;
  373. }
  374. /* Bind this PCB to port 69 */
  375. err = udp_bind(UDPpcb, IP_ADDR_ANY, port);
  376. if (err == ERR_OK)
  377. {
  378. /* Initialize receive callback function */
  379. udp_recv(UDPpcb, IAP_tftp_recv_callback, NULL);
  380. }
  381. else
  382. {
  383. DEBUG_ERROR("Can not create pcb \r\n");
  384. }
  385. }
  386. /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/