Select one of the symbols to view example projects that use it.
 
Outline
#include "tftpserver.h"
#include "flash_if.h"
#include <string.h>
#include <stdio.h>
#include "main.h"
#include "lcd_log.h"
Private variables
Flash_Write_Address
UDPpcb
total_count
Private function prototypes
Private functions
IAP_tftp_decode_op(char *)
IAP_tftp_extract_block(char *)
IAP_tftp_set_opcode(char *, tftp_opcode)
IAP_tftp_set_block(char *, u16_t)
IAP_tftp_send_ack_packet(struct udp_pcb *, const ip_addr_t *, int, int)
IAP_wrq_recv_callback(void *, struct udp_pcb *, struct pbuf *, const ip_addr_t *, u16_t)
IAP_tftp_process_write(struct udp_pcb *, const ip_addr_t *, int)
IAP_tftp_recv_callback(void *, struct udp_pcb *, struct pbuf *, const ip_addr_t *, u16_t)
IAP_tftp_cleanup_wr(struct udp_pcb *, tftp_connection_args *)
Global functions
IAP_tftpd_init()
Files
loading...
CodeScopeSTM32 Libraries and SamplesLwIP_IAPSrc/tftpserver.c
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/** ****************************************************************************** * @file LwIP/LwIP_IAP/Src/tftpserver.c * @author MCD Application Team * @brief basic tftp server implementation for IAP (only Write Req supported) ****************************************************************************** * @attention * * Copyright (c) 2017 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** *//* ... */ /* Includes ------------------------------------------------------------------*/ #include "tftpserver.h" #include "flash_if.h" #include <string.h> #include <stdio.h> #include "main.h" #include "lcd_log.h" 6 includes #ifdef USE_IAP_TFTP /* Private variables ---------------------------------------------------------*/ static uint32_t Flash_Write_Address; static struct udp_pcb *UDPpcb; static __IO uint32_t total_count=0; Private variables /* 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 function prototypes /* 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 */ { #ifdef USE_LCD LCD_ErrLog("Can not allocate pbuf\n"); #endif 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 structure * @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; #ifdef USE_LCD char message[40]; #endif if (pkt_buf->len != pkt_buf->tot_len) { #ifdef USE_LCD LCD_ErrLog("Invalid data length\n"); #endif return; }if (pkt_buf->len != pkt_buf->tot_len) { ... } /* 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); /* 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. *//* ... */ }if ((pkt_buf->len > TFTP_DATA_PKT_HDR_LEN) && (IAP_tftp_extract_block(pkt_buf->payload) == (args->block + 1))) { ... } 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++; }else if (IAP_tftp_extract_block(pkt_buf->payload) == (args->block + 1)) { ... } /* 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) { IAP_tftp_cleanup_wr(upcb, args); pbuf_free(pkt_buf); #ifdef USE_LCD sprintf(message, "%d bytes ",(int)total_count); LCD_UsrLog("Tot bytes Received:, %s\n", message); LCD_UsrLog(" State: Prog Finished \n"); LCD_UsrLog("Reset the board \n");/* ... */ #endif }if (pkt_buf->len < TFTP_DATA_PKT_LEN_MAX) { ... } else { pbuf_free(pkt_buf); return; }else { ... } }{ ... } /** * @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) { #ifdef USE_LCD LCD_ErrLog("Memory error \n"); #endif IAP_tftp_cleanup_wr(upcb, args); return 0; }if (!args) { ... } 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(USER_FLASH_FIRST_PAGE_ADDRESS); Flash_Write_Address = USER_FLASH_FIRST_PAGE_ADDRESS; /* initiate the write transaction by sending the first ack */ IAP_tftp_send_ack_packet(upcb, to, to_port, args->block); #ifdef USE_LCD LCD_UsrLog(" State: Programming... \n"); #endif 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; #ifdef USE_LCD uint32_t i; char filename[40],message[46], *ptr;/* ... */ #endif /* create new UDP PCB structure */ upcb_tftp_data = udp_new(); if (!upcb_tftp_data) { /* Error creating PCB. Out of Memory */ #ifdef USE_LCD LCD_ErrLog("Can not create pcb \n"); #endif return; }if (!upcb_tftp_data) { ... } /* 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 */ #ifdef USE_LCD LCD_ErrLog("Can not create pcb \n"); #endif return; }if (err != ERR_OK) { ... } op = IAP_tftp_decode_op(pkt_buf->payload); if (op != TFTP_WRQ) { /* remove PCB */ #ifdef USE_LCD LCD_ErrLog("Bad TFTP opcode \n"); #endif udp_remove(upcb_tftp_data); }if (op != TFTP_WRQ) { ... } else { #ifdef USE_LCD ptr = pkt_buf->payload; ptr = ptr +2; /*extract file name info */ i= 0; while (*(ptr+i)!=0x0) { i++; }while (*(ptr+i)!=0x0) { ... } strncpy(filename, ptr, i+1); LCD_UsrLog("IAP using TFTP \n"); sprintf(message, "File: %s",filename); LCD_UsrLog("%s\n", message); LCD_UsrLog(" State: Erasing...\n");/* ... */ #endif /* Start the TFTP write mode*/ IAP_tftp_process_write(upcb_tftp_data, addr, port); }else { ... } 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); }{ ... } Private functions/* 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 */ #ifdef USE_LCD LCD_ErrLog("Can not create pcb \n"); #endif return; }if (!UDPpcb) { ... } /* 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); }if (err == ERR_OK) { ... } else { #ifdef USE_LCD LCD_ErrLog("Can not create pcb \n"); #endif }else { ... } }{ ... } Global functions#endif/* ... */ /* USE_IAP_TFTP */