
10 changed files with 1947 additions and 0 deletions
@ -0,0 +1,42 @@
|
||||
# name of your application
|
||||
APPLICATION = gnrc_tftp
|
||||
|
||||
# If no BOARD is found in the environment, use this default:
|
||||
BOARD ?= native
|
||||
|
||||
# This has to be the absolute path to the RIOT base directory:
|
||||
RIOTBASE ?= $(CURDIR)/../..
|
||||
|
||||
BOARD_INSUFFICIENT_MEMORY := airfy-beacon chronos msb-430 msb-430h nrf51dongle \
|
||||
nrf6310 nucleo-f334 pca10000 pca10005 spark-core \
|
||||
stm32f0discovery telosb weio wsn430-v1_3b wsn430-v1_4 \
|
||||
yunjia-nrf51822 z1
|
||||
|
||||
# Include packages that pull up and auto-init the link layer.
|
||||
# NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present
|
||||
USEMODULE += gnrc_netif_default
|
||||
USEMODULE += auto_init_gnrc_netif
|
||||
# Specify the mandatory networking modules for IPv6 and UDP
|
||||
USEMODULE += gnrc_ipv6_router_default
|
||||
USEMODULE += gnrc_udp
|
||||
# Add a routing protocol
|
||||
USEMODULE += gnrc_rpl
|
||||
# This application dumps received packets to STDIO using the pktdump module
|
||||
USEMODULE += gnrc_pktdump
|
||||
# Additional networking modules that can be dropped if not needed
|
||||
USEMODULE += gnrc_icmpv6_echo
|
||||
USEMODULE += gnrc_tftp
|
||||
# Add also the shell, some shell commands
|
||||
USEMODULE += shell
|
||||
USEMODULE += shell_commands
|
||||
USEMODULE += ps
|
||||
|
||||
# Comment this out to disable code in RIOT that does safety checking
|
||||
# which is not needed in a production environment but helps in the
|
||||
# development process:
|
||||
CFLAGS += -DDEVELHELP
|
||||
|
||||
# Change this to 0 show compiler invocation lines by default:
|
||||
QUIET ?= 1
|
||||
|
||||
include $(RIOTBASE)/Makefile.include |
@ -0,0 +1,86 @@
|
||||
# gnrc_tftp example |
||||
|
||||
## Connecting RIOT native and the Linux host |
||||
|
||||
> **Note:** RIOT does not support IPv4, so you need to stick to IPv6 anytime. To establish a connection between RIOT and the Linux host, |
||||
you will need `tftp` (with IPv6 support). On Ubuntu and Debian you would need the package `tftp-hpa` for TFTP client and `tftpd-hpa` for TFTP server. |
||||
Be aware that many programs require you to add an option such as -6 to tell them to use IPv6, otherwise they |
||||
will fail. If you're using a _Raspberry Pi_, run `sudo modprobe ipv6` before trying this example, because raspbian does not load the |
||||
IPv6 module automatically. |
||||
On some systems (openSUSE for example), the _firewall_ may interfere, and prevent some packets to arrive at the application (they will |
||||
however show up in Wireshark, which can be confusing). So be sure to adjust your firewall rules, or turn it off (who needs security anyway). |
||||
|
||||
First, create a tap interface (to which RIOT will connect) and a bridge (to which Linux will connect) from the RIOT main directory run: |
||||
|
||||
./dist/tools/tapsetup/tapsetup -c 1 |
||||
|
||||
Now you can start the `gnrc_tftp` example by invoking `make term`. This should automatically connect to the `tap0` interface. If |
||||
this doesn't work for some reason, run `make` without any arguments, and then run the binary manually like so (assuming you are in the `examples/gnrc_tftp` directory): |
||||
|
||||
To verify that there is connectivity between RIOT and Linux, go to the RIOT console and run `ifconfig`: |
||||
|
||||
> ifconfig |
||||
Iface 6 HWaddr: 7e:ed:d2:ee:e1:07 |
||||
MTU:1280 |
||||
Source address length: 6 |
||||
Link type: wired |
||||
inet6 addr: ff02::1/128 scope: local [multicast] |
||||
inet6 addr: fe80::7ced:d2ff:feee:e107/64 scope: local |
||||
inet6 addr: ff02::1:ffee:e107/128 scope: local [multicast] |
||||
|
||||
|
||||
Copy the [link-local address](https://en.wikipedia.org/wiki/Link-local_address) of the RIOT node (prefixed with `fe80`) and try to ping it **from the Linux node**: |
||||
|
||||
ping6 fe80::7ced:d2ff:feee:e107%tapbr0 |
||||
|
||||
Note that the interface on which to send the ping needs to be appended to the IPv6 address, `%tapbr0` in the above example. When talking to the RIOT node, you always want to send to/receive from the `tapbr0` interface. |
||||
|
||||
If the pings succeed you can go on to send UDP packets. To do that, first start a UDP server on the RIOT node: |
||||
|
||||
> tftps start |
||||
tftp_server: Starting TFTP service at port 69 |
||||
|
||||
Now, on the Linux host, you can run tftp to connect with RIOT's TFTP server: |
||||
|
||||
$ tftp -v -6 fe80::7ced:d2ff:feee:e107%tapbr0 -c get welcome.txt |
||||
|
||||
The output will be something like: |
||||
|
||||
Connected to fe80::7ced:d2ff:feee:e107%tapbr0 (fe80::7ced:d2ff:feee:e107), port 69 |
||||
getting from fe80::7ced:d2ff:feee:e107%tapbr0:welcome.txt to welcome.txt [netascii] |
||||
Received 94 bytes in 0.0 seconds [113425 bit/s] |
||||
|
||||
The `-6` option is necessary to tell tftp to use IPv6 only and the `-v` is to tell the tftp client to be verbose. |
||||
|
||||
You should now see that the TFTP messages are received on the RIOT side. Opening a TFTP server on the Linux side is also possible. To do that, write down the IP address of the host (run on Linux): |
||||
|
||||
ifconfig tapbr0 |
||||
tapbr0 Link encap:Ethernet HWaddr 0e:bc:0f:49:7f:e4 |
||||
inet6 addr: fe80::cbc:fff:fe49:7fe4/64 Scope:Link |
||||
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 |
||||
RX packets:22 errors:0 dropped:0 overruns:0 frame:0 |
||||
TX packets:53 errors:0 dropped:0 overruns:0 carrier:0 |
||||
collisions:0 txqueuelen:0 |
||||
RX bytes:1928 (1.9 KB) TX bytes:6217 (6.2 KB) |
||||
|
||||
And start the tftp server on Linux: |
||||
|
||||
$ sudo /etc/init.d/tftpd-hpa stop && mkdir -p tftpserv && echo "hello world" > tftpserv/welcome.txt && sudo in.tftpd -vvv -L -6 -c -s -u ${USER} ./tftpserv |
||||
|
||||
Now, on the RIOT side, send a UDP packet using: |
||||
|
||||
tftpc get welcome.txt octet 1 fe80::cbc:fff:fe49:7fe4 |
||||
|
||||
You will get output that looks like this: |
||||
|
||||
tftp_client: bin read welcome.txt:12 |
||||
|
||||
-- CLIENT DATA -- |
||||
hello worl |
||||
-- CLIENT DATA -- |
||||
|
||||
-- CLIENT DATA -- |
||||
d |
||||
|
||||
-- CLIENT DATA -- |
||||
tftp_client: SUCCESS: (null) |
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Engineering-Spirit |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup examples |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Example application for demonstrating the RIOT TFTP stack |
||||
* |
||||
* @author Nick van IJzendoorn <nijzendoorn@engineering-spirit.nl> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include <unistd.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
|
||||
#include "shell.h" |
||||
#include "msg.h" |
||||
|
||||
extern int tftp_client_cmd(int argc, char * *argv); |
||||
extern int tftp_server_cmd(int argc, char * *argv); |
||||
|
||||
#define MAIN_QUEUE_SIZE (4) |
||||
static msg_t _main_msg_queue[MAIN_QUEUE_SIZE]; |
||||
|
||||
static const shell_command_t shell_commands[] = { |
||||
{ "tftpc", "get/put data to a TFTP server", tftp_client_cmd }, |
||||
{ "tftps", "start and stop the TFTP server", tftp_server_cmd }, |
||||
{ NULL, NULL, NULL } |
||||
}; |
||||
|
||||
int main(void) |
||||
{ |
||||
/* we need a message queue for the thread running the shell in order to
|
||||
* receive potentially fast incoming networking packets */ |
||||
msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE); |
||||
puts("RIOT TFTP stack example application"); |
||||
|
||||
/* start shell */ |
||||
puts("All up, running the shell now"); |
||||
char line_buf[SHELL_DEFAULT_BUFSIZE]; |
||||
|
||||
shell_run(shell_commands, line_buf, SHELL_DEFAULT_BUFSIZE); |
||||
|
||||
/* should be never reached */ |
||||
return 0; |
||||
} |
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Engineering-Spirit |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup examples |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Demonstrating the sending and receiving of data via the TFTP client |
||||
* |
||||
* @author Nick van IJzendoorn <nijzendoorn@engineering-spirit.nl> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <inttypes.h> |
||||
|
||||
#include "kernel.h" |
||||
#include "net/gnrc/tftp.h" |
||||
|
||||
static const char *_tftp_default_host = "::1"; |
||||
|
||||
/* default server text which can be received */ |
||||
static const char _tftp_client_hello[] = "Hello,\n" |
||||
"\n" |
||||
"Client text would also need to exist to be able to put data.\n" |
||||
"\n" |
||||
"Enjoy the RIOT-OS\n"; |
||||
|
||||
static tftp_action_t _tftp_action; |
||||
|
||||
/**
|
||||
* @brief called at every transaction start |
||||
*/ |
||||
static bool _tftp_client_start_cb(tftp_action_t action, tftp_mode_t mode, |
||||
const char *file_name, size_t *len) |
||||
{ |
||||
/* translate the mode */ |
||||
const char *str_mode = "ascii"; |
||||
|
||||
if (mode == TTM_OCTET) { |
||||
str_mode = "bin"; |
||||
} |
||||
else if (mode == TTM_MAIL) { |
||||
str_mode = "mail"; |
||||
} |
||||
|
||||
/* translate the action */ |
||||
const char *str_action = "read"; |
||||
if (action == TFTP_WRITE) { |
||||
str_action = "write"; |
||||
} |
||||
|
||||
/* display the action being performed */ |
||||
printf("tftp_client: %s %s %s:%u\n", str_mode, str_action, file_name, *len); |
||||
|
||||
/* return the length of the text, if this is an read action */ |
||||
if (action == TFTP_READ) { |
||||
*len = sizeof(_tftp_client_hello); |
||||
} |
||||
|
||||
/* remember the action of the current transfer */ |
||||
_tftp_action = action; |
||||
|
||||
/* we accept the transfer to take place so we return true */ |
||||
return true; |
||||
} |
||||
|
||||
/**
|
||||
* @brief called to get or put data, depending on the mode received by `_tftp_start_cb(action, ...)` |
||||
*/ |
||||
static int _tftp_client_data_cb(uint32_t offset, void *data, size_t data_len) |
||||
{ |
||||
char *c = (char *) data; |
||||
|
||||
/* if we are reading return the part of the data that is being requested */ |
||||
if (_tftp_action == TFTP_WRITE) { |
||||
/* calculate the length of the data block to transfer */ |
||||
if (offset + data_len > sizeof(_tftp_client_hello)) { |
||||
data_len -= (offset + data_len) - sizeof(_tftp_client_hello); |
||||
} |
||||
|
||||
/* copy the block to the output buffer */ |
||||
memcpy(data, _tftp_client_hello + offset, data_len); |
||||
} |
||||
else { |
||||
/* we received a data block which we output to the console */ |
||||
printf("\n -- CLIENT DATA --\n%.*s\n -- CLIENT DATA --\n", data_len, c); |
||||
} |
||||
|
||||
/* return the length of the data block */ |
||||
return data_len; |
||||
} |
||||
|
||||
/**
|
||||
* @brief the transfer has stopped, see the event argument to determined if it was successful |
||||
* or not. |
||||
*/ |
||||
static void _tftp_client_stop_cb(tftp_event_t event, const char *msg) |
||||
{ |
||||
/* decode the stop event received */ |
||||
const char *cause = "UNKOWN"; |
||||
|
||||
if (event == TFTP_SUCCESS) { |
||||
cause = "SUCCESS"; |
||||
} |
||||
else if (event == TFTP_PEER_ERROR) { |
||||
cause = "ERROR From Client"; |
||||
} |
||||
else if (event == TFTP_INTERN_ERROR) { |
||||
cause = "ERROR Internal Server Error"; |
||||
} |
||||
|
||||
/* print the transfer result to the console */ |
||||
printf("tftp_client: %s: %s\n", cause, msg); |
||||
} |
||||
|
||||
static int _tftp_client_cmd(int argc, char * *argv) |
||||
{ |
||||
ipv6_addr_t ip; |
||||
const char *file_name = argv[2]; |
||||
tftp_mode_t mode = TTM_OCTET; |
||||
bool use_options = true; |
||||
|
||||
ipv6_addr_from_str(&ip, _tftp_default_host); |
||||
|
||||
if (argc >= 3 && argc <= 6) { |
||||
/* decode the action */ |
||||
if (strcmp(argv[1], "get") == 0) { |
||||
_tftp_action = TFTP_READ; |
||||
} |
||||
else if (strcmp(argv[1], "put") == 0) { |
||||
_tftp_action = TFTP_WRITE; |
||||
} |
||||
else { |
||||
return -1; |
||||
} |
||||
|
||||
/* get the transfer mode */ |
||||
if (argc >= 4) { |
||||
if (strcmp(argv[3], "octet") == 0) { |
||||
mode = TTM_OCTET; |
||||
} |
||||
else if (strcmp(argv[3], "ascii") == 0) { |
||||
mode = TTM_ASCII; |
||||
} |
||||
else if (strcmp(argv[3], "mail") == 0) { |
||||
mode = TTM_MAIL; |
||||
} |
||||
else { |
||||
puts("tftp: couldn't parse the TFTP transfer mode"); |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
/* decode if we must use the TFTP option extension or not */ |
||||
if (argc >= 5) { |
||||
if (strcmp(argv[4], "0") == 0) { |
||||
use_options = false; |
||||
} |
||||
else if (strcmp(argv[4], "1") == 0) { |
||||
use_options = true; |
||||
} |
||||
else { |
||||
puts("tftp: invalid options choose 0 or 1"); |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
/* decode the address */ |
||||
if (argc >= 6) { |
||||
if (!ipv6_addr_from_str(&ip, argv[5])) { |
||||
puts("tftp: invalid IP address"); |
||||
return -1; |
||||
} |
||||
} |
||||
} |
||||
else { |
||||
return -1; |
||||
} |
||||
|
||||
if (_tftp_action == TFTP_READ) { |
||||
puts("tftp: starting read request"); |
||||
|
||||
gnrc_tftp_client_read(&ip, file_name, mode, _tftp_client_data_cb, |
||||
_tftp_client_start_cb, _tftp_client_stop_cb, use_options); |
||||
} |
||||
else if (_tftp_action == TFTP_WRITE) { |
||||
puts("tftp: starting write request"); |
||||
|
||||
gnrc_tftp_client_write(&ip, file_name, mode, _tftp_client_data_cb, |
||||
sizeof(_tftp_client_hello), _tftp_client_stop_cb, use_options); |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
/**
|
||||
* @brief start the TFTP server by creating a thread |
||||
*/ |
||||
int tftp_client_cmd(int argc, char * *argv) |
||||
{ |
||||
if (_tftp_client_cmd(argc, argv) < 0) { |
||||
printf("usage: %s <action[get|put]> <file_name> <mode[ascii | octet(default) | mail]>\n" |
||||
"\t<use_options[1 (default) | 0]> <addr(default: ::1)>\n", argv[0]); |
||||
} |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Engineering-Spirit |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser |
||||
* General Public License v2.1. See the file LICENSE in the top level |
||||
* directory for more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @ingroup examples |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief Demonstrating the sending and receiving of data via the TFTP server |
||||
* |
||||
* @author Nick van IJzendoorn <nijzendoorn@engineering-spirit.nl> |
||||
* |
||||
* @} |
||||
*/ |
||||
|
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <unistd.h> |
||||
#include <inttypes.h> |
||||
|
||||
#include "thread.h" |
||||
#include "net/gnrc/tftp.h" |
||||
|
||||
/* the message queues */ |
||||
#define TFTP_QUEUE_SIZE (4) |
||||
static msg_t _tftp_msg_queue[TFTP_QUEUE_SIZE]; |
||||
|
||||
/* allocate the stack */ |
||||
char _tftp_stack[THREAD_STACKSIZE_MAIN + THREAD_EXTRA_STACKSIZE_PRINTF]; |
||||
|
||||
/* default server text which can be received */ |
||||
static const char _tftp_server_hello[] = "Hello world,\n" |
||||
"\n" |
||||
"Welcome to the wonderful world of IoT and embedded systems.\n" |
||||
"\n" |
||||
"Enjoy the RIOT-OS\n"; |
||||
|
||||
static tftp_action_t _tftp_action; |
||||
|
||||
/**
|
||||
* @brief called at every transcation start |
||||
*/ |
||||
static bool _tftp_server_start_cb(tftp_action_t action, tftp_mode_t mode, |
||||
const char *file_name, size_t *len) |
||||
{ |
||||
/* translate the mode */ |
||||
const char *str_mode = "ascii"; |
||||
|
||||
if (mode == TTM_OCTET) { |
||||
str_mode = "bin"; |
||||
} |
||||
else if (mode == TTM_MAIL) { |
||||
str_mode = "mail"; |
||||
} |
||||
|
||||
/* translate the action */ |
||||
const char *str_action = "read"; |
||||
if (action == TFTP_WRITE) { |
||||
str_action = "write"; |
||||
} |
||||
|
||||
/* display the action being performed */ |
||||
printf("tftp_server: %s %s %s:%u\n", str_mode, str_action, file_name, *len); |
||||
|
||||
/* return the length of the text, if this is an read action */ |
||||
if (action == TFTP_READ) { |
||||
*len = sizeof(_tftp_server_hello); |
||||
} |
||||
|
||||
/* remember the action of the current transfer */ |
||||
_tftp_action = action; |
||||
|
||||
/* we accept the transfer to take place so we return true */ |
||||
return true; |
||||
} |
||||
|
||||
/**
|
||||
* @brief called to get or put data, depending on the mode received by `_tftp_start_cb(action, ...)` |
||||
*/ |
||||
static int _tftp_server_data_cb(uint32_t offset, void *data, size_t data_len) |
||||
{ |
||||
char *c = (char *) data; |
||||
|
||||
/* if we are reading return the part of the data that is being requested */ |
||||
if (_tftp_action == TFTP_READ) { |
||||
/* calculate the length of the data block to transfer */ |
||||
if (offset + data_len > sizeof(_tftp_server_hello)) { |
||||
data_len -= (offset + data_len) - sizeof(_tftp_server_hello); |
||||
} |
||||
|
||||
/* copy the block to the output buffer */ |
||||
memcpy(data, _tftp_server_hello + offset, data_len); |
||||
} |
||||
else { |
||||
/* we received a data block which we output to the console */ |
||||
printf("\n -- SERVER DATA --\n%.*s\n -- SERVER DATA --\n", data_len, c); |
||||
} |
||||
|
||||
/* return the length of the data block */ |
||||
return data_len; |
||||
} |
||||
|
||||
/**
|
||||
* @brief the transfer has stopped, see the event argument to determined if it was successful |
||||
* or not. |
||||
*/ |
||||
static void _tftp_server_stop_cb(tftp_event_t event, const char *msg) |
||||
{ |
||||
/* decode the stop event received */ |
||||
const char *cause = "UNKOWN"; |
||||
|
||||
if (event == TFTP_SUCCESS) { |
||||
cause = "SUCCESS"; |
||||
} |
||||
else if (event == TFTP_PEER_ERROR) { |
||||
cause = "ERROR From Client"; |
||||
} |
||||
else if (event == TFTP_INTERN_ERROR) { |
||||
cause = "ERROR Internal Server Error"; |
||||
} |
||||
|
||||
/* print the transfer result to the console */ |
||||
printf("tftp_server: %s: %s\n", cause, (msg == NULL) ? "NULL" : msg); |
||||
} |
||||
|
||||
/**
|
||||
* @brief the TFTP server thread |
||||
*/ |
||||
void *tftp_server_wrapper(void *arg) |
||||
{ |
||||
(void)arg; |
||||
|
||||
/* A message queue is needed to register for incoming packets */ |
||||
msg_init_queue(_tftp_msg_queue, TFTP_QUEUE_SIZE); |
||||
|
||||
/* inform the user */ |
||||
puts("tftp_server: Starting TFTP service at port 69"); |
||||
|
||||
/* run the TFTP server */ |
||||
gnrc_tftp_server(_tftp_server_data_cb, _tftp_server_start_cb, _tftp_server_stop_cb, true); |
||||
|
||||
/* the TFTP server has been stopped */ |
||||
puts("tftp_server: Stopped TFTP service"); |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
/**
|
||||
* @brief start the TFTP server by creating a thread |
||||
*/ |
||||
void tftp_server_start(void) |
||||
{ |
||||
thread_create(_tftp_stack, sizeof(_tftp_stack), |
||||
1, CREATE_WOUT_YIELD | CREATE_STACKTEST, |
||||
tftp_server_wrapper, NULL, "TFTP Server"); |
||||
} |
||||
|
||||
/**
|
||||
* @brief stop the TFTP server by sending a message to the thread |
||||
*/ |
||||
void tftp_server_stop(void) |
||||
{ |
||||
gnrc_tftp_server_stop(); |
||||
} |
||||
|
||||
int tftp_server_cmd(int argc, char * *argv) |
||||
{ |
||||
switch (argc) { |
||||
case 2: |
||||
if (strcmp(argv[1], "start") == 0) { |
||||
tftp_server_start(); |
||||
return 0; |
||||
} |
||||
else if (strcmp(argv[1], "stop") == 0) { |
||||
tftp_server_stop(); |
||||
return 0; |
||||
} |
||||
/* no break */ |
||||
|
||||
default: |
||||
printf("usage: %s [start|stop]\n", argv[0]); |
||||
return 0; |
||||
} |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Nick van IJzendoorn <nijzendoorn@engineering-spirit.nl> |
||||
* |
||||
* This file is subject to the terms and conditions of the GNU Lesser General |
||||
* Public License v2.1. See the file LICENSE in the top level directory for |
||||
* more details. |
||||
*/ |
||||
|
||||
/**
|
||||
* @defgroup net_gnrc_tftp TFTP Support Library |
||||
* @ingroup net_gnrc |
||||
* @brief Add's support for TFTP protocol parsing |
||||
* @{ |
||||
* |
||||
* @file |
||||
* @brief TFTP support library |
||||
* |
||||
* The TFTP module add's support for the TFTP protocol. |
||||
* It implements the following RFC's: |
||||
* - https://tools.ietf.org/html/rfc1350
|
||||
* (RFC1350 The TFTP Protocol (Revision 2) |
||||
* |
||||
* - https://tools.ietf.org/html/rfc2347
|
||||
* (RFC2347 TFTP Option Extension) |
||||
* |
||||
* - https://tools.ietf.org/html/rfc2348
|
||||
* (RFC2348 TFTP Blocksize Option) |
||||
* |
||||
* - https://tools.ietf.org/html/rfc2349
|
||||
* (RFC2349 TFTP Timeout Interval and Transfer Size Options) |
||||
* |
||||
* @author Nick van IJzendoorn <nijzendoorn@engineering-spirit.nl> |
||||
*/ |
||||
|
||||
#ifndef GNRC_TFTP_H_ |
||||
#define GNRC_TFTP_H_ |
||||
|
||||
#include <inttypes.h> |
||||
|
||||
#include "byteorder.h" |
||||
#include "kernel_types.h" |
||||
#include "net/ipv6/addr.h" |
||||
#include "net/gnrc/nettype.h" |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" { |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief The maximum allowed length of the transfer filename |
||||
*/ |
||||
#ifndef GNRC_TFTP_MAX_FILENAME_LEN |
||||
#define GNRC_TFTP_MAX_FILENAME_LEN (64) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief The base source port to be used by TFTP |
||||
*/ |
||||
#ifndef GNRC_TFTP_DEFAULT_SRC_PORT |
||||
#define GNRC_TFTP_DEFAULT_SRC_PORT (10690) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief The default destination port of the TFTP server |
||||
*/ |
||||
#ifndef GNRC_TFTP_DEFAULT_DST_PORT |
||||
#define GNRC_TFTP_DEFAULT_DST_PORT (69) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief The maximum allowed data bytes in the data packet |
||||
*/ |
||||
#ifndef GNRC_TFTP_MAX_TRANSFER_UNIT |
||||
#define GNRC_TFTP_MAX_TRANSFER_UNIT (512) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief The number of retries that must be made before stopping a transfer |
||||
*/ |
||||
#ifndef GNRC_TFTP_MAX_RETRIES |
||||
#define GNRC_TFTP_MAX_RETRIES (5) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief The default timeout of a data packet |
||||
*/ |
||||
#ifndef GNRC_TFTP_DEFAULT_TIMEOUT |
||||
#define GNRC_TFTP_DEFAULT_TIMEOUT (1 * SEC_IN_USEC) |
||||
#endif |
||||
|
||||
/**
|
||||
* @brief TFTP action to perform |
||||
*/ |
||||
typedef enum { |
||||
TFTP_READ, |
||||
TFTP_WRITE |
||||
} tftp_action_t; |
||||
|
||||
/**
|
||||
* @brief TFTP Transfer modes |
||||
*/ |
||||
typedef enum { |
||||
TTM_ASCII, |
||||
TTM_OCTET, |
||||
TTM_MAIL |
||||
} tftp_mode_t; |
||||
|
||||
/**
|
||||
* @brief TFTP stop / finish events |
||||
*/ |
||||
typedef enum { |
||||
TFTP_SUCCESS, /**< The transfer was successful */ |
||||
TFTP_PEER_ERROR, /**< The peer send the given error */ |
||||
TFTP_INTERN_ERROR /**< There was an internal error */ |
||||
} tftp_event_t; |
||||
|
||||
/**
|
||||
* @brief callback define which is called when a new server request is placed |
||||
* or when an client read request is made and the data length option is received |
||||
* |
||||
* @param [in] action The action the transfer want to perform |
||||
* @param [in] mode The data mode of the transfer |
||||
* @param [in] file_name The filename of the file being transfered |
||||
* @param [in/out] data_len When a read action is performed, the application must give |
||||
* the total transfer size of the data. When a write action |
||||
* is performed the total transfer size will be given. |
||||
*/ |
||||
typedef bool (*tftp_start_cb_t)(tftp_action_t action, tftp_mode_t mode, |
||||
const char *file_name, size_t *data_len); |
||||
|
||||
/**
|
||||
* @brief callback define which is called to get or set data from/to the user application |
||||
*/ |
||||
typedef int (*tftp_data_cb_t)(uint32_t offset, void *data, size_t data_len); |
||||
|
||||
/**
|
||||
* @brief callback define which is called when an transfer is stopped |
||||
*/ |
||||
typedef void (*tftp_stop_cb_t)(tftp_event_t event, const char *msg); |
||||
|
||||
/**
|
||||
* @brief Start the TFTP server |
||||
* |
||||
* @param [in] data_cb called for each read data block |
||||
* @param [in] start_cb called if a new client connection is requested |
||||
* @param [in] stop_cb called if the transfer has finished |
||||
* @param [in] use_options when set the client uses the option extensions |
||||
* |
||||
* @return 1 on success |
||||
* @return -1 on failure |
||||
*/ |
||||
int gnrc_tftp_server(tftp_data_cb_t data_cb, tftp_start_cb_t start_cb, tftp_stop_cb_t stop_cb, bool use_options); |
||||
|
||||
/**
|
||||
* @brief Stop the TFTP server |
||||
* |
||||
* @return 1 on success |
||||
* @return -1 on failure |
||||
*/ |
||||
int gnrc_tftp_server_stop(void); |
||||
|
||||
/**
|
||||
* @brief Start an TFTP client read action from the given destination |
||||
* |
||||
* @param [in] addr the address of the server |
||||
* @param [in] file_name the filename of the file to get |
||||
* @param [in] mode the transfer mode |
||||
* @param [in] data_cb called for each read data block |
||||
* @param [in] start_cb called if the server returns the transfer_size option |
||||
* @param [in] stop_cb called if the transfer has finished |
||||
* @param [in] use_option when set the client uses the option extensions |
||||
* |
||||
* @return 1 on success |
||||
* @return -1 on failure |
||||
*/ |
||||
int gnrc_tftp_client_read(ipv6_addr_t *addr, const char *file_name, tftp_mode_t mode, |
||||
tftp_data_cb_t data_cb, tftp_start_cb_t start_cb, tftp_stop_cb_t stop_cb, |
||||
bool use_option); |
||||
|
||||
/**
|
||||
* @brief Start an TFTP client write action to the given destination |
||||
* |
||||
* @param [in] addr the address of the server |
||||
* @param [in] file_name the filename of the file to write |
||||
* @param [in] mode the transfer mode |
||||
* @param [in] data_cb called to store the received block |
||||
* @param [in] total_size the total size of the transfer |
||||
* @param [in] stop_cb called if the server returns the transfer_size option |
||||
* @param [in] use_option when set the client uses the option extensions |
||||
* |
||||
* @return 1 on success |
||||
* @return -1 on failure |
||||
*/ |
||||
int gnrc_tftp_client_write(ipv6_addr_t *addr, const char *file_name, tftp_mode_t mode, |
||||
tftp_data_cb_t data_cb, size_t total_size, tftp_stop_cb_t stop_cb, |
||||
bool use_option); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* GNRC_TFTP_H_ */ |
||||
|
||||
/**
|
||||
* @} |
||||
*/ |
@ -0,0 +1,3 @@
|
||||
MODULE = gnrc_tftp
|
||||
|
||||
include $(RIOTBASE)/Makefile.base |
Loading…
Reference in new issue