Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of OmniWheels by
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 { 00228 const char tftp_null = 0; 00229 char filename[TFTP_MAX_FILENAME_LEN]; 00230 char mode[TFTP_MAX_MODE_LEN]; 00231 u16_t filename_end_offset; 00232 u16_t mode_end_offset; 00233 00234 if(tftp_state.handle != NULL) { 00235 send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Only one connection at a time is supported"); 00236 break; 00237 } 00238 00239 sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL); 00240 00241 /* find \0 in pbuf -> end of filename string */ 00242 filename_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), 2); 00243 if((u16_t)(filename_end_offset-2) > sizeof(filename)) { 00244 send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Filename too long/not NULL terminated"); 00245 break; 00246 } 00247 pbuf_copy_partial(p, filename, filename_end_offset-2, 2); 00248 00249 /* find \0 in pbuf -> end of mode string */ 00250 mode_end_offset = pbuf_memfind(p, &tftp_null, sizeof(tftp_null), filename_end_offset+1); 00251 if((u16_t)(mode_end_offset-filename_end_offset) > sizeof(mode)) { 00252 send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Mode too long/not NULL terminated"); 00253 break; 00254 } 00255 pbuf_copy_partial(p, mode, mode_end_offset-filename_end_offset, filename_end_offset+1); 00256 00257 tftp_state.handle = tftp_state.ctx->open(filename, mode, opcode == PP_HTONS(TFTP_WRQ)); 00258 tftp_state.blknum = 1; 00259 00260 if (!tftp_state.handle) { 00261 send_error(addr, port, TFTP_ERROR_FILE_NOT_FOUND, "Unable to open requested file."); 00262 break; 00263 } 00264 00265 LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: %s request from ", (opcode == PP_HTONS(TFTP_WRQ)) ? "write" : "read")); 00266 ip_addr_debug_print(TFTP_DEBUG | LWIP_DBG_STATE, addr); 00267 LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, (" for '%s' mode '%s'\n", filename, mode)); 00268 00269 ip_addr_copy(tftp_state.addr, *addr); 00270 tftp_state.port = port; 00271 00272 if (opcode == PP_HTONS(TFTP_WRQ)) { 00273 tftp_state.mode_write = 1; 00274 send_ack(0); 00275 } else { 00276 tftp_state.mode_write = 0; 00277 send_data(); 00278 } 00279 00280 break; 00281 } 00282 00283 case PP_HTONS(TFTP_DATA): 00284 { 00285 int ret; 00286 u16_t blknum; 00287 00288 if (tftp_state.handle == NULL) { 00289 send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection"); 00290 break; 00291 } 00292 00293 if (tftp_state.mode_write != 1) { 00294 send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Not a write connection"); 00295 break; 00296 } 00297 00298 blknum = lwip_ntohs(sbuf[1]); 00299 pbuf_header(p, -TFTP_HEADER_LENGTH); 00300 00301 ret = tftp_state.ctx->write(tftp_state.handle, p); 00302 if (ret < 0) { 00303 send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "error writing file"); 00304 close_handle(); 00305 } else { 00306 send_ack(blknum); 00307 } 00308 00309 if (p->tot_len < TFTP_MAX_PAYLOAD_SIZE) { 00310 close_handle(); 00311 } 00312 break; 00313 } 00314 00315 case PP_HTONS(TFTP_ACK): 00316 { 00317 u16_t blknum; 00318 int lastpkt; 00319 00320 if (tftp_state.handle == NULL) { 00321 send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "No connection"); 00322 break; 00323 } 00324 00325 if (tftp_state.mode_write != 0) { 00326 send_error(addr, port, TFTP_ERROR_ACCESS_VIOLATION, "Not a read connection"); 00327 break; 00328 } 00329 00330 blknum = lwip_ntohs(sbuf[1]); 00331 if (blknum != tftp_state.blknum) { 00332 send_error(addr, port, TFTP_ERROR_UNKNOWN_TRFR_ID, "Wrong block number"); 00333 break; 00334 } 00335 00336 lastpkt = 0; 00337 00338 if (tftp_state.last_data != NULL) { 00339 lastpkt = tftp_state.last_data->tot_len != (TFTP_MAX_PAYLOAD_SIZE + TFTP_HEADER_LENGTH); 00340 } 00341 00342 if (!lastpkt) { 00343 tftp_state.blknum++; 00344 send_data(); 00345 } else { 00346 close_handle(); 00347 } 00348 00349 break; 00350 } 00351 00352 default: 00353 send_error(addr, port, TFTP_ERROR_ILLEGAL_OPERATION, "Unknown operation"); 00354 break; 00355 } 00356 00357 pbuf_free(p); 00358 } 00359 00360 static void 00361 tftp_tmr(void* arg) 00362 { 00363 LWIP_UNUSED_ARG(arg); 00364 00365 tftp_state.timer++; 00366 00367 if (tftp_state.handle == NULL) { 00368 return; 00369 } 00370 00371 sys_timeout(TFTP_TIMER_MSECS, tftp_tmr, NULL); 00372 00373 if ((tftp_state.timer - tftp_state.last_pkt) > (TFTP_TIMEOUT_MSECS / TFTP_TIMER_MSECS)) { 00374 if ((tftp_state.last_data != NULL) && (tftp_state.retries < TFTP_MAX_RETRIES)) { 00375 LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: timeout, retrying\n")); 00376 resend_data(); 00377 tftp_state.retries++; 00378 } else { 00379 LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: timeout\n")); 00380 close_handle(); 00381 } 00382 } 00383 } 00384 00385 /** @ingroup tftp 00386 * Initialize TFTP server. 00387 * @param ctx TFTP callback struct 00388 */ 00389 err_t 00390 tftp_init(const struct tftp_context *ctx) 00391 { 00392 err_t ret; 00393 00394 struct udp_pcb *pcb = udp_new_ip_type(IPADDR_TYPE_ANY); 00395 if (pcb == NULL) { 00396 return ERR_MEM; 00397 } 00398 00399 ret = udp_bind(pcb, IP_ANY_TYPE, TFTP_PORT); 00400 if (ret != ERR_OK) { 00401 udp_remove(pcb); 00402 return ret; 00403 } 00404 00405 tftp_state.handle = NULL; 00406 tftp_state.port = 0; 00407 tftp_state.ctx = ctx; 00408 tftp_state.timer = 0; 00409 tftp_state.last_data = NULL; 00410 tftp_state.upcb = pcb; 00411 00412 udp_recv(pcb, recv, NULL); 00413 00414 return ERR_OK; 00415 } 00416 00417 #endif /* LWIP_UDP */
Generated on Fri Jul 22 2022 04:53:53 by
1.7.2
