summaryrefslogtreecommitdiffstats
path: root/cpukit/libnetworking
diff options
context:
space:
mode:
authorVijay Kumar Banerjee <vijay@rtems.org>2021-02-24 12:27:29 -0700
committerVijay Kumar Banerjee <vijay@rtems.org>2021-04-07 16:15:38 -0600
commita28eafb2a4d7418ad1efb3f8b72e9cbb014c1c0b (patch)
treed5a5703fd9f0fb924a2f2de14dc58fc5fe44dc4a /cpukit/libnetworking
parentspec: Remove RTEMS_NETWORKING options (diff)
downloadrtems-a28eafb2a4d7418ad1efb3f8b72e9cbb014c1c0b.tar.bz2
cpukit: Move ftpfs from libnetworking to libfs
Update #3850
Diffstat (limited to 'cpukit/libnetworking')
-rw-r--r--cpukit/libnetworking/lib/ftpfs.c1430
-rw-r--r--cpukit/libnetworking/lib/tftpDriver.c1066
2 files changed, 0 insertions, 2496 deletions
diff --git a/cpukit/libnetworking/lib/ftpfs.c b/cpukit/libnetworking/lib/ftpfs.c
deleted file mode 100644
index 5e0cb95dd3..0000000000
--- a/cpukit/libnetworking/lib/ftpfs.c
+++ /dev/null
@@ -1,1430 +0,0 @@
-/**
- * @file
- *
- * File Transfer Protocol file system (FTP client).
- */
-
-/*
- * Copyright (c) 2009-2012 embedded brains GmbH.
- *
- * embedded brains GmbH
- * Obere Lagerstr. 30
- * 82178 Puchheim
- * Germany
- * <rtems@embedded-brains.de>
- *
- * (c) Copyright 2002
- * Thomas Doerfler
- * IMD Ingenieurbuero fuer Microcomputertechnik
- * Herbststr. 8
- * 82178 Puchheim, Germany
- * <Thomas.Doerfler@imd-systems.de>
- *
- * This code has been created after closly inspecting "tftpdriver.c" from Eric
- * Norum.
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.org/license/LICENSE.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <malloc.h>
-#include <netdb.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-#include <sys/select.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-
-#include <rtems.h>
-#include <rtems/ftpfs.h>
-#include <rtems/libio_.h>
-#include <rtems/seterr.h>
-
-#ifdef DEBUG
- #define DEBUG_PRINTF(...) printf(__VA_ARGS__)
-#else
- #define DEBUG_PRINTF(...)
-#endif
-
-/**
- * Connection entry for each open file stream.
- */
-typedef struct {
- off_t file_size;
-
- /**
- * Control connection socket.
- */
- int ctrl_socket;
-
- uint32_t client_address;
-
- /**
- * Data transfer socket.
- */
- int data_socket;
-
- /**
- * Current index into the reply buffer.
- */
- size_t reply_current;
-
- /**
- * End index of the reply buffer.
- */
- size_t reply_end;
-
- /**
- * Buffer for relpy data.
- */
- char reply_buffer [128];
-
- /**
- * End of file flag.
- */
- bool eof;
-
- bool write;
-
- /**
- * Indicates if we should do a SIZE command.
- *
- * The first call to the rtems_ftpfs_fstat() handler is issued by the path
- * evaluation to check for access permission. For this case we avoid the
- * SIZE command.
- */
- bool do_size_command;
-
- ino_t ino;
-
- const char *user;
-
- const char *password;
-
- const char *hostname;
-
- const char *filename;
-
- char buffer [];
-} rtems_ftpfs_entry;
-
-/**
- * Mount entry for each file system instance.
- */
-typedef struct {
- /**
- * Verbose mode enabled or disabled.
- */
- bool verbose;
-
- /**
- * Timeout value
- */
- struct timeval timeout;
-
- /**
- * Inode counter.
- */
- ino_t ino;
-} rtems_ftpfs_mount_entry;
-
-static const rtems_filesystem_operations_table rtems_ftpfs_ops;
-
-static const rtems_filesystem_file_handlers_r rtems_ftpfs_handlers;
-
-static const rtems_filesystem_file_handlers_r rtems_ftpfs_root_handlers;
-
-static bool rtems_ftpfs_use_timeout(const struct timeval *to)
-{
- return to->tv_sec != 0 || to->tv_usec != 0;
-}
-
-static int rtems_ftpfs_set_connection_timeout(
- int socket,
- const struct timeval *to
-)
-{
- if (rtems_ftpfs_use_timeout(to)) {
- int rv = 0;
-
- rv = setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, to, sizeof(*to));
- if (rv != 0) {
- return EIO;
- }
-
- rv = setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, to, sizeof(*to));
- if (rv != 0) {
- return EIO;
- }
- }
-
- return 0;
-}
-
-static rtems_status_code rtems_ftpfs_do_ioctl(
- const char *mount_point,
- ioctl_command_t req,
- ...
-)
-{
- rtems_status_code sc = RTEMS_SUCCESSFUL;
- int rv = 0;
- int fd = 0;
- va_list ap;
-
- if (mount_point == NULL) {
- mount_point = RTEMS_FTPFS_MOUNT_POINT_DEFAULT;
- }
-
- fd = open(mount_point, O_RDWR);
- if (fd < 0) {
- return RTEMS_INVALID_NAME;
- }
-
- va_start(ap, req);
- rv = ioctl(fd, req, va_arg(ap, void *));
- va_end(ap);
- if (rv != 0) {
- sc = RTEMS_INVALID_NUMBER;
- }
-
- rv = close(fd);
- if (rv != 0 && sc == RTEMS_SUCCESSFUL) {
- sc = RTEMS_IO_ERROR;
- }
-
- return sc;
-}
-
-rtems_status_code rtems_ftpfs_get_verbose(const char *mount_point, bool *verbose)
-{
- return rtems_ftpfs_do_ioctl(
- mount_point,
- RTEMS_FTPFS_IOCTL_GET_VERBOSE,
- verbose
- );
-}
-
-rtems_status_code rtems_ftpfs_set_verbose(const char *mount_point, bool verbose)
-{
- return rtems_ftpfs_do_ioctl(
- mount_point,
- RTEMS_FTPFS_IOCTL_SET_VERBOSE,
- &verbose
- );
-}
-
-rtems_status_code rtems_ftpfs_get_timeout(
- const char *mount_point,
- struct timeval *timeout
-)
-{
- return rtems_ftpfs_do_ioctl(
- mount_point,
- RTEMS_FTPFS_IOCTL_GET_TIMEOUT,
- timeout
- );
-}
-
-rtems_status_code rtems_ftpfs_set_timeout(
- const char *mount_point,
- const struct timeval *timeout
-)
-{
- return rtems_ftpfs_do_ioctl(
- mount_point,
- RTEMS_FTPFS_IOCTL_SET_TIMEOUT,
- timeout
- );
-}
-
-typedef void (*rtems_ftpfs_reply_parser)(
- const char * /* reply fragment */,
- size_t /* reply fragment length */,
- void * /* parser argument */
-);
-
-typedef enum {
- RTEMS_FTPFS_REPLY_START,
- RTEMS_FTPFS_REPLY_SINGLE_LINE,
- RTEMS_FTPFS_REPLY_DONE,
- RTEMS_FTPFS_REPLY_MULTI_LINE,
- RTEMS_FTPFS_REPLY_MULTI_LINE_START
-} rtems_ftpfs_reply_state;
-
-typedef enum {
- RTEMS_FTPFS_REPLY_ERROR = 0,
- RTEMS_FTPFS_REPLY_1 = '1',
- RTEMS_FTPFS_REPLY_2 = '2',
- RTEMS_FTPFS_REPLY_3 = '3',
- RTEMS_FTPFS_REPLY_4 = '4',
- RTEMS_FTPFS_REPLY_5 = '5'
-} rtems_ftpfs_reply;
-
-#define RTEMS_FTPFS_REPLY_SIZE 3
-
-static bool rtems_ftpfs_is_reply_code_valid(unsigned char *reply)
-{
- return isdigit(reply [0]) && isdigit(reply [1]) && isdigit(reply [2]);
-}
-
-static rtems_ftpfs_reply rtems_ftpfs_get_reply(
- rtems_ftpfs_entry *e,
- rtems_ftpfs_reply_parser parser,
- void *parser_arg,
- bool verbose
-)
-{
- rtems_ftpfs_reply_state state = RTEMS_FTPFS_REPLY_START;
- unsigned char reply_code [RTEMS_FTPFS_REPLY_SIZE] = { 'a', 'a', 'a' };
- size_t reply_code_index = 0;
-
- while (state != RTEMS_FTPFS_REPLY_DONE) {
- char *buf = NULL;
- size_t i = 0;
- size_t n = 0;
-
- /* Receive reply fragment from socket */
- if (e->reply_current == e->reply_end) {
- ssize_t rv = 0;
-
- e->reply_current = 0;
- e->reply_end = 0;
-
- rv = recv(
- e->ctrl_socket,
- &e->reply_buffer [0],
- sizeof(e->reply_buffer),
- 0
- );
-
- if (rv > 0) {
- e->reply_end = (size_t) rv;
- } else {
- return RTEMS_FTPFS_REPLY_ERROR;
- }
- }
-
- buf = &e->reply_buffer [e->reply_current];
- n = e->reply_end - e->reply_current;
-
- /* Invoke parser if necessary */
- if (parser != NULL) {
- parser(buf, n, parser_arg);
- }
-
- /* Parse reply fragment */
- for (i = 0; i < n && state != RTEMS_FTPFS_REPLY_DONE; ++i) {
- char c = buf [i];
-
- switch (state) {
- case RTEMS_FTPFS_REPLY_START:
- if (reply_code_index < RTEMS_FTPFS_REPLY_SIZE) {
- reply_code [reply_code_index] = c;
- ++reply_code_index;
- } else if (rtems_ftpfs_is_reply_code_valid(reply_code)) {
- if (c == '-') {
- state = RTEMS_FTPFS_REPLY_MULTI_LINE;
- } else {
- state = RTEMS_FTPFS_REPLY_SINGLE_LINE;
- }
- } else {
- return RTEMS_FTPFS_REPLY_ERROR;
- }
- break;
- case RTEMS_FTPFS_REPLY_SINGLE_LINE:
- if (c == '\n') {
- state = RTEMS_FTPFS_REPLY_DONE;
- }
- break;
- case RTEMS_FTPFS_REPLY_MULTI_LINE:
- if (c == '\n') {
- state = RTEMS_FTPFS_REPLY_MULTI_LINE_START;
- reply_code_index = 0;
- }
- break;
- case RTEMS_FTPFS_REPLY_MULTI_LINE_START:
- if (reply_code_index < RTEMS_FTPFS_REPLY_SIZE) {
- if (reply_code [reply_code_index] == c) {
- ++reply_code_index;
- } else {
- state = RTEMS_FTPFS_REPLY_MULTI_LINE;
- }
- } else {
- if (c == ' ') {
- state = RTEMS_FTPFS_REPLY_SINGLE_LINE;
- } else {
- state = RTEMS_FTPFS_REPLY_MULTI_LINE;
- }
- }
- break;
- default:
- return RTEMS_FTPFS_REPLY_ERROR;
- }
- }
-
- /* Be verbose if necessary */
- if (verbose) {
- write(STDERR_FILENO, buf, i);
- }
-
- /* Update reply index */
- e->reply_current += i;
- }
-
- return reply_code [0];
-}
-
-static rtems_ftpfs_reply rtems_ftpfs_send_command_with_parser(
- rtems_ftpfs_entry *e,
- const char *cmd,
- const char *arg,
- rtems_ftpfs_reply_parser parser,
- void *parser_arg,
- bool verbose
-)
-{
- rtems_ftpfs_reply reply = RTEMS_FTPFS_REPLY_ERROR;
- size_t cmd_len = strlen(cmd);
- size_t arg_len = arg != NULL ? strlen(arg) : 0;
- size_t len = cmd_len + arg_len + 2;
- char *buf = malloc(len);
-
- if (buf != NULL) {
- ssize_t n = 0;
- char *buf_arg = buf + cmd_len;
- char *buf_eol = buf_arg + arg_len;
-
- memcpy(buf, cmd, cmd_len);
- memcpy(buf_arg, arg, arg_len);
- buf_eol [0] = '\r';
- buf_eol [1] = '\n';
-
- /* Send */
- n = send(e->ctrl_socket, buf, len, 0);
- if (n == (ssize_t) len) {
- if (verbose) {
- write(STDERR_FILENO, buf, len);
- }
-
- /* Reply */
- reply = rtems_ftpfs_get_reply(e, parser, parser_arg, verbose);
- }
-
- free(buf);
- }
-
- return reply;
-}
-
-static rtems_ftpfs_reply rtems_ftpfs_send_command(
- rtems_ftpfs_entry *e,
- const char *cmd,
- const char *arg,
- bool verbose
-)
-{
- return rtems_ftpfs_send_command_with_parser(
- e,
- cmd,
- arg,
- NULL,
- NULL,
- verbose
- );
-}
-
-typedef enum {
- STATE_USER_NAME,
- STATE_START_PASSWORD,
- STATE_START_HOST_NAME,
- STATE_START_HOST_NAME_OR_PATH,
- STATE_START_PATH,
- STATE_PASSWORD,
- STATE_HOST_NAME,
- STATE_DONE,
- STATE_INVALID
-} split_state;
-
-static int rtems_ftpfs_split_names (
- char *s,
- const char **user,
- const char **password,
- const char **hostname,
- const char **path
-)
-{
- split_state state = STATE_USER_NAME;
- size_t len = strlen(s);
- size_t i = 0;
-
- *user = s;
-
- for (i = 0; i < len; ++i) {
- char c = s [i];
-
- switch (state) {
- case STATE_USER_NAME:
- if (c == ':') {
- state = STATE_START_PASSWORD;
- s [i] = '\0';
- } else if (c == '@') {
- state = STATE_START_HOST_NAME;
- s [i] = '\0';
- } else if (c == '/') {
- state = STATE_START_HOST_NAME_OR_PATH;
- s [i] = '\0';
- }
- break;
- case STATE_START_PASSWORD:
- state = STATE_PASSWORD;
- *password = &s [i];
- --i;
- break;
- case STATE_START_HOST_NAME:
- state = STATE_HOST_NAME;
- *hostname = &s [i];
- --i;
- break;
- case STATE_START_HOST_NAME_OR_PATH:
- if (c == '@') {
- state = STATE_START_HOST_NAME;
- } else {
- state = STATE_DONE;
- *path = &s [i];
- goto done;
- }
- break;
- case STATE_START_PATH:
- state = STATE_DONE;
- *path = &s [i];
- goto done;
- case STATE_PASSWORD:
- if (c == '@') {
- state = STATE_START_HOST_NAME;
- s [i] = '\0';
- } else if (c == '/') {
- state = STATE_START_HOST_NAME_OR_PATH;
- s [i] = '\0';
- }
- break;
- case STATE_HOST_NAME:
- if (c == '/') {
- state = STATE_START_PATH;
- s [i] = '\0';
- }
- break;
- default:
- state = STATE_INVALID;
- goto done;
- }
- }
-
-done:
-
- /* This is a special case with no username and password */
- if (*hostname == NULL) {
- *hostname = &s [0];
- *user = "anonymous";
- *password = *user;
- }
-
- /* If we have no password use the user name */
- if (*password == NULL) {
- *password = *user;
- }
-
- return state == STATE_DONE ? 0 : ENOENT;
-}
-
-static socklen_t rtems_ftpfs_create_address(
- struct sockaddr_in *sa,
- unsigned long address,
- unsigned short port
-)
-{
- memset(sa, 0, sizeof(*sa));
-
- sa->sin_family = AF_INET;
- sa->sin_addr.s_addr = address;
- sa->sin_port = port;
- sa->sin_len = sizeof(*sa);
-
- return sizeof(*sa);
-}
-
-static int rtems_ftpfs_close_data_connection(
- rtems_ftpfs_entry *e,
- bool verbose,
- bool error
-)
-{
- int eno = 0;
-
- /* Close data connection if necessary */
- if (e->data_socket >= 0) {
- int rv = close(e->data_socket);
-
- e->data_socket = -1;
- if (rv != 0) {
- eno = EIO;
- }
-
- /* For write connections we have to obtain the transfer reply */
- if (e->write && !error) {
- rtems_ftpfs_reply reply =
- rtems_ftpfs_get_reply(e, NULL, NULL, verbose);
-
- if (reply != RTEMS_FTPFS_REPLY_2) {
- eno = EIO;
- }
- }
- }
-
- return eno;
-}
-
-static int rtems_ftpfs_open_ctrl_connection(
- rtems_ftpfs_entry *e,
- bool verbose,
- const struct timeval *timeout
-)
-{
- int rv = 0;
- int eno = 0;
- rtems_ftpfs_reply reply = RTEMS_FTPFS_REPLY_ERROR;
- struct in_addr address = { .s_addr = 0 };
- struct sockaddr_in sa;
- socklen_t size = 0;
-
- /* Create the socket for the control connection */
- e->ctrl_socket = socket(AF_INET, SOCK_STREAM, 0);
- if (e->ctrl_socket < 0) {
- return ENOMEM;
- }
-
- /* Set up the server address from the hostname */
- if (inet_aton(e->hostname, &address) == 0) {
- /* Try to get the address by name */
- struct hostent *he = gethostbyname(e->hostname);
-
- if (he != NULL) {
- memcpy(&address, he->h_addr, sizeof(address));
- } else {
- return ENOENT;
- }
- }
- rtems_ftpfs_create_address(&sa, address.s_addr, htons(RTEMS_FTPFS_CTRL_PORT));
- DEBUG_PRINTF("server = %s\n", inet_ntoa(sa.sin_addr));
-
- /* Open control connection */
- rv = connect(
- e->ctrl_socket,
- (struct sockaddr *) &sa,
- sizeof(sa)
- );
- if (rv != 0) {
- return ENOENT;
- }
-
- /* Set control connection timeout */
- eno = rtems_ftpfs_set_connection_timeout(e->ctrl_socket, timeout);
- if (eno != 0) {
- return eno;
- }
-
- /* Get client address */
- size = rtems_ftpfs_create_address(&sa, INADDR_ANY, 0);
- rv = getsockname(
- e->ctrl_socket,
- (struct sockaddr *) &sa,
- &size
- );
- if (rv != 0) {
- return ENOMEM;
- }
- e->client_address = ntohl(sa.sin_addr.s_addr);
- DEBUG_PRINTF("client = %s\n", inet_ntoa(sa.sin_addr));
-
- /* Now we should get a welcome message from the server */
- reply = rtems_ftpfs_get_reply(e, NULL, NULL, verbose);
- if (reply != RTEMS_FTPFS_REPLY_2) {
- return ENOENT;
- }
-
- /* Send USER command */
- reply = rtems_ftpfs_send_command(e, "USER ", e->user, verbose);
- if (reply == RTEMS_FTPFS_REPLY_3) {
- /* Send PASS command */
- reply = rtems_ftpfs_send_command(e, "PASS ", e->password, verbose);
- if (reply != RTEMS_FTPFS_REPLY_2) {
- return EACCES;
- }
-
- /* TODO: Some server may require an account */
- } else if (reply != RTEMS_FTPFS_REPLY_2) {
- return EACCES;
- }
-
- /* Send TYPE command to set binary mode for all data transfers */
- reply = rtems_ftpfs_send_command(e, "TYPE I", NULL, verbose);
- if (reply != RTEMS_FTPFS_REPLY_2) {
- return EIO;
- }
-
- return 0;
-}
-
-static int rtems_ftpfs_open_data_connection_active(
- rtems_ftpfs_entry *e,
- const char *file_command,
- bool verbose,
- const struct timeval *timeout
-)
-{
- int rv = 0;
- int eno = 0;
- rtems_ftpfs_reply reply = RTEMS_FTPFS_REPLY_ERROR;
- struct sockaddr_in sa;
- socklen_t size = 0;
- int port_socket = -1;
- char port_command [] = "PORT 000,000,000,000,000,000";
- uint16_t data_port = 0;
-
- /* Create port socket to establish a data data connection */
- port_socket = socket(AF_INET, SOCK_STREAM, 0);
- if (port_socket < 0) {
- eno = ENOMEM;
- goto cleanup;
- }
-
- /* Bind port socket */
- rtems_ftpfs_create_address(&sa, INADDR_ANY, 0);
- rv = bind(
- port_socket,
- (struct sockaddr *) &sa,
- sizeof(sa)
- );
- if (rv != 0) {
- eno = EBUSY;
- goto cleanup;
- }
-
- /* Get port number for data socket */
- size = rtems_ftpfs_create_address(&sa, INADDR_ANY, 0);
- rv = getsockname(
- port_socket,
- (struct sockaddr *) &sa,
- &size
- );
- if (rv != 0) {
- eno = ENOMEM;
- goto cleanup;
- }
- data_port = ntohs(sa.sin_port);
-
- /* Send PORT command to set data connection port for server */
- snprintf(
- port_command,
- sizeof(port_command),
- "PORT %lu,%lu,%lu,%lu,%lu,%lu",
- (e->client_address >> 24) & 0xffUL,
- (e->client_address >> 16) & 0xffUL,
- (e->client_address >> 8) & 0xffUL,
- (e->client_address >> 0) & 0xffUL,
- (data_port >> 8) & 0xffUL,
- (data_port >> 0) & 0xffUL
- );
- reply = rtems_ftpfs_send_command(e, port_command, NULL, verbose);
- if (reply != RTEMS_FTPFS_REPLY_2) {
- eno = ENOTSUP;
- goto cleanup;
- }
-
- /* Listen on port socket for incoming data connections */
- rv = listen(port_socket, 1);
- if (rv != 0) {
- eno = EBUSY;
- goto cleanup;
- }
-
- /* Send RETR or STOR command with filename */
- reply = rtems_ftpfs_send_command(e, file_command, e->filename, verbose);
- if (reply != RTEMS_FTPFS_REPLY_1) {
- eno = EIO;
- goto cleanup;
- }
-
- /* Wait for connect on data connection if necessary */
- if (rtems_ftpfs_use_timeout(timeout)) {
- struct timeval to = *timeout;
- fd_set fds;
-
- FD_ZERO(&fds);
- FD_SET(port_socket, &fds);
-
- rv = select(port_socket + 1, &fds, NULL, NULL, &to);
- if (rv <= 0) {
- eno = EIO;
- goto cleanup;
- }
- }
-
- /* Accept data connection */
- size = sizeof(sa);
- e->data_socket = accept(
- port_socket,
- (struct sockaddr *) &sa,
- &size
- );
- if (e->data_socket < 0) {
- eno = EIO;
- goto cleanup;
- }
-
-cleanup:
-
- /* Close port socket if necessary */
- if (port_socket >= 0) {
- rv = close(port_socket);
- if (rv != 0) {
- eno = EIO;
- }
- }
-
- return eno;
-}
-
-typedef enum {
- RTEMS_FTPFS_PASV_START = 0,
- RTEMS_FTPFS_PASV_JUNK,
- RTEMS_FTPFS_PASV_DATA,
- RTEMS_FTPFS_PASV_DONE
-} rtems_ftpfs_pasv_state;
-
-typedef struct {
- rtems_ftpfs_pasv_state state;
- size_t index;
- uint8_t data [6];
-} rtems_ftpfs_pasv_entry;
-
-static void rtems_ftpfs_pasv_parser(
- const char* buf,
- size_t len,
- void *arg
-)
-{
- rtems_ftpfs_pasv_entry *pe = arg;
- size_t i = 0;
-
- for (i = 0; i < len; ++i) {
- int c = buf [i];
-
- switch (pe->state) {
- case RTEMS_FTPFS_PASV_START:
- if (!isdigit(c)) {
- pe->state = RTEMS_FTPFS_PASV_JUNK;
- pe->index = 0;
- }
- break;
- case RTEMS_FTPFS_PASV_JUNK:
- if (isdigit(c)) {
- pe->state = RTEMS_FTPFS_PASV_DATA;
- pe->data [pe->index] = (uint8_t) (c - '0');
- }
- break;
- case RTEMS_FTPFS_PASV_DATA:
- if (isdigit(c)) {
- pe->data [pe->index] =
- (uint8_t) (pe->data [pe->index] * 10 + c - '0');
- } else if (c == ',') {
- ++pe->index;
- if (pe->index < sizeof(pe->data)) {
- pe->data [pe->index] = 0;
- } else {
- pe->state = RTEMS_FTPFS_PASV_DONE;
- }
- } else {
- pe->state = RTEMS_FTPFS_PASV_DONE;
- }
- break;
- default:
- return;
- }
- }
-}
-
-static int rtems_ftpfs_open_data_connection_passive(
- rtems_ftpfs_entry *e,
- const char *file_command,
- bool verbose,
- const struct timeval *timeout
-)
-{
- int rv = 0;
- rtems_ftpfs_reply reply = RTEMS_FTPFS_REPLY_ERROR;
- struct sockaddr_in sa;
- uint32_t data_address = 0;
- uint16_t data_port = 0;
- rtems_ftpfs_pasv_entry pe;
-
- memset(&pe, 0, sizeof(pe));
-
- /* Send PASV command */
- reply = rtems_ftpfs_send_command_with_parser(
- e,
- "PASV",
- NULL,
- rtems_ftpfs_pasv_parser,
- &pe,
- verbose
- );
- if (reply != RTEMS_FTPFS_REPLY_2) {
- return ENOTSUP;
- }
- data_address = ((uint32_t)(pe.data [0]) << 24)
- + ((uint32_t)(pe.data [1]) << 16)
- + ((uint32_t)(pe.data [2]) << 8)
- + ((uint32_t)(pe.data [3]));
- data_port = (uint16_t) ((pe.data [4] << 8) + pe.data [5]);
- rtems_ftpfs_create_address(&sa, htonl(data_address), htons(data_port));
- DEBUG_PRINTF(
- "server data = %s:%u\n",
- inet_ntoa(sa.sin_addr),
- (unsigned) ntohs(sa.sin_port)
- );
-
- /* Create data socket */
- e->data_socket = socket(AF_INET, SOCK_STREAM, 0);
- if (e->data_socket < 0) {
- return ENOMEM;
- }
-
- /* Open data connection */
- rv = connect(
- e->data_socket,
- (struct sockaddr *) &sa,
- sizeof(sa)
- );
- if (rv != 0) {
- return EIO;
- }
-
- /* Send RETR or STOR command with filename */
- reply = rtems_ftpfs_send_command(e, file_command, e->filename, verbose);
- if (reply != RTEMS_FTPFS_REPLY_1) {
- return EIO;
- }
-
- return 0;
-}
-
-typedef enum {
- RTEMS_FTPFS_SIZE_START = 0,
- RTEMS_FTPFS_SIZE_SPACE,
- RTEMS_FTPFS_SIZE_NUMBER,
- RTEMS_FTPFS_SIZE_NL
-} rtems_ftpfs_size_state;
-
-typedef struct {
- rtems_ftpfs_size_state state;
- size_t index;
- off_t size;
-} rtems_ftpfs_size_entry;
-
-static void rtems_ftpfs_size_parser(
- const char* buf,
- size_t len,
- void *arg
-)
-{
- rtems_ftpfs_size_entry *se = arg;
- size_t i = 0;
-
- for (i = 0; se->size >= 0 && i < len; ++i, ++se->index) {
- int c = buf [i];
-
- switch (se->state) {
- case RTEMS_FTPFS_SIZE_START:
- if (se->index == 2) {
- se->state = RTEMS_FTPFS_SIZE_SPACE;
- }
- break;
- case RTEMS_FTPFS_SIZE_SPACE:
- if (c == ' ') {
- se->state = RTEMS_FTPFS_SIZE_NUMBER;
- } else {
- se->size = -1;
- }
- break;
- case RTEMS_FTPFS_SIZE_NUMBER:
- if (isdigit(c)) {
- se->size = 10 * se->size + c - '0';
- } else if (c == '\r') {
- se->state = RTEMS_FTPFS_SIZE_NL;
- } else {
- se->size = -1;
- }
- break;
- case RTEMS_FTPFS_SIZE_NL:
- if (c != '\n') {
- se->size = -1;
- }
- break;
- default:
- se->size = -1;
- break;
- }
- }
-}
-
-static void rtems_ftpfs_get_file_size(rtems_ftpfs_entry *e, bool verbose)
-{
- if (e->file_size < 0) {
- if (e->write) {
- e->file_size = 0;
- } else {
- rtems_ftpfs_size_entry se;
- rtems_ftpfs_reply reply = RTEMS_FTPFS_REPLY_ERROR;
-
- memset(&se, 0, sizeof(se));
-
- reply = rtems_ftpfs_send_command_with_parser(
- e,
- "SIZE ",
- e->filename,
- rtems_ftpfs_size_parser,
- &se,
- verbose
- );
- if (reply == RTEMS_FTPFS_REPLY_2 && se.size >= 0) {
- e->file_size = se.size;
- } else {
- e->file_size = 0;
- }
- }
- }
-}
-
-static int rtems_ftpfs_open(
- rtems_libio_t *iop,
- const char *path,
- int oflag,
- mode_t mode
-)
-{
- int eno = 0;
- rtems_ftpfs_entry *e = iop->pathinfo.node_access;
- rtems_ftpfs_mount_entry *me = iop->pathinfo.mt_entry->fs_info;
- bool verbose = me->verbose;
- const struct timeval *timeout = &me->timeout;
-
- e->write = rtems_libio_iop_is_writeable(iop);
-
- /* Check for either read-only or write-only flags */
- if (
- rtems_libio_iop_is_writeable(iop)
- && rtems_libio_iop_is_readable(iop)
- ) {
- eno = ENOTSUP;
- }
-
- if (eno == 0) {
- rtems_ftpfs_get_file_size(e, verbose);
- }
-
- if (eno == 0) {
- const char *file_command = e->write ? "STOR " : "RETR ";
-
- /* Open passive data connection */
- eno = rtems_ftpfs_open_data_connection_passive(
- e,
- file_command,
- verbose,
- timeout
- );
- if (eno == ENOTSUP) {
- /* Open active data connection */
- eno = rtems_ftpfs_open_data_connection_active(
- e,
- file_command,
- verbose,
- timeout
- );
- }
- }
-
- /* Set data connection timeout */
- if (eno == 0) {
- eno = rtems_ftpfs_set_connection_timeout(e->data_socket, timeout);
- }
-
- if (eno == 0) {
- return 0;
- } else {
- rtems_ftpfs_close_data_connection(e, verbose, true);
-
- rtems_set_errno_and_return_minus_one(eno);
- }
-}
-
-static ssize_t rtems_ftpfs_read(
- rtems_libio_t *iop,
- void *buffer,
- size_t count
-)
-{
- rtems_ftpfs_entry *e = iop->pathinfo.node_access;
- const rtems_ftpfs_mount_entry *me = iop->pathinfo.mt_entry->fs_info;
- bool verbose = me->verbose;
- char *in = buffer;
- size_t todo = count;
-
- if (e->eof) {
- return 0;
- }
-
- while (todo > 0) {
- ssize_t rv = recv(e->data_socket, in, todo, 0);
-
- if (rv <= 0) {
- if (rv == 0) {
- rtems_ftpfs_reply reply =
- rtems_ftpfs_get_reply(e, NULL, NULL, verbose);
-
- if (reply == RTEMS_FTPFS_REPLY_2) {
- e->eof = true;
- break;
- }
- }
-
- rtems_set_errno_and_return_minus_one(EIO);
- }
-
- in += rv;
- todo -= (size_t) rv;
- }
-
- return (ssize_t) (count - todo);
-}
-
-static ssize_t rtems_ftpfs_write(
- rtems_libio_t *iop,
- const void *buffer,
- size_t count
-)
-{
- rtems_ftpfs_entry *e = iop->pathinfo.node_access;
- const char *out = buffer;
- size_t todo = count;
-
- while (todo > 0) {
- ssize_t rv = send(e->data_socket, out, todo, 0);
-
- if (rv <= 0) {
- if (rv == 0) {
- break;
- } else {
- rtems_set_errno_and_return_minus_one(EIO);
- }
- }
-
- out += rv;
- todo -= (size_t) rv;
-
- e->file_size += rv;
- }
-
- return (ssize_t) (count - todo);
-}
-
-static int rtems_ftpfs_close(rtems_libio_t *iop)
-{
- rtems_ftpfs_entry *e = iop->pathinfo.node_access;
- const rtems_ftpfs_mount_entry *me = iop->pathinfo.mt_entry->fs_info;
- int eno = rtems_ftpfs_close_data_connection(e, me->verbose, false);
-
- if (eno == 0) {
- return 0;
- } else {
- rtems_set_errno_and_return_minus_one(eno);
- }
-}
-
-/* Dummy version to let fopen(*,"w") work properly */
-static int rtems_ftpfs_ftruncate(rtems_libio_t *iop, off_t count)
-{
- return 0;
-}
-
-static void rtems_ftpfs_eval_path(
- rtems_filesystem_eval_path_context_t *self
-)
-{
- int eno = 0;
-
- rtems_filesystem_eval_path_eat_delimiter(self);
-
- if (rtems_filesystem_eval_path_has_path(self)) {
- const char *path = rtems_filesystem_eval_path_get_path(self);
- size_t pathlen = rtems_filesystem_eval_path_get_pathlen(self);
- rtems_ftpfs_entry *e = calloc(1, sizeof(*e) + pathlen + 1);
-
- rtems_filesystem_eval_path_clear_path(self);
-
- if (e != NULL) {
- memcpy(e->buffer, path, pathlen);
-
- eno = rtems_ftpfs_split_names(
- e->buffer,
- &e->user,
- &e->password,
- &e->hostname,
- &e->filename
- );
-
- DEBUG_PRINTF(
- "user = '%s', password = '%s', filename = '%s'\n",
- e->user,
- e->password,
- e->filename
- );
-
- if (eno == 0) {
- rtems_filesystem_location_info_t *currentloc =
- rtems_filesystem_eval_path_get_currentloc(self);
- rtems_ftpfs_mount_entry *me = currentloc->mt_entry->fs_info;
-
- rtems_libio_lock();
- ++me->ino;
- e->ino = me->ino;
- rtems_libio_unlock();
-
- e->file_size = -1;
- e->ctrl_socket = -1;
-
- eno = rtems_ftpfs_open_ctrl_connection(
- e,
- me->verbose,
- &me->timeout
- );
- if (eno == 0) {
- currentloc->node_access = e;
- currentloc->handlers = &rtems_ftpfs_handlers;
- }
- }
-
- if (eno != 0) {
- free(e);
- }
- } else {
- eno = ENOMEM;
- }
- }
-
- if (eno != 0) {
- rtems_filesystem_eval_path_error(self, eno);
- }
-}
-
-static void rtems_ftpfs_free_node(const rtems_filesystem_location_info_t *loc)
-{
- rtems_ftpfs_entry *e = loc->node_access;
-
- /* The root node handler has no entry */
- if (e != NULL) {
- const rtems_ftpfs_mount_entry *me = loc->mt_entry->fs_info;
-
- /* Close control connection if necessary */
- if (e->ctrl_socket >= 0) {
- rtems_ftpfs_send_command(e, "QUIT", NULL, me->verbose);
-
- close(e->ctrl_socket);
- }
-
- free(e);
- }
-}
-
-int rtems_ftpfs_initialize(
- rtems_filesystem_mount_table_entry_t *e,
- const void *d
-)
-{
- rtems_ftpfs_mount_entry *me = calloc(1, sizeof(*me));
-
- /* Mount entry for FTP file system instance */
- e->fs_info = me;
- if (e->fs_info == NULL) {
- rtems_set_errno_and_return_minus_one(ENOMEM);
- }
- me->verbose = false;
- me->timeout.tv_sec = 0;
- me->timeout.tv_usec = 0;
-
- /* Set handler and oparations table */
- e->mt_fs_root->location.handlers = &rtems_ftpfs_root_handlers;
- e->ops = &rtems_ftpfs_ops;
-
- /* We maintain no real file system nodes, so there is no real root */
- e->mt_fs_root->location.node_access = NULL;
-
- return 0;
-}
-
-static void rtems_ftpfs_unmount_me(
- rtems_filesystem_mount_table_entry_t *e
-)
-{
- free(e->fs_info);
-}
-
-static int rtems_ftpfs_ioctl(
- rtems_libio_t *iop,
- ioctl_command_t command,
- void *arg
-)
-{
- rtems_ftpfs_mount_entry *me = iop->pathinfo.mt_entry->fs_info;
- bool *verbose = arg;
- struct timeval *timeout = arg;
-
- if (arg == NULL) {
- rtems_set_errno_and_return_minus_one(EINVAL);
- }
-
- switch (command) {
- case RTEMS_FTPFS_IOCTL_GET_VERBOSE:
- *verbose = me->verbose;
- break;
- case RTEMS_FTPFS_IOCTL_SET_VERBOSE:
- me->verbose = *verbose;
- break;
- case RTEMS_FTPFS_IOCTL_GET_TIMEOUT:
- *timeout = me->timeout;
- break;
- case RTEMS_FTPFS_IOCTL_SET_TIMEOUT:
- me->timeout = *timeout;
- break;
- default:
- rtems_set_errno_and_return_minus_one(EINVAL);
- }
-
- return 0;
-}
-
-/*
- * The stat() support is intended only for the cp shell command. Each request
- * will return that we have a regular file with read, write and execute
- * permissions for every one. The node index uses a global counter to support
- * a remote to remote copy. This is not a very sophisticated method.
- */
-static int rtems_ftpfs_fstat(
- const rtems_filesystem_location_info_t *loc,
- struct stat *st
-)
-{
- int eno = 0;
- rtems_ftpfs_entry *e = loc->node_access;
-
- /* FIXME */
- st->st_ino = e->ino;
- st->st_dev = rtems_filesystem_make_dev_t(0xcc494cd6U, 0x1d970b4dU);
-
- st->st_mode = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO;
-
- if (e->do_size_command) {
- const rtems_ftpfs_mount_entry *me = loc->mt_entry->fs_info;
-
- rtems_ftpfs_get_file_size(e, me->verbose);
- st->st_size = e->file_size;
- } else {
- e->do_size_command = true;
- }
-
- if (eno == 0) {
- return 0;
- } else {
- rtems_set_errno_and_return_minus_one(eno);
- }
-}
-
-static void rtems_ftpfs_lock_or_unlock(
- const rtems_filesystem_mount_table_entry_t *mt_entry
-)
-{
- /* Do nothing */
-}
-
-static const rtems_filesystem_operations_table rtems_ftpfs_ops = {
- .lock_h = rtems_ftpfs_lock_or_unlock,
- .unlock_h = rtems_ftpfs_lock_or_unlock,
- .eval_path_h = rtems_ftpfs_eval_path,
- .link_h = rtems_filesystem_default_link,
- .are_nodes_equal_h = rtems_filesystem_default_are_nodes_equal,
- .mknod_h = rtems_filesystem_default_mknod,
- .rmnod_h = rtems_filesystem_default_rmnod,
- .fchmod_h = rtems_filesystem_default_fchmod,
- .chown_h = rtems_filesystem_default_chown,
- .clonenod_h = rtems_filesystem_default_clonenode,
- .freenod_h = rtems_ftpfs_free_node,
- .mount_h = rtems_filesystem_default_mount,
- .unmount_h = rtems_filesystem_default_unmount,
- .fsunmount_me_h = rtems_ftpfs_unmount_me,
- .utime_h = rtems_filesystem_default_utime,
- .symlink_h = rtems_filesystem_default_symlink,
- .readlink_h = rtems_filesystem_default_readlink,
- .rename_h = rtems_filesystem_default_rename,
- .statvfs_h = rtems_filesystem_default_statvfs
-};
-
-static const rtems_filesystem_file_handlers_r rtems_ftpfs_handlers = {
- .open_h = rtems_ftpfs_open,
- .close_h = rtems_ftpfs_close,
- .read_h = rtems_ftpfs_read,
- .write_h = rtems_ftpfs_write,
- .ioctl_h = rtems_filesystem_default_ioctl,
- .lseek_h = rtems_filesystem_default_lseek,
- .fstat_h = rtems_ftpfs_fstat,
- .ftruncate_h = rtems_ftpfs_ftruncate,
- .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
- .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
- .fcntl_h = rtems_filesystem_default_fcntl,
- .kqfilter_h = rtems_filesystem_default_kqfilter,
- .mmap_h = rtems_filesystem_default_mmap,
- .poll_h = rtems_filesystem_default_poll,
- .readv_h = rtems_filesystem_default_readv,
- .writev_h = rtems_filesystem_default_writev
-};
-
-static const rtems_filesystem_file_handlers_r rtems_ftpfs_root_handlers = {
- .open_h = rtems_filesystem_default_open,
- .close_h = rtems_filesystem_default_close,
- .read_h = rtems_filesystem_default_read,
- .write_h = rtems_filesystem_default_write,
- .ioctl_h = rtems_ftpfs_ioctl,
- .lseek_h = rtems_filesystem_default_lseek,
- .fstat_h = rtems_filesystem_default_fstat,
- .ftruncate_h = rtems_filesystem_default_ftruncate,
- .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
- .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
- .fcntl_h = rtems_filesystem_default_fcntl,
- .kqfilter_h = rtems_filesystem_default_kqfilter,
- .mmap_h = rtems_filesystem_default_mmap,
- .poll_h = rtems_filesystem_default_poll,
- .readv_h = rtems_filesystem_default_readv,
- .writev_h = rtems_filesystem_default_writev
-};
diff --git a/cpukit/libnetworking/lib/tftpDriver.c b/cpukit/libnetworking/lib/tftpDriver.c
deleted file mode 100644
index 7cbb402b63..0000000000
--- a/cpukit/libnetworking/lib/tftpDriver.c
+++ /dev/null
@@ -1,1066 +0,0 @@
-/*
- * Trivial File Transfer Protocol (RFC 1350)
- *
- * Transfer file to/from remote host
- *
- * W. Eric Norum
- * Saskatchewan Accelerator Laboratory
- * University of Saskatchewan
- * Saskatoon, Saskatchewan, CANADA
- * eric@skatter.usask.ca
- *
- * Modifications to support reference counting in the file system are
- * Copyright (c) 2012 embedded brains GmbH.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <malloc.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <rtems.h>
-#include <rtems/libio_.h>
-#include <rtems/seterr.h>
-#include <rtems/tftp.h>
-#include <rtems/thread.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-
-#ifdef RTEMS_NETWORKING
-#include <rtems/rtems_bsdnet.h>
-#endif
-
-#ifdef RTEMS_TFTP_DRIVER_DEBUG
-int rtems_tftp_driver_debug = 1;
-#endif
-
-/*
- * Range of UDP ports to try
- */
-#define UDP_PORT_BASE 3180
-
-/*
- * Default limits
- */
-#define PACKET_FIRST_TIMEOUT_MILLISECONDS 400L
-#define PACKET_TIMEOUT_MILLISECONDS 6000L
-#define OPEN_RETRY_LIMIT 10
-#define IO_RETRY_LIMIT 10
-
-/*
- * TFTP opcodes
- */
-#define TFTP_OPCODE_RRQ 1
-#define TFTP_OPCODE_WRQ 2
-#define TFTP_OPCODE_DATA 3
-#define TFTP_OPCODE_ACK 4
-#define TFTP_OPCODE_ERROR 5
-
-/*
- * Largest data transfer
- */
-#define TFTP_BUFSIZE 512
-
-/*
- * Packets transferred between machines
- */
-union tftpPacket {
- /*
- * RRQ/WRQ packet
- */
- struct tftpRWRQ {
- uint16_t opcode;
- char filename_mode[TFTP_BUFSIZE];
- } tftpRWRQ;
-
- /*
- * DATA packet
- */
- struct tftpDATA {
- uint16_t opcode;
- uint16_t blocknum;
- uint8_t data[TFTP_BUFSIZE];
- } tftpDATA;
-
- /*
- * ACK packet
- */
- struct tftpACK {
- uint16_t opcode;
- uint16_t blocknum;
- } tftpACK;
-
- /*
- * ERROR packet
- */
- struct tftpERROR {
- uint16_t opcode;
- uint16_t errorCode;
- char errorMessage[TFTP_BUFSIZE];
- } tftpERROR;
-};
-
-/*
- * State of each TFTP stream
- */
-struct tftpStream {
- /*
- * Buffer for storing most recently-received packet
- */
- union tftpPacket pkbuf;
-
- /*
- * Last block number transferred
- */
- uint16_t blocknum;
-
- /*
- * Data transfer socket
- */
- int socket;
- struct sockaddr_in myAddress;
- struct sockaddr_in farAddress;
-
- /*
- * Indices into buffer
- */
- int nleft;
- int nused;
-
- /*
- * Flags
- */
- int firstReply;
- int eof;
- int writing;
-};
-
-/*
- * Flags for filesystem info.
- */
-#define TFTPFS_VERBOSE (1 << 0)
-
-/*
- * TFTP File system info.
- */
-typedef struct tftpfs_info_s {
- uint32_t flags;
- rtems_mutex tftp_mutex;
- int nStreams;
- struct tftpStream ** volatile tftpStreams;
-} tftpfs_info_t;
-
-#define tftpfs_info_mount_table(_mt) ((tftpfs_info_t*) ((_mt)->fs_info))
-#define tftpfs_info_pathloc(_pl) ((tftpfs_info_t*) ((_pl)->mt_entry->fs_info))
-#define tftpfs_info_iop(_iop) (tftpfs_info_pathloc (&((_iop)->pathinfo)))
-
-/*
- * Number of streams open at the same time
- */
-
-static const rtems_filesystem_operations_table rtems_tftp_ops;
-static const rtems_filesystem_file_handlers_r rtems_tftp_handlers;
-
-static bool rtems_tftp_is_directory(
- const char *path,
- size_t pathlen
-)
-{
- return path [pathlen - 1] == '/';
-}
-
-int rtems_tftpfs_initialize(
- rtems_filesystem_mount_table_entry_t *mt_entry,
- const void *data
-)
-{
- const char *device = mt_entry->dev;
- size_t devicelen = strlen (device);
- tftpfs_info_t *fs = NULL;
- char *root_path;
-
- if (devicelen == 0) {
- root_path = malloc (1);
- if (root_path == NULL)
- goto error;
- root_path [0] = '\0';
- }
- else {
- root_path = malloc (devicelen + 2);
- if (root_path == NULL)
- goto error;
-
- root_path = memcpy (root_path, device, devicelen);
- root_path [devicelen] = '/';
- root_path [devicelen + 1] = '\0';
- }
-
- fs = malloc (sizeof (*fs));
- if (fs == NULL)
- goto error;
- fs->flags = 0;
- fs->nStreams = 0;
- fs->tftpStreams = 0;
-
- mt_entry->fs_info = fs;
- mt_entry->mt_fs_root->location.node_access = root_path;
- mt_entry->mt_fs_root->location.handlers = &rtems_tftp_handlers;
- mt_entry->ops = &rtems_tftp_ops;
-
- /*
- * Now allocate a semaphore for mutual exclusion.
- *
- * NOTE: This could be in an fsinfo for this filesystem type.
- */
-
- rtems_mutex_init (&fs->tftp_mutex, "TFTPFS");
-
- if (data) {
- char* config = (char*) data;
- char* token;
- char* saveptr;
- token = strtok_r (config, " ", &saveptr);
- while (token) {
- if (strcmp (token, "verbose") == 0)
- fs->flags |= TFTPFS_VERBOSE;
- token = strtok_r (NULL, " ", &saveptr);
- }
- }
-
- return 0;
-
-error:
-
- free (fs);
- free (root_path);
-
- rtems_set_errno_and_return_minus_one (ENOMEM);
-}
-
-/*
- * Release a stream and clear the pointer to it
- */
-static void
-releaseStream (tftpfs_info_t *fs, int s)
-{
- if (fs->tftpStreams[s] && (fs->tftpStreams[s]->socket >= 0))
- close (fs->tftpStreams[s]->socket);
- rtems_mutex_lock (&fs->tftp_mutex);
- free (fs->tftpStreams[s]);
- fs->tftpStreams[s] = NULL;
- rtems_mutex_unlock (&fs->tftp_mutex);
-}
-
-static void
-rtems_tftpfs_shutdown (rtems_filesystem_mount_table_entry_t* mt_entry)
-{
- tftpfs_info_t *fs = tftpfs_info_mount_table (mt_entry);
- int s;
- for (s = 0; s < fs->nStreams; s++)
- releaseStream (fs, s);
- rtems_mutex_destroy (&fs->tftp_mutex);
- free (fs);
- free (mt_entry->mt_fs_root->location.node_access);
-}
-
-/*
- * Map error message
- */
-static int
-tftpErrno (struct tftpStream *tp)
-{
- unsigned int tftpError;
- static const int errorMap[] = {
- EINVAL,
- ENOENT,
- EPERM,
- ENOSPC,
- EINVAL,
- ENXIO,
- EEXIST,
- ESRCH,
- };
-
- tftpError = ntohs (tp->pkbuf.tftpERROR.errorCode);
- if (tftpError < (sizeof errorMap / sizeof errorMap[0]))
- return errorMap[tftpError];
- else
- return 1000 + tftpError;
-}
-
-/*
- * Send a message to make the other end shut up
- */
-static void
-sendStifle (struct tftpStream *tp, struct sockaddr_in *to)
-{
- int len;
- struct {
- uint16_t opcode;
- uint16_t errorCode;
- char errorMessage[12];
- } msg;
-
- /*
- * Create the error packet (Unknown transfer ID).
- */
- msg.opcode = htons (TFTP_OPCODE_ERROR);
- msg.errorCode = htons (5);
- len = sizeof msg.opcode + sizeof msg.errorCode + 1;
- len += sprintf (msg.errorMessage, "GO AWAY");
-
- /*
- * Send it
- */
- sendto (tp->socket, (char *)&msg, len, 0, (struct sockaddr *)to, sizeof *to);
-}
-
-/*
- * Wait for a data packet
- */
-static int
-getPacket (struct tftpStream *tp, int retryCount)
-{
- int len;
- struct timeval tv;
-
- if (retryCount == 0) {
- tv.tv_sec = PACKET_FIRST_TIMEOUT_MILLISECONDS / 1000L;
- tv.tv_usec = (PACKET_FIRST_TIMEOUT_MILLISECONDS % 1000L) * 1000L;
- }
- else {
- tv.tv_sec = PACKET_TIMEOUT_MILLISECONDS / 1000L;
- tv.tv_usec = (PACKET_TIMEOUT_MILLISECONDS % 1000L) * 1000L;
- }
- setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
- for (;;) {
- union {
- struct sockaddr s;
- struct sockaddr_in i;
- } from;
- socklen_t fromlen = sizeof from;
- len = recvfrom (tp->socket, &tp->pkbuf,
- sizeof tp->pkbuf, 0,
- &from.s, &fromlen);
- if (len < 0)
- break;
- if (from.i.sin_addr.s_addr == tp->farAddress.sin_addr.s_addr) {
- if (tp->firstReply) {
- tp->firstReply = 0;
- tp->farAddress.sin_port = from.i.sin_port;
- }
- if (tp->farAddress.sin_port == from.i.sin_port)
- break;
- }
-
- /*
- * Packet is from someone with whom we are
- * not interested. Tell them to go away.
- */
- sendStifle (tp, &from.i);
- }
- tv.tv_sec = 0;
- tv.tv_usec = 0;
- setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv);
-#ifdef RTEMS_TFTP_DRIVER_DEBUG
- if (rtems_tftp_driver_debug) {
- if (len >= (int) sizeof tp->pkbuf.tftpACK) {
- int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
- switch (opcode) {
- default:
- printf ("TFTP: OPCODE %d\n", opcode);
- break;
-
- case TFTP_OPCODE_DATA:
- printf ("TFTP: RECV %d\n", ntohs (tp->pkbuf.tftpDATA.blocknum));
- break;
-
- case TFTP_OPCODE_ACK:
- printf ("TFTP: GOT ACK %d\n", ntohs (tp->pkbuf.tftpACK.blocknum));
- break;
- }
- }
- else {
- printf ("TFTP: %d-byte packet\n", len);
- }
- }
-#endif
- return len;
-}
-
-/*
- * Send an acknowledgement
- */
-static int
-sendAck (struct tftpStream *tp)
-{
-#ifdef RTEMS_TFTP_DRIVER_DEBUG
- if (rtems_tftp_driver_debug)
- printf ("TFTP: ACK %d\n", tp->blocknum);
-#endif
-
- /*
- * Create the acknowledgement
- */
- tp->pkbuf.tftpACK.opcode = htons (TFTP_OPCODE_ACK);
- tp->pkbuf.tftpACK.blocknum = htons (tp->blocknum);
-
- /*
- * Send it
- */
- if (sendto (tp->socket, (char *)&tp->pkbuf, sizeof tp->pkbuf.tftpACK, 0,
- (struct sockaddr *)&tp->farAddress,
- sizeof tp->farAddress) < 0)
- return errno;
- return 0;
-}
-
-/*
- * Convert a path to canonical form
- */
-static void
-fixPath (char *path)
-{
- char *inp, *outp, *base;
-
- outp = inp = path;
- base = NULL;
- for (;;) {
- if (inp[0] == '.') {
- if (inp[1] == '\0')
- break;
- if (inp[1] == '/') {
- inp += 2;
- continue;
- }
- if (inp[1] == '.') {
- if (inp[2] == '\0') {
- if ((base != NULL) && (outp > base)) {
- outp--;
- while ((outp > base) && (outp[-1] != '/'))
- outp--;
- }
- break;
- }
- if (inp[2] == '/') {
- inp += 3;
- if (base == NULL)
- continue;
- if (outp > base) {
- outp--;
- while ((outp > base) && (outp[-1] != '/'))
- outp--;
- }
- continue;
- }
- }
- }
- if (base == NULL)
- base = inp;
- while (inp[0] != '/') {
- if ((*outp++ = *inp++) == '\0')
- return;
- }
- *outp++ = '/';
- while (inp[0] == '/')
- inp++;
- }
- *outp = '\0';
- return;
-}
-
-static void rtems_tftp_eval_path(rtems_filesystem_eval_path_context_t *self)
-{
- int eval_flags = rtems_filesystem_eval_path_get_flags (self);
-
- if ((eval_flags & RTEMS_FS_MAKE) == 0) {
- int rw = RTEMS_FS_PERMS_READ | RTEMS_FS_PERMS_WRITE;
-
- if ((eval_flags & rw) != rw) {
- rtems_filesystem_location_info_t *currentloc =
- rtems_filesystem_eval_path_get_currentloc (self);
- char *current = currentloc->node_access;
- size_t currentlen = strlen (current);
- const char *path = rtems_filesystem_eval_path_get_path (self);
- size_t pathlen = rtems_filesystem_eval_path_get_pathlen (self);
- size_t len = currentlen + pathlen;
-
- rtems_filesystem_eval_path_clear_path (self);
-
- current = realloc (current, len + 1);
- if (current != NULL) {
- memcpy (current + currentlen, path, pathlen);
- current [len] = '\0';
- if (!rtems_tftp_is_directory (current, len)) {
- fixPath (current);
- }
- currentloc->node_access = current;
- } else {
- rtems_filesystem_eval_path_error (self, ENOMEM);
- }
- } else {
- rtems_filesystem_eval_path_error (self, EINVAL);
- }
- } else {
- rtems_filesystem_eval_path_error (self, EIO);
- }
-}
-
-/*
- * The routine which does most of the work for the IMFS open handler
- */
-static int rtems_tftp_open_worker(
- rtems_libio_t *iop,
- char *full_path_name,
- int oflag
-)
-{
- tftpfs_info_t *fs;
- struct tftpStream *tp;
- int retryCount;
- struct in_addr farAddress;
- int s;
- int len;
- char *cp1;
- char *cp2;
- char *remoteFilename;
- rtems_interval now;
- char *hostname;
-
- /*
- * Get the file system info.
- */
- fs = tftpfs_info_iop (iop);
-
- /*
- * Extract the host name component
- */
- if (*full_path_name == '/')
- full_path_name++;
-
- hostname = full_path_name;
- cp1 = strchr (full_path_name, ':');
- if (!cp1) {
-#ifdef RTEMS_NETWORKING
- hostname = "BOOTP_HOST";
-#endif
- } else {
- *cp1 = '\0';
- ++cp1;
- }
-
- /*
- * Convert hostname to Internet address
- */
-#ifdef RTEMS_NETWORKING
- if (strcmp (hostname, "BOOTP_HOST") == 0)
- farAddress = rtems_bsdnet_bootp_server_address;
- else
-#endif
- if (inet_aton (hostname, &farAddress) == 0) {
- struct hostent *he = gethostbyname(hostname);
- if (he == NULL)
- return ENOENT;
- memcpy (&farAddress, he->h_addr, sizeof (farAddress));
- }
-
- /*
- * Extract file pathname component
- */
-#ifdef RTEMS_NETWORKING
- if (strcmp (cp1, "BOOTP_FILE") == 0) {
- cp1 = rtems_bsdnet_bootp_boot_file_name;
- }
-#endif
- if (*cp1 == '\0')
- return ENOENT;
- remoteFilename = cp1;
- if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
- return ENOENT;
-
- /*
- * Find a free stream
- */
- rtems_mutex_lock (&fs->tftp_mutex);
- for (s = 0 ; s < fs->nStreams ; s++) {
- if (fs->tftpStreams[s] == NULL)
- break;
- }
- if (s == fs->nStreams) {
- /*
- * Reallocate stream pointers
- * Guard against the case where realloc() returns NULL.
- */
- struct tftpStream **np;
-
- np = realloc (fs->tftpStreams, ++fs->nStreams * sizeof *fs->tftpStreams);
- if (np == NULL) {
- rtems_mutex_unlock (&fs->tftp_mutex);
- return ENOMEM;
- }
- fs->tftpStreams = np;
- }
- tp = fs->tftpStreams[s] = malloc (sizeof (struct tftpStream));
- rtems_mutex_unlock (&fs->tftp_mutex);
- if (tp == NULL)
- return ENOMEM;
- iop->data0 = s;
- iop->data1 = tp;
-
- /*
- * Create the socket
- */
- if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
- releaseStream (fs, s);
- return ENOMEM;
- }
-
- /*
- * Bind the socket to a local address
- */
- retryCount = 0;
- now = rtems_clock_get_ticks_since_boot();
- for (;;) {
- int try = (now + retryCount) % 10;
-
- tp->myAddress.sin_family = AF_INET;
- tp->myAddress.sin_port = htons (UDP_PORT_BASE + fs->nStreams * try + s);
- tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
- if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
- break;
- if (++retryCount == 10) {
- releaseStream (fs, s);
- return EBUSY;
- }
- }
-
- /*
- * Set the UDP destination to the TFTP server
- * port on the remote machine.
- */
- tp->farAddress.sin_family = AF_INET;
- tp->farAddress.sin_addr = farAddress;
- tp->farAddress.sin_port = htons (69);
-
- /*
- * Start the transfer
- */
- tp->firstReply = 1;
- retryCount = 0;
- for (;;) {
- /*
- * Create the request
- */
- if ((oflag & O_ACCMODE) == O_RDONLY) {
- tp->writing = 0;
- tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
- }
- else {
- tp->writing = 1;
- tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_WRQ);
- }
- cp1 = (char *) tp->pkbuf.tftpRWRQ.filename_mode;
- cp2 = (char *) remoteFilename;
- while ((*cp1++ = *cp2++) != '\0')
- continue;
- cp2 = "octet";
- while ((*cp1++ = *cp2++) != '\0')
- continue;
- len = cp1 - (char *)&tp->pkbuf.tftpRWRQ;
-
- /*
- * Send the request
- */
- if (sendto (tp->socket, (char *)&tp->pkbuf, len, 0,
- (struct sockaddr *)&tp->farAddress,
- sizeof tp->farAddress) < 0) {
- releaseStream (fs, s);
- return EIO;
- }
-
- /*
- * Get reply
- */
- len = getPacket (tp, retryCount);
- if (len >= (int) sizeof tp->pkbuf.tftpACK) {
- int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
- if (!tp->writing
- && (opcode == TFTP_OPCODE_DATA)
- && (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) {
- tp->nused = 0;
- tp->blocknum = 1;
- tp->nleft = len - 2 * sizeof (uint16_t );
- tp->eof = (tp->nleft < TFTP_BUFSIZE);
- if (sendAck (tp) != 0) {
- releaseStream (fs, s);
- return EIO;
- }
- break;
- }
- if (tp->writing
- && (opcode == TFTP_OPCODE_ACK)
- && (ntohs (tp->pkbuf.tftpACK.blocknum) == 0)) {
- tp->nused = 0;
- tp->blocknum = 1;
- break;
- }
- if (opcode == TFTP_OPCODE_ERROR) {
- int e = tftpErrno (tp);
- releaseStream (fs, s);
- return e;
- }
- }
-
- /*
- * Keep trying
- */
- if (++retryCount >= OPEN_RETRY_LIMIT) {
- releaseStream (fs, s);
- return EIO;
- }
- }
- return 0;
-}
-
-static int rtems_tftp_open(
- rtems_libio_t *iop,
- const char *new_name,
- int oflag,
- mode_t mode
-)
-{
- tftpfs_info_t *fs;
- char *full_path_name;
- int err;
-
- full_path_name = iop->pathinfo.node_access;
-
- if (rtems_tftp_is_directory (full_path_name, strlen (full_path_name))) {
- rtems_set_errno_and_return_minus_one (ENOTSUP);
- }
-
- /*
- * Get the file system info.
- */
- fs = tftpfs_info_iop (iop);
-
- if (fs->flags & TFTPFS_VERBOSE)
- printf ("TFTPFS: %s\n", full_path_name);
-
- err = rtems_tftp_open_worker (iop, full_path_name, oflag);
- if (err != 0) {
- rtems_set_errno_and_return_minus_one (err);
- }
-
- return 0;
-}
-
-/*
- * Read from a TFTP stream
- */
-static ssize_t rtems_tftp_read(
- rtems_libio_t *iop,
- void *buffer,
- size_t count
-)
-{
- char *bp;
- struct tftpStream *tp = iop->data1;
- int retryCount;
- int nwant;
-
- if (!tp)
- rtems_set_errno_and_return_minus_one( EIO );
-
- /*
- * Read till user request is satisfied or EOF is reached
- */
- bp = buffer;
- nwant = count;
- while (nwant) {
- if (tp->nleft) {
- int ncopy;
- if (nwant < tp->nleft)
- ncopy = nwant;
- else
- ncopy = tp->nleft;
- memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], ncopy);
- tp->nused += ncopy;
- tp->nleft -= ncopy;
- bp += ncopy;
- nwant -= ncopy;
- if (nwant == 0)
- break;
- }
- if (tp->eof)
- break;
-
- /*
- * Wait for the next packet
- */
- retryCount = 0;
- for (;;) {
- int len = getPacket (tp, retryCount);
- if (len >= (int)sizeof tp->pkbuf.tftpACK) {
- int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
- uint16_t nextBlock = tp->blocknum + 1;
- if ((opcode == TFTP_OPCODE_DATA)
- && (ntohs (tp->pkbuf.tftpDATA.blocknum) == nextBlock)) {
- tp->nused = 0;
- tp->nleft = len - 2 * sizeof (uint16_t);
- tp->eof = (tp->nleft < TFTP_BUFSIZE);
- tp->blocknum++;
- if (sendAck (tp) != 0)
- rtems_set_errno_and_return_minus_one (EIO);
- break;
- }
- if (opcode == TFTP_OPCODE_ERROR)
- rtems_set_errno_and_return_minus_one (tftpErrno (tp));
- }
-
- /*
- * Keep trying?
- */
- if (++retryCount == IO_RETRY_LIMIT)
- rtems_set_errno_and_return_minus_one (EIO);
- if (sendAck (tp) != 0)
- rtems_set_errno_and_return_minus_one (EIO);
- }
- }
- return count - nwant;
-}
-
-/*
- * Flush a write buffer and wait for acknowledgement
- */
-static int rtems_tftp_flush (struct tftpStream *tp)
-{
- int wlen, rlen;
- int retryCount = 0;
-
- wlen = tp->nused + 2 * sizeof (uint16_t );
- for (;;) {
- tp->pkbuf.tftpDATA.opcode = htons (TFTP_OPCODE_DATA);
- tp->pkbuf.tftpDATA.blocknum = htons (tp->blocknum);
-#ifdef RTEMS_TFTP_DRIVER_DEBUG
- if (rtems_tftp_driver_debug)
- printf ("TFTP: SEND %d (%d)\n", tp->blocknum, tp->nused);
-#endif
- if (sendto (tp->socket, (char *)&tp->pkbuf, wlen, 0,
- (struct sockaddr *)&tp->farAddress,
- sizeof tp->farAddress) < 0)
- return EIO;
- rlen = getPacket (tp, retryCount);
- /*
- * Our last packet won't necessarily be acknowledged!
- */
- if ((rlen < 0) && (tp->nused < sizeof tp->pkbuf.tftpDATA.data))
- return 0;
- if (rlen >= (int)sizeof tp->pkbuf.tftpACK) {
- int opcode = ntohs (tp->pkbuf.tftpACK.opcode);
- if ((opcode == TFTP_OPCODE_ACK)
- && (ntohs (tp->pkbuf.tftpACK.blocknum) == tp->blocknum)) {
- tp->nused = 0;
- tp->blocknum++;
- return 0;
- }
- if (opcode == TFTP_OPCODE_ERROR)
- return tftpErrno (tp);
- }
-
- /*
- * Keep trying?
- */
- if (++retryCount == IO_RETRY_LIMIT)
- return EIO;
- }
-}
-
-/*
- * Close a TFTP stream
- */
-static int rtems_tftp_close(
- rtems_libio_t *iop
-)
-{
- tftpfs_info_t *fs;
- struct tftpStream *tp = iop->data1;
- int e = 0;
-
- /*
- * Get the file system info.
- */
- fs = tftpfs_info_iop (iop);
-
- if (!tp)
- rtems_set_errno_and_return_minus_one (EIO);
-
- if (tp->writing)
- e = rtems_tftp_flush (tp);
- if (!tp->eof && !tp->firstReply) {
- /*
- * Tell the other end to stop
- */
- rtems_interval ticksPerSecond;
- sendStifle (tp, &tp->farAddress);
- ticksPerSecond = rtems_clock_get_ticks_per_second();
- rtems_task_wake_after (1 + ticksPerSecond / 10);
- }
- releaseStream (fs, iop->data0);
- if (e)
- rtems_set_errno_and_return_minus_one (e);
- return 0;
-}
-
-static ssize_t rtems_tftp_write(
- rtems_libio_t *iop,
- const void *buffer,
- size_t count
-)
-{
- const char *bp;
- struct tftpStream *tp = iop->data1;
- int nleft, nfree, ncopy;
-
- /*
- * Bail out if an error has occurred
- */
- if (!tp->writing)
- rtems_set_errno_and_return_minus_one (EIO);
-
- /*
- * Write till user request is satisfied
- * Notice that the buffer is flushed as soon as it is filled rather
- * than waiting for the next write or a close. This ensures that
- * the flush in close writes a less than full buffer so the far
- * end can detect the end-of-file condition.
- */
- bp = buffer;
- nleft = count;
- while (nleft) {
- nfree = sizeof tp->pkbuf.tftpDATA.data - tp->nused;
- if (nleft < nfree)
- ncopy = nleft;
- else
- ncopy = nfree;
- memcpy (&tp->pkbuf.tftpDATA.data[tp->nused], bp, ncopy);
- tp->nused += ncopy;
- nleft -= ncopy;
- bp += ncopy;
- if (tp->nused == sizeof tp->pkbuf.tftpDATA.data) {
- int e = rtems_tftp_flush (tp);
- if (e) {
- tp->writing = 0;
- rtems_set_errno_and_return_minus_one (e);
- }
- }
- }
- return count;
-}
-
-/*
- * Dummy version to let fopen(xxxx,"w") work properly.
- */
-static int rtems_tftp_ftruncate(
- rtems_libio_t *iop RTEMS_UNUSED,
- off_t count RTEMS_UNUSED
-)
-{
- return 0;
-}
-
-static int rtems_tftp_fstat(
- const rtems_filesystem_location_info_t *loc,
- struct stat *buf
-)
-{
- const char *path = loc->node_access;
- size_t pathlen = strlen (path);
-
- buf->st_mode = S_IRWXU | S_IRWXG | S_IRWXO
- | (rtems_tftp_is_directory (path, pathlen) ? S_IFDIR : S_IFREG);
-
- return 0;
-}
-
-static int rtems_tftp_clone(
- rtems_filesystem_location_info_t *loc
-)
-{
- int rv = 0;
-
- loc->node_access = strdup (loc->node_access);
-
- if (loc->node_access == NULL) {
- errno = ENOMEM;
- rv = -1;
- }
-
- return rv;
-}
-
-static void rtems_tftp_free_node_info(
- const rtems_filesystem_location_info_t *loc
-)
-{
- free (loc->node_access);
-}
-
-static bool rtems_tftp_are_nodes_equal(
- const rtems_filesystem_location_info_t *a,
- const rtems_filesystem_location_info_t *b
-)
-{
- return strcmp (a->node_access, b->node_access) == 0;
-}
-
-static const rtems_filesystem_operations_table rtems_tftp_ops = {
- .lock_h = rtems_filesystem_default_lock,
- .unlock_h = rtems_filesystem_default_unlock,
- .eval_path_h = rtems_tftp_eval_path,
- .link_h = rtems_filesystem_default_link,
- .are_nodes_equal_h = rtems_tftp_are_nodes_equal,
- .mknod_h = rtems_filesystem_default_mknod,
- .rmnod_h = rtems_filesystem_default_rmnod,
- .fchmod_h = rtems_filesystem_default_fchmod,
- .chown_h = rtems_filesystem_default_chown,
- .clonenod_h = rtems_tftp_clone,
- .freenod_h = rtems_tftp_free_node_info,
- .mount_h = rtems_filesystem_default_mount,
- .unmount_h = rtems_filesystem_default_unmount,
- .fsunmount_me_h = rtems_tftpfs_shutdown,
- .utime_h = rtems_filesystem_default_utime,
- .symlink_h = rtems_filesystem_default_symlink,
- .readlink_h = rtems_filesystem_default_readlink,
- .rename_h = rtems_filesystem_default_rename,
- .statvfs_h = rtems_filesystem_default_statvfs
-};
-
-static const rtems_filesystem_file_handlers_r rtems_tftp_handlers = {
- .open_h = rtems_tftp_open,
- .close_h = rtems_tftp_close,
- .read_h = rtems_tftp_read,
- .write_h = rtems_tftp_write,
- .ioctl_h = rtems_filesystem_default_ioctl,
- .lseek_h = rtems_filesystem_default_lseek,
- .fstat_h = rtems_tftp_fstat,
- .ftruncate_h = rtems_tftp_ftruncate,
- .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
- .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
- .fcntl_h = rtems_filesystem_default_fcntl,
- .kqfilter_h = rtems_filesystem_default_kqfilter,
- .mmap_h = rtems_filesystem_default_mmap,
- .poll_h = rtems_filesystem_default_poll,
- .readv_h = rtems_filesystem_default_readv,
- .writev_h = rtems_filesystem_default_writev
-};