Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_tftp_server.c Source File

lwip_tftp_server.c

00001 /**
00002  *
00003  * @file tftp_server.c
00004  *
00005  * @author   Logan Gunthorpe <logang@deltatee.com>
00006  *           Dirk Ziegelmeier <dziegel@gmx.de>
00007  *
00008  * @brief    Trivial File Transfer Protocol (RFC 1350)
00009  *
00010  * Copyright (c) Deltatee Enterprises Ltd. 2013
00011  * All rights reserved.
00012  *
00013  */
00014 
00015 /*
00016  * Redistribution and use in source and binary forms, with or without
00017  * modification,are permitted provided that the following conditions are met:
00018  *
00019  * 1. Redistributions of source code must retain the above copyright notice,
00020  *    this list of conditions and the following disclaimer.
00021  * 2. Redistributions in binary form must reproduce the above copyright notice,
00022  *    this list of conditions and the following disclaimer in the documentation
00023  *    and/or other materials provided with the distribution.
00024  * 3. The name of the author may not be used to endorse or promote products
00025  *    derived from this software without specific prior written permission.
00026  *
00027  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00028  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00029  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
00030  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00031  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00032  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00033  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00034  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00035  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00036  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00037  *
00038  * Author: Logan Gunthorpe <logang@deltatee.com>
00039  *         Dirk Ziegelmeier <dziegel@gmx.de>
00040  *
00041  */
00042 
00043 /**
00044  * @defgroup tftp TFTP server
00045  * @ingroup apps
00046  *
00047  * This is simple TFTP server for the lwIP raw API.
00048  */
00049 
00050 #include "lwip/apps/tftp_server.h"
00051 
00052 #if LWIP_UDP
00053 
00054 #include "lwip/udp.h"
00055 #include "lwip/timeouts.h"
00056 #include "lwip/debug.h"
00057 
00058 #define TFTP_MAX_PAYLOAD_SIZE 512
00059 #define TFTP_HEADER_LENGTH    4
00060 
00061 #define TFTP_RRQ   1
00062 #define TFTP_WRQ   2
00063 #define TFTP_DATA  3
00064 #define TFTP_ACK   4
00065 #define TFTP_ERROR 5
00066 
00067 enum tftp_error {
00068   TFTP_ERROR_FILE_NOT_FOUND    = 1,
00069   TFTP_ERROR_ACCESS_VIOLATION  = 2,
00070   TFTP_ERROR_DISK_FULL         = 3,
00071   TFTP_ERROR_ILLEGAL_OPERATION = 4,
00072   TFTP_ERROR_UNKNOWN_TRFR_ID   = 5,
00073   TFTP_ERROR_FILE_EXISTS       = 6,
00074   TFTP_ERROR_NO_SUCH_USER      = 7
00075 };
00076 
00077 #include <string.h>
00078 
00079 struct tftp_state {
00080   const struct tftp_context *ctx;
00081   void *handle;
00082   struct pbuf *last_data;
00083   struct udp_pcb *upcb;
00084   ip_addr_t addr;
00085   u16_t port;
00086   int timer;
00087   int last_pkt;
00088   u16_t blknum;
00089   u8_t retries;
00090   u8_t mode_write;
00091 };
00092 
00093 static struct tftp_state tftp_state;
00094 
00095 static void tftp_tmr(void *arg);
00096 
00097 static void
00098 close_handle(void)
00099 {
00100   tftp_state.port = 0;
00101   ip_addr_set_any(0, &tftp_state.addr);
00102 
00103   if (tftp_state.last_data != NULL) {
00104     pbuf_free(tftp_state.last_data);
00105     tftp_state.last_data = NULL;
00106   }
00107 
00108   sys_untimeout(tftp_tmr, NULL);
00109 
00110   if (tftp_state.handle) {
00111     tftp_state.ctx->close(tftp_state.handle);
00112     tftp_state.handle = NULL;
00113     LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: closing\n"));
00114   }
00115 }
00116 
00117 static void
00118 send_error(const ip_addr_t *addr, u16_t port, enum tftp_error code, const char *str)
00119 {
00120   int str_length = strlen(str);
00121   struct pbuf *p;
00122   u16_t *payload;
00123 
00124   p = pbuf_alloc(PBUF_TRANSPORT, (u16_t)(TFTP_HEADER_LENGTH + str_length + 1), PBUF_RAM);
00125   if (p == NULL) {
00126     return;
00127   }
00128 
00129   payload = (u16_t *) p->payload;
00130   payload[0] = PP_HTONS(TFTP_ERROR);
00131   payload[1] = lwip_htons(code);
00132   MEMCPY(&payload[2], str, str_length + 1);
00133 
00134   udp_sendto(tftp_state.upcb, p, addr, port);
00135   pbuf_free(p);
00136 }
00137 
00138 static void
00139 send_ack(u16_t blknum)
00140 {
00141   struct pbuf *p;
00142   u16_t *payload;
00143 
00144   p = pbuf_alloc(PBUF_TRANSPORT, TFTP_HEADER_LENGTH, PBUF_RAM);
00145   if (p == NULL) {
00146     return;
00147   }
00148   payload = (u16_t *) p->payload;
00149 
00150   payload[0] = PP_HTONS(TFTP_ACK);
00151   payload[1] = lwip_htons(blknum);
00152   udp_sendto(tftp_state.upcb, p, &tftp_state.addr, tftp_state.port);
00153   pbuf_free(p);
00154 }
00155 
00156 static void
00157 resend_data(void)
00158 {
00159   struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, tftp_state.last_data->len, PBUF_RAM);
00160   if (p == NULL) {
00161     return;
00162   }
00163 
00164   if (pbuf_copy(p, tftp_state.last_data) != ERR_OK) {
00165     pbuf_free(p);
00166     return;
00167   }
00168 
00169   udp_sendto(tftp_state.upcb, p, &tftp_state.addr, tftp_state.port);
00170   pbuf_free(p);
00171 }
00172 
00173 static void
00174 send_data(void)
00175 {
00176   u16_t *payload;
00177   int ret;
00178 
00179   if (tftp_state.last_data != NULL) {
00180     pbuf_free(tftp_state.last_data);
00181   }
00182 
00183   tftp_state.last_data = pbuf_alloc(PBUF_TRANSPORT, TFTP_HEADER_LENGTH + TFTP_MAX_PAYLOAD_SIZE, PBUF_RAM);
00184   if (tftp_state.last_data == NULL) {
00185     return;
00186   }
00187 
00188   payload = (u16_t *) tftp_state.last_data->payload;
00189   payload[0] = PP_HTONS(TFTP_DATA);
00190   payload[1] = lwip_htons(tftp_state.blknum);
00191 
00192   ret = tftp_state.ctx->read(tftp_state.handle, &payload[2], TFTP_MAX_PAYLOAD_SIZE);
00193   if (ret < 0) {
00194     send_error(&tftp_state.addr, tftp_state.port, TFTP_ERROR_ACCESS_VIOLATION, "Error occured while reading the file.");
00195     close_handle();
00196     return;
00197   }
00198 
00199   pbuf_realloc(tftp_state.last_data, (u16_t)(TFTP_HEADER_LENGTH + ret));
00200   resend_data();
00201 }
00202 
00203 static void
00204 recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
00205 {
00206   u16_t *sbuf = (u16_t *) p->payload;
00207   int opcode;
00208 
00209   LWIP_UNUSED_ARG(arg);
00210   LWIP_UNUSED_ARG(upcb);
00211 
00212   if (((tftp_state.port != 0) && (port != tftp_state.port)) ||
00213       (!ip_addr_isany_val(tftp_state.addr) && !ip_addr_cmp(&tftp_state.addr, addr))) {
00214     send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported");
00215     pbuf_free(p);
00216     return;
00217   }
00218 
00219   opcode = sbuf[0];
00220 
00221   tftp_state.last_pkt = tftp_state.timer;
00222   tftp_state.retries = 0;
00223 
00224   switch (opcode) {
00225     case PP_HTONS(TFTP_RRQ): /* fall through */
00226     case PP_HTONS(TFTP_WRQ): {
00227       const char tftp_null = 0;
00228       char filename[TFTP_MAX_FILENAME_LEN + 1];
00229       char mode[TFTP_MAX_MODE_LEN + 1];
00230       u16_t filename_end_offset;
00231       u16_t mode_end_offset;
00232 
00233       if (tftp_state.handle != NULL) {
00234         send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported");
00235         break;
00236       }
00237 
00238       sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL);
00239 
00240       /* find \0 in pbuf -> end of filename string */
00241       filename_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), 2);
00242       if ((u16_t)(filename_end_offset - 1) > sizeof(filename)) {
00243         send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Filename too long/not NULL terminated");
00244         break;
00245       }
00246       pbuf_copy_partial(p, filename, filename_end_offset - 1, 2);
00247 
00248       /* find \0 in pbuf -> end of mode string */
00249       mode_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), filename_end_offset + 1);
00250       if ((u16_t)(mode_end_offset - filename_end_offset) > sizeof(mode)) {
00251         send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Mode too long/not NULL terminated");
00252         break;
00253       }
00254       pbuf_copy_partial(p, mode, mode_end_offset - filename_end_offset, filename_end_offset + 1);
00255 
00256       tftp_state.handle = tftp_state.ctx->open(filename, mode, opcode == PP_HTONS(TFTP_WRQ));
00257       tftp_state.blknum = 1;
00258 
00259       if (!tftp_state.handle) {
00260         send_error(addr, port, TFTP_ERROR_FILE_NOT_FOUND, "Unable to open requested file.");
00261         break;
00262       }
00263 
00264       LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: %s request from ", (opcode == PP_HTONS(TFTP_WRQ)) ? "write" : "read"));
00265       ip_addr_debug_print(TFTP_DEBUG | LWIP_DBG_STATE, addr);
00266       LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, (" for '%s' mode '%s'\n", filename, mode));
00267 
00268       ip_addr_copy(tftp_state.addr, *addr);
00269       tftp_state.port = port;
00270 
00271       if (opcode == PP_HTONS(TFTP_WRQ)) {
00272         tftp_state.mode_write = 1;
00273         send_ack(0);
00274       } else {
00275         tftp_state.mode_write = 0;
00276         send_data();
00277       }
00278 
00279       break;
00280     }
00281 
00282     case PP_HTONS(TFTP_DATA): {
00283       int ret;
00284       u16_t blknum;
00285 
00286       if (tftp_state.handle == NULL) {
00287         send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection");
00288         break;
00289       }
00290 
00291       if (tftp_state.mode_write != 1) {
00292         send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Not a write connection");
00293         break;
00294       }
00295 
00296       blknum = lwip_ntohs(sbuf[1]);
00297       if (blknum == tftp_state.blknum) {
00298         pbuf_remove_header(p, TFTP_HEADER_LENGTH);
00299 
00300         ret = tftp_state.ctx->write(tftp_state.handle, p);
00301         if (ret < 0) {
00302           send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "error writing file");
00303           close_handle();
00304         } else {
00305           send_ack(blknum);
00306         }
00307 
00308         if (p->tot_len < TFTP_MAX_PAYLOAD_SIZE) {
00309           close_handle();
00310         } else {
00311           tftp_state.blknum++;
00312         }
00313       } else if ((u16_t)(blknum + 1) == tftp_state.blknum) {
00314         /* retransmit of previous block, ack again (casting to u16_t to care for overflow) */
00315         send_ack(blknum);
00316       } else {
00317         send_error(addr, port, TFTP_ERROR_UNKNOWN_TRFR_ID, "Wrong block number");
00318       }
00319       break;
00320     }
00321 
00322     case PP_HTONS(TFTP_ACK): {
00323       u16_t blknum;
00324       int lastpkt;
00325 
00326       if (tftp_state.handle == NULL) {
00327         send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection");
00328         break;
00329       }
00330 
00331       if (tftp_state.mode_write != 0) {
00332         send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Not a read connection");
00333         break;
00334       }
00335 
00336       blknum = lwip_ntohs(sbuf[1]);
00337       if (blknum != tftp_state.blknum) {
00338         send_error(addr, port, TFTP_ERROR_UNKNOWN_TRFR_ID, "Wrong block number");
00339         break;
00340       }
00341 
00342       lastpkt = 0;
00343 
00344       if (tftp_state.last_data != NULL) {
00345         lastpkt = tftp_state.last_data->tot_len != (TFTP_MAX_PAYLOAD_SIZE + TFTP_HEADER_LENGTH);
00346       }
00347 
00348       if (!lastpkt) {
00349         tftp_state.blknum++;
00350         send_data();
00351       } else {
00352         close_handle();
00353       }
00354 
00355       break;
00356     }
00357 
00358     default:
00359       send_error(addr, port, TFTP_ERROR_ILLEGAL_OPERATION, "Unknown operation");
00360       break;
00361   }
00362 
00363   pbuf_free(p);
00364 }
00365 
00366 static void
00367 tftp_tmr(void *arg)
00368 {
00369   LWIP_UNUSED_ARG(arg);
00370 
00371   tftp_state.timer++;
00372 
00373   if (tftp_state.handle == NULL) {
00374     return;
00375   }
00376 
00377   sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL);
00378 
00379   if ((tftp_state.timer - tftp_state.last_pkt) > (TFTP_TIMEOUT_MSECS / TFTP_TIMER_MSECS)) {
00380     if ((tftp_state.last_data != NULL) && (tftp_state.retries < TFTP_MAX_RETRIES)) {
00381       LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: timeout, retrying\n"));
00382       resend_data();
00383       tftp_state.retries++;
00384     } else {
00385       LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: timeout\n"));
00386       close_handle();
00387     }
00388   }
00389 }
00390 
00391 /** @ingroup tftp
00392  * Initialize TFTP server.
00393  * @param ctx TFTP callback struct
00394  */
00395 err_t
00396 tftp_init(const struct tftp_context *ctx)
00397 {
00398   err_t ret;
00399 
00400   /* LWIP_ASSERT_CORE_LOCKED(); is checked by udp_new() */
00401   struct udp_pcb *pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
00402   if (pcb == NULL) {
00403     return ERR_MEM;
00404   }
00405 
00406   ret = udp_bind(pcb, IP_ANY_TYPE, TFTP_PORT);
00407   if (ret != ERR_OK) {
00408     udp_remove(pcb);
00409     return ret;
00410   }
00411 
00412   tftp_state.handle    = NULL;
00413   tftp_state.port      = 0;
00414   tftp_state.ctx       = ctx;
00415   tftp_state.timer     = 0;
00416   tftp_state.last_data = NULL;
00417   tftp_state.upcb      = pcb;
00418 
00419   udp_recv(pcb, recv, NULL);
00420 
00421   return ERR_OK;
00422 }
00423 
00424 /** @ingroup tftp
00425  * Deinitialize ("turn off") TFTP server.
00426  */
00427 void tftp_cleanup(void)
00428 {
00429   LWIP_ASSERT("Cleanup called on non-initialized TFTP", tftp_state.upcb != NULL);
00430   udp_remove(tftp_state.upcb);
00431   close_handle();
00432   memset(&tftp_state, 0, sizeof(tftp_state));
00433 }
00434 
00435 #endif /* LWIP_UDP */