BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 *
3 * @file tftp_server.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 server
45 * @ingroup apps
46 *
47 * This is simple TFTP server for the lwIP raw API.
48 */
49  
50 #include "lwip/apps/tftp_server.h"
51  
52 #if LWIP_UDP
53  
54 #include "lwip/udp.h"
55 #include "lwip/timeouts.h"
56 #include "lwip/debug.h"
57  
58 #define TFTP_MAX_PAYLOAD_SIZE 512
59 #define TFTP_HEADER_LENGTH 4
60  
61 #define TFTP_RRQ 1
62 #define TFTP_WRQ 2
63 #define TFTP_DATA 3
64 #define TFTP_ACK 4
65 #define TFTP_ERROR 5
66  
67 enum tftp_error {
68 TFTP_ERROR_FILE_NOT_FOUND = 1,
69 TFTP_ERROR_ACCESS_VIOLATION = 2,
70 TFTP_ERROR_DISK_FULL = 3,
71 TFTP_ERROR_ILLEGAL_OPERATION = 4,
72 TFTP_ERROR_UNKNOWN_TRFR_ID = 5,
73 TFTP_ERROR_FILE_EXISTS = 6,
74 TFTP_ERROR_NO_SUCH_USER = 7
75 };
76  
77 #include <string.h>
78  
79 struct tftp_state {
80 const struct tftp_context *ctx;
81 void *handle;
82 struct pbuf *last_data;
83 struct udp_pcb *upcb;
84 ip_addr_t addr;
85 u16_t port;
86 int timer;
87 int last_pkt;
88 u16_t blknum;
89 u8_t retries;
90 u8_t mode_write;
91 };
92  
93 static struct tftp_state tftp_state;
94  
95 static void tftp_tmr(void *arg);
96  
97 static void
98 close_handle(void)
99 {
100 tftp_state.port = 0;
101 ip_addr_set_any(0, &tftp_state.addr);
102  
103 if (tftp_state.last_data != NULL) {
104 pbuf_free(tftp_state.last_data);
105 tftp_state.last_data = NULL;
106 }
107  
108 sys_untimeout(tftp_tmr, NULL);
109  
110 if (tftp_state.handle) {
111 tftp_state.ctx->close(tftp_state.handle);
112 tftp_state.handle = NULL;
113 LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: closing\n"));
114 }
115 }
116  
117 static void
118 send_error(const ip_addr_t *addr, u16_t port, enum tftp_error code, const char *str)
119 {
120 int str_length = strlen(str);
121 struct pbuf *p;
122 u16_t *payload;
123  
124 p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(TFTP_HEADER_LENGTH + str_length + 1), PBUF_RAM);
125 if (p == NULL) {
126 return;
127 }
128  
129 payload = (u16_t *) p->payload;
130 payload[0] = PP_HTONS(TFTP_ERROR);
131 payload[1] = lwip_htons(code);
132 MEMCPY(&payload[2], str, str_length + 1);
133  
134 udp_sendto(tftp_state.upcb, p, addr, port);
135 pbuf_free(p);
136 }
137  
138 static void
139 send_ack(u16_t blknum)
140 {
141 struct pbuf *p;
142 u16_t *payload;
143  
144 p = pbuf_alloc(PBUF_TRANSPORT, TFTP_HEADER_LENGTH, PBUF_RAM);
145 if (p == NULL) {
146 return;
147 }
148 payload = (u16_t *) p->payload;
149  
150 payload[0] = PP_HTONS(TFTP_ACK);
151 payload[1] = lwip_htons(blknum);
152 udp_sendto(tftp_state.upcb, p, &tftp_state.addr, tftp_state.port);
153 pbuf_free(p);
154 }
155  
156 static void
157 resend_data(void)
158 {
159 struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, tftp_state.last_data->len, PBUF_RAM);
160 if (p == NULL) {
161 return;
162 }
163  
164 if (pbuf_copy(p, tftp_state.last_data) != ERR_OK) {
165 pbuf_free(p);
166 return;
167 }
168  
169 udp_sendto(tftp_state.upcb, p, &tftp_state.addr, tftp_state.port);
170 pbuf_free(p);
171 }
172  
173 static void
174 send_data(void)
175 {
176 u16_t *payload;
177 int ret;
178  
179 if (tftp_state.last_data != NULL) {
180 pbuf_free(tftp_state.last_data);
181 }
182  
183 tftp_state.last_data = pbuf_alloc(PBUF_TRANSPORT, TFTP_HEADER_LENGTH + TFTP_MAX_PAYLOAD_SIZE, PBUF_RAM);
184 if (tftp_state.last_data == NULL) {
185 return;
186 }
187  
188 payload = (u16_t *) tftp_state.last_data->payload;
189 payload[0] = PP_HTONS(TFTP_DATA);
190 payload[1] = lwip_htons(tftp_state.blknum);
191  
192 ret = tftp_state.ctx->read(tftp_state.handle, &payload[2], TFTP_MAX_PAYLOAD_SIZE);
193 if (ret < 0) {
194 send_error(&tftp_state.addr, tftp_state.port, TFTP_ERROR_ACCESS_VIOLATION, "Error occured while reading the file.");
195 close_handle();
196 return;
197 }
198  
199 pbuf_realloc(tftp_state.last_data, (u16_t)(TFTP_HEADER_LENGTH + ret));
200 resend_data();
201 }
202  
203 static void
204 recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
205 {
206 u16_t *sbuf = (u16_t *) p->payload;
207 int opcode;
208  
209 LWIP_UNUSED_ARG(arg);
210 LWIP_UNUSED_ARG(upcb);
211  
212 if (((tftp_state.port != 0) && (port != tftp_state.port)) ||
213 (!ip_addr_isany_val(tftp_state.addr) && !ip_addr_cmp(&tftp_state.addr, addr))) {
214 send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported");
215 pbuf_free(p);
216 return;
217 }
218  
219 opcode = sbuf[0];
220  
221 tftp_state.last_pkt = tftp_state.timer;
222 tftp_state.retries = 0;
223  
224 switch (opcode) {
225 case PP_HTONS(TFTP_RRQ): /* fall through */
226 case PP_HTONS(TFTP_WRQ): {
227 const char tftp_null = 0;
228 char filename[TFTP_MAX_FILENAME_LEN + 1];
229 char mode[TFTP_MAX_MODE_LEN + 1];
230 u16_t filename_end_offset;
231 u16_t mode_end_offset;
232  
233 if (tftp_state.handle != NULL) {
234 send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported");
235 break;
236 }
237  
238 sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL);
239  
240 /* find \0 in pbuf -> end of filename string */
241 filename_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), 2);
242 if ((u16_t)(filename_end_offset - 1) > sizeof(filename)) {
243 send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Filename too long/not NULL terminated");
244 break;
245 }
246 pbuf_copy_partial(p, filename, filename_end_offset - 1, 2);
247  
248 /* find \0 in pbuf -> end of mode string */
249 mode_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), filename_end_offset + 1);
250 if ((u16_t)(mode_end_offset - filename_end_offset) > sizeof(mode)) {
251 send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Mode too long/not NULL terminated");
252 break;
253 }
254 pbuf_copy_partial(p, mode, mode_end_offset - filename_end_offset, filename_end_offset + 1);
255  
256 tftp_state.handle = tftp_state.ctx->open(filename, mode, opcode == PP_HTONS(TFTP_WRQ));
257 tftp_state.blknum = 1;
258  
259 if (!tftp_state.handle) {
260 send_error(addr, port, TFTP_ERROR_FILE_NOT_FOUND, "Unable to open requested file.");
261 break;
262 }
263  
264 LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: %s request from ", (opcode == PP_HTONS(TFTP_WRQ)) ? "write" : "read"));
265 ip_addr_debug_print(TFTP_DEBUG | LWIP_DBG_STATE, addr);
266 LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, (" for '%s' mode '%s'\n", filename, mode));
267  
268 ip_addr_copy(tftp_state.addr, *addr);
269 tftp_state.port = port;
270  
271 if (opcode == PP_HTONS(TFTP_WRQ)) {
272 tftp_state.mode_write = 1;
273 send_ack(0);
274 } else {
275 tftp_state.mode_write = 0;
276 send_data();
277 }
278  
279 break;
280 }
281  
282 case PP_HTONS(TFTP_DATA): {
283 int ret;
284 u16_t blknum;
285  
286 if (tftp_state.handle == NULL) {
287 send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection");
288 break;
289 }
290  
291 if (tftp_state.mode_write != 1) {
292 send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Not a write connection");
293 break;
294 }
295  
296 blknum = lwip_ntohs(sbuf[1]);
297 pbuf_remove_header(p, TFTP_HEADER_LENGTH);
298  
299 ret = tftp_state.ctx->write(tftp_state.handle, p);
300 if (ret < 0) {
301 send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "error writing file");
302 close_handle();
303 } else {
304 send_ack(blknum);
305 }
306  
307 if (p->tot_len < TFTP_MAX_PAYLOAD_SIZE) {
308 close_handle();
309 }
310 break;
311 }
312  
313 case PP_HTONS(TFTP_ACK): {
314 u16_t blknum;
315 int lastpkt;
316  
317 if (tftp_state.handle == NULL) {
318 send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection");
319 break;
320 }
321  
322 if (tftp_state.mode_write != 0) {
323 send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Not a read connection");
324 break;
325 }
326  
327 blknum = lwip_ntohs(sbuf[1]);
328 if (blknum != tftp_state.blknum) {
329 send_error(addr, port, TFTP_ERROR_UNKNOWN_TRFR_ID, "Wrong block number");
330 break;
331 }
332  
333 lastpkt = 0;
334  
335 if (tftp_state.last_data != NULL) {
336 lastpkt = tftp_state.last_data->tot_len != (TFTP_MAX_PAYLOAD_SIZE + TFTP_HEADER_LENGTH);
337 }
338  
339 if (!lastpkt) {
340 tftp_state.blknum++;
341 send_data();
342 } else {
343 close_handle();
344 }
345  
346 break;
347 }
348  
349 default:
350 send_error(addr, port, TFTP_ERROR_ILLEGAL_OPERATION, "Unknown operation");
351 break;
352 }
353  
354 pbuf_free(p);
355 }
356  
357 static void
358 tftp_tmr(void *arg)
359 {
360 LWIP_UNUSED_ARG(arg);
361  
362 tftp_state.timer++;
363  
364 if (tftp_state.handle == NULL) {
365 return;
366 }
367  
368 sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL);
369  
370 if ((tftp_state.timer - tftp_state.last_pkt) > (TFTP_TIMEOUT_MSECS / TFTP_TIMER_MSECS)) {
371 if ((tftp_state.last_data != NULL) && (tftp_state.retries < TFTP_MAX_RETRIES)) {
372 LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: timeout, retrying\n"));
373 resend_data();
374 tftp_state.retries++;
375 } else {
376 LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: timeout\n"));
377 close_handle();
378 }
379 }
380 }
381  
382 /** @ingroup tftp
383 * Initialize TFTP server.
384 * @param ctx TFTP callback struct
385 */
386 err_t
387 tftp_init(const struct tftp_context *ctx)
388 {
389 err_t ret;
390  
391 struct udp_pcb *pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
392 if (pcb == NULL) {
393 return ERR_MEM;
394 }
395  
396 ret = udp_bind(pcb, IP_ANY_TYPE, TFTP_PORT);
397 if (ret != ERR_OK) {
398 udp_remove(pcb);
399 return ret;
400 }
401  
402 tftp_state.handle = NULL;
403 tftp_state.port = 0;
404 tftp_state.ctx = ctx;
405 tftp_state.timer = 0;
406 tftp_state.last_data = NULL;
407 tftp_state.upcb = pcb;
408  
409 udp_recv(pcb, recv, NULL);
410  
411 return ERR_OK;
412 }
413  
414 #endif /* LWIP_UDP */