tftpc TFTP Client
Overview
tftpc is a lightweight, RFC 1350-compliant Trivial File Transfer Protocol (TFTP)
client library and utility for Apache NuttX. Designed specifically for resource-constrained
embedded systems, it facilitates low-overhead file transfers over UDP.
In NuttX environments, tftpc is widely used for:
Bootloaders, remote firmware updates, and Over-The-Air (OTA) image transfers.
Transferring small configuration files and system logs without requiring a complex TCP stack, TLS handshakes, or HTTP parsers.
Interactive file retrieval and upload directly from the NuttShell (NSH).
Note
Security Consideration: TFTP provides no authentication, encryption, or access control mechanisms. When performing firmware updates or transferring sensitive binaries over TFTP, operations should be restricted to trusted, isolated networks, and the receiving system must independently verify the image prior to installation using a verified digital signature (or a cryptographic digest received over a trusted out-of-band channel) to guarantee both origin authenticity and integrity.
It serves two primary roles:
Underlying Engine for NSH ``get`` and ``put`` Commands: Powers interactive terminal file transfer commands in the NuttShell.
Programmatic C API: Provides embedded applications with simple synchronous helpers (
tftpget(),tftpput()) as well as streaming callback interfaces (tftpget_cb(),tftpput_cb()) that stream blocks directly into memory, flash partitions, or custom buffers without requiring a temporary local filesystem file.
Key Features
RFC 1350 Compliance: Standard-compliant TFTP client protocol implementation.
Binary and Text Transfer Modes: Supports both
octet(binary) andnetascii(text) transfer modes.Streaming Callback Architecture: User-defined
tftp_callback_thandlers process incoming or outgoing chunks on-the-fly, allowing direct flashing of MTD/flash partitions with minimal RAM consumption.Dynamic Port Negotiation: Connects to the server’s well-known port (typically 69) and seamlessly adapts to the server’s negotiated Transfer Identifier (TID) port.
Configurable Retransmission: Built-in retransmission timeouts and retry counters to tolerate packet loss over wireless or congested networks.
Requirements & Dependencies
To use tftpc, the following network subsystem features must be enabled:
IPv4 Networking:
CONFIG_NET=yandCONFIG_NET_IPv4=yUDP Protocol:
CONFIG_NET_UDP=yEnable the Client Library:
CONFIG_NETUTILS_TFTPC=yFor NSH Commands:
!CONFIG_NSH_DISABLE_GETand!CONFIG_NSH_DISABLE_PUT
Configuration Options
The behavior of the TFTP client can be customized via Kconfig and configuration settings:
Setting |
Default |
Description |
|---|---|---|
|
|
Enables the TFTP client library in |
|
|
Target well-known TFTP server port used for the initial request. |
|
|
Socket receive timeout in deci-seconds (10 = 1 second). |
|
Defined |
Debug option to dump transmitted and received packet buffers to stdout. |
NSH Usage
When CONFIG_NETUTILS_TFTPC is enabled along with NSH UDP network commands, the
get and put commands are available directly in the NuttShell.
Downloading Files (get)
The get command downloads a file from a remote TFTP server:
get [-b|-n] [-f <local-path>] -h <ip-address> <remote-path>
Options:
-b: Transfer file in binary (octet) mode (default).-n: Transfer file in text (netascii) mode.-f <local-path>: Destination path on the local filesystem. If omitted, the file is written to the current directory using<remote-path>as the filename.-h <ip-address>: IPv4 address of the remote TFTP server.<remote-path>: Path or filename of the file on the remote server.
Example:
nsh> get -h 192.168.1.100 -f /mnt/sdcard/firmware.bin app_update.bin
nsh> ls -l /mnt/sdcard/firmware.bin
Uploading Files (put)
The put command uploads a local file to a remote TFTP server:
put [-b|-n] [-f <remote-path>] -h <ip-address> <local-path>
Options:
-b: Transfer file in binary (octet) mode (default).-n: Transfer file in text (netascii) mode.-f <remote-path>: Destination filename on the remote TFTP server. If omitted, the file is written with the basename of<local-path>.-h <ip-address>: IPv4 address of the remote TFTP server.<local-path>: Path to the local file to transmit.
Example:
nsh> put -h 192.168.1.100 -f remote_syslog.txt /var/log/syslog.txt
C API Reference
The public C interface is declared in apps/include/netutils/tftp.h.
Standard Filesystem APIs
For standard file-to-file transfers using paths in the VFS:
#include <arpa/inet.h>
#include <stdbool.h>
#include <netutils/tftp.h>
int tftpget(FAR const char *remote, FAR const char *local, in_addr_t addr,
bool binary);
int tftpput(FAR const char *local, FAR const char *remote, in_addr_t addr,
bool binary);
Parameters:
remote: Filename on the remote TFTP server.local: Filename in the local NuttX filesystem.addr: IPv4 network address of the TFTP server in network byte order (e.g., frominet_addr()).binary: Passtruefor binary (octet) mode, orfalsefor text (netascii) mode.
Return Value:
Returns
OK(0) on success, or a negated errno value (orERROR) on failure.
Streaming Callback APIs
For transfers directly to/from memory, raw flash, or custom sinks:
typedef ssize_t (*tftp_callback_t)(FAR void *ctx, uint32_t offset,
FAR uint8_t *buf, size_t len);
int tftpget_cb(FAR const char *remote, in_addr_t addr, bool binary,
tftp_callback_t cb, FAR void *ctx);
int tftpput_cb(FAR const char *remote, in_addr_t addr, bool binary,
tftp_callback_t cb, FAR void *ctx);
Callback semantics:
GET (Download):
offsetis zero.bufpoints to the received block (up to 512 bytes).lenis the number of received bytes. The callback must return the number of bytes successfully processed, or a negative value to abort the transfer.PUT (Upload):
offsetindicates the current stream byte position.bufpoints to the destination buffer to populate.lenspecifies the buffer size. The callback must return the number of bytes supplied, 0 on end-of-file (EOF), or a negative value to abort the transfer.
Application Example
Below is a complete example demonstrating how an application can download a remote configuration
file using the streaming callback API tftpget_cb():
#include <nuttx/config.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <netutils/tftp.h>
struct memory_sink_s
{
FAR uint8_t *buffer;
size_t max_size;
size_t total_received;
};
static ssize_t tftp_recv_cb(FAR void *ctx, uint32_t offset,
FAR uint8_t *buf, size_t len)
{
FAR struct memory_sink_s *sink = (FAR struct memory_sink_s *)ctx;
if (sink->total_received + len > sink->max_size)
{
fprintf(stderr, "Buffer overflow: payload exceeds capacity\n");
return -ENOMEM;
}
memcpy(sink->buffer + sink->total_received, buf, len);
sink->total_received += len;
return len;
}
int fetch_config(FAR const char *server_ip, FAR const char *filename,
FAR uint8_t *dest_buf, size_t max_len)
{
struct memory_sink_s sink;
in_addr_t server_addr;
int ret;
server_addr = inet_addr(server_ip);
if (server_addr == INADDR_NONE)
{
return -EINVAL;
}
sink.buffer = dest_buf;
sink.max_size = max_len;
sink.total_received = 0;
ret = tftpget_cb(filename, server_addr, true, tftp_recv_cb, &sink);
if (ret < 0)
{
return ret;
}
return (int)sink.total_received;
}