forked from Imagelibrary/rtems
Debugged and now works except for handling of minor number.
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <rtems.h>
|
#include <rtems.h>
|
||||||
#include <rtems/libio.h>
|
#include <rtems/libio.h>
|
||||||
#include <rtems/rtems_bsdnet.h>
|
#include <rtems/rtems_bsdnet.h>
|
||||||
@@ -139,35 +140,65 @@ struct tftpStream {
|
|||||||
/*
|
/*
|
||||||
* Number of streams open at the same time
|
* Number of streams open at the same time
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static rtems_id tftp_mutex;
|
static rtems_id tftp_mutex;
|
||||||
static int nStreams;
|
static int nStreams;
|
||||||
static struct tftpStream ** volatile tftpStreams;
|
static struct tftpStream ** volatile tftpStreams;
|
||||||
|
|
||||||
typedef struct {
|
typedef const char *tftp_node;
|
||||||
rtems_id tftp_mutex;
|
extern rtems_filesystem_operations_table rtems_tftp_ops;
|
||||||
int nStreams;
|
extern rtems_filesystem_file_handlers_r rtems_tftp_handlers;
|
||||||
struct tftpStream ** volatile tftpStreams;
|
|
||||||
rtems_filesystem_mount_table_entry_t *mt_entry;
|
/*
|
||||||
} tftp_fs_info;
|
* Direct copy from the IMFS. Look at this.
|
||||||
|
*/
|
||||||
|
|
||||||
|
rtems_filesystem_limits_and_options_t rtems_tftp_limits_and_options = {
|
||||||
|
5, /* link_max */
|
||||||
|
6, /* max_canon */
|
||||||
|
7, /* max_input */
|
||||||
|
255, /* name_max */
|
||||||
|
255, /* path_max */
|
||||||
|
2, /* pipe_buf */
|
||||||
|
1, /* posix_async_io */
|
||||||
|
2, /* posix_chown_restrictions */
|
||||||
|
3, /* posix_no_trunc */
|
||||||
|
4, /* posix_prio_io */
|
||||||
|
5, /* posix_sync_io */
|
||||||
|
6 /* posix_vdisable */
|
||||||
|
};
|
||||||
|
|
||||||
int rtems_tftp_mount_me(
|
int rtems_tftp_mount_me(
|
||||||
rtems_filesystem_mount_table_entry_t *temp_mt_entry
|
rtems_filesystem_mount_table_entry_t *temp_mt_entry
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
tftp_fs_info *fs_info;
|
|
||||||
rtems_status_code sc;
|
rtems_status_code sc;
|
||||||
|
|
||||||
|
temp_mt_entry->mt_fs_root.handlers = &rtems_tftp_handlers;
|
||||||
|
temp_mt_entry->mt_fs_root.ops = &rtems_tftp_ops;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate stuff for this file system.
|
* We have no tftp filesystem specific data to maintain. This
|
||||||
|
* filesystem may only be mounted ONCE.
|
||||||
|
*
|
||||||
|
* And we maintain no real filesystem nodes, so there is no real root.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fs_info = calloc( 1, sizeof( tftp_fs_info ));
|
temp_mt_entry->fs_info = NULL;
|
||||||
if ( !fs_info )
|
temp_mt_entry->mt_fs_root.node_access = NULL;
|
||||||
set_errno_and_return_minus_one( ENOMEM );
|
|
||||||
|
|
||||||
temp_mt_entry->fs_info = fs_info;
|
/*
|
||||||
temp_mt_entry->mt_fs_root.node_access = fs_info;
|
* These need to be looked at for full POSIX semantics.
|
||||||
|
*/
|
||||||
|
|
||||||
|
temp_mt_entry->pathconf_limits_and_options = rtems_tftp_limits_and_options;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now allocate a semaphore for mutual exclusion.
|
||||||
|
*
|
||||||
|
* NOTE: This could be in an fsinfo for this filesystem type.
|
||||||
|
*/
|
||||||
|
|
||||||
sc = rtems_semaphore_create (
|
sc = rtems_semaphore_create (
|
||||||
rtems_build_name('T', 'F', 'T', 'P'),
|
rtems_build_name('T', 'F', 'T', 'P'),
|
||||||
@@ -178,11 +209,11 @@ int rtems_tftp_mount_me(
|
|||||||
RTEMS_NO_PRIORITY_CEILING |
|
RTEMS_NO_PRIORITY_CEILING |
|
||||||
RTEMS_LOCAL,
|
RTEMS_LOCAL,
|
||||||
0,
|
0,
|
||||||
&fs_info->tftp_mutex
|
&tftp_mutex
|
||||||
);
|
);
|
||||||
|
|
||||||
if (sc != RTEMS_SUCCESSFUL)
|
if (sc != RTEMS_SUCCESSFUL)
|
||||||
set_errno_and_return_minus_one( ENOMEM ); /* ??? */
|
set_errno_and_return_minus_one( ENOMEM );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -190,18 +221,28 @@ int rtems_tftp_mount_me(
|
|||||||
/*
|
/*
|
||||||
* Initialize the TFTP driver
|
* Initialize the TFTP driver
|
||||||
*/
|
*/
|
||||||
/* XXX change name to rtems_bsdnet_initialize_tftp_filesystem ("mountpt") */
|
|
||||||
/* XXX this won't be a driver when we are finished */
|
|
||||||
rtems_device_driver rtems_tftp_initialize(
|
|
||||||
rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *pargp
|
|
||||||
)
|
|
||||||
{
|
|
||||||
|
|
||||||
/* XXX change to a mount */
|
int rtems_bsdnet_initialize_tftp_filesystem ()
|
||||||
rtems_io_register_name (TFTP_PATHNAME_PREFIX, major, minor);
|
{
|
||||||
return RTEMS_SUCCESSFUL;
|
int status;
|
||||||
|
rtems_filesystem_mount_table_entry_t *entry;
|
||||||
|
|
||||||
|
status = mkdir( TFTP_PATHNAME_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO );
|
||||||
|
if ( status == -1 )
|
||||||
|
return status;
|
||||||
|
|
||||||
|
status = mount(
|
||||||
|
&entry,
|
||||||
|
&rtems_tftp_ops,
|
||||||
|
"RO",
|
||||||
|
NULL,
|
||||||
|
TFTP_PATHNAME_PREFIX
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( status )
|
||||||
|
perror( "TFTP mount failed" );
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -340,36 +381,61 @@ int rtems_tftp_evaluate_for_make(
|
|||||||
{
|
{
|
||||||
set_errno_and_return_minus_one( EIO );
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX - Fix return values.
|
* XXX - Fix return values.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int TFTP_eval_path(
|
int rtems_tftp_eval_path(
|
||||||
const char *pathname, /* IN */
|
const char *pathname, /* IN */
|
||||||
int flags, /* IN */
|
int flags, /* IN */
|
||||||
rtems_filesystem_location_info_t *pathloc /* IN/OUT */
|
rtems_filesystem_location_info_t *pathloc /* IN/OUT */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read-only for now
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( (flags & O_WRONLY) == O_WRONLY )
|
||||||
|
set_errno_and_return_minus_one( ENOENT );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The File system is mounted at TFTP_PATHNAME_PREFIX
|
||||||
|
* the caller of this routine has striped off this part of the
|
||||||
|
* name. Save the remainder of the name for use by the open routine.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pathloc->node_access = (void * ) pathname;
|
||||||
|
pathloc->handlers = &rtems_tftp_handlers;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int rtems_tftp_open(
|
||||||
|
rtems_libio_t *iop,
|
||||||
|
const char *new_name,
|
||||||
|
unsigned32 flag,
|
||||||
|
unsigned32 mode
|
||||||
|
)
|
||||||
|
{
|
||||||
|
struct tftpStream *tp;
|
||||||
|
int retryCount;
|
||||||
rtems_unsigned32 farAddress;
|
rtems_unsigned32 farAddress;
|
||||||
|
int s;
|
||||||
int len;
|
int len;
|
||||||
const char *remoteFilename;
|
char *cp1;
|
||||||
|
char *cp2;
|
||||||
tftp_fs_info *fs_info;
|
char *remoteFilename;
|
||||||
const char *cp1, *cp2;
|
rtems_interval now;
|
||||||
|
rtems_status_code sc;
|
||||||
fs_info = pathloc->node_access;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pick apart the name into a host:pathname pair
|
* This came from the evaluate path.
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* XXX - I think this is handled by the caller of
|
|
||||||
* the evaluate routine. ? Am I starting at the right
|
|
||||||
* place?
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
cp2 = pathname+1;
|
cp2 = iop->file_info;
|
||||||
|
|
||||||
if (*cp2 == '/') {
|
if (*cp2 == '/') {
|
||||||
farAddress = rtems_bsdnet_bootp_server_address.s_addr;
|
farAddress = rtems_bsdnet_bootp_server_address.s_addr;
|
||||||
}
|
}
|
||||||
@@ -379,67 +445,44 @@ int TFTP_eval_path(
|
|||||||
cp1 = cp2;
|
cp1 = cp2;
|
||||||
while (*cp2 != '/') {
|
while (*cp2 != '/') {
|
||||||
if (*cp2 == '\0')
|
if (*cp2 == '\0')
|
||||||
return RTEMS_INVALID_NAME;
|
set_errno_and_return_minus_one( ENOENT );
|
||||||
cp2++;
|
cp2++;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = cp2 - cp1;
|
len = cp2 - cp1;
|
||||||
hostname = malloc (len + 1);
|
hostname = malloc (len + 1);
|
||||||
if (hostname == NULL)
|
if (hostname == NULL)
|
||||||
return RTEMS_NO_MEMORY;
|
set_errno_and_return_minus_one( ENOMEM );
|
||||||
|
|
||||||
strncpy (hostname, cp1, len);
|
strncpy (hostname, cp1, len);
|
||||||
hostname[len] = '\0';
|
hostname[len] = '\0';
|
||||||
farAddress = inet_addr (hostname);
|
farAddress = inet_addr (hostname);
|
||||||
free (hostname);
|
free (hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((farAddress == 0) || (farAddress == ~0))
|
if ((farAddress == 0) || (farAddress == ~0))
|
||||||
return RTEMS_INVALID_NAME;
|
set_errno_and_return_minus_one( ENOENT );
|
||||||
|
|
||||||
if (*++cp2 == '\0')
|
if (*++cp2 == '\0')
|
||||||
return RTEMS_INVALID_NAME;
|
set_errno_and_return_minus_one( ENOENT );
|
||||||
|
|
||||||
remoteFilename = cp2;
|
remoteFilename = cp2;
|
||||||
if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
|
if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
|
||||||
return RTEMS_INVALID_NAME;
|
set_errno_and_return_minus_one( ENOENT );
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Open a TFTP stream
|
|
||||||
*/
|
|
||||||
rtems_device_driver rtems_tftp_open(
|
|
||||||
rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *pargp
|
|
||||||
)
|
|
||||||
{
|
|
||||||
rtems_libio_open_close_args_t *ap = pargp;
|
|
||||||
struct tftpStream *tp;
|
|
||||||
int retryCount;
|
|
||||||
rtems_unsigned32 farAddress = 0; /* XXX - node parameter */
|
|
||||||
int s;
|
|
||||||
int len;
|
|
||||||
char *cp1, *cp2;
|
|
||||||
char *remoteFilename = NULL; /* XXX - node parameter */
|
|
||||||
rtems_interval now;
|
|
||||||
rtems_status_code sc;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read-only for now
|
|
||||||
*/
|
|
||||||
/* XXX - Move to the open routine */
|
|
||||||
if (ap->flags & LIBIO_FLAGS_WRITE)
|
|
||||||
return RTEMS_NOT_IMPLEMENTED;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find a free stream
|
* Find a free stream
|
||||||
*/
|
*/
|
||||||
|
|
||||||
sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||||
if (sc != RTEMS_SUCCESSFUL)
|
if (sc != RTEMS_SUCCESSFUL)
|
||||||
return sc;
|
set_errno_and_return_minus_one( EBUSY );
|
||||||
|
|
||||||
for (s = 0 ; s < nStreams ; s++) {
|
for (s = 0 ; s < nStreams ; s++) {
|
||||||
if (tftpStreams[s] == NULL)
|
if (tftpStreams[s] == NULL)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s == nStreams) {
|
if (s == nStreams) {
|
||||||
/*
|
/*
|
||||||
* Reallocate stream pointers
|
* Reallocate stream pointers
|
||||||
@@ -450,42 +493,52 @@ rtems_device_driver rtems_tftp_open(
|
|||||||
np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);
|
np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);
|
||||||
if (np == NULL) {
|
if (np == NULL) {
|
||||||
rtems_semaphore_release (tftp_mutex);
|
rtems_semaphore_release (tftp_mutex);
|
||||||
return RTEMS_NO_MEMORY;
|
set_errno_and_return_minus_one( ENOMEM );
|
||||||
}
|
}
|
||||||
tftpStreams = np;
|
tftpStreams = np;
|
||||||
}
|
}
|
||||||
|
|
||||||
tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));
|
tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));
|
||||||
rtems_semaphore_release (tftp_mutex);
|
rtems_semaphore_release (tftp_mutex);
|
||||||
if (tp == NULL)
|
if (tp == NULL)
|
||||||
return RTEMS_NO_MEMORY;
|
set_errno_and_return_minus_one( ENOMEM );
|
||||||
ap->iop->data0 = s;
|
iop->data0 = s;
|
||||||
ap->iop->data1 = tp;
|
iop->data1 = tp;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the socket
|
* Create the socket
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
|
if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||||
releaseStream (s);
|
releaseStream (s);
|
||||||
return RTEMS_TOO_MANY;
|
set_errno_and_return_minus_one( ENOMEM );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bind the socket to a local address
|
* Bind the socket to a local address
|
||||||
*/
|
*/
|
||||||
|
|
||||||
retryCount = 0;
|
retryCount = 0;
|
||||||
rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
|
rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int try = (now + retryCount) % 10;
|
int try = (now + retryCount) % 10;
|
||||||
|
|
||||||
tp->myAddress.sin_family = AF_INET;
|
tp->myAddress.sin_family = AF_INET;
|
||||||
tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + minor);
|
/*
|
||||||
|
* XXX Eric .. how do we get the minor information???
|
||||||
|
* tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + minor);
|
||||||
|
*/
|
||||||
|
tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try);
|
||||||
tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
|
tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
|
||||||
if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
|
if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
|
||||||
break;
|
break;
|
||||||
if (++retryCount == 10) {
|
if (++retryCount == 10) {
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
|
/*
|
||||||
|
* XXX Eric .. how do we get the minor information to release this???
|
||||||
releaseStream (minor);
|
releaseStream (minor);
|
||||||
return RTEMS_RESOURCE_IN_USE;
|
*/
|
||||||
|
set_errno_and_return_minus_one( EBUSY );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,8 +559,12 @@ rtems_device_driver rtems_tftp_open(
|
|||||||
* Create the request
|
* Create the request
|
||||||
*/
|
*/
|
||||||
tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
|
tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
|
||||||
cp1 = tp->pkbuf.tftpRWRQ.filename_mode;
|
/*
|
||||||
cp2 = remoteFilename;
|
* XXX Eric .. is this cast taking the const off right?
|
||||||
|
*/
|
||||||
|
|
||||||
|
cp1 = (char *) tp->pkbuf.tftpRWRQ.filename_mode;
|
||||||
|
cp2 = (char *) remoteFilename;
|
||||||
while ((*cp1++ = *cp2++) != '\0')
|
while ((*cp1++ = *cp2++) != '\0')
|
||||||
continue;
|
continue;
|
||||||
cp2 = "octet";
|
cp2 = "octet";
|
||||||
@@ -522,8 +579,11 @@ rtems_device_driver rtems_tftp_open(
|
|||||||
(struct sockaddr *)&tp->farAddress,
|
(struct sockaddr *)&tp->farAddress,
|
||||||
sizeof tp->farAddress) < 0) {
|
sizeof tp->farAddress) < 0) {
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
|
/*
|
||||||
|
* XXX Eric .. how do we get the minor information to release this???
|
||||||
releaseStream (minor);
|
releaseStream (minor);
|
||||||
return RTEMS_UNSATISFIED;
|
*/
|
||||||
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -540,16 +600,23 @@ rtems_device_driver rtems_tftp_open(
|
|||||||
tp->eof = (tp->nleft < TFTP_BUFSIZE);
|
tp->eof = (tp->nleft < TFTP_BUFSIZE);
|
||||||
if (sendAck (tp) != 0) {
|
if (sendAck (tp) != 0) {
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
|
/*
|
||||||
|
* XXX Eric .. how do we get the minor information to release this???
|
||||||
releaseStream (minor);
|
releaseStream (minor);
|
||||||
return RTEMS_UNSATISFIED;
|
*/
|
||||||
|
|
||||||
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (opcode == TFTP_OPCODE_ERROR) {
|
if (opcode == TFTP_OPCODE_ERROR) {
|
||||||
tftpSetErrno (tp);
|
tftpSetErrno (tp);
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
releaseStream (ap->iop->data0);
|
/*
|
||||||
return RTEMS_INTERNAL_ERROR;
|
* XXX Eric .. how do we get the minor information to release this???
|
||||||
|
* releaseStream (minor);
|
||||||
|
*/
|
||||||
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -558,35 +625,40 @@ rtems_device_driver rtems_tftp_open(
|
|||||||
*/
|
*/
|
||||||
if (++retryCount >= OPEN_RETRY_LIMIT) {
|
if (++retryCount >= OPEN_RETRY_LIMIT) {
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
|
/*
|
||||||
|
* XXX Eric .. how do we get the minor information to release this???
|
||||||
releaseStream (minor);
|
releaseStream (minor);
|
||||||
return RTEMS_UNSATISFIED;
|
*/
|
||||||
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return RTEMS_SUCCESSFUL;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read from a TFTP stream
|
* Read from a TFTP stream
|
||||||
*/
|
*/
|
||||||
rtems_device_driver rtems_tftp_read(
|
|
||||||
rtems_device_major_number major,
|
int rtems_tftp_read(
|
||||||
rtems_device_minor_number minor,
|
rtems_libio_t *iop,
|
||||||
void *pargp
|
void *buffer,
|
||||||
|
unsigned32 count
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
rtems_libio_rw_args_t *ap = pargp;
|
|
||||||
char *bp;
|
char *bp;
|
||||||
struct tftpStream *tp;
|
struct tftpStream *tp;
|
||||||
int retryCount;
|
int retryCount;
|
||||||
int nwant;
|
int nwant;
|
||||||
|
|
||||||
tp = ap->iop->data1;
|
tp = iop->data1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read till user request is satisfied or EOF is reached
|
* Read till user request is satisfied or EOF is reached
|
||||||
*/
|
*/
|
||||||
bp = ap->buffer;
|
|
||||||
nwant = ap->count;
|
bp = buffer;
|
||||||
|
nwant = count;
|
||||||
while (nwant) {
|
while (nwant) {
|
||||||
if (tp->nleft) {
|
if (tp->nleft) {
|
||||||
int count;
|
int count;
|
||||||
@@ -621,7 +693,7 @@ rtems_device_driver rtems_tftp_read(
|
|||||||
tp->eof = (tp->nleft < TFTP_BUFSIZE);
|
tp->eof = (tp->nleft < TFTP_BUFSIZE);
|
||||||
tp->blocknum++;
|
tp->blocknum++;
|
||||||
if (sendAck (tp) != 0)
|
if (sendAck (tp) != 0)
|
||||||
return RTEMS_IO_ERROR;
|
set_errno_and_return_minus_one( EIO );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (opcode == TFTP_OPCODE_ERROR) {
|
if (opcode == TFTP_OPCODE_ERROR) {
|
||||||
@@ -634,26 +706,27 @@ rtems_device_driver rtems_tftp_read(
|
|||||||
* Keep trying?
|
* Keep trying?
|
||||||
*/
|
*/
|
||||||
if (++retryCount == IO_RETRY_LIMIT)
|
if (++retryCount == IO_RETRY_LIMIT)
|
||||||
return RTEMS_IO_ERROR;
|
set_errno_and_return_minus_one( EIO );
|
||||||
if (sendAck (tp) != 0)
|
if (sendAck (tp) != 0)
|
||||||
return RTEMS_IO_ERROR;
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ap->bytes_moved = ap->count - nwant;
|
|
||||||
return RTEMS_SUCCESSFUL;
|
/*
|
||||||
|
* XXX - Eric is this right?
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
return count - nwant;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close a TFTP stream
|
* Close a TFTP stream
|
||||||
*/
|
*/
|
||||||
rtems_device_driver rtems_tftp_close(
|
int rtems_tftp_close(
|
||||||
rtems_device_major_number major,
|
rtems_libio_t *iop
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *pargp
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
rtems_libio_open_close_args_t *ap = pargp;
|
struct tftpStream *tp = iop->data1;;
|
||||||
struct tftpStream *tp = ap->iop->data1;;
|
|
||||||
|
|
||||||
if (!tp->eof && !tp->firstReply) {
|
if (!tp->eof && !tp->firstReply) {
|
||||||
/*
|
/*
|
||||||
@@ -665,14 +738,14 @@ rtems_device_driver rtems_tftp_close(
|
|||||||
rtems_task_wake_after (1 + ticksPerSecond / 10);
|
rtems_task_wake_after (1 + ticksPerSecond / 10);
|
||||||
}
|
}
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
releaseStream (ap->iop->data0);
|
releaseStream (iop->data0);
|
||||||
return RTEMS_SUCCESSFUL;
|
return RTEMS_SUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtems_device_driver rtems_tftp_write(
|
int rtems_tftp_write(
|
||||||
rtems_device_major_number major,
|
rtems_libio_t *iop,
|
||||||
rtems_device_minor_number minor,
|
const void *buffer,
|
||||||
void *pargp
|
unsigned32 count
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return RTEMS_NOT_CONFIGURED;
|
return RTEMS_NOT_CONFIGURED;
|
||||||
@@ -686,3 +759,46 @@ rtems_device_driver rtems_tftp_control(
|
|||||||
{
|
{
|
||||||
return RTEMS_NOT_CONFIGURED;
|
return RTEMS_NOT_CONFIGURED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rtems_filesystem_node_types_t rtems_tftp_node_type(
|
||||||
|
rtems_filesystem_location_info_t *pathloc /* IN */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return RTEMS_FILESYSTEM_MEMORY_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rtems_filesystem_operations_table rtems_tftp_ops = {
|
||||||
|
rtems_tftp_eval_path, /* eval_path */
|
||||||
|
rtems_tftp_evaluate_for_make, /* evaluate_for_make */
|
||||||
|
NULL, /* link */
|
||||||
|
NULL, /* unlink */
|
||||||
|
rtems_tftp_node_type, /* node_type */
|
||||||
|
NULL, /* mknod */
|
||||||
|
NULL, /* rmnod */
|
||||||
|
NULL, /* chown */
|
||||||
|
NULL, /* freenodinfo */
|
||||||
|
NULL, /* mount */
|
||||||
|
rtems_tftp_mount_me, /* initialize */
|
||||||
|
NULL, /* unmount */
|
||||||
|
NULL, /* fsunmount */
|
||||||
|
NULL, /* utime, */
|
||||||
|
NULL, /* evaluate_link */
|
||||||
|
NULL, /* symlink */
|
||||||
|
NULL, /* readlin */
|
||||||
|
};
|
||||||
|
|
||||||
|
rtems_filesystem_file_handlers_r rtems_tftp_handlers = {
|
||||||
|
rtems_tftp_open,
|
||||||
|
rtems_tftp_close,
|
||||||
|
rtems_tftp_read,
|
||||||
|
rtems_tftp_write,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <rtems.h>
|
#include <rtems.h>
|
||||||
#include <rtems/libio.h>
|
#include <rtems/libio.h>
|
||||||
#include <rtems/rtems_bsdnet.h>
|
#include <rtems/rtems_bsdnet.h>
|
||||||
@@ -139,35 +140,65 @@ struct tftpStream {
|
|||||||
/*
|
/*
|
||||||
* Number of streams open at the same time
|
* Number of streams open at the same time
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static rtems_id tftp_mutex;
|
static rtems_id tftp_mutex;
|
||||||
static int nStreams;
|
static int nStreams;
|
||||||
static struct tftpStream ** volatile tftpStreams;
|
static struct tftpStream ** volatile tftpStreams;
|
||||||
|
|
||||||
typedef struct {
|
typedef const char *tftp_node;
|
||||||
rtems_id tftp_mutex;
|
extern rtems_filesystem_operations_table rtems_tftp_ops;
|
||||||
int nStreams;
|
extern rtems_filesystem_file_handlers_r rtems_tftp_handlers;
|
||||||
struct tftpStream ** volatile tftpStreams;
|
|
||||||
rtems_filesystem_mount_table_entry_t *mt_entry;
|
/*
|
||||||
} tftp_fs_info;
|
* Direct copy from the IMFS. Look at this.
|
||||||
|
*/
|
||||||
|
|
||||||
|
rtems_filesystem_limits_and_options_t rtems_tftp_limits_and_options = {
|
||||||
|
5, /* link_max */
|
||||||
|
6, /* max_canon */
|
||||||
|
7, /* max_input */
|
||||||
|
255, /* name_max */
|
||||||
|
255, /* path_max */
|
||||||
|
2, /* pipe_buf */
|
||||||
|
1, /* posix_async_io */
|
||||||
|
2, /* posix_chown_restrictions */
|
||||||
|
3, /* posix_no_trunc */
|
||||||
|
4, /* posix_prio_io */
|
||||||
|
5, /* posix_sync_io */
|
||||||
|
6 /* posix_vdisable */
|
||||||
|
};
|
||||||
|
|
||||||
int rtems_tftp_mount_me(
|
int rtems_tftp_mount_me(
|
||||||
rtems_filesystem_mount_table_entry_t *temp_mt_entry
|
rtems_filesystem_mount_table_entry_t *temp_mt_entry
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
tftp_fs_info *fs_info;
|
|
||||||
rtems_status_code sc;
|
rtems_status_code sc;
|
||||||
|
|
||||||
|
temp_mt_entry->mt_fs_root.handlers = &rtems_tftp_handlers;
|
||||||
|
temp_mt_entry->mt_fs_root.ops = &rtems_tftp_ops;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate stuff for this file system.
|
* We have no tftp filesystem specific data to maintain. This
|
||||||
|
* filesystem may only be mounted ONCE.
|
||||||
|
*
|
||||||
|
* And we maintain no real filesystem nodes, so there is no real root.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fs_info = calloc( 1, sizeof( tftp_fs_info ));
|
temp_mt_entry->fs_info = NULL;
|
||||||
if ( !fs_info )
|
temp_mt_entry->mt_fs_root.node_access = NULL;
|
||||||
set_errno_and_return_minus_one( ENOMEM );
|
|
||||||
|
|
||||||
temp_mt_entry->fs_info = fs_info;
|
/*
|
||||||
temp_mt_entry->mt_fs_root.node_access = fs_info;
|
* These need to be looked at for full POSIX semantics.
|
||||||
|
*/
|
||||||
|
|
||||||
|
temp_mt_entry->pathconf_limits_and_options = rtems_tftp_limits_and_options;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now allocate a semaphore for mutual exclusion.
|
||||||
|
*
|
||||||
|
* NOTE: This could be in an fsinfo for this filesystem type.
|
||||||
|
*/
|
||||||
|
|
||||||
sc = rtems_semaphore_create (
|
sc = rtems_semaphore_create (
|
||||||
rtems_build_name('T', 'F', 'T', 'P'),
|
rtems_build_name('T', 'F', 'T', 'P'),
|
||||||
@@ -178,11 +209,11 @@ int rtems_tftp_mount_me(
|
|||||||
RTEMS_NO_PRIORITY_CEILING |
|
RTEMS_NO_PRIORITY_CEILING |
|
||||||
RTEMS_LOCAL,
|
RTEMS_LOCAL,
|
||||||
0,
|
0,
|
||||||
&fs_info->tftp_mutex
|
&tftp_mutex
|
||||||
);
|
);
|
||||||
|
|
||||||
if (sc != RTEMS_SUCCESSFUL)
|
if (sc != RTEMS_SUCCESSFUL)
|
||||||
set_errno_and_return_minus_one( ENOMEM ); /* ??? */
|
set_errno_and_return_minus_one( ENOMEM );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -190,18 +221,28 @@ int rtems_tftp_mount_me(
|
|||||||
/*
|
/*
|
||||||
* Initialize the TFTP driver
|
* Initialize the TFTP driver
|
||||||
*/
|
*/
|
||||||
/* XXX change name to rtems_bsdnet_initialize_tftp_filesystem ("mountpt") */
|
|
||||||
/* XXX this won't be a driver when we are finished */
|
|
||||||
rtems_device_driver rtems_tftp_initialize(
|
|
||||||
rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *pargp
|
|
||||||
)
|
|
||||||
{
|
|
||||||
|
|
||||||
/* XXX change to a mount */
|
int rtems_bsdnet_initialize_tftp_filesystem ()
|
||||||
rtems_io_register_name (TFTP_PATHNAME_PREFIX, major, minor);
|
{
|
||||||
return RTEMS_SUCCESSFUL;
|
int status;
|
||||||
|
rtems_filesystem_mount_table_entry_t *entry;
|
||||||
|
|
||||||
|
status = mkdir( TFTP_PATHNAME_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO );
|
||||||
|
if ( status == -1 )
|
||||||
|
return status;
|
||||||
|
|
||||||
|
status = mount(
|
||||||
|
&entry,
|
||||||
|
&rtems_tftp_ops,
|
||||||
|
"RO",
|
||||||
|
NULL,
|
||||||
|
TFTP_PATHNAME_PREFIX
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( status )
|
||||||
|
perror( "TFTP mount failed" );
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -340,36 +381,61 @@ int rtems_tftp_evaluate_for_make(
|
|||||||
{
|
{
|
||||||
set_errno_and_return_minus_one( EIO );
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX - Fix return values.
|
* XXX - Fix return values.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int TFTP_eval_path(
|
int rtems_tftp_eval_path(
|
||||||
const char *pathname, /* IN */
|
const char *pathname, /* IN */
|
||||||
int flags, /* IN */
|
int flags, /* IN */
|
||||||
rtems_filesystem_location_info_t *pathloc /* IN/OUT */
|
rtems_filesystem_location_info_t *pathloc /* IN/OUT */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read-only for now
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( (flags & O_WRONLY) == O_WRONLY )
|
||||||
|
set_errno_and_return_minus_one( ENOENT );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The File system is mounted at TFTP_PATHNAME_PREFIX
|
||||||
|
* the caller of this routine has striped off this part of the
|
||||||
|
* name. Save the remainder of the name for use by the open routine.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pathloc->node_access = (void * ) pathname;
|
||||||
|
pathloc->handlers = &rtems_tftp_handlers;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int rtems_tftp_open(
|
||||||
|
rtems_libio_t *iop,
|
||||||
|
const char *new_name,
|
||||||
|
unsigned32 flag,
|
||||||
|
unsigned32 mode
|
||||||
|
)
|
||||||
|
{
|
||||||
|
struct tftpStream *tp;
|
||||||
|
int retryCount;
|
||||||
rtems_unsigned32 farAddress;
|
rtems_unsigned32 farAddress;
|
||||||
|
int s;
|
||||||
int len;
|
int len;
|
||||||
const char *remoteFilename;
|
char *cp1;
|
||||||
|
char *cp2;
|
||||||
tftp_fs_info *fs_info;
|
char *remoteFilename;
|
||||||
const char *cp1, *cp2;
|
rtems_interval now;
|
||||||
|
rtems_status_code sc;
|
||||||
fs_info = pathloc->node_access;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pick apart the name into a host:pathname pair
|
* This came from the evaluate path.
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* XXX - I think this is handled by the caller of
|
|
||||||
* the evaluate routine. ? Am I starting at the right
|
|
||||||
* place?
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
cp2 = pathname+1;
|
cp2 = iop->file_info;
|
||||||
|
|
||||||
if (*cp2 == '/') {
|
if (*cp2 == '/') {
|
||||||
farAddress = rtems_bsdnet_bootp_server_address.s_addr;
|
farAddress = rtems_bsdnet_bootp_server_address.s_addr;
|
||||||
}
|
}
|
||||||
@@ -379,67 +445,44 @@ int TFTP_eval_path(
|
|||||||
cp1 = cp2;
|
cp1 = cp2;
|
||||||
while (*cp2 != '/') {
|
while (*cp2 != '/') {
|
||||||
if (*cp2 == '\0')
|
if (*cp2 == '\0')
|
||||||
return RTEMS_INVALID_NAME;
|
set_errno_and_return_minus_one( ENOENT );
|
||||||
cp2++;
|
cp2++;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = cp2 - cp1;
|
len = cp2 - cp1;
|
||||||
hostname = malloc (len + 1);
|
hostname = malloc (len + 1);
|
||||||
if (hostname == NULL)
|
if (hostname == NULL)
|
||||||
return RTEMS_NO_MEMORY;
|
set_errno_and_return_minus_one( ENOMEM );
|
||||||
|
|
||||||
strncpy (hostname, cp1, len);
|
strncpy (hostname, cp1, len);
|
||||||
hostname[len] = '\0';
|
hostname[len] = '\0';
|
||||||
farAddress = inet_addr (hostname);
|
farAddress = inet_addr (hostname);
|
||||||
free (hostname);
|
free (hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((farAddress == 0) || (farAddress == ~0))
|
if ((farAddress == 0) || (farAddress == ~0))
|
||||||
return RTEMS_INVALID_NAME;
|
set_errno_and_return_minus_one( ENOENT );
|
||||||
|
|
||||||
if (*++cp2 == '\0')
|
if (*++cp2 == '\0')
|
||||||
return RTEMS_INVALID_NAME;
|
set_errno_and_return_minus_one( ENOENT );
|
||||||
|
|
||||||
remoteFilename = cp2;
|
remoteFilename = cp2;
|
||||||
if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
|
if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
|
||||||
return RTEMS_INVALID_NAME;
|
set_errno_and_return_minus_one( ENOENT );
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Open a TFTP stream
|
|
||||||
*/
|
|
||||||
rtems_device_driver rtems_tftp_open(
|
|
||||||
rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *pargp
|
|
||||||
)
|
|
||||||
{
|
|
||||||
rtems_libio_open_close_args_t *ap = pargp;
|
|
||||||
struct tftpStream *tp;
|
|
||||||
int retryCount;
|
|
||||||
rtems_unsigned32 farAddress = 0; /* XXX - node parameter */
|
|
||||||
int s;
|
|
||||||
int len;
|
|
||||||
char *cp1, *cp2;
|
|
||||||
char *remoteFilename = NULL; /* XXX - node parameter */
|
|
||||||
rtems_interval now;
|
|
||||||
rtems_status_code sc;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read-only for now
|
|
||||||
*/
|
|
||||||
/* XXX - Move to the open routine */
|
|
||||||
if (ap->flags & LIBIO_FLAGS_WRITE)
|
|
||||||
return RTEMS_NOT_IMPLEMENTED;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find a free stream
|
* Find a free stream
|
||||||
*/
|
*/
|
||||||
|
|
||||||
sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||||
if (sc != RTEMS_SUCCESSFUL)
|
if (sc != RTEMS_SUCCESSFUL)
|
||||||
return sc;
|
set_errno_and_return_minus_one( EBUSY );
|
||||||
|
|
||||||
for (s = 0 ; s < nStreams ; s++) {
|
for (s = 0 ; s < nStreams ; s++) {
|
||||||
if (tftpStreams[s] == NULL)
|
if (tftpStreams[s] == NULL)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s == nStreams) {
|
if (s == nStreams) {
|
||||||
/*
|
/*
|
||||||
* Reallocate stream pointers
|
* Reallocate stream pointers
|
||||||
@@ -450,42 +493,52 @@ rtems_device_driver rtems_tftp_open(
|
|||||||
np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);
|
np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);
|
||||||
if (np == NULL) {
|
if (np == NULL) {
|
||||||
rtems_semaphore_release (tftp_mutex);
|
rtems_semaphore_release (tftp_mutex);
|
||||||
return RTEMS_NO_MEMORY;
|
set_errno_and_return_minus_one( ENOMEM );
|
||||||
}
|
}
|
||||||
tftpStreams = np;
|
tftpStreams = np;
|
||||||
}
|
}
|
||||||
|
|
||||||
tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));
|
tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));
|
||||||
rtems_semaphore_release (tftp_mutex);
|
rtems_semaphore_release (tftp_mutex);
|
||||||
if (tp == NULL)
|
if (tp == NULL)
|
||||||
return RTEMS_NO_MEMORY;
|
set_errno_and_return_minus_one( ENOMEM );
|
||||||
ap->iop->data0 = s;
|
iop->data0 = s;
|
||||||
ap->iop->data1 = tp;
|
iop->data1 = tp;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the socket
|
* Create the socket
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
|
if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||||
releaseStream (s);
|
releaseStream (s);
|
||||||
return RTEMS_TOO_MANY;
|
set_errno_and_return_minus_one( ENOMEM );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bind the socket to a local address
|
* Bind the socket to a local address
|
||||||
*/
|
*/
|
||||||
|
|
||||||
retryCount = 0;
|
retryCount = 0;
|
||||||
rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
|
rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int try = (now + retryCount) % 10;
|
int try = (now + retryCount) % 10;
|
||||||
|
|
||||||
tp->myAddress.sin_family = AF_INET;
|
tp->myAddress.sin_family = AF_INET;
|
||||||
tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + minor);
|
/*
|
||||||
|
* XXX Eric .. how do we get the minor information???
|
||||||
|
* tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + minor);
|
||||||
|
*/
|
||||||
|
tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try);
|
||||||
tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
|
tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
|
||||||
if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
|
if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
|
||||||
break;
|
break;
|
||||||
if (++retryCount == 10) {
|
if (++retryCount == 10) {
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
|
/*
|
||||||
|
* XXX Eric .. how do we get the minor information to release this???
|
||||||
releaseStream (minor);
|
releaseStream (minor);
|
||||||
return RTEMS_RESOURCE_IN_USE;
|
*/
|
||||||
|
set_errno_and_return_minus_one( EBUSY );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,8 +559,12 @@ rtems_device_driver rtems_tftp_open(
|
|||||||
* Create the request
|
* Create the request
|
||||||
*/
|
*/
|
||||||
tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
|
tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
|
||||||
cp1 = tp->pkbuf.tftpRWRQ.filename_mode;
|
/*
|
||||||
cp2 = remoteFilename;
|
* XXX Eric .. is this cast taking the const off right?
|
||||||
|
*/
|
||||||
|
|
||||||
|
cp1 = (char *) tp->pkbuf.tftpRWRQ.filename_mode;
|
||||||
|
cp2 = (char *) remoteFilename;
|
||||||
while ((*cp1++ = *cp2++) != '\0')
|
while ((*cp1++ = *cp2++) != '\0')
|
||||||
continue;
|
continue;
|
||||||
cp2 = "octet";
|
cp2 = "octet";
|
||||||
@@ -522,8 +579,11 @@ rtems_device_driver rtems_tftp_open(
|
|||||||
(struct sockaddr *)&tp->farAddress,
|
(struct sockaddr *)&tp->farAddress,
|
||||||
sizeof tp->farAddress) < 0) {
|
sizeof tp->farAddress) < 0) {
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
|
/*
|
||||||
|
* XXX Eric .. how do we get the minor information to release this???
|
||||||
releaseStream (minor);
|
releaseStream (minor);
|
||||||
return RTEMS_UNSATISFIED;
|
*/
|
||||||
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -540,16 +600,23 @@ rtems_device_driver rtems_tftp_open(
|
|||||||
tp->eof = (tp->nleft < TFTP_BUFSIZE);
|
tp->eof = (tp->nleft < TFTP_BUFSIZE);
|
||||||
if (sendAck (tp) != 0) {
|
if (sendAck (tp) != 0) {
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
|
/*
|
||||||
|
* XXX Eric .. how do we get the minor information to release this???
|
||||||
releaseStream (minor);
|
releaseStream (minor);
|
||||||
return RTEMS_UNSATISFIED;
|
*/
|
||||||
|
|
||||||
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (opcode == TFTP_OPCODE_ERROR) {
|
if (opcode == TFTP_OPCODE_ERROR) {
|
||||||
tftpSetErrno (tp);
|
tftpSetErrno (tp);
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
releaseStream (ap->iop->data0);
|
/*
|
||||||
return RTEMS_INTERNAL_ERROR;
|
* XXX Eric .. how do we get the minor information to release this???
|
||||||
|
* releaseStream (minor);
|
||||||
|
*/
|
||||||
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -558,35 +625,40 @@ rtems_device_driver rtems_tftp_open(
|
|||||||
*/
|
*/
|
||||||
if (++retryCount >= OPEN_RETRY_LIMIT) {
|
if (++retryCount >= OPEN_RETRY_LIMIT) {
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
|
/*
|
||||||
|
* XXX Eric .. how do we get the minor information to release this???
|
||||||
releaseStream (minor);
|
releaseStream (minor);
|
||||||
return RTEMS_UNSATISFIED;
|
*/
|
||||||
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return RTEMS_SUCCESSFUL;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read from a TFTP stream
|
* Read from a TFTP stream
|
||||||
*/
|
*/
|
||||||
rtems_device_driver rtems_tftp_read(
|
|
||||||
rtems_device_major_number major,
|
int rtems_tftp_read(
|
||||||
rtems_device_minor_number minor,
|
rtems_libio_t *iop,
|
||||||
void *pargp
|
void *buffer,
|
||||||
|
unsigned32 count
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
rtems_libio_rw_args_t *ap = pargp;
|
|
||||||
char *bp;
|
char *bp;
|
||||||
struct tftpStream *tp;
|
struct tftpStream *tp;
|
||||||
int retryCount;
|
int retryCount;
|
||||||
int nwant;
|
int nwant;
|
||||||
|
|
||||||
tp = ap->iop->data1;
|
tp = iop->data1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read till user request is satisfied or EOF is reached
|
* Read till user request is satisfied or EOF is reached
|
||||||
*/
|
*/
|
||||||
bp = ap->buffer;
|
|
||||||
nwant = ap->count;
|
bp = buffer;
|
||||||
|
nwant = count;
|
||||||
while (nwant) {
|
while (nwant) {
|
||||||
if (tp->nleft) {
|
if (tp->nleft) {
|
||||||
int count;
|
int count;
|
||||||
@@ -621,7 +693,7 @@ rtems_device_driver rtems_tftp_read(
|
|||||||
tp->eof = (tp->nleft < TFTP_BUFSIZE);
|
tp->eof = (tp->nleft < TFTP_BUFSIZE);
|
||||||
tp->blocknum++;
|
tp->blocknum++;
|
||||||
if (sendAck (tp) != 0)
|
if (sendAck (tp) != 0)
|
||||||
return RTEMS_IO_ERROR;
|
set_errno_and_return_minus_one( EIO );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (opcode == TFTP_OPCODE_ERROR) {
|
if (opcode == TFTP_OPCODE_ERROR) {
|
||||||
@@ -634,26 +706,27 @@ rtems_device_driver rtems_tftp_read(
|
|||||||
* Keep trying?
|
* Keep trying?
|
||||||
*/
|
*/
|
||||||
if (++retryCount == IO_RETRY_LIMIT)
|
if (++retryCount == IO_RETRY_LIMIT)
|
||||||
return RTEMS_IO_ERROR;
|
set_errno_and_return_minus_one( EIO );
|
||||||
if (sendAck (tp) != 0)
|
if (sendAck (tp) != 0)
|
||||||
return RTEMS_IO_ERROR;
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ap->bytes_moved = ap->count - nwant;
|
|
||||||
return RTEMS_SUCCESSFUL;
|
/*
|
||||||
|
* XXX - Eric is this right?
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
return count - nwant;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close a TFTP stream
|
* Close a TFTP stream
|
||||||
*/
|
*/
|
||||||
rtems_device_driver rtems_tftp_close(
|
int rtems_tftp_close(
|
||||||
rtems_device_major_number major,
|
rtems_libio_t *iop
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *pargp
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
rtems_libio_open_close_args_t *ap = pargp;
|
struct tftpStream *tp = iop->data1;;
|
||||||
struct tftpStream *tp = ap->iop->data1;;
|
|
||||||
|
|
||||||
if (!tp->eof && !tp->firstReply) {
|
if (!tp->eof && !tp->firstReply) {
|
||||||
/*
|
/*
|
||||||
@@ -665,14 +738,14 @@ rtems_device_driver rtems_tftp_close(
|
|||||||
rtems_task_wake_after (1 + ticksPerSecond / 10);
|
rtems_task_wake_after (1 + ticksPerSecond / 10);
|
||||||
}
|
}
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
releaseStream (ap->iop->data0);
|
releaseStream (iop->data0);
|
||||||
return RTEMS_SUCCESSFUL;
|
return RTEMS_SUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtems_device_driver rtems_tftp_write(
|
int rtems_tftp_write(
|
||||||
rtems_device_major_number major,
|
rtems_libio_t *iop,
|
||||||
rtems_device_minor_number minor,
|
const void *buffer,
|
||||||
void *pargp
|
unsigned32 count
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return RTEMS_NOT_CONFIGURED;
|
return RTEMS_NOT_CONFIGURED;
|
||||||
@@ -686,3 +759,46 @@ rtems_device_driver rtems_tftp_control(
|
|||||||
{
|
{
|
||||||
return RTEMS_NOT_CONFIGURED;
|
return RTEMS_NOT_CONFIGURED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rtems_filesystem_node_types_t rtems_tftp_node_type(
|
||||||
|
rtems_filesystem_location_info_t *pathloc /* IN */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return RTEMS_FILESYSTEM_MEMORY_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rtems_filesystem_operations_table rtems_tftp_ops = {
|
||||||
|
rtems_tftp_eval_path, /* eval_path */
|
||||||
|
rtems_tftp_evaluate_for_make, /* evaluate_for_make */
|
||||||
|
NULL, /* link */
|
||||||
|
NULL, /* unlink */
|
||||||
|
rtems_tftp_node_type, /* node_type */
|
||||||
|
NULL, /* mknod */
|
||||||
|
NULL, /* rmnod */
|
||||||
|
NULL, /* chown */
|
||||||
|
NULL, /* freenodinfo */
|
||||||
|
NULL, /* mount */
|
||||||
|
rtems_tftp_mount_me, /* initialize */
|
||||||
|
NULL, /* unmount */
|
||||||
|
NULL, /* fsunmount */
|
||||||
|
NULL, /* utime, */
|
||||||
|
NULL, /* evaluate_link */
|
||||||
|
NULL, /* symlink */
|
||||||
|
NULL, /* readlin */
|
||||||
|
};
|
||||||
|
|
||||||
|
rtems_filesystem_file_handlers_r rtems_tftp_handlers = {
|
||||||
|
rtems_tftp_open,
|
||||||
|
rtems_tftp_close,
|
||||||
|
rtems_tftp_read,
|
||||||
|
rtems_tftp_write,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <rtems.h>
|
#include <rtems.h>
|
||||||
#include <rtems/libio.h>
|
#include <rtems/libio.h>
|
||||||
#include <rtems/rtems_bsdnet.h>
|
#include <rtems/rtems_bsdnet.h>
|
||||||
@@ -139,35 +140,65 @@ struct tftpStream {
|
|||||||
/*
|
/*
|
||||||
* Number of streams open at the same time
|
* Number of streams open at the same time
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static rtems_id tftp_mutex;
|
static rtems_id tftp_mutex;
|
||||||
static int nStreams;
|
static int nStreams;
|
||||||
static struct tftpStream ** volatile tftpStreams;
|
static struct tftpStream ** volatile tftpStreams;
|
||||||
|
|
||||||
typedef struct {
|
typedef const char *tftp_node;
|
||||||
rtems_id tftp_mutex;
|
extern rtems_filesystem_operations_table rtems_tftp_ops;
|
||||||
int nStreams;
|
extern rtems_filesystem_file_handlers_r rtems_tftp_handlers;
|
||||||
struct tftpStream ** volatile tftpStreams;
|
|
||||||
rtems_filesystem_mount_table_entry_t *mt_entry;
|
/*
|
||||||
} tftp_fs_info;
|
* Direct copy from the IMFS. Look at this.
|
||||||
|
*/
|
||||||
|
|
||||||
|
rtems_filesystem_limits_and_options_t rtems_tftp_limits_and_options = {
|
||||||
|
5, /* link_max */
|
||||||
|
6, /* max_canon */
|
||||||
|
7, /* max_input */
|
||||||
|
255, /* name_max */
|
||||||
|
255, /* path_max */
|
||||||
|
2, /* pipe_buf */
|
||||||
|
1, /* posix_async_io */
|
||||||
|
2, /* posix_chown_restrictions */
|
||||||
|
3, /* posix_no_trunc */
|
||||||
|
4, /* posix_prio_io */
|
||||||
|
5, /* posix_sync_io */
|
||||||
|
6 /* posix_vdisable */
|
||||||
|
};
|
||||||
|
|
||||||
int rtems_tftp_mount_me(
|
int rtems_tftp_mount_me(
|
||||||
rtems_filesystem_mount_table_entry_t *temp_mt_entry
|
rtems_filesystem_mount_table_entry_t *temp_mt_entry
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
tftp_fs_info *fs_info;
|
|
||||||
rtems_status_code sc;
|
rtems_status_code sc;
|
||||||
|
|
||||||
|
temp_mt_entry->mt_fs_root.handlers = &rtems_tftp_handlers;
|
||||||
|
temp_mt_entry->mt_fs_root.ops = &rtems_tftp_ops;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate stuff for this file system.
|
* We have no tftp filesystem specific data to maintain. This
|
||||||
|
* filesystem may only be mounted ONCE.
|
||||||
|
*
|
||||||
|
* And we maintain no real filesystem nodes, so there is no real root.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fs_info = calloc( 1, sizeof( tftp_fs_info ));
|
temp_mt_entry->fs_info = NULL;
|
||||||
if ( !fs_info )
|
temp_mt_entry->mt_fs_root.node_access = NULL;
|
||||||
set_errno_and_return_minus_one( ENOMEM );
|
|
||||||
|
|
||||||
temp_mt_entry->fs_info = fs_info;
|
/*
|
||||||
temp_mt_entry->mt_fs_root.node_access = fs_info;
|
* These need to be looked at for full POSIX semantics.
|
||||||
|
*/
|
||||||
|
|
||||||
|
temp_mt_entry->pathconf_limits_and_options = rtems_tftp_limits_and_options;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now allocate a semaphore for mutual exclusion.
|
||||||
|
*
|
||||||
|
* NOTE: This could be in an fsinfo for this filesystem type.
|
||||||
|
*/
|
||||||
|
|
||||||
sc = rtems_semaphore_create (
|
sc = rtems_semaphore_create (
|
||||||
rtems_build_name('T', 'F', 'T', 'P'),
|
rtems_build_name('T', 'F', 'T', 'P'),
|
||||||
@@ -178,11 +209,11 @@ int rtems_tftp_mount_me(
|
|||||||
RTEMS_NO_PRIORITY_CEILING |
|
RTEMS_NO_PRIORITY_CEILING |
|
||||||
RTEMS_LOCAL,
|
RTEMS_LOCAL,
|
||||||
0,
|
0,
|
||||||
&fs_info->tftp_mutex
|
&tftp_mutex
|
||||||
);
|
);
|
||||||
|
|
||||||
if (sc != RTEMS_SUCCESSFUL)
|
if (sc != RTEMS_SUCCESSFUL)
|
||||||
set_errno_and_return_minus_one( ENOMEM ); /* ??? */
|
set_errno_and_return_minus_one( ENOMEM );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -190,18 +221,28 @@ int rtems_tftp_mount_me(
|
|||||||
/*
|
/*
|
||||||
* Initialize the TFTP driver
|
* Initialize the TFTP driver
|
||||||
*/
|
*/
|
||||||
/* XXX change name to rtems_bsdnet_initialize_tftp_filesystem ("mountpt") */
|
|
||||||
/* XXX this won't be a driver when we are finished */
|
|
||||||
rtems_device_driver rtems_tftp_initialize(
|
|
||||||
rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *pargp
|
|
||||||
)
|
|
||||||
{
|
|
||||||
|
|
||||||
/* XXX change to a mount */
|
int rtems_bsdnet_initialize_tftp_filesystem ()
|
||||||
rtems_io_register_name (TFTP_PATHNAME_PREFIX, major, minor);
|
{
|
||||||
return RTEMS_SUCCESSFUL;
|
int status;
|
||||||
|
rtems_filesystem_mount_table_entry_t *entry;
|
||||||
|
|
||||||
|
status = mkdir( TFTP_PATHNAME_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO );
|
||||||
|
if ( status == -1 )
|
||||||
|
return status;
|
||||||
|
|
||||||
|
status = mount(
|
||||||
|
&entry,
|
||||||
|
&rtems_tftp_ops,
|
||||||
|
"RO",
|
||||||
|
NULL,
|
||||||
|
TFTP_PATHNAME_PREFIX
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( status )
|
||||||
|
perror( "TFTP mount failed" );
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -340,36 +381,61 @@ int rtems_tftp_evaluate_for_make(
|
|||||||
{
|
{
|
||||||
set_errno_and_return_minus_one( EIO );
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX - Fix return values.
|
* XXX - Fix return values.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int TFTP_eval_path(
|
int rtems_tftp_eval_path(
|
||||||
const char *pathname, /* IN */
|
const char *pathname, /* IN */
|
||||||
int flags, /* IN */
|
int flags, /* IN */
|
||||||
rtems_filesystem_location_info_t *pathloc /* IN/OUT */
|
rtems_filesystem_location_info_t *pathloc /* IN/OUT */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read-only for now
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( (flags & O_WRONLY) == O_WRONLY )
|
||||||
|
set_errno_and_return_minus_one( ENOENT );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The File system is mounted at TFTP_PATHNAME_PREFIX
|
||||||
|
* the caller of this routine has striped off this part of the
|
||||||
|
* name. Save the remainder of the name for use by the open routine.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pathloc->node_access = (void * ) pathname;
|
||||||
|
pathloc->handlers = &rtems_tftp_handlers;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int rtems_tftp_open(
|
||||||
|
rtems_libio_t *iop,
|
||||||
|
const char *new_name,
|
||||||
|
unsigned32 flag,
|
||||||
|
unsigned32 mode
|
||||||
|
)
|
||||||
|
{
|
||||||
|
struct tftpStream *tp;
|
||||||
|
int retryCount;
|
||||||
rtems_unsigned32 farAddress;
|
rtems_unsigned32 farAddress;
|
||||||
|
int s;
|
||||||
int len;
|
int len;
|
||||||
const char *remoteFilename;
|
char *cp1;
|
||||||
|
char *cp2;
|
||||||
tftp_fs_info *fs_info;
|
char *remoteFilename;
|
||||||
const char *cp1, *cp2;
|
rtems_interval now;
|
||||||
|
rtems_status_code sc;
|
||||||
fs_info = pathloc->node_access;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pick apart the name into a host:pathname pair
|
* This came from the evaluate path.
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* XXX - I think this is handled by the caller of
|
|
||||||
* the evaluate routine. ? Am I starting at the right
|
|
||||||
* place?
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
cp2 = pathname+1;
|
cp2 = iop->file_info;
|
||||||
|
|
||||||
if (*cp2 == '/') {
|
if (*cp2 == '/') {
|
||||||
farAddress = rtems_bsdnet_bootp_server_address.s_addr;
|
farAddress = rtems_bsdnet_bootp_server_address.s_addr;
|
||||||
}
|
}
|
||||||
@@ -379,67 +445,44 @@ int TFTP_eval_path(
|
|||||||
cp1 = cp2;
|
cp1 = cp2;
|
||||||
while (*cp2 != '/') {
|
while (*cp2 != '/') {
|
||||||
if (*cp2 == '\0')
|
if (*cp2 == '\0')
|
||||||
return RTEMS_INVALID_NAME;
|
set_errno_and_return_minus_one( ENOENT );
|
||||||
cp2++;
|
cp2++;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = cp2 - cp1;
|
len = cp2 - cp1;
|
||||||
hostname = malloc (len + 1);
|
hostname = malloc (len + 1);
|
||||||
if (hostname == NULL)
|
if (hostname == NULL)
|
||||||
return RTEMS_NO_MEMORY;
|
set_errno_and_return_minus_one( ENOMEM );
|
||||||
|
|
||||||
strncpy (hostname, cp1, len);
|
strncpy (hostname, cp1, len);
|
||||||
hostname[len] = '\0';
|
hostname[len] = '\0';
|
||||||
farAddress = inet_addr (hostname);
|
farAddress = inet_addr (hostname);
|
||||||
free (hostname);
|
free (hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((farAddress == 0) || (farAddress == ~0))
|
if ((farAddress == 0) || (farAddress == ~0))
|
||||||
return RTEMS_INVALID_NAME;
|
set_errno_and_return_minus_one( ENOENT );
|
||||||
|
|
||||||
if (*++cp2 == '\0')
|
if (*++cp2 == '\0')
|
||||||
return RTEMS_INVALID_NAME;
|
set_errno_and_return_minus_one( ENOENT );
|
||||||
|
|
||||||
remoteFilename = cp2;
|
remoteFilename = cp2;
|
||||||
if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
|
if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
|
||||||
return RTEMS_INVALID_NAME;
|
set_errno_and_return_minus_one( ENOENT );
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Open a TFTP stream
|
|
||||||
*/
|
|
||||||
rtems_device_driver rtems_tftp_open(
|
|
||||||
rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *pargp
|
|
||||||
)
|
|
||||||
{
|
|
||||||
rtems_libio_open_close_args_t *ap = pargp;
|
|
||||||
struct tftpStream *tp;
|
|
||||||
int retryCount;
|
|
||||||
rtems_unsigned32 farAddress = 0; /* XXX - node parameter */
|
|
||||||
int s;
|
|
||||||
int len;
|
|
||||||
char *cp1, *cp2;
|
|
||||||
char *remoteFilename = NULL; /* XXX - node parameter */
|
|
||||||
rtems_interval now;
|
|
||||||
rtems_status_code sc;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read-only for now
|
|
||||||
*/
|
|
||||||
/* XXX - Move to the open routine */
|
|
||||||
if (ap->flags & LIBIO_FLAGS_WRITE)
|
|
||||||
return RTEMS_NOT_IMPLEMENTED;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find a free stream
|
* Find a free stream
|
||||||
*/
|
*/
|
||||||
|
|
||||||
sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||||
if (sc != RTEMS_SUCCESSFUL)
|
if (sc != RTEMS_SUCCESSFUL)
|
||||||
return sc;
|
set_errno_and_return_minus_one( EBUSY );
|
||||||
|
|
||||||
for (s = 0 ; s < nStreams ; s++) {
|
for (s = 0 ; s < nStreams ; s++) {
|
||||||
if (tftpStreams[s] == NULL)
|
if (tftpStreams[s] == NULL)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s == nStreams) {
|
if (s == nStreams) {
|
||||||
/*
|
/*
|
||||||
* Reallocate stream pointers
|
* Reallocate stream pointers
|
||||||
@@ -450,42 +493,52 @@ rtems_device_driver rtems_tftp_open(
|
|||||||
np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);
|
np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);
|
||||||
if (np == NULL) {
|
if (np == NULL) {
|
||||||
rtems_semaphore_release (tftp_mutex);
|
rtems_semaphore_release (tftp_mutex);
|
||||||
return RTEMS_NO_MEMORY;
|
set_errno_and_return_minus_one( ENOMEM );
|
||||||
}
|
}
|
||||||
tftpStreams = np;
|
tftpStreams = np;
|
||||||
}
|
}
|
||||||
|
|
||||||
tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));
|
tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));
|
||||||
rtems_semaphore_release (tftp_mutex);
|
rtems_semaphore_release (tftp_mutex);
|
||||||
if (tp == NULL)
|
if (tp == NULL)
|
||||||
return RTEMS_NO_MEMORY;
|
set_errno_and_return_minus_one( ENOMEM );
|
||||||
ap->iop->data0 = s;
|
iop->data0 = s;
|
||||||
ap->iop->data1 = tp;
|
iop->data1 = tp;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the socket
|
* Create the socket
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
|
if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||||
releaseStream (s);
|
releaseStream (s);
|
||||||
return RTEMS_TOO_MANY;
|
set_errno_and_return_minus_one( ENOMEM );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bind the socket to a local address
|
* Bind the socket to a local address
|
||||||
*/
|
*/
|
||||||
|
|
||||||
retryCount = 0;
|
retryCount = 0;
|
||||||
rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
|
rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int try = (now + retryCount) % 10;
|
int try = (now + retryCount) % 10;
|
||||||
|
|
||||||
tp->myAddress.sin_family = AF_INET;
|
tp->myAddress.sin_family = AF_INET;
|
||||||
tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + minor);
|
/*
|
||||||
|
* XXX Eric .. how do we get the minor information???
|
||||||
|
* tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + minor);
|
||||||
|
*/
|
||||||
|
tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try);
|
||||||
tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
|
tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
|
||||||
if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
|
if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
|
||||||
break;
|
break;
|
||||||
if (++retryCount == 10) {
|
if (++retryCount == 10) {
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
|
/*
|
||||||
|
* XXX Eric .. how do we get the minor information to release this???
|
||||||
releaseStream (minor);
|
releaseStream (minor);
|
||||||
return RTEMS_RESOURCE_IN_USE;
|
*/
|
||||||
|
set_errno_and_return_minus_one( EBUSY );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,8 +559,12 @@ rtems_device_driver rtems_tftp_open(
|
|||||||
* Create the request
|
* Create the request
|
||||||
*/
|
*/
|
||||||
tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
|
tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
|
||||||
cp1 = tp->pkbuf.tftpRWRQ.filename_mode;
|
/*
|
||||||
cp2 = remoteFilename;
|
* XXX Eric .. is this cast taking the const off right?
|
||||||
|
*/
|
||||||
|
|
||||||
|
cp1 = (char *) tp->pkbuf.tftpRWRQ.filename_mode;
|
||||||
|
cp2 = (char *) remoteFilename;
|
||||||
while ((*cp1++ = *cp2++) != '\0')
|
while ((*cp1++ = *cp2++) != '\0')
|
||||||
continue;
|
continue;
|
||||||
cp2 = "octet";
|
cp2 = "octet";
|
||||||
@@ -522,8 +579,11 @@ rtems_device_driver rtems_tftp_open(
|
|||||||
(struct sockaddr *)&tp->farAddress,
|
(struct sockaddr *)&tp->farAddress,
|
||||||
sizeof tp->farAddress) < 0) {
|
sizeof tp->farAddress) < 0) {
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
|
/*
|
||||||
|
* XXX Eric .. how do we get the minor information to release this???
|
||||||
releaseStream (minor);
|
releaseStream (minor);
|
||||||
return RTEMS_UNSATISFIED;
|
*/
|
||||||
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -540,16 +600,23 @@ rtems_device_driver rtems_tftp_open(
|
|||||||
tp->eof = (tp->nleft < TFTP_BUFSIZE);
|
tp->eof = (tp->nleft < TFTP_BUFSIZE);
|
||||||
if (sendAck (tp) != 0) {
|
if (sendAck (tp) != 0) {
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
|
/*
|
||||||
|
* XXX Eric .. how do we get the minor information to release this???
|
||||||
releaseStream (minor);
|
releaseStream (minor);
|
||||||
return RTEMS_UNSATISFIED;
|
*/
|
||||||
|
|
||||||
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (opcode == TFTP_OPCODE_ERROR) {
|
if (opcode == TFTP_OPCODE_ERROR) {
|
||||||
tftpSetErrno (tp);
|
tftpSetErrno (tp);
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
releaseStream (ap->iop->data0);
|
/*
|
||||||
return RTEMS_INTERNAL_ERROR;
|
* XXX Eric .. how do we get the minor information to release this???
|
||||||
|
* releaseStream (minor);
|
||||||
|
*/
|
||||||
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -558,35 +625,40 @@ rtems_device_driver rtems_tftp_open(
|
|||||||
*/
|
*/
|
||||||
if (++retryCount >= OPEN_RETRY_LIMIT) {
|
if (++retryCount >= OPEN_RETRY_LIMIT) {
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
|
/*
|
||||||
|
* XXX Eric .. how do we get the minor information to release this???
|
||||||
releaseStream (minor);
|
releaseStream (minor);
|
||||||
return RTEMS_UNSATISFIED;
|
*/
|
||||||
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return RTEMS_SUCCESSFUL;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read from a TFTP stream
|
* Read from a TFTP stream
|
||||||
*/
|
*/
|
||||||
rtems_device_driver rtems_tftp_read(
|
|
||||||
rtems_device_major_number major,
|
int rtems_tftp_read(
|
||||||
rtems_device_minor_number minor,
|
rtems_libio_t *iop,
|
||||||
void *pargp
|
void *buffer,
|
||||||
|
unsigned32 count
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
rtems_libio_rw_args_t *ap = pargp;
|
|
||||||
char *bp;
|
char *bp;
|
||||||
struct tftpStream *tp;
|
struct tftpStream *tp;
|
||||||
int retryCount;
|
int retryCount;
|
||||||
int nwant;
|
int nwant;
|
||||||
|
|
||||||
tp = ap->iop->data1;
|
tp = iop->data1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read till user request is satisfied or EOF is reached
|
* Read till user request is satisfied or EOF is reached
|
||||||
*/
|
*/
|
||||||
bp = ap->buffer;
|
|
||||||
nwant = ap->count;
|
bp = buffer;
|
||||||
|
nwant = count;
|
||||||
while (nwant) {
|
while (nwant) {
|
||||||
if (tp->nleft) {
|
if (tp->nleft) {
|
||||||
int count;
|
int count;
|
||||||
@@ -621,7 +693,7 @@ rtems_device_driver rtems_tftp_read(
|
|||||||
tp->eof = (tp->nleft < TFTP_BUFSIZE);
|
tp->eof = (tp->nleft < TFTP_BUFSIZE);
|
||||||
tp->blocknum++;
|
tp->blocknum++;
|
||||||
if (sendAck (tp) != 0)
|
if (sendAck (tp) != 0)
|
||||||
return RTEMS_IO_ERROR;
|
set_errno_and_return_minus_one( EIO );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (opcode == TFTP_OPCODE_ERROR) {
|
if (opcode == TFTP_OPCODE_ERROR) {
|
||||||
@@ -634,26 +706,27 @@ rtems_device_driver rtems_tftp_read(
|
|||||||
* Keep trying?
|
* Keep trying?
|
||||||
*/
|
*/
|
||||||
if (++retryCount == IO_RETRY_LIMIT)
|
if (++retryCount == IO_RETRY_LIMIT)
|
||||||
return RTEMS_IO_ERROR;
|
set_errno_and_return_minus_one( EIO );
|
||||||
if (sendAck (tp) != 0)
|
if (sendAck (tp) != 0)
|
||||||
return RTEMS_IO_ERROR;
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ap->bytes_moved = ap->count - nwant;
|
|
||||||
return RTEMS_SUCCESSFUL;
|
/*
|
||||||
|
* XXX - Eric is this right?
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
return count - nwant;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close a TFTP stream
|
* Close a TFTP stream
|
||||||
*/
|
*/
|
||||||
rtems_device_driver rtems_tftp_close(
|
int rtems_tftp_close(
|
||||||
rtems_device_major_number major,
|
rtems_libio_t *iop
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *pargp
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
rtems_libio_open_close_args_t *ap = pargp;
|
struct tftpStream *tp = iop->data1;;
|
||||||
struct tftpStream *tp = ap->iop->data1;;
|
|
||||||
|
|
||||||
if (!tp->eof && !tp->firstReply) {
|
if (!tp->eof && !tp->firstReply) {
|
||||||
/*
|
/*
|
||||||
@@ -665,14 +738,14 @@ rtems_device_driver rtems_tftp_close(
|
|||||||
rtems_task_wake_after (1 + ticksPerSecond / 10);
|
rtems_task_wake_after (1 + ticksPerSecond / 10);
|
||||||
}
|
}
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
releaseStream (ap->iop->data0);
|
releaseStream (iop->data0);
|
||||||
return RTEMS_SUCCESSFUL;
|
return RTEMS_SUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtems_device_driver rtems_tftp_write(
|
int rtems_tftp_write(
|
||||||
rtems_device_major_number major,
|
rtems_libio_t *iop,
|
||||||
rtems_device_minor_number minor,
|
const void *buffer,
|
||||||
void *pargp
|
unsigned32 count
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return RTEMS_NOT_CONFIGURED;
|
return RTEMS_NOT_CONFIGURED;
|
||||||
@@ -686,3 +759,46 @@ rtems_device_driver rtems_tftp_control(
|
|||||||
{
|
{
|
||||||
return RTEMS_NOT_CONFIGURED;
|
return RTEMS_NOT_CONFIGURED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rtems_filesystem_node_types_t rtems_tftp_node_type(
|
||||||
|
rtems_filesystem_location_info_t *pathloc /* IN */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return RTEMS_FILESYSTEM_MEMORY_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rtems_filesystem_operations_table rtems_tftp_ops = {
|
||||||
|
rtems_tftp_eval_path, /* eval_path */
|
||||||
|
rtems_tftp_evaluate_for_make, /* evaluate_for_make */
|
||||||
|
NULL, /* link */
|
||||||
|
NULL, /* unlink */
|
||||||
|
rtems_tftp_node_type, /* node_type */
|
||||||
|
NULL, /* mknod */
|
||||||
|
NULL, /* rmnod */
|
||||||
|
NULL, /* chown */
|
||||||
|
NULL, /* freenodinfo */
|
||||||
|
NULL, /* mount */
|
||||||
|
rtems_tftp_mount_me, /* initialize */
|
||||||
|
NULL, /* unmount */
|
||||||
|
NULL, /* fsunmount */
|
||||||
|
NULL, /* utime, */
|
||||||
|
NULL, /* evaluate_link */
|
||||||
|
NULL, /* symlink */
|
||||||
|
NULL, /* readlin */
|
||||||
|
};
|
||||||
|
|
||||||
|
rtems_filesystem_file_handlers_r rtems_tftp_handlers = {
|
||||||
|
rtems_tftp_open,
|
||||||
|
rtems_tftp_close,
|
||||||
|
rtems_tftp_read,
|
||||||
|
rtems_tftp_write,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <rtems.h>
|
#include <rtems.h>
|
||||||
#include <rtems/libio.h>
|
#include <rtems/libio.h>
|
||||||
#include <rtems/rtems_bsdnet.h>
|
#include <rtems/rtems_bsdnet.h>
|
||||||
@@ -139,35 +140,65 @@ struct tftpStream {
|
|||||||
/*
|
/*
|
||||||
* Number of streams open at the same time
|
* Number of streams open at the same time
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static rtems_id tftp_mutex;
|
static rtems_id tftp_mutex;
|
||||||
static int nStreams;
|
static int nStreams;
|
||||||
static struct tftpStream ** volatile tftpStreams;
|
static struct tftpStream ** volatile tftpStreams;
|
||||||
|
|
||||||
typedef struct {
|
typedef const char *tftp_node;
|
||||||
rtems_id tftp_mutex;
|
extern rtems_filesystem_operations_table rtems_tftp_ops;
|
||||||
int nStreams;
|
extern rtems_filesystem_file_handlers_r rtems_tftp_handlers;
|
||||||
struct tftpStream ** volatile tftpStreams;
|
|
||||||
rtems_filesystem_mount_table_entry_t *mt_entry;
|
/*
|
||||||
} tftp_fs_info;
|
* Direct copy from the IMFS. Look at this.
|
||||||
|
*/
|
||||||
|
|
||||||
|
rtems_filesystem_limits_and_options_t rtems_tftp_limits_and_options = {
|
||||||
|
5, /* link_max */
|
||||||
|
6, /* max_canon */
|
||||||
|
7, /* max_input */
|
||||||
|
255, /* name_max */
|
||||||
|
255, /* path_max */
|
||||||
|
2, /* pipe_buf */
|
||||||
|
1, /* posix_async_io */
|
||||||
|
2, /* posix_chown_restrictions */
|
||||||
|
3, /* posix_no_trunc */
|
||||||
|
4, /* posix_prio_io */
|
||||||
|
5, /* posix_sync_io */
|
||||||
|
6 /* posix_vdisable */
|
||||||
|
};
|
||||||
|
|
||||||
int rtems_tftp_mount_me(
|
int rtems_tftp_mount_me(
|
||||||
rtems_filesystem_mount_table_entry_t *temp_mt_entry
|
rtems_filesystem_mount_table_entry_t *temp_mt_entry
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
tftp_fs_info *fs_info;
|
|
||||||
rtems_status_code sc;
|
rtems_status_code sc;
|
||||||
|
|
||||||
|
temp_mt_entry->mt_fs_root.handlers = &rtems_tftp_handlers;
|
||||||
|
temp_mt_entry->mt_fs_root.ops = &rtems_tftp_ops;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate stuff for this file system.
|
* We have no tftp filesystem specific data to maintain. This
|
||||||
|
* filesystem may only be mounted ONCE.
|
||||||
|
*
|
||||||
|
* And we maintain no real filesystem nodes, so there is no real root.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fs_info = calloc( 1, sizeof( tftp_fs_info ));
|
temp_mt_entry->fs_info = NULL;
|
||||||
if ( !fs_info )
|
temp_mt_entry->mt_fs_root.node_access = NULL;
|
||||||
set_errno_and_return_minus_one( ENOMEM );
|
|
||||||
|
|
||||||
temp_mt_entry->fs_info = fs_info;
|
/*
|
||||||
temp_mt_entry->mt_fs_root.node_access = fs_info;
|
* These need to be looked at for full POSIX semantics.
|
||||||
|
*/
|
||||||
|
|
||||||
|
temp_mt_entry->pathconf_limits_and_options = rtems_tftp_limits_and_options;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now allocate a semaphore for mutual exclusion.
|
||||||
|
*
|
||||||
|
* NOTE: This could be in an fsinfo for this filesystem type.
|
||||||
|
*/
|
||||||
|
|
||||||
sc = rtems_semaphore_create (
|
sc = rtems_semaphore_create (
|
||||||
rtems_build_name('T', 'F', 'T', 'P'),
|
rtems_build_name('T', 'F', 'T', 'P'),
|
||||||
@@ -178,11 +209,11 @@ int rtems_tftp_mount_me(
|
|||||||
RTEMS_NO_PRIORITY_CEILING |
|
RTEMS_NO_PRIORITY_CEILING |
|
||||||
RTEMS_LOCAL,
|
RTEMS_LOCAL,
|
||||||
0,
|
0,
|
||||||
&fs_info->tftp_mutex
|
&tftp_mutex
|
||||||
);
|
);
|
||||||
|
|
||||||
if (sc != RTEMS_SUCCESSFUL)
|
if (sc != RTEMS_SUCCESSFUL)
|
||||||
set_errno_and_return_minus_one( ENOMEM ); /* ??? */
|
set_errno_and_return_minus_one( ENOMEM );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -190,18 +221,28 @@ int rtems_tftp_mount_me(
|
|||||||
/*
|
/*
|
||||||
* Initialize the TFTP driver
|
* Initialize the TFTP driver
|
||||||
*/
|
*/
|
||||||
/* XXX change name to rtems_bsdnet_initialize_tftp_filesystem ("mountpt") */
|
|
||||||
/* XXX this won't be a driver when we are finished */
|
|
||||||
rtems_device_driver rtems_tftp_initialize(
|
|
||||||
rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *pargp
|
|
||||||
)
|
|
||||||
{
|
|
||||||
|
|
||||||
/* XXX change to a mount */
|
int rtems_bsdnet_initialize_tftp_filesystem ()
|
||||||
rtems_io_register_name (TFTP_PATHNAME_PREFIX, major, minor);
|
{
|
||||||
return RTEMS_SUCCESSFUL;
|
int status;
|
||||||
|
rtems_filesystem_mount_table_entry_t *entry;
|
||||||
|
|
||||||
|
status = mkdir( TFTP_PATHNAME_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO );
|
||||||
|
if ( status == -1 )
|
||||||
|
return status;
|
||||||
|
|
||||||
|
status = mount(
|
||||||
|
&entry,
|
||||||
|
&rtems_tftp_ops,
|
||||||
|
"RO",
|
||||||
|
NULL,
|
||||||
|
TFTP_PATHNAME_PREFIX
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( status )
|
||||||
|
perror( "TFTP mount failed" );
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -340,36 +381,61 @@ int rtems_tftp_evaluate_for_make(
|
|||||||
{
|
{
|
||||||
set_errno_and_return_minus_one( EIO );
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX - Fix return values.
|
* XXX - Fix return values.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int TFTP_eval_path(
|
int rtems_tftp_eval_path(
|
||||||
const char *pathname, /* IN */
|
const char *pathname, /* IN */
|
||||||
int flags, /* IN */
|
int flags, /* IN */
|
||||||
rtems_filesystem_location_info_t *pathloc /* IN/OUT */
|
rtems_filesystem_location_info_t *pathloc /* IN/OUT */
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read-only for now
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( (flags & O_WRONLY) == O_WRONLY )
|
||||||
|
set_errno_and_return_minus_one( ENOENT );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The File system is mounted at TFTP_PATHNAME_PREFIX
|
||||||
|
* the caller of this routine has striped off this part of the
|
||||||
|
* name. Save the remainder of the name for use by the open routine.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pathloc->node_access = (void * ) pathname;
|
||||||
|
pathloc->handlers = &rtems_tftp_handlers;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int rtems_tftp_open(
|
||||||
|
rtems_libio_t *iop,
|
||||||
|
const char *new_name,
|
||||||
|
unsigned32 flag,
|
||||||
|
unsigned32 mode
|
||||||
|
)
|
||||||
|
{
|
||||||
|
struct tftpStream *tp;
|
||||||
|
int retryCount;
|
||||||
rtems_unsigned32 farAddress;
|
rtems_unsigned32 farAddress;
|
||||||
|
int s;
|
||||||
int len;
|
int len;
|
||||||
const char *remoteFilename;
|
char *cp1;
|
||||||
|
char *cp2;
|
||||||
tftp_fs_info *fs_info;
|
char *remoteFilename;
|
||||||
const char *cp1, *cp2;
|
rtems_interval now;
|
||||||
|
rtems_status_code sc;
|
||||||
fs_info = pathloc->node_access;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pick apart the name into a host:pathname pair
|
* This came from the evaluate path.
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* XXX - I think this is handled by the caller of
|
|
||||||
* the evaluate routine. ? Am I starting at the right
|
|
||||||
* place?
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
cp2 = pathname+1;
|
cp2 = iop->file_info;
|
||||||
|
|
||||||
if (*cp2 == '/') {
|
if (*cp2 == '/') {
|
||||||
farAddress = rtems_bsdnet_bootp_server_address.s_addr;
|
farAddress = rtems_bsdnet_bootp_server_address.s_addr;
|
||||||
}
|
}
|
||||||
@@ -379,67 +445,44 @@ int TFTP_eval_path(
|
|||||||
cp1 = cp2;
|
cp1 = cp2;
|
||||||
while (*cp2 != '/') {
|
while (*cp2 != '/') {
|
||||||
if (*cp2 == '\0')
|
if (*cp2 == '\0')
|
||||||
return RTEMS_INVALID_NAME;
|
set_errno_and_return_minus_one( ENOENT );
|
||||||
cp2++;
|
cp2++;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = cp2 - cp1;
|
len = cp2 - cp1;
|
||||||
hostname = malloc (len + 1);
|
hostname = malloc (len + 1);
|
||||||
if (hostname == NULL)
|
if (hostname == NULL)
|
||||||
return RTEMS_NO_MEMORY;
|
set_errno_and_return_minus_one( ENOMEM );
|
||||||
|
|
||||||
strncpy (hostname, cp1, len);
|
strncpy (hostname, cp1, len);
|
||||||
hostname[len] = '\0';
|
hostname[len] = '\0';
|
||||||
farAddress = inet_addr (hostname);
|
farAddress = inet_addr (hostname);
|
||||||
free (hostname);
|
free (hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((farAddress == 0) || (farAddress == ~0))
|
if ((farAddress == 0) || (farAddress == ~0))
|
||||||
return RTEMS_INVALID_NAME;
|
set_errno_and_return_minus_one( ENOENT );
|
||||||
|
|
||||||
if (*++cp2 == '\0')
|
if (*++cp2 == '\0')
|
||||||
return RTEMS_INVALID_NAME;
|
set_errno_and_return_minus_one( ENOENT );
|
||||||
|
|
||||||
remoteFilename = cp2;
|
remoteFilename = cp2;
|
||||||
if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
|
if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
|
||||||
return RTEMS_INVALID_NAME;
|
set_errno_and_return_minus_one( ENOENT );
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Open a TFTP stream
|
|
||||||
*/
|
|
||||||
rtems_device_driver rtems_tftp_open(
|
|
||||||
rtems_device_major_number major,
|
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *pargp
|
|
||||||
)
|
|
||||||
{
|
|
||||||
rtems_libio_open_close_args_t *ap = pargp;
|
|
||||||
struct tftpStream *tp;
|
|
||||||
int retryCount;
|
|
||||||
rtems_unsigned32 farAddress = 0; /* XXX - node parameter */
|
|
||||||
int s;
|
|
||||||
int len;
|
|
||||||
char *cp1, *cp2;
|
|
||||||
char *remoteFilename = NULL; /* XXX - node parameter */
|
|
||||||
rtems_interval now;
|
|
||||||
rtems_status_code sc;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read-only for now
|
|
||||||
*/
|
|
||||||
/* XXX - Move to the open routine */
|
|
||||||
if (ap->flags & LIBIO_FLAGS_WRITE)
|
|
||||||
return RTEMS_NOT_IMPLEMENTED;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find a free stream
|
* Find a free stream
|
||||||
*/
|
*/
|
||||||
|
|
||||||
sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
|
||||||
if (sc != RTEMS_SUCCESSFUL)
|
if (sc != RTEMS_SUCCESSFUL)
|
||||||
return sc;
|
set_errno_and_return_minus_one( EBUSY );
|
||||||
|
|
||||||
for (s = 0 ; s < nStreams ; s++) {
|
for (s = 0 ; s < nStreams ; s++) {
|
||||||
if (tftpStreams[s] == NULL)
|
if (tftpStreams[s] == NULL)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s == nStreams) {
|
if (s == nStreams) {
|
||||||
/*
|
/*
|
||||||
* Reallocate stream pointers
|
* Reallocate stream pointers
|
||||||
@@ -450,42 +493,52 @@ rtems_device_driver rtems_tftp_open(
|
|||||||
np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);
|
np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams);
|
||||||
if (np == NULL) {
|
if (np == NULL) {
|
||||||
rtems_semaphore_release (tftp_mutex);
|
rtems_semaphore_release (tftp_mutex);
|
||||||
return RTEMS_NO_MEMORY;
|
set_errno_and_return_minus_one( ENOMEM );
|
||||||
}
|
}
|
||||||
tftpStreams = np;
|
tftpStreams = np;
|
||||||
}
|
}
|
||||||
|
|
||||||
tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));
|
tp = tftpStreams[s] = malloc (sizeof (struct tftpStream));
|
||||||
rtems_semaphore_release (tftp_mutex);
|
rtems_semaphore_release (tftp_mutex);
|
||||||
if (tp == NULL)
|
if (tp == NULL)
|
||||||
return RTEMS_NO_MEMORY;
|
set_errno_and_return_minus_one( ENOMEM );
|
||||||
ap->iop->data0 = s;
|
iop->data0 = s;
|
||||||
ap->iop->data1 = tp;
|
iop->data1 = tp;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the socket
|
* Create the socket
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
|
if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
|
||||||
releaseStream (s);
|
releaseStream (s);
|
||||||
return RTEMS_TOO_MANY;
|
set_errno_and_return_minus_one( ENOMEM );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bind the socket to a local address
|
* Bind the socket to a local address
|
||||||
*/
|
*/
|
||||||
|
|
||||||
retryCount = 0;
|
retryCount = 0;
|
||||||
rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
|
rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int try = (now + retryCount) % 10;
|
int try = (now + retryCount) % 10;
|
||||||
|
|
||||||
tp->myAddress.sin_family = AF_INET;
|
tp->myAddress.sin_family = AF_INET;
|
||||||
tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + minor);
|
/*
|
||||||
|
* XXX Eric .. how do we get the minor information???
|
||||||
|
* tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + minor);
|
||||||
|
*/
|
||||||
|
tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try);
|
||||||
tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
|
tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY);
|
||||||
if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
|
if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0)
|
||||||
break;
|
break;
|
||||||
if (++retryCount == 10) {
|
if (++retryCount == 10) {
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
|
/*
|
||||||
|
* XXX Eric .. how do we get the minor information to release this???
|
||||||
releaseStream (minor);
|
releaseStream (minor);
|
||||||
return RTEMS_RESOURCE_IN_USE;
|
*/
|
||||||
|
set_errno_and_return_minus_one( EBUSY );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,8 +559,12 @@ rtems_device_driver rtems_tftp_open(
|
|||||||
* Create the request
|
* Create the request
|
||||||
*/
|
*/
|
||||||
tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
|
tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
|
||||||
cp1 = tp->pkbuf.tftpRWRQ.filename_mode;
|
/*
|
||||||
cp2 = remoteFilename;
|
* XXX Eric .. is this cast taking the const off right?
|
||||||
|
*/
|
||||||
|
|
||||||
|
cp1 = (char *) tp->pkbuf.tftpRWRQ.filename_mode;
|
||||||
|
cp2 = (char *) remoteFilename;
|
||||||
while ((*cp1++ = *cp2++) != '\0')
|
while ((*cp1++ = *cp2++) != '\0')
|
||||||
continue;
|
continue;
|
||||||
cp2 = "octet";
|
cp2 = "octet";
|
||||||
@@ -522,8 +579,11 @@ rtems_device_driver rtems_tftp_open(
|
|||||||
(struct sockaddr *)&tp->farAddress,
|
(struct sockaddr *)&tp->farAddress,
|
||||||
sizeof tp->farAddress) < 0) {
|
sizeof tp->farAddress) < 0) {
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
|
/*
|
||||||
|
* XXX Eric .. how do we get the minor information to release this???
|
||||||
releaseStream (minor);
|
releaseStream (minor);
|
||||||
return RTEMS_UNSATISFIED;
|
*/
|
||||||
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -540,16 +600,23 @@ rtems_device_driver rtems_tftp_open(
|
|||||||
tp->eof = (tp->nleft < TFTP_BUFSIZE);
|
tp->eof = (tp->nleft < TFTP_BUFSIZE);
|
||||||
if (sendAck (tp) != 0) {
|
if (sendAck (tp) != 0) {
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
|
/*
|
||||||
|
* XXX Eric .. how do we get the minor information to release this???
|
||||||
releaseStream (minor);
|
releaseStream (minor);
|
||||||
return RTEMS_UNSATISFIED;
|
*/
|
||||||
|
|
||||||
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (opcode == TFTP_OPCODE_ERROR) {
|
if (opcode == TFTP_OPCODE_ERROR) {
|
||||||
tftpSetErrno (tp);
|
tftpSetErrno (tp);
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
releaseStream (ap->iop->data0);
|
/*
|
||||||
return RTEMS_INTERNAL_ERROR;
|
* XXX Eric .. how do we get the minor information to release this???
|
||||||
|
* releaseStream (minor);
|
||||||
|
*/
|
||||||
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -558,35 +625,40 @@ rtems_device_driver rtems_tftp_open(
|
|||||||
*/
|
*/
|
||||||
if (++retryCount >= OPEN_RETRY_LIMIT) {
|
if (++retryCount >= OPEN_RETRY_LIMIT) {
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
|
/*
|
||||||
|
* XXX Eric .. how do we get the minor information to release this???
|
||||||
releaseStream (minor);
|
releaseStream (minor);
|
||||||
return RTEMS_UNSATISFIED;
|
*/
|
||||||
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return RTEMS_SUCCESSFUL;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read from a TFTP stream
|
* Read from a TFTP stream
|
||||||
*/
|
*/
|
||||||
rtems_device_driver rtems_tftp_read(
|
|
||||||
rtems_device_major_number major,
|
int rtems_tftp_read(
|
||||||
rtems_device_minor_number minor,
|
rtems_libio_t *iop,
|
||||||
void *pargp
|
void *buffer,
|
||||||
|
unsigned32 count
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
rtems_libio_rw_args_t *ap = pargp;
|
|
||||||
char *bp;
|
char *bp;
|
||||||
struct tftpStream *tp;
|
struct tftpStream *tp;
|
||||||
int retryCount;
|
int retryCount;
|
||||||
int nwant;
|
int nwant;
|
||||||
|
|
||||||
tp = ap->iop->data1;
|
tp = iop->data1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read till user request is satisfied or EOF is reached
|
* Read till user request is satisfied or EOF is reached
|
||||||
*/
|
*/
|
||||||
bp = ap->buffer;
|
|
||||||
nwant = ap->count;
|
bp = buffer;
|
||||||
|
nwant = count;
|
||||||
while (nwant) {
|
while (nwant) {
|
||||||
if (tp->nleft) {
|
if (tp->nleft) {
|
||||||
int count;
|
int count;
|
||||||
@@ -621,7 +693,7 @@ rtems_device_driver rtems_tftp_read(
|
|||||||
tp->eof = (tp->nleft < TFTP_BUFSIZE);
|
tp->eof = (tp->nleft < TFTP_BUFSIZE);
|
||||||
tp->blocknum++;
|
tp->blocknum++;
|
||||||
if (sendAck (tp) != 0)
|
if (sendAck (tp) != 0)
|
||||||
return RTEMS_IO_ERROR;
|
set_errno_and_return_minus_one( EIO );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (opcode == TFTP_OPCODE_ERROR) {
|
if (opcode == TFTP_OPCODE_ERROR) {
|
||||||
@@ -634,26 +706,27 @@ rtems_device_driver rtems_tftp_read(
|
|||||||
* Keep trying?
|
* Keep trying?
|
||||||
*/
|
*/
|
||||||
if (++retryCount == IO_RETRY_LIMIT)
|
if (++retryCount == IO_RETRY_LIMIT)
|
||||||
return RTEMS_IO_ERROR;
|
set_errno_and_return_minus_one( EIO );
|
||||||
if (sendAck (tp) != 0)
|
if (sendAck (tp) != 0)
|
||||||
return RTEMS_IO_ERROR;
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ap->bytes_moved = ap->count - nwant;
|
|
||||||
return RTEMS_SUCCESSFUL;
|
/*
|
||||||
|
* XXX - Eric is this right?
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
return count - nwant;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Close a TFTP stream
|
* Close a TFTP stream
|
||||||
*/
|
*/
|
||||||
rtems_device_driver rtems_tftp_close(
|
int rtems_tftp_close(
|
||||||
rtems_device_major_number major,
|
rtems_libio_t *iop
|
||||||
rtems_device_minor_number minor,
|
|
||||||
void *pargp
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
rtems_libio_open_close_args_t *ap = pargp;
|
struct tftpStream *tp = iop->data1;;
|
||||||
struct tftpStream *tp = ap->iop->data1;;
|
|
||||||
|
|
||||||
if (!tp->eof && !tp->firstReply) {
|
if (!tp->eof && !tp->firstReply) {
|
||||||
/*
|
/*
|
||||||
@@ -665,14 +738,14 @@ rtems_device_driver rtems_tftp_close(
|
|||||||
rtems_task_wake_after (1 + ticksPerSecond / 10);
|
rtems_task_wake_after (1 + ticksPerSecond / 10);
|
||||||
}
|
}
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
releaseStream (ap->iop->data0);
|
releaseStream (iop->data0);
|
||||||
return RTEMS_SUCCESSFUL;
|
return RTEMS_SUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtems_device_driver rtems_tftp_write(
|
int rtems_tftp_write(
|
||||||
rtems_device_major_number major,
|
rtems_libio_t *iop,
|
||||||
rtems_device_minor_number minor,
|
const void *buffer,
|
||||||
void *pargp
|
unsigned32 count
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return RTEMS_NOT_CONFIGURED;
|
return RTEMS_NOT_CONFIGURED;
|
||||||
@@ -686,3 +759,46 @@ rtems_device_driver rtems_tftp_control(
|
|||||||
{
|
{
|
||||||
return RTEMS_NOT_CONFIGURED;
|
return RTEMS_NOT_CONFIGURED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rtems_filesystem_node_types_t rtems_tftp_node_type(
|
||||||
|
rtems_filesystem_location_info_t *pathloc /* IN */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return RTEMS_FILESYSTEM_MEMORY_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
rtems_filesystem_operations_table rtems_tftp_ops = {
|
||||||
|
rtems_tftp_eval_path, /* eval_path */
|
||||||
|
rtems_tftp_evaluate_for_make, /* evaluate_for_make */
|
||||||
|
NULL, /* link */
|
||||||
|
NULL, /* unlink */
|
||||||
|
rtems_tftp_node_type, /* node_type */
|
||||||
|
NULL, /* mknod */
|
||||||
|
NULL, /* rmnod */
|
||||||
|
NULL, /* chown */
|
||||||
|
NULL, /* freenodinfo */
|
||||||
|
NULL, /* mount */
|
||||||
|
rtems_tftp_mount_me, /* initialize */
|
||||||
|
NULL, /* unmount */
|
||||||
|
NULL, /* fsunmount */
|
||||||
|
NULL, /* utime, */
|
||||||
|
NULL, /* evaluate_link */
|
||||||
|
NULL, /* symlink */
|
||||||
|
NULL, /* readlin */
|
||||||
|
};
|
||||||
|
|
||||||
|
rtems_filesystem_file_handlers_r rtems_tftp_handlers = {
|
||||||
|
rtems_tftp_open,
|
||||||
|
rtems_tftp_close,
|
||||||
|
rtems_tftp_read,
|
||||||
|
rtems_tftp_write,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user