1 /**
2  *
3  * @file tftp.c
4  *
5  * @author   Logan Gunthorpe <logang@deltatee.com>
6  *           Dirk Ziegelmeier <dziegel@gmx.de>
7  *
8  * @brief    Trivial File Transfer Protocol (RFC 1350)
9  *
10  * Copyright (c) Deltatee Enterprises Ltd. 2013
11  * All rights reserved.
12  *
13  */
14 
15 /*
16  * Redistribution and use in source and binary forms, with or without
17  * modification,are permitted provided that the following conditions are met:
18  *
19  * 1. Redistributions of source code must retain the above copyright notice,
20  *    this list of conditions and the following disclaimer.
21  * 2. Redistributions in binary form must reproduce the above copyright notice,
22  *    this list of conditions and the following disclaimer in the documentation
23  *    and/or other materials provided with the distribution.
24  * 3. The name of the author may not be used to endorse or promote products
25  *    derived from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
28  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
29  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
30  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
32  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37  *
38  * Author: Logan Gunthorpe <logang@deltatee.com>
39  *         Dirk Ziegelmeier <dziegel@gmx.de>
40  *
41  */
42 
43 /**
44  * @defgroup tftp TFTP client/server
45  * @ingroup apps
46  *
47  * This is simple TFTP client/server for the lwIP raw API.
48  * You need to increase MEMP_NUM_SYS_TIMEOUT by one if you use TFTP!
49  */
50 
51 #include "lwip/apps/tftp_client.h"
52 #include "lwip/apps/tftp_server.h"
53 
54 #if LWIP_UDP
55 
56 #include "lwip/udp.h"
57 #include "lwip/timeouts.h"
58 #include "lwip/debug.h"
59 
60 #define TFTP_DEFAULT_BLOCK_SIZE 512
61 #define TFTP_HEADER_LENGTH    4
62 
63 #define TFTP_RRQ   1
64 #define TFTP_WRQ   2
65 #define TFTP_DATA  3
66 #define TFTP_ACK   4
67 #define TFTP_ERROR 5
68 #define TFTP_OACK  6
69 
70 enum tftp_error {
71   TFTP_ERROR_FILE_NOT_FOUND    = 1,
72   TFTP_ERROR_ACCESS_VIOLATION  = 2,
73   TFTP_ERROR_DISK_FULL         = 3,
74   TFTP_ERROR_ILLEGAL_OPERATION = 4,
75   TFTP_ERROR_UNKNOWN_TRFR_ID   = 5,
76   TFTP_ERROR_FILE_EXISTS       = 6,
77   TFTP_ERROR_NO_SUCH_USER      = 7
78 };
79 
80 #include <string.h>
81 
82 struct tftp_req {
83   ip_addr_t addr;
84   u16_t port;
85   u16_t opcode;
86   enum tftp_transfer_mode mode;
87   char* fname;
88 };
89 
90 struct tftp_state {
91   const struct tftp_context *ctx;
92   void *handle;
93   struct pbuf *last_data;
94   struct udp_pcb *upcb;
95   ip_addr_t addr;
96   u16_t port;
97   int timer;
98   int last_pkt;
99   u16_t blknum;
100   u16_t blksize;
101   u8_t retries;
102   u8_t mode_write;
103   u8_t tftp_mode;
104   bool wait_oack;
105 };
106 
107 static struct tftp_state tftp_state;
108 static struct tftp_req tftp_req;
109 
110 static void tftp_tmr(void *arg);
111 static void tftp_req_tmr(void *arg);
112 static const char *mode_to_string(enum tftp_transfer_mode mode);
113 
114 static void
clear_req(void)115 clear_req(void)
116 {
117   ip_addr_set_any(0, &tftp_req.addr);
118   tftp_req.port = 0;
119   tftp_req.opcode = 0;
120   free(tftp_req.fname);
121   tftp_req.fname = NULL;
122   tftp_req.mode = 0;
123 
124   sys_untimeout(tftp_req_tmr, NULL);
125 }
126 
127 static void
close_handle(void)128 close_handle(void)
129 {
130   clear_req();
131 
132   tftp_state.port = 0;
133   ip_addr_set_any(0, &tftp_state.addr);
134   tftp_state.retries = 0;
135 
136   if (tftp_state.last_data != NULL) {
137     pbuf_free(tftp_state.last_data);
138     tftp_state.last_data = NULL;
139   }
140 
141   sys_untimeout(tftp_tmr, NULL);
142 
143   if (tftp_state.handle) {
144     tftp_state.ctx->close(tftp_state.handle);
145     tftp_state.handle = NULL;
146     LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: closing\n"));
147   }
148 }
149 
150 static struct pbuf*
init_packet(u16_t opcode,u16_t extra,size_t size)151 init_packet(u16_t opcode, u16_t extra, size_t size)
152 {
153   struct pbuf* p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(TFTP_HEADER_LENGTH + size), PBUF_RAM);
154   u16_t* payload;
155 
156   if (p != NULL) {
157     payload = (u16_t*) p->payload;
158     payload[0] = PP_HTONS(opcode);
159     payload[1] = lwip_htons(extra);
160   }
161 
162   return p;
163 }
164 
165 static err_t
send_request(const ip_addr_t * addr,u16_t port,u16_t opcode,const char * fname,const char * mode)166 send_request(const ip_addr_t *addr, u16_t port, u16_t opcode, const char* fname, const char* mode)
167 {
168   size_t fname_length = strlen(fname)+1;
169   size_t mode_length = strlen(mode)+1;
170   size_t blksize_length = 0;
171   int blksize = tftp_state.blksize;
172   struct pbuf* p;
173   char* payload;
174   err_t ret;
175 
176   if (blksize) {
177     /* 'blksize\0'.\0" with . = 1 digit */
178     blksize_length = strlen("blksize") + 1 + 1 + 1;
179     while (blksize >= 10) {
180       blksize /= 10;
181       blksize_length++;
182     }
183   }
184 
185   p = init_packet(opcode, 0, fname_length + mode_length + blksize_length - 2);
186   if (p == NULL) {
187     return ERR_MEM;
188   }
189 
190   payload = (char*) p->payload;
191   MEMCPY(payload+2,              fname, fname_length);
192   MEMCPY(payload+2+fname_length, mode,  mode_length);
193   if (tftp_state.blksize)
194     sprintf(payload+2+fname_length+mode_length, "blksize%c%d%c", 0, tftp_state.blksize, 0);
195 
196   tftp_state.wait_oack = true;
197   ret = udp_sendto(tftp_state.upcb, p, addr, port);
198   pbuf_free(p);
199   return ret;
200 }
201 
202 static err_t
send_error(const ip_addr_t * addr,u16_t port,enum tftp_error code,const char * str)203 send_error(const ip_addr_t *addr, u16_t port, enum tftp_error code, const char *str)
204 {
205   int str_length = strlen(str);
206   struct pbuf *p;
207   u16_t *payload;
208   err_t ret;
209 
210   p = init_packet(TFTP_ERROR, code, str_length + 1);
211   if (p == NULL) {
212     return ERR_MEM;
213   }
214 
215   payload = (u16_t *) p->payload;
216   MEMCPY(&payload[2], str, str_length + 1);
217 
218   ret = udp_sendto(tftp_state.upcb, p, addr, port);
219   pbuf_free(p);
220   return ret;
221 }
222 
223 static err_t
send_ack(const ip_addr_t * addr,u16_t port,u16_t blknum)224 send_ack(const ip_addr_t *addr, u16_t port, u16_t blknum)
225 {
226   struct pbuf *p;
227   err_t ret;
228 
229   p = init_packet(TFTP_ACK, blknum, 0);
230   if (p == NULL) {
231     return ERR_MEM;
232   }
233 
234   ret = udp_sendto(tftp_state.upcb, p, addr, port);
235   pbuf_free(p);
236   return ret;
237 }
238 
239 static err_t
resend_request(void)240 resend_request(void)
241 {
242   return send_request(&tftp_req.addr, tftp_req.port, tftp_req.opcode, tftp_req.fname, mode_to_string(tftp_req.mode));
243 }
244 
245 static err_t
resend_data(const ip_addr_t * addr,u16_t port)246 resend_data(const ip_addr_t *addr, u16_t port)
247 {
248   err_t ret;
249   struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, tftp_state.last_data->len, PBUF_RAM);
250   if (p == NULL) {
251     return ERR_MEM;
252   }
253 
254   ret = pbuf_copy(p, tftp_state.last_data);
255   if (ret != ERR_OK) {
256     pbuf_free(p);
257     return ret;
258   }
259 
260   ret = udp_sendto(tftp_state.upcb, p, addr, port);
261   pbuf_free(p);
262   return ret;
263 }
264 
265 static void
send_data(const ip_addr_t * addr,u16_t port)266 send_data(const ip_addr_t *addr, u16_t port)
267 {
268   u16_t *payload;
269   int ret;
270 
271   if (tftp_state.last_data != NULL) {
272     pbuf_free(tftp_state.last_data);
273   }
274 
275   tftp_state.last_data = init_packet(TFTP_DATA, tftp_state.blknum, TFTP_DEFAULT_BLOCK_SIZE);
276   if (tftp_state.last_data == NULL) {
277     return;
278   }
279 
280   payload = (u16_t *) tftp_state.last_data->payload;
281 
282   ret = tftp_state.ctx->read(tftp_state.handle, &payload[2], TFTP_DEFAULT_BLOCK_SIZE);
283   if (ret < 0) {
284     send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Error occurred while reading the file.");
285     close_handle();
286     return;
287   }
288 
289   pbuf_realloc(tftp_state.last_data, (u16_t)(TFTP_HEADER_LENGTH + ret));
290   resend_data(addr, port);
291 }
292 
payload_size(void)293 static u16_t payload_size(void)
294 {
295   if (tftp_state.blksize)
296     return tftp_state.blksize;
297   return TFTP_DEFAULT_BLOCK_SIZE;
298 }
299 
300 /**
301  * find_option() - check if OACK message contains option
302  *
303  * @p:		message buffer
304  * @option:	option key
305  * Return:	option value
306  */
307 static const char *
find_option(struct pbuf * p,const char * option)308 find_option(struct pbuf *p, const char *option)
309 {
310 	const char *pos = p->payload;
311 	int rem = p->len;
312 
313 	/*
314 	 * According to RFC 2347 the OACK packet has the following format:
315 	 *
316 	 * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+
317 	 * |  opc  |  opt1  | 0 | value1 | 0 |  optN  | 0 | valueN | 0 |
318 	 * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+
319 	 */
320 
321 	/* Skip opc */
322 	pos += 2;
323 	rem -= 2;
324 	if (rem <= 0)
325 		return NULL;
326 
327 	for (;;) {
328 		int len;
329 		int diff;
330 
331 		len = strnlen(pos, rem) + 1;
332 		if (rem < len)
333 			break;
334 		diff = strcmp(pos, option);
335 		/* Skip option */
336 		pos += len;
337 		rem -= len;
338 		len = strnlen(pos, rem) + 1;
339 		if (rem < len)
340 			break;
341 		if (!diff)
342 			return pos;
343 		/* Skip value */
344 		pos += len;
345 		rem -= len;
346 	}
347 
348 	return NULL;
349 }
350 
351 static void
tftp_recv(void * arg,struct udp_pcb * upcb,struct pbuf * p,const ip_addr_t * addr,u16_t port)352 tftp_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
353 {
354   u16_t *sbuf = (u16_t *) p->payload;
355   int opcode;
356 
357   LWIP_UNUSED_ARG(arg);
358   LWIP_UNUSED_ARG(upcb);
359 
360   if (((tftp_state.port != 0) && (port != tftp_state.port)) ||
361       (!ip_addr_isany_val(tftp_state.addr) && !ip_addr_eq(&tftp_state.addr, addr))) {
362     send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported");
363     pbuf_free(p);
364     return;
365   }
366 
367   opcode = sbuf[0];
368 
369   tftp_state.last_pkt = tftp_state.timer;
370   tftp_state.retries = 0;
371 
372   if (tftp_req.fname)
373     clear_req();
374 
375   switch (opcode) {
376     case PP_HTONS(TFTP_RRQ): /* fall through */
377     case PP_HTONS(TFTP_WRQ): {
378       const char tftp_null = 0;
379       char filename[TFTP_MAX_FILENAME_LEN + 1];
380       char mode[TFTP_MAX_MODE_LEN + 1];
381       u16_t filename_end_offset;
382       u16_t mode_end_offset;
383 
384       if (tftp_state.handle != NULL) {
385         send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported");
386         break;
387       }
388 
389       if ((tftp_state.tftp_mode & LWIP_TFTP_MODE_SERVER) == 0) {
390         send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "TFTP server not enabled");
391         break;
392       }
393 
394       sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL);
395 
396       /* find \0 in pbuf -> end of filename string */
397       filename_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), 2);
398       if ((u16_t)(filename_end_offset - 1) > sizeof(filename)) {
399         send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Filename too long/not NULL terminated");
400         break;
401       }
402       pbuf_copy_partial(p, filename, filename_end_offset - 1, 2);
403 
404       /* find \0 in pbuf -> end of mode string */
405       mode_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), filename_end_offset + 1);
406       if ((u16_t)(mode_end_offset - filename_end_offset) > sizeof(mode)) {
407         send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Mode too long/not NULL terminated");
408         break;
409       }
410       pbuf_copy_partial(p, mode, mode_end_offset - filename_end_offset, filename_end_offset + 1);
411 
412       tftp_state.handle = tftp_state.ctx->open(filename, mode, opcode == PP_HTONS(TFTP_WRQ));
413       tftp_state.blknum = 1;
414 
415       if (!tftp_state.handle) {
416         send_error(addr, port, TFTP_ERROR_FILE_NOT_FOUND, "Unable to open requested file.");
417         break;
418       }
419 
420       LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: %s request from ", (opcode == PP_HTONS(TFTP_WRQ)) ? "write" : "read"));
421       ip_addr_debug_print(TFTP_DEBUG | LWIP_DBG_STATE, addr);
422       LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, (" for '%s' mode '%s'\n", filename, mode));
423 
424       ip_addr_copy(tftp_state.addr, *addr);
425       tftp_state.port = port;
426 
427       if (opcode == PP_HTONS(TFTP_WRQ)) {
428         tftp_state.mode_write = 1;
429         send_ack(addr, port, 0);
430       } else {
431         tftp_state.mode_write = 0;
432         send_data(addr, port);
433       }
434 
435       break;
436     }
437 
438     case PP_HTONS(TFTP_DATA): {
439       int ret;
440       u16_t blknum;
441 
442       if (tftp_state.handle == NULL) {
443         send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection");
444         break;
445       }
446 
447       if (tftp_state.mode_write != 1) {
448         send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Not a write connection");
449         break;
450       }
451 
452       blknum = lwip_ntohs(sbuf[1]);
453       if (tftp_state.blksize && tftp_state.wait_oack) {
454         /*
455          * Data received while we are expecting an OACK for our blksize option.
456          * This means the server doesn't support it, let's switch back to the
457          * default block size.
458          */
459        tftp_state.blksize = 0;
460        tftp_state.wait_oack = false;
461       }
462       if (blknum == tftp_state.blknum) {
463         pbuf_remove_header(p, TFTP_HEADER_LENGTH);
464 
465         ret = tftp_state.ctx->write(tftp_state.handle, p);
466         if (ret < 0) {
467           send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "error writing file");
468           close_handle();
469         } else {
470           send_ack(addr, port, blknum);
471         }
472 
473         if (p->tot_len < payload_size()) {
474           close_handle();
475         } else {
476           tftp_state.blknum++;
477         }
478       } else if ((u16_t)(blknum + 1) == tftp_state.blknum) {
479         /* retransmit of previous block, ack again (casting to u16_t to care for overflow) */
480         send_ack(addr, port, blknum);
481       } else {
482         send_error(addr, port, TFTP_ERROR_UNKNOWN_TRFR_ID, "Wrong block number");
483       }
484       break;
485     }
486 
487     case PP_HTONS(TFTP_ACK): {
488       u16_t blknum;
489       int lastpkt;
490 
491       if (tftp_state.handle == NULL) {
492         send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection");
493         break;
494       }
495 
496       if (tftp_state.mode_write != 0) {
497         send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Not a read connection");
498         break;
499       }
500 
501       blknum = lwip_ntohs(sbuf[1]);
502       if (blknum != tftp_state.blknum) {
503         send_error(addr, port, TFTP_ERROR_UNKNOWN_TRFR_ID, "Wrong block number");
504         break;
505       }
506 
507       lastpkt = 0;
508 
509       if (tftp_state.last_data != NULL) {
510         lastpkt = tftp_state.last_data->tot_len != (TFTP_DEFAULT_BLOCK_SIZE + TFTP_HEADER_LENGTH);
511       }
512 
513       if (!lastpkt) {
514         tftp_state.blknum++;
515         send_data(addr, port);
516       } else {
517         close_handle();
518       }
519 
520       break;
521     }
522     case PP_HTONS(TFTP_ERROR):
523       if (tftp_state.handle != NULL) {
524         pbuf_remove_header(p, TFTP_HEADER_LENGTH);
525         tftp_state.ctx->error(tftp_state.handle, sbuf[1], (const char*)p->payload, p->len);
526         close_handle();
527       }
528       break;
529     case PP_HTONS(TFTP_OACK): {
530       const char *optval = find_option(p, "blksize");
531       u16_t srv_blksize = 0;
532       tftp_state.wait_oack = false;
533       if (optval) {
534 	if (!tftp_state.blksize) {
535 	  /* We did not request this option */
536           send_error(addr, port, TFTP_ERROR_ILLEGAL_OPERATION, "blksize unexpected");
537 	}
538 	srv_blksize = atoi(optval);
539 	if (srv_blksize <= 0 || srv_blksize > tftp_state.blksize) {
540 	  send_error(addr, port, TFTP_ERROR_ILLEGAL_OPERATION, "Invalid blksize");
541 	}
542 	LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: accepting blksize=%d\n", srv_blksize));
543 	tftp_state.blksize = srv_blksize;
544       }
545       send_ack(addr, port, 0);
546       break;
547     }
548     default:
549       send_error(addr, port, TFTP_ERROR_ILLEGAL_OPERATION, "Unknown operation");
550       break;
551   }
552 
553   pbuf_free(p);
554 }
555 
556 static void
tftp_tmr(void * arg)557 tftp_tmr(void *arg)
558 {
559   LWIP_UNUSED_ARG(arg);
560 
561   tftp_state.timer++;
562 
563   if (tftp_state.handle == NULL) {
564     return;
565   }
566 
567   sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL);
568 
569   if ((tftp_state.timer - tftp_state.last_pkt) > (TFTP_TIMEOUT_MSECS / TFTP_TIMER_MSECS)) {
570     if ((tftp_state.last_data != NULL) && (tftp_state.retries < TFTP_MAX_RETRIES)) {
571       LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: timeout, retrying\n"));
572       resend_data(&tftp_state.addr, tftp_state.port);
573       tftp_state.retries++;
574     } else {
575       LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: timeout\n"));
576       close_handle();
577     }
578   }
579 }
580 
581 static void
tftp_req_tmr(void * arg)582 tftp_req_tmr(void *arg)
583 {
584   if (tftp_state.handle == NULL) {
585     return;
586   }
587 
588   sys_timeout(TFTP_TIMER_MSECS, tftp_req_tmr, NULL);
589 
590   if (tftp_state.retries < TFTP_MAX_RETRIES) {
591     LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: req timeout, retrying\n"));
592     resend_request();
593     tftp_state.retries++;
594   } else {
595     LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: req timeout\n"));
596     tftp_state.ctx->error(tftp_state.handle, -1, "Request timeout", strlen("Request timeout"));
597     close_handle();
598   }
599 }
600 
601 /**
602  * Initialize TFTP client/server.
603  * @param mode TFTP mode (client/server)
604  * @param ctx TFTP callback struct
605  */
606 err_t
tftp_init_common(u8_t mode,const struct tftp_context * ctx)607 tftp_init_common(u8_t mode, const struct tftp_context *ctx)
608 {
609   err_t ret;
610 
611   /* LWIP_ASSERT_CORE_LOCKED(); is checked by udp_new() */
612   struct udp_pcb *pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
613   if (pcb == NULL) {
614     return ERR_MEM;
615   }
616 
617   if (mode == LWIP_TFTP_MODE_SERVER) {
618     ret = udp_bind(pcb, IP_ANY_TYPE, TFTP_PORT);
619     if (ret != ERR_OK) {
620       udp_remove(pcb);
621       return ret;
622     }
623   }
624 
625   tftp_state.handle    = NULL;
626   tftp_state.port      = 0;
627   tftp_state.ctx       = ctx;
628   tftp_state.timer     = 0;
629   tftp_state.last_data = NULL;
630   tftp_state.upcb      = pcb;
631   tftp_state.tftp_mode = mode;
632 
633   udp_recv(pcb, tftp_recv, NULL);
634 
635   return ERR_OK;
636 }
637 
638 /** @ingroup tftp
639  * Initialize TFTP server.
640  * @param ctx TFTP callback struct
641  */
642 err_t
tftp_init_server(const struct tftp_context * ctx)643 tftp_init_server(const struct tftp_context *ctx)
644 {
645   return tftp_init_common(LWIP_TFTP_MODE_SERVER, ctx);
646 }
647 
648 /** @ingroup tftp
649  * Initialize TFTP client.
650  * @param ctx TFTP callback struct
651  */
652 err_t
tftp_init_client(const struct tftp_context * ctx)653 tftp_init_client(const struct tftp_context *ctx)
654 {
655   return tftp_init_common(LWIP_TFTP_MODE_CLIENT, ctx);
656 }
657 
658 /** @ingroup tftp
659  * Set the block size to be used by the TFTP client. The server may choose to
660  * accept a lower value.
661  * @param blksize Block size in bytes
662  */
663 void
tftp_client_set_blksize(u16_t blksize)664 tftp_client_set_blksize(u16_t blksize)
665 {
666   if (blksize != TFTP_DEFAULT_BLOCK_SIZE)
667     tftp_state.blksize = blksize;
668 }
669 
670 /** @ingroup tftp
671  * Deinitialize ("turn off") TFTP client/server.
672  */
tftp_cleanup(void)673 void tftp_cleanup(void)
674 {
675   LWIP_ASSERT("Cleanup called on non-initialized TFTP", tftp_state.upcb != NULL);
676   udp_remove(tftp_state.upcb);
677   close_handle();
678   memset(&tftp_state, 0, sizeof(tftp_state));
679 }
680 
681 static const char *
mode_to_string(enum tftp_transfer_mode mode)682 mode_to_string(enum tftp_transfer_mode mode)
683 {
684   if (mode == TFTP_MODE_OCTET) {
685     return "octet";
686   }
687   if (mode == TFTP_MODE_NETASCII) {
688     return "netascii";
689   }
690   if (mode == TFTP_MODE_BINARY) {
691     return "binary";
692   }
693   return NULL;
694 }
695 
696 err_t
start_send_requests(const ip_addr_t * addr,u16_t port,u16_t opcode,const char * fname,enum tftp_transfer_mode mode)697 start_send_requests(const ip_addr_t *addr, u16_t port, u16_t opcode, const char* fname, enum tftp_transfer_mode mode)
698 {
699   tftp_req.addr = *addr;
700   tftp_req.port = port;
701   tftp_req.opcode = opcode;
702   tftp_req.fname = strdup(fname);
703   tftp_req.mode = mode;
704   if (!tftp_req.fname)
705     return ERR_MEM;
706   sys_timeout(TFTP_TIMER_MSECS, tftp_req_tmr, NULL);
707   return resend_request();
708 }
709 
710 err_t
tftp_get(void * handle,const ip_addr_t * addr,u16_t port,const char * fname,enum tftp_transfer_mode mode)711 tftp_get(void* handle, const ip_addr_t *addr, u16_t port, const char* fname, enum tftp_transfer_mode mode)
712 {
713   LWIP_ERROR("TFTP client is not enabled (tftp_init)", (tftp_state.tftp_mode & LWIP_TFTP_MODE_CLIENT) != 0, return ERR_VAL);
714   LWIP_ERROR("tftp_get: invalid file name", fname != NULL, return ERR_VAL);
715   LWIP_ERROR("tftp_get: invalid mode", mode <= TFTP_MODE_BINARY, return ERR_VAL);
716 
717   tftp_state.handle = handle;
718   tftp_state.blknum = 1;
719   tftp_state.mode_write = 1; /* We want to receive data */
720   return start_send_requests(addr, port, TFTP_RRQ, fname, mode);
721 }
722 
723 err_t
tftp_put(void * handle,const ip_addr_t * addr,u16_t port,const char * fname,enum tftp_transfer_mode mode)724 tftp_put(void* handle, const ip_addr_t *addr, u16_t port, const char* fname, enum tftp_transfer_mode mode)
725 {
726   LWIP_ERROR("TFTP client is not enabled (tftp_init)", (tftp_state.tftp_mode & LWIP_TFTP_MODE_CLIENT) != 0, return ERR_VAL);
727   LWIP_ERROR("tftp_put: invalid file name", fname != NULL, return ERR_VAL);
728   LWIP_ERROR("tftp_put: invalid mode", mode <= TFTP_MODE_BINARY, return ERR_VAL);
729 
730   tftp_state.handle = handle;
731   tftp_state.blknum = 1;
732   tftp_state.mode_write = 0; /* We want to send data */
733   return start_send_requests(addr, port, TFTP_WRQ, fname, mode);
734 }
735 
736 #endif /* LWIP_UDP */
737