forked from Imagelibrary/rtems
2000-12-14 Eric Norum <eric.norum@usask.ca>
* lib/tftpDriver.c: Added write capability.
This commit is contained in:
@@ -1,3 +1,7 @@
|
|||||||
|
2000-12-14 Eric Norum <eric.norum@usask.ca>
|
||||||
|
|
||||||
|
* lib/tftpDriver.c: Added write capability.
|
||||||
|
|
||||||
2000-12-08 Joel Sherrill <joel@OARcorp.com>
|
2000-12-08 Joel Sherrill <joel@OARcorp.com>
|
||||||
|
|
||||||
* libc/linkaddr.c: Initialized variable to remove warning.
|
* libc/linkaddr.c: Initialized variable to remove warning.
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
* vim: set expandtab tabstop=4 shiftwidth=4 ai :
|
||||||
|
*
|
||||||
* Trivial File Transfer Protocol (RFC 1350)
|
* Trivial File Transfer Protocol (RFC 1350)
|
||||||
*
|
*
|
||||||
* Transfer file to/from remote host
|
* Transfer file to/from remote host
|
||||||
@@ -10,6 +12,7 @@
|
|||||||
* eric@skatter.usask.ca
|
* eric@skatter.usask.ca
|
||||||
*
|
*
|
||||||
* $Id$
|
* $Id$
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -113,7 +116,7 @@ struct tftpStream {
|
|||||||
union tftpPacket pkbuf;
|
union tftpPacket pkbuf;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Last block number received
|
* Last block number transferred
|
||||||
*/
|
*/
|
||||||
rtems_unsigned16 blocknum;
|
rtems_unsigned16 blocknum;
|
||||||
|
|
||||||
@@ -135,6 +138,7 @@ struct tftpStream {
|
|||||||
*/
|
*/
|
||||||
int firstReply;
|
int firstReply;
|
||||||
int eof;
|
int eof;
|
||||||
|
int writing;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -168,7 +172,7 @@ rtems_filesystem_limits_and_options_t rtems_tftp_limits_and_options = {
|
|||||||
6 /* posix_vdisable */
|
6 /* posix_vdisable */
|
||||||
};
|
};
|
||||||
|
|
||||||
int rtems_tftp_mount_me(
|
static int rtems_tftp_mount_me(
|
||||||
rtems_filesystem_mount_table_entry_t *temp_mt_entry
|
rtems_filesystem_mount_table_entry_t *temp_mt_entry
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -234,7 +238,7 @@ int rtems_bsdnet_initialize_tftp_filesystem ()
|
|||||||
status = mount(
|
status = mount(
|
||||||
&entry,
|
&entry,
|
||||||
&rtems_tftp_ops,
|
&rtems_tftp_ops,
|
||||||
RTEMS_FILESYSTEM_READ_ONLY,
|
RTEMS_FILESYSTEM_READ_WRITE,
|
||||||
NULL,
|
NULL,
|
||||||
TFTP_PATHNAME_PREFIX
|
TFTP_PATHNAME_PREFIX
|
||||||
);
|
);
|
||||||
@@ -246,15 +250,14 @@ int rtems_bsdnet_initialize_tftp_filesystem ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set error message
|
* Map error message
|
||||||
* This RTEMS/UNIX error mapping needs to be fixed!
|
|
||||||
*/
|
*/
|
||||||
static void
|
static int
|
||||||
tftpSetErrno (struct tftpStream *tp)
|
tftpErrno (struct tftpStream *tp)
|
||||||
{
|
{
|
||||||
unsigned int tftpError;
|
unsigned int tftpError;
|
||||||
static const int errorMap[] = {
|
static const int errorMap[] = {
|
||||||
0,
|
EINVAL,
|
||||||
ENOENT,
|
ENOENT,
|
||||||
EPERM,
|
EPERM,
|
||||||
ENOSPC,
|
ENOSPC,
|
||||||
@@ -262,14 +265,13 @@ tftpSetErrno (struct tftpStream *tp)
|
|||||||
ENXIO,
|
ENXIO,
|
||||||
EEXIST,
|
EEXIST,
|
||||||
ESRCH,
|
ESRCH,
|
||||||
0,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
tftpError = ntohs (tp->pkbuf.tftpERROR.errorCode);
|
tftpError = ntohs (tp->pkbuf.tftpERROR.errorCode);
|
||||||
if (tftpError < (sizeof errorMap / sizeof errorMap[0]))
|
if (tftpError < (sizeof errorMap / sizeof errorMap[0]))
|
||||||
errno = errorMap[tftpError];
|
return errorMap[tftpError];
|
||||||
else
|
else
|
||||||
errno = 1000 + tftpError;
|
return 1000 + tftpError;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -279,21 +281,24 @@ static void
|
|||||||
sendStifle (struct tftpStream *tp, struct sockaddr_in *to)
|
sendStifle (struct tftpStream *tp, struct sockaddr_in *to)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
|
struct {
|
||||||
|
rtems_unsigned16 opcode;
|
||||||
|
rtems_unsigned16 errorCode;
|
||||||
|
char errorMessage[12];
|
||||||
|
} msg;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the error packet (Unknown transfer ID).
|
* Create the error packet (Unknown transfer ID).
|
||||||
*/
|
*/
|
||||||
tp->pkbuf.tftpERROR.opcode = htons (TFTP_OPCODE_ERROR);
|
msg.opcode = htons (TFTP_OPCODE_ERROR);
|
||||||
tp->pkbuf.tftpERROR.errorCode = htons (5);
|
msg.errorCode = htons (5);
|
||||||
len = sizeof tp->pkbuf.tftpERROR.opcode +
|
len = sizeof msg.opcode + sizeof msg.errorCode + 1;
|
||||||
sizeof tp->pkbuf.tftpERROR.errorCode + 1;
|
len += sprintf (msg.errorMessage, "GO AWAY");
|
||||||
len += sprintf (tp->pkbuf.tftpERROR.errorMessage, "GO AWAY");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send it
|
* Send it
|
||||||
*/
|
*/
|
||||||
sendto (tp->socket, (char *)&tp->pkbuf, len, 0,
|
sendto (tp->socket, (char *)&msg, len, 0, (struct sockaddr *)to, sizeof *to);
|
||||||
(struct sockaddr *)to, sizeof *to);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -374,7 +379,7 @@ releaseStream (int s)
|
|||||||
rtems_semaphore_release (tftp_mutex);
|
rtems_semaphore_release (tftp_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtems_tftp_evaluate_for_make(
|
static int rtems_tftp_evaluate_for_make(
|
||||||
const char *path, /* IN */
|
const char *path, /* IN */
|
||||||
rtems_filesystem_location_info_t *pathloc, /* IN/OUT */
|
rtems_filesystem_location_info_t *pathloc, /* IN/OUT */
|
||||||
const char **name /* OUT */
|
const char **name /* OUT */
|
||||||
@@ -383,11 +388,8 @@ int rtems_tftp_evaluate_for_make(
|
|||||||
set_errno_and_return_minus_one( EIO );
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX - Fix return values.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int rtems_tftp_eval_path(
|
static 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 */
|
||||||
@@ -395,35 +397,32 @@ int rtems_tftp_eval_path(
|
|||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read-only for now
|
* Read-only or write-only for now
|
||||||
*/
|
*/
|
||||||
|
flags &= RTEMS_LIBIO_PERMS_READ | RTEMS_LIBIO_PERMS_WRITE;
|
||||||
if ( (flags & O_WRONLY) == O_WRONLY )
|
if ((flags != RTEMS_LIBIO_PERMS_READ) && (flags != RTEMS_LIBIO_PERMS_WRITE) )
|
||||||
set_errno_and_return_minus_one( ENOENT );
|
set_errno_and_return_minus_one( EINVAL );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The File system is mounted at TFTP_PATHNAME_PREFIX
|
* The File system is mounted at TFTP_PATHNAME_PREFIX
|
||||||
* the caller of this routine has striped off this part of the
|
* 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.
|
* name. Save the remainder of the name for use by the open routine.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pathloc->node_access = (void * ) pathname;
|
pathloc->node_access = (void * ) pathname;
|
||||||
pathloc->handlers = &rtems_tftp_handlers;
|
pathloc->handlers = &rtems_tftp_handlers;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rtems_tftp_open(
|
||||||
int rtems_tftp_open(
|
|
||||||
rtems_libio_t *iop,
|
rtems_libio_t *iop,
|
||||||
const char *new_name,
|
const char *new_name,
|
||||||
unsigned32 flag,
|
unsigned32 flags,
|
||||||
unsigned32 mode
|
unsigned32 mode
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
struct tftpStream *tp;
|
struct tftpStream *tp;
|
||||||
int retryCount;
|
int retryCount;
|
||||||
rtems_unsigned32 farAddress;
|
struct in_addr farAddress;
|
||||||
int s;
|
int s;
|
||||||
int len;
|
int len;
|
||||||
char *cp1;
|
char *cp1;
|
||||||
@@ -435,33 +434,44 @@ int rtems_tftp_open(
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* This came from the evaluate path.
|
* This came from the evaluate path.
|
||||||
|
* Extract host name component
|
||||||
*/
|
*/
|
||||||
|
cp1 = cp2 = iop->file_info;
|
||||||
cp2 = iop->file_info;
|
|
||||||
|
|
||||||
cp1 = cp2;
|
|
||||||
while (*cp2 != '/') {
|
while (*cp2 != '/') {
|
||||||
if (*cp2 == '\0')
|
if (*cp2 == '\0')
|
||||||
return ENOENT;
|
return ENOENT;
|
||||||
cp2++;
|
cp2++;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = cp2 - cp1;
|
len = cp2 - cp1;
|
||||||
hostname = malloc (len + 1);
|
hostname = malloc (len + 1);
|
||||||
if (hostname == NULL)
|
if (hostname == NULL)
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
|
|
||||||
strncpy (hostname, cp1, len);
|
strncpy (hostname, cp1, len);
|
||||||
hostname[len] = '\0';
|
hostname[len] = '\0';
|
||||||
farAddress = inet_addr (hostname);
|
|
||||||
|
/*
|
||||||
|
* Convert hostname to Internet address
|
||||||
|
*/
|
||||||
|
if (strcmp (hostname, "BOOTP_HOST") == 0)
|
||||||
|
farAddress = rtems_bsdnet_bootp_server_address;
|
||||||
|
else
|
||||||
|
farAddress.s_addr = inet_addr (hostname);
|
||||||
free (hostname);
|
free (hostname);
|
||||||
|
if ((farAddress.s_addr == 0) || (farAddress.s_addr == ~0))
|
||||||
if ((farAddress == 0) || (farAddress == ~0))
|
|
||||||
return ENOENT;
|
return ENOENT;
|
||||||
|
|
||||||
if (*++cp2 == '\0')
|
/*
|
||||||
|
* Extract file pathname component
|
||||||
|
*/
|
||||||
|
while (*cp2 == '/')
|
||||||
|
cp2++;
|
||||||
|
if (strcmp (cp2, "BOOTP_FILE") == 0) {
|
||||||
|
cp2 = rtems_bsdnet_bootp_boot_file_name;
|
||||||
|
while (*cp2 == '/')
|
||||||
|
cp2++;
|
||||||
|
}
|
||||||
|
if (*cp2 == '\0')
|
||||||
return ENOENT;
|
return ENOENT;
|
||||||
|
|
||||||
remoteFilename = cp2;
|
remoteFilename = cp2;
|
||||||
if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
|
if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
|
||||||
return ENOENT;
|
return ENOENT;
|
||||||
@@ -469,16 +479,13 @@ int rtems_tftp_open(
|
|||||||
/*
|
/*
|
||||||
* 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 EBUSY;
|
return 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
|
||||||
@@ -493,7 +500,6 @@ int rtems_tftp_open(
|
|||||||
}
|
}
|
||||||
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)
|
||||||
@@ -504,7 +510,6 @@ int rtems_tftp_open(
|
|||||||
/*
|
/*
|
||||||
* 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 ENOMEM;
|
return ENOMEM;
|
||||||
@@ -513,7 +518,6 @@ int rtems_tftp_open(
|
|||||||
/*
|
/*
|
||||||
* 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 (;;) {
|
||||||
@@ -536,7 +540,7 @@ int rtems_tftp_open(
|
|||||||
* port on the remote machine.
|
* port on the remote machine.
|
||||||
*/
|
*/
|
||||||
tp->farAddress.sin_family = AF_INET;
|
tp->farAddress.sin_family = AF_INET;
|
||||||
tp->farAddress.sin_addr.s_addr = farAddress;
|
tp->farAddress.sin_addr = farAddress;
|
||||||
tp->farAddress.sin_port = htons (69);
|
tp->farAddress.sin_port = htons (69);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -547,7 +551,14 @@ int rtems_tftp_open(
|
|||||||
/*
|
/*
|
||||||
* Create the request
|
* Create the request
|
||||||
*/
|
*/
|
||||||
|
if ((flags & O_ACCMODE) == O_RDONLY) {
|
||||||
|
tp->writing = 0;
|
||||||
tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
|
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;
|
cp1 = (char *) tp->pkbuf.tftpRWRQ.filename_mode;
|
||||||
cp2 = (char *) remoteFilename;
|
cp2 = (char *) remoteFilename;
|
||||||
while ((*cp1++ = *cp2++) != '\0')
|
while ((*cp1++ = *cp2++) != '\0')
|
||||||
@@ -574,7 +585,8 @@ int rtems_tftp_open(
|
|||||||
len = getPacket (tp);
|
len = getPacket (tp);
|
||||||
if (len >= (int) sizeof tp->pkbuf.tftpACK) {
|
if (len >= (int) sizeof tp->pkbuf.tftpACK) {
|
||||||
int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
|
int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
|
||||||
if ((opcode == TFTP_OPCODE_DATA)
|
if (!tp->writing
|
||||||
|
&& (opcode == TFTP_OPCODE_DATA)
|
||||||
&& (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) {
|
&& (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) {
|
||||||
tp->nused = 0;
|
tp->nused = 0;
|
||||||
tp->blocknum = 1;
|
tp->blocknum = 1;
|
||||||
@@ -587,11 +599,18 @@ int rtems_tftp_open(
|
|||||||
}
|
}
|
||||||
break;
|
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) {
|
if (opcode == TFTP_OPCODE_ERROR) {
|
||||||
tftpSetErrno (tp);
|
int e = tftpErrno (tp);
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
releaseStream (s);
|
releaseStream (s);
|
||||||
return EIO;
|
return e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -604,45 +623,41 @@ int rtems_tftp_open(
|
|||||||
return EIO;
|
return EIO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read from a TFTP stream
|
* Read from a TFTP stream
|
||||||
*/
|
*/
|
||||||
|
static int rtems_tftp_read(
|
||||||
int rtems_tftp_read(
|
|
||||||
rtems_libio_t *iop,
|
rtems_libio_t *iop,
|
||||||
void *buffer,
|
void *buffer,
|
||||||
unsigned32 count
|
unsigned32 count
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
char *bp;
|
char *bp;
|
||||||
struct tftpStream *tp;
|
struct tftpStream *tp = iop->data1;
|
||||||
int retryCount;
|
int retryCount;
|
||||||
int nwant;
|
int nwant;
|
||||||
|
|
||||||
tp = iop->data1;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read till user request is satisfied or EOF is reached
|
* Read till user request is satisfied or EOF is reached
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bp = buffer;
|
bp = buffer;
|
||||||
nwant = count;
|
nwant = count;
|
||||||
while (nwant) {
|
while (nwant) {
|
||||||
if (tp->nleft) {
|
if (tp->nleft) {
|
||||||
int count;
|
int ncopy;
|
||||||
if (nwant < tp->nleft)
|
if (nwant < tp->nleft)
|
||||||
count = nwant;
|
ncopy = nwant;
|
||||||
else
|
else
|
||||||
count = tp->nleft;
|
ncopy = tp->nleft;
|
||||||
memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], count);
|
memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], ncopy);
|
||||||
tp->nused += count;
|
tp->nused += ncopy;
|
||||||
tp->nleft -= count;
|
tp->nleft -= ncopy;
|
||||||
bp += count;
|
bp += ncopy;
|
||||||
nwant -= count;
|
nwant -= ncopy;
|
||||||
if (nwant == 0)
|
if (nwant == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -668,10 +683,8 @@ int rtems_tftp_read(
|
|||||||
set_errno_and_return_minus_one( EIO );
|
set_errno_and_return_minus_one( EIO );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (opcode == TFTP_OPCODE_ERROR) {
|
if (opcode == TFTP_OPCODE_ERROR)
|
||||||
tftpSetErrno (tp);
|
set_errno_and_return_minus_one( tftpErrno (tp) );
|
||||||
return RTEMS_INTERNAL_ERROR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -683,23 +696,57 @@ int rtems_tftp_read(
|
|||||||
set_errno_and_return_minus_one( EIO );
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return count - nwant;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX - Eric is this right?
|
* Flush a write buffer and wait for acknowledgement
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
return count - nwant;
|
static int rtems_tftp_flush ( struct tftpStream *tp )
|
||||||
|
{
|
||||||
|
int wlen, rlen;
|
||||||
|
int retryCount = 0;
|
||||||
|
|
||||||
|
wlen = tp->nused + 2 * sizeof (rtems_unsigned16);
|
||||||
|
for (;;) {
|
||||||
|
tp->pkbuf.tftpDATA.opcode = htons (TFTP_OPCODE_DATA);
|
||||||
|
tp->pkbuf.tftpDATA.blocknum = htons (tp->blocknum);
|
||||||
|
if (sendto (tp->socket, (char *)&tp->pkbuf, wlen, 0,
|
||||||
|
(struct sockaddr *)&tp->farAddress,
|
||||||
|
sizeof tp->farAddress) < 0)
|
||||||
|
return EIO;
|
||||||
|
rlen = getPacket (tp);
|
||||||
|
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
|
* Close a TFTP stream
|
||||||
*/
|
*/
|
||||||
int rtems_tftp_close(
|
static int rtems_tftp_close(
|
||||||
rtems_libio_t *iop
|
rtems_libio_t *iop
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
struct tftpStream *tp = iop->data1;;
|
struct tftpStream *tp = iop->data1;;
|
||||||
|
|
||||||
|
if (tp->writing)
|
||||||
|
rtems_tftp_flush (tp);
|
||||||
if (!tp->eof && !tp->firstReply) {
|
if (!tp->eof && !tp->firstReply) {
|
||||||
/*
|
/*
|
||||||
* Tell the other end to stop
|
* Tell the other end to stop
|
||||||
@@ -714,22 +761,62 @@ int rtems_tftp_close(
|
|||||||
return RTEMS_SUCCESSFUL;
|
return RTEMS_SUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtems_tftp_write(
|
static int rtems_tftp_write(
|
||||||
rtems_libio_t *iop,
|
rtems_libio_t *iop,
|
||||||
const void *buffer,
|
const void *buffer,
|
||||||
unsigned32 count
|
unsigned32 count
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return RTEMS_NOT_CONFIGURED;
|
const char *bp;
|
||||||
|
struct tftpStream *tp = iop->data1;
|
||||||
|
int nleft, nfree, ncopy;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bail out if an error has occurred
|
||||||
|
*/
|
||||||
|
if (!tp->writing)
|
||||||
|
return 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;
|
||||||
|
set_errno_and_return_minus_one (e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtems_device_driver rtems_tftp_control(
|
/*
|
||||||
rtems_device_major_number major,
|
* Dummy version to let fopen(xxxx,"w") work properly.
|
||||||
rtems_device_minor_number minor,
|
*/
|
||||||
void *pargp
|
static int rtems_tftp_ftruncate(
|
||||||
|
rtems_libio_t *iop,
|
||||||
|
off_t count
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return RTEMS_NOT_CONFIGURED;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtems_filesystem_node_types_t rtems_tftp_node_type(
|
rtems_filesystem_node_types_t rtems_tftp_node_type(
|
||||||
@@ -768,7 +855,7 @@ rtems_filesystem_file_handlers_r rtems_tftp_handlers = {
|
|||||||
NULL, /* lseek */
|
NULL, /* lseek */
|
||||||
NULL, /* fstat */
|
NULL, /* fstat */
|
||||||
NULL, /* fchmod */
|
NULL, /* fchmod */
|
||||||
NULL, /* ftruncate */
|
rtems_tftp_ftruncate, /* ftruncate */
|
||||||
NULL, /* fpathconf */
|
NULL, /* fpathconf */
|
||||||
NULL, /* fsync */
|
NULL, /* fsync */
|
||||||
NULL, /* fdatasync */
|
NULL, /* fdatasync */
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
2000-12-14 Eric Norum <eric.norum@usask.ca>
|
||||||
|
|
||||||
|
* lib/tftpDriver.c: Added write capability.
|
||||||
|
|
||||||
2000-12-08 Joel Sherrill <joel@OARcorp.com>
|
2000-12-08 Joel Sherrill <joel@OARcorp.com>
|
||||||
|
|
||||||
* libc/linkaddr.c: Initialized variable to remove warning.
|
* libc/linkaddr.c: Initialized variable to remove warning.
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
* vim: set expandtab tabstop=4 shiftwidth=4 ai :
|
||||||
|
*
|
||||||
* Trivial File Transfer Protocol (RFC 1350)
|
* Trivial File Transfer Protocol (RFC 1350)
|
||||||
*
|
*
|
||||||
* Transfer file to/from remote host
|
* Transfer file to/from remote host
|
||||||
@@ -10,6 +12,7 @@
|
|||||||
* eric@skatter.usask.ca
|
* eric@skatter.usask.ca
|
||||||
*
|
*
|
||||||
* $Id$
|
* $Id$
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -113,7 +116,7 @@ struct tftpStream {
|
|||||||
union tftpPacket pkbuf;
|
union tftpPacket pkbuf;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Last block number received
|
* Last block number transferred
|
||||||
*/
|
*/
|
||||||
rtems_unsigned16 blocknum;
|
rtems_unsigned16 blocknum;
|
||||||
|
|
||||||
@@ -135,6 +138,7 @@ struct tftpStream {
|
|||||||
*/
|
*/
|
||||||
int firstReply;
|
int firstReply;
|
||||||
int eof;
|
int eof;
|
||||||
|
int writing;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -168,7 +172,7 @@ rtems_filesystem_limits_and_options_t rtems_tftp_limits_and_options = {
|
|||||||
6 /* posix_vdisable */
|
6 /* posix_vdisable */
|
||||||
};
|
};
|
||||||
|
|
||||||
int rtems_tftp_mount_me(
|
static int rtems_tftp_mount_me(
|
||||||
rtems_filesystem_mount_table_entry_t *temp_mt_entry
|
rtems_filesystem_mount_table_entry_t *temp_mt_entry
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -234,7 +238,7 @@ int rtems_bsdnet_initialize_tftp_filesystem ()
|
|||||||
status = mount(
|
status = mount(
|
||||||
&entry,
|
&entry,
|
||||||
&rtems_tftp_ops,
|
&rtems_tftp_ops,
|
||||||
RTEMS_FILESYSTEM_READ_ONLY,
|
RTEMS_FILESYSTEM_READ_WRITE,
|
||||||
NULL,
|
NULL,
|
||||||
TFTP_PATHNAME_PREFIX
|
TFTP_PATHNAME_PREFIX
|
||||||
);
|
);
|
||||||
@@ -246,15 +250,14 @@ int rtems_bsdnet_initialize_tftp_filesystem ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set error message
|
* Map error message
|
||||||
* This RTEMS/UNIX error mapping needs to be fixed!
|
|
||||||
*/
|
*/
|
||||||
static void
|
static int
|
||||||
tftpSetErrno (struct tftpStream *tp)
|
tftpErrno (struct tftpStream *tp)
|
||||||
{
|
{
|
||||||
unsigned int tftpError;
|
unsigned int tftpError;
|
||||||
static const int errorMap[] = {
|
static const int errorMap[] = {
|
||||||
0,
|
EINVAL,
|
||||||
ENOENT,
|
ENOENT,
|
||||||
EPERM,
|
EPERM,
|
||||||
ENOSPC,
|
ENOSPC,
|
||||||
@@ -262,14 +265,13 @@ tftpSetErrno (struct tftpStream *tp)
|
|||||||
ENXIO,
|
ENXIO,
|
||||||
EEXIST,
|
EEXIST,
|
||||||
ESRCH,
|
ESRCH,
|
||||||
0,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
tftpError = ntohs (tp->pkbuf.tftpERROR.errorCode);
|
tftpError = ntohs (tp->pkbuf.tftpERROR.errorCode);
|
||||||
if (tftpError < (sizeof errorMap / sizeof errorMap[0]))
|
if (tftpError < (sizeof errorMap / sizeof errorMap[0]))
|
||||||
errno = errorMap[tftpError];
|
return errorMap[tftpError];
|
||||||
else
|
else
|
||||||
errno = 1000 + tftpError;
|
return 1000 + tftpError;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -279,21 +281,24 @@ static void
|
|||||||
sendStifle (struct tftpStream *tp, struct sockaddr_in *to)
|
sendStifle (struct tftpStream *tp, struct sockaddr_in *to)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
|
struct {
|
||||||
|
rtems_unsigned16 opcode;
|
||||||
|
rtems_unsigned16 errorCode;
|
||||||
|
char errorMessage[12];
|
||||||
|
} msg;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the error packet (Unknown transfer ID).
|
* Create the error packet (Unknown transfer ID).
|
||||||
*/
|
*/
|
||||||
tp->pkbuf.tftpERROR.opcode = htons (TFTP_OPCODE_ERROR);
|
msg.opcode = htons (TFTP_OPCODE_ERROR);
|
||||||
tp->pkbuf.tftpERROR.errorCode = htons (5);
|
msg.errorCode = htons (5);
|
||||||
len = sizeof tp->pkbuf.tftpERROR.opcode +
|
len = sizeof msg.opcode + sizeof msg.errorCode + 1;
|
||||||
sizeof tp->pkbuf.tftpERROR.errorCode + 1;
|
len += sprintf (msg.errorMessage, "GO AWAY");
|
||||||
len += sprintf (tp->pkbuf.tftpERROR.errorMessage, "GO AWAY");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send it
|
* Send it
|
||||||
*/
|
*/
|
||||||
sendto (tp->socket, (char *)&tp->pkbuf, len, 0,
|
sendto (tp->socket, (char *)&msg, len, 0, (struct sockaddr *)to, sizeof *to);
|
||||||
(struct sockaddr *)to, sizeof *to);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -374,7 +379,7 @@ releaseStream (int s)
|
|||||||
rtems_semaphore_release (tftp_mutex);
|
rtems_semaphore_release (tftp_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtems_tftp_evaluate_for_make(
|
static int rtems_tftp_evaluate_for_make(
|
||||||
const char *path, /* IN */
|
const char *path, /* IN */
|
||||||
rtems_filesystem_location_info_t *pathloc, /* IN/OUT */
|
rtems_filesystem_location_info_t *pathloc, /* IN/OUT */
|
||||||
const char **name /* OUT */
|
const char **name /* OUT */
|
||||||
@@ -383,11 +388,8 @@ int rtems_tftp_evaluate_for_make(
|
|||||||
set_errno_and_return_minus_one( EIO );
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX - Fix return values.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int rtems_tftp_eval_path(
|
static 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 */
|
||||||
@@ -395,35 +397,32 @@ int rtems_tftp_eval_path(
|
|||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read-only for now
|
* Read-only or write-only for now
|
||||||
*/
|
*/
|
||||||
|
flags &= RTEMS_LIBIO_PERMS_READ | RTEMS_LIBIO_PERMS_WRITE;
|
||||||
if ( (flags & O_WRONLY) == O_WRONLY )
|
if ((flags != RTEMS_LIBIO_PERMS_READ) && (flags != RTEMS_LIBIO_PERMS_WRITE) )
|
||||||
set_errno_and_return_minus_one( ENOENT );
|
set_errno_and_return_minus_one( EINVAL );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The File system is mounted at TFTP_PATHNAME_PREFIX
|
* The File system is mounted at TFTP_PATHNAME_PREFIX
|
||||||
* the caller of this routine has striped off this part of the
|
* 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.
|
* name. Save the remainder of the name for use by the open routine.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pathloc->node_access = (void * ) pathname;
|
pathloc->node_access = (void * ) pathname;
|
||||||
pathloc->handlers = &rtems_tftp_handlers;
|
pathloc->handlers = &rtems_tftp_handlers;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rtems_tftp_open(
|
||||||
int rtems_tftp_open(
|
|
||||||
rtems_libio_t *iop,
|
rtems_libio_t *iop,
|
||||||
const char *new_name,
|
const char *new_name,
|
||||||
unsigned32 flag,
|
unsigned32 flags,
|
||||||
unsigned32 mode
|
unsigned32 mode
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
struct tftpStream *tp;
|
struct tftpStream *tp;
|
||||||
int retryCount;
|
int retryCount;
|
||||||
rtems_unsigned32 farAddress;
|
struct in_addr farAddress;
|
||||||
int s;
|
int s;
|
||||||
int len;
|
int len;
|
||||||
char *cp1;
|
char *cp1;
|
||||||
@@ -435,33 +434,44 @@ int rtems_tftp_open(
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* This came from the evaluate path.
|
* This came from the evaluate path.
|
||||||
|
* Extract host name component
|
||||||
*/
|
*/
|
||||||
|
cp1 = cp2 = iop->file_info;
|
||||||
cp2 = iop->file_info;
|
|
||||||
|
|
||||||
cp1 = cp2;
|
|
||||||
while (*cp2 != '/') {
|
while (*cp2 != '/') {
|
||||||
if (*cp2 == '\0')
|
if (*cp2 == '\0')
|
||||||
return ENOENT;
|
return ENOENT;
|
||||||
cp2++;
|
cp2++;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = cp2 - cp1;
|
len = cp2 - cp1;
|
||||||
hostname = malloc (len + 1);
|
hostname = malloc (len + 1);
|
||||||
if (hostname == NULL)
|
if (hostname == NULL)
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
|
|
||||||
strncpy (hostname, cp1, len);
|
strncpy (hostname, cp1, len);
|
||||||
hostname[len] = '\0';
|
hostname[len] = '\0';
|
||||||
farAddress = inet_addr (hostname);
|
|
||||||
|
/*
|
||||||
|
* Convert hostname to Internet address
|
||||||
|
*/
|
||||||
|
if (strcmp (hostname, "BOOTP_HOST") == 0)
|
||||||
|
farAddress = rtems_bsdnet_bootp_server_address;
|
||||||
|
else
|
||||||
|
farAddress.s_addr = inet_addr (hostname);
|
||||||
free (hostname);
|
free (hostname);
|
||||||
|
if ((farAddress.s_addr == 0) || (farAddress.s_addr == ~0))
|
||||||
if ((farAddress == 0) || (farAddress == ~0))
|
|
||||||
return ENOENT;
|
return ENOENT;
|
||||||
|
|
||||||
if (*++cp2 == '\0')
|
/*
|
||||||
|
* Extract file pathname component
|
||||||
|
*/
|
||||||
|
while (*cp2 == '/')
|
||||||
|
cp2++;
|
||||||
|
if (strcmp (cp2, "BOOTP_FILE") == 0) {
|
||||||
|
cp2 = rtems_bsdnet_bootp_boot_file_name;
|
||||||
|
while (*cp2 == '/')
|
||||||
|
cp2++;
|
||||||
|
}
|
||||||
|
if (*cp2 == '\0')
|
||||||
return ENOENT;
|
return ENOENT;
|
||||||
|
|
||||||
remoteFilename = cp2;
|
remoteFilename = cp2;
|
||||||
if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
|
if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
|
||||||
return ENOENT;
|
return ENOENT;
|
||||||
@@ -469,16 +479,13 @@ int rtems_tftp_open(
|
|||||||
/*
|
/*
|
||||||
* 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 EBUSY;
|
return 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
|
||||||
@@ -493,7 +500,6 @@ int rtems_tftp_open(
|
|||||||
}
|
}
|
||||||
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)
|
||||||
@@ -504,7 +510,6 @@ int rtems_tftp_open(
|
|||||||
/*
|
/*
|
||||||
* 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 ENOMEM;
|
return ENOMEM;
|
||||||
@@ -513,7 +518,6 @@ int rtems_tftp_open(
|
|||||||
/*
|
/*
|
||||||
* 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 (;;) {
|
||||||
@@ -536,7 +540,7 @@ int rtems_tftp_open(
|
|||||||
* port on the remote machine.
|
* port on the remote machine.
|
||||||
*/
|
*/
|
||||||
tp->farAddress.sin_family = AF_INET;
|
tp->farAddress.sin_family = AF_INET;
|
||||||
tp->farAddress.sin_addr.s_addr = farAddress;
|
tp->farAddress.sin_addr = farAddress;
|
||||||
tp->farAddress.sin_port = htons (69);
|
tp->farAddress.sin_port = htons (69);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -547,7 +551,14 @@ int rtems_tftp_open(
|
|||||||
/*
|
/*
|
||||||
* Create the request
|
* Create the request
|
||||||
*/
|
*/
|
||||||
|
if ((flags & O_ACCMODE) == O_RDONLY) {
|
||||||
|
tp->writing = 0;
|
||||||
tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
|
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;
|
cp1 = (char *) tp->pkbuf.tftpRWRQ.filename_mode;
|
||||||
cp2 = (char *) remoteFilename;
|
cp2 = (char *) remoteFilename;
|
||||||
while ((*cp1++ = *cp2++) != '\0')
|
while ((*cp1++ = *cp2++) != '\0')
|
||||||
@@ -574,7 +585,8 @@ int rtems_tftp_open(
|
|||||||
len = getPacket (tp);
|
len = getPacket (tp);
|
||||||
if (len >= (int) sizeof tp->pkbuf.tftpACK) {
|
if (len >= (int) sizeof tp->pkbuf.tftpACK) {
|
||||||
int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
|
int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
|
||||||
if ((opcode == TFTP_OPCODE_DATA)
|
if (!tp->writing
|
||||||
|
&& (opcode == TFTP_OPCODE_DATA)
|
||||||
&& (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) {
|
&& (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) {
|
||||||
tp->nused = 0;
|
tp->nused = 0;
|
||||||
tp->blocknum = 1;
|
tp->blocknum = 1;
|
||||||
@@ -587,11 +599,18 @@ int rtems_tftp_open(
|
|||||||
}
|
}
|
||||||
break;
|
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) {
|
if (opcode == TFTP_OPCODE_ERROR) {
|
||||||
tftpSetErrno (tp);
|
int e = tftpErrno (tp);
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
releaseStream (s);
|
releaseStream (s);
|
||||||
return EIO;
|
return e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -604,45 +623,41 @@ int rtems_tftp_open(
|
|||||||
return EIO;
|
return EIO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read from a TFTP stream
|
* Read from a TFTP stream
|
||||||
*/
|
*/
|
||||||
|
static int rtems_tftp_read(
|
||||||
int rtems_tftp_read(
|
|
||||||
rtems_libio_t *iop,
|
rtems_libio_t *iop,
|
||||||
void *buffer,
|
void *buffer,
|
||||||
unsigned32 count
|
unsigned32 count
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
char *bp;
|
char *bp;
|
||||||
struct tftpStream *tp;
|
struct tftpStream *tp = iop->data1;
|
||||||
int retryCount;
|
int retryCount;
|
||||||
int nwant;
|
int nwant;
|
||||||
|
|
||||||
tp = iop->data1;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read till user request is satisfied or EOF is reached
|
* Read till user request is satisfied or EOF is reached
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bp = buffer;
|
bp = buffer;
|
||||||
nwant = count;
|
nwant = count;
|
||||||
while (nwant) {
|
while (nwant) {
|
||||||
if (tp->nleft) {
|
if (tp->nleft) {
|
||||||
int count;
|
int ncopy;
|
||||||
if (nwant < tp->nleft)
|
if (nwant < tp->nleft)
|
||||||
count = nwant;
|
ncopy = nwant;
|
||||||
else
|
else
|
||||||
count = tp->nleft;
|
ncopy = tp->nleft;
|
||||||
memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], count);
|
memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], ncopy);
|
||||||
tp->nused += count;
|
tp->nused += ncopy;
|
||||||
tp->nleft -= count;
|
tp->nleft -= ncopy;
|
||||||
bp += count;
|
bp += ncopy;
|
||||||
nwant -= count;
|
nwant -= ncopy;
|
||||||
if (nwant == 0)
|
if (nwant == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -668,10 +683,8 @@ int rtems_tftp_read(
|
|||||||
set_errno_and_return_minus_one( EIO );
|
set_errno_and_return_minus_one( EIO );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (opcode == TFTP_OPCODE_ERROR) {
|
if (opcode == TFTP_OPCODE_ERROR)
|
||||||
tftpSetErrno (tp);
|
set_errno_and_return_minus_one( tftpErrno (tp) );
|
||||||
return RTEMS_INTERNAL_ERROR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -683,23 +696,57 @@ int rtems_tftp_read(
|
|||||||
set_errno_and_return_minus_one( EIO );
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return count - nwant;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX - Eric is this right?
|
* Flush a write buffer and wait for acknowledgement
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
return count - nwant;
|
static int rtems_tftp_flush ( struct tftpStream *tp )
|
||||||
|
{
|
||||||
|
int wlen, rlen;
|
||||||
|
int retryCount = 0;
|
||||||
|
|
||||||
|
wlen = tp->nused + 2 * sizeof (rtems_unsigned16);
|
||||||
|
for (;;) {
|
||||||
|
tp->pkbuf.tftpDATA.opcode = htons (TFTP_OPCODE_DATA);
|
||||||
|
tp->pkbuf.tftpDATA.blocknum = htons (tp->blocknum);
|
||||||
|
if (sendto (tp->socket, (char *)&tp->pkbuf, wlen, 0,
|
||||||
|
(struct sockaddr *)&tp->farAddress,
|
||||||
|
sizeof tp->farAddress) < 0)
|
||||||
|
return EIO;
|
||||||
|
rlen = getPacket (tp);
|
||||||
|
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
|
* Close a TFTP stream
|
||||||
*/
|
*/
|
||||||
int rtems_tftp_close(
|
static int rtems_tftp_close(
|
||||||
rtems_libio_t *iop
|
rtems_libio_t *iop
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
struct tftpStream *tp = iop->data1;;
|
struct tftpStream *tp = iop->data1;;
|
||||||
|
|
||||||
|
if (tp->writing)
|
||||||
|
rtems_tftp_flush (tp);
|
||||||
if (!tp->eof && !tp->firstReply) {
|
if (!tp->eof && !tp->firstReply) {
|
||||||
/*
|
/*
|
||||||
* Tell the other end to stop
|
* Tell the other end to stop
|
||||||
@@ -714,22 +761,62 @@ int rtems_tftp_close(
|
|||||||
return RTEMS_SUCCESSFUL;
|
return RTEMS_SUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtems_tftp_write(
|
static int rtems_tftp_write(
|
||||||
rtems_libio_t *iop,
|
rtems_libio_t *iop,
|
||||||
const void *buffer,
|
const void *buffer,
|
||||||
unsigned32 count
|
unsigned32 count
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return RTEMS_NOT_CONFIGURED;
|
const char *bp;
|
||||||
|
struct tftpStream *tp = iop->data1;
|
||||||
|
int nleft, nfree, ncopy;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bail out if an error has occurred
|
||||||
|
*/
|
||||||
|
if (!tp->writing)
|
||||||
|
return 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;
|
||||||
|
set_errno_and_return_minus_one (e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtems_device_driver rtems_tftp_control(
|
/*
|
||||||
rtems_device_major_number major,
|
* Dummy version to let fopen(xxxx,"w") work properly.
|
||||||
rtems_device_minor_number minor,
|
*/
|
||||||
void *pargp
|
static int rtems_tftp_ftruncate(
|
||||||
|
rtems_libio_t *iop,
|
||||||
|
off_t count
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return RTEMS_NOT_CONFIGURED;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtems_filesystem_node_types_t rtems_tftp_node_type(
|
rtems_filesystem_node_types_t rtems_tftp_node_type(
|
||||||
@@ -768,7 +855,7 @@ rtems_filesystem_file_handlers_r rtems_tftp_handlers = {
|
|||||||
NULL, /* lseek */
|
NULL, /* lseek */
|
||||||
NULL, /* fstat */
|
NULL, /* fstat */
|
||||||
NULL, /* fchmod */
|
NULL, /* fchmod */
|
||||||
NULL, /* ftruncate */
|
rtems_tftp_ftruncate, /* ftruncate */
|
||||||
NULL, /* fpathconf */
|
NULL, /* fpathconf */
|
||||||
NULL, /* fsync */
|
NULL, /* fsync */
|
||||||
NULL, /* fdatasync */
|
NULL, /* fdatasync */
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
2000-12-14 Eric Norum <eric.norum@usask.ca>
|
||||||
|
|
||||||
|
* lib/tftpDriver.c: Added write capability.
|
||||||
|
|
||||||
2000-12-08 Joel Sherrill <joel@OARcorp.com>
|
2000-12-08 Joel Sherrill <joel@OARcorp.com>
|
||||||
|
|
||||||
* libc/linkaddr.c: Initialized variable to remove warning.
|
* libc/linkaddr.c: Initialized variable to remove warning.
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
|
* vim: set expandtab tabstop=4 shiftwidth=4 ai :
|
||||||
|
*
|
||||||
* Trivial File Transfer Protocol (RFC 1350)
|
* Trivial File Transfer Protocol (RFC 1350)
|
||||||
*
|
*
|
||||||
* Transfer file to/from remote host
|
* Transfer file to/from remote host
|
||||||
@@ -10,6 +12,7 @@
|
|||||||
* eric@skatter.usask.ca
|
* eric@skatter.usask.ca
|
||||||
*
|
*
|
||||||
* $Id$
|
* $Id$
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -113,7 +116,7 @@ struct tftpStream {
|
|||||||
union tftpPacket pkbuf;
|
union tftpPacket pkbuf;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Last block number received
|
* Last block number transferred
|
||||||
*/
|
*/
|
||||||
rtems_unsigned16 blocknum;
|
rtems_unsigned16 blocknum;
|
||||||
|
|
||||||
@@ -135,6 +138,7 @@ struct tftpStream {
|
|||||||
*/
|
*/
|
||||||
int firstReply;
|
int firstReply;
|
||||||
int eof;
|
int eof;
|
||||||
|
int writing;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -168,7 +172,7 @@ rtems_filesystem_limits_and_options_t rtems_tftp_limits_and_options = {
|
|||||||
6 /* posix_vdisable */
|
6 /* posix_vdisable */
|
||||||
};
|
};
|
||||||
|
|
||||||
int rtems_tftp_mount_me(
|
static int rtems_tftp_mount_me(
|
||||||
rtems_filesystem_mount_table_entry_t *temp_mt_entry
|
rtems_filesystem_mount_table_entry_t *temp_mt_entry
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -234,7 +238,7 @@ int rtems_bsdnet_initialize_tftp_filesystem ()
|
|||||||
status = mount(
|
status = mount(
|
||||||
&entry,
|
&entry,
|
||||||
&rtems_tftp_ops,
|
&rtems_tftp_ops,
|
||||||
RTEMS_FILESYSTEM_READ_ONLY,
|
RTEMS_FILESYSTEM_READ_WRITE,
|
||||||
NULL,
|
NULL,
|
||||||
TFTP_PATHNAME_PREFIX
|
TFTP_PATHNAME_PREFIX
|
||||||
);
|
);
|
||||||
@@ -246,15 +250,14 @@ int rtems_bsdnet_initialize_tftp_filesystem ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set error message
|
* Map error message
|
||||||
* This RTEMS/UNIX error mapping needs to be fixed!
|
|
||||||
*/
|
*/
|
||||||
static void
|
static int
|
||||||
tftpSetErrno (struct tftpStream *tp)
|
tftpErrno (struct tftpStream *tp)
|
||||||
{
|
{
|
||||||
unsigned int tftpError;
|
unsigned int tftpError;
|
||||||
static const int errorMap[] = {
|
static const int errorMap[] = {
|
||||||
0,
|
EINVAL,
|
||||||
ENOENT,
|
ENOENT,
|
||||||
EPERM,
|
EPERM,
|
||||||
ENOSPC,
|
ENOSPC,
|
||||||
@@ -262,14 +265,13 @@ tftpSetErrno (struct tftpStream *tp)
|
|||||||
ENXIO,
|
ENXIO,
|
||||||
EEXIST,
|
EEXIST,
|
||||||
ESRCH,
|
ESRCH,
|
||||||
0,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
tftpError = ntohs (tp->pkbuf.tftpERROR.errorCode);
|
tftpError = ntohs (tp->pkbuf.tftpERROR.errorCode);
|
||||||
if (tftpError < (sizeof errorMap / sizeof errorMap[0]))
|
if (tftpError < (sizeof errorMap / sizeof errorMap[0]))
|
||||||
errno = errorMap[tftpError];
|
return errorMap[tftpError];
|
||||||
else
|
else
|
||||||
errno = 1000 + tftpError;
|
return 1000 + tftpError;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -279,21 +281,24 @@ static void
|
|||||||
sendStifle (struct tftpStream *tp, struct sockaddr_in *to)
|
sendStifle (struct tftpStream *tp, struct sockaddr_in *to)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
|
struct {
|
||||||
|
rtems_unsigned16 opcode;
|
||||||
|
rtems_unsigned16 errorCode;
|
||||||
|
char errorMessage[12];
|
||||||
|
} msg;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the error packet (Unknown transfer ID).
|
* Create the error packet (Unknown transfer ID).
|
||||||
*/
|
*/
|
||||||
tp->pkbuf.tftpERROR.opcode = htons (TFTP_OPCODE_ERROR);
|
msg.opcode = htons (TFTP_OPCODE_ERROR);
|
||||||
tp->pkbuf.tftpERROR.errorCode = htons (5);
|
msg.errorCode = htons (5);
|
||||||
len = sizeof tp->pkbuf.tftpERROR.opcode +
|
len = sizeof msg.opcode + sizeof msg.errorCode + 1;
|
||||||
sizeof tp->pkbuf.tftpERROR.errorCode + 1;
|
len += sprintf (msg.errorMessage, "GO AWAY");
|
||||||
len += sprintf (tp->pkbuf.tftpERROR.errorMessage, "GO AWAY");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send it
|
* Send it
|
||||||
*/
|
*/
|
||||||
sendto (tp->socket, (char *)&tp->pkbuf, len, 0,
|
sendto (tp->socket, (char *)&msg, len, 0, (struct sockaddr *)to, sizeof *to);
|
||||||
(struct sockaddr *)to, sizeof *to);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -374,7 +379,7 @@ releaseStream (int s)
|
|||||||
rtems_semaphore_release (tftp_mutex);
|
rtems_semaphore_release (tftp_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtems_tftp_evaluate_for_make(
|
static int rtems_tftp_evaluate_for_make(
|
||||||
const char *path, /* IN */
|
const char *path, /* IN */
|
||||||
rtems_filesystem_location_info_t *pathloc, /* IN/OUT */
|
rtems_filesystem_location_info_t *pathloc, /* IN/OUT */
|
||||||
const char **name /* OUT */
|
const char **name /* OUT */
|
||||||
@@ -383,11 +388,8 @@ int rtems_tftp_evaluate_for_make(
|
|||||||
set_errno_and_return_minus_one( EIO );
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX - Fix return values.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int rtems_tftp_eval_path(
|
static 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 */
|
||||||
@@ -395,35 +397,32 @@ int rtems_tftp_eval_path(
|
|||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read-only for now
|
* Read-only or write-only for now
|
||||||
*/
|
*/
|
||||||
|
flags &= RTEMS_LIBIO_PERMS_READ | RTEMS_LIBIO_PERMS_WRITE;
|
||||||
if ( (flags & O_WRONLY) == O_WRONLY )
|
if ((flags != RTEMS_LIBIO_PERMS_READ) && (flags != RTEMS_LIBIO_PERMS_WRITE) )
|
||||||
set_errno_and_return_minus_one( ENOENT );
|
set_errno_and_return_minus_one( EINVAL );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The File system is mounted at TFTP_PATHNAME_PREFIX
|
* The File system is mounted at TFTP_PATHNAME_PREFIX
|
||||||
* the caller of this routine has striped off this part of the
|
* 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.
|
* name. Save the remainder of the name for use by the open routine.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pathloc->node_access = (void * ) pathname;
|
pathloc->node_access = (void * ) pathname;
|
||||||
pathloc->handlers = &rtems_tftp_handlers;
|
pathloc->handlers = &rtems_tftp_handlers;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rtems_tftp_open(
|
||||||
int rtems_tftp_open(
|
|
||||||
rtems_libio_t *iop,
|
rtems_libio_t *iop,
|
||||||
const char *new_name,
|
const char *new_name,
|
||||||
unsigned32 flag,
|
unsigned32 flags,
|
||||||
unsigned32 mode
|
unsigned32 mode
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
struct tftpStream *tp;
|
struct tftpStream *tp;
|
||||||
int retryCount;
|
int retryCount;
|
||||||
rtems_unsigned32 farAddress;
|
struct in_addr farAddress;
|
||||||
int s;
|
int s;
|
||||||
int len;
|
int len;
|
||||||
char *cp1;
|
char *cp1;
|
||||||
@@ -435,33 +434,44 @@ int rtems_tftp_open(
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* This came from the evaluate path.
|
* This came from the evaluate path.
|
||||||
|
* Extract host name component
|
||||||
*/
|
*/
|
||||||
|
cp1 = cp2 = iop->file_info;
|
||||||
cp2 = iop->file_info;
|
|
||||||
|
|
||||||
cp1 = cp2;
|
|
||||||
while (*cp2 != '/') {
|
while (*cp2 != '/') {
|
||||||
if (*cp2 == '\0')
|
if (*cp2 == '\0')
|
||||||
return ENOENT;
|
return ENOENT;
|
||||||
cp2++;
|
cp2++;
|
||||||
}
|
}
|
||||||
|
|
||||||
len = cp2 - cp1;
|
len = cp2 - cp1;
|
||||||
hostname = malloc (len + 1);
|
hostname = malloc (len + 1);
|
||||||
if (hostname == NULL)
|
if (hostname == NULL)
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
|
|
||||||
strncpy (hostname, cp1, len);
|
strncpy (hostname, cp1, len);
|
||||||
hostname[len] = '\0';
|
hostname[len] = '\0';
|
||||||
farAddress = inet_addr (hostname);
|
|
||||||
|
/*
|
||||||
|
* Convert hostname to Internet address
|
||||||
|
*/
|
||||||
|
if (strcmp (hostname, "BOOTP_HOST") == 0)
|
||||||
|
farAddress = rtems_bsdnet_bootp_server_address;
|
||||||
|
else
|
||||||
|
farAddress.s_addr = inet_addr (hostname);
|
||||||
free (hostname);
|
free (hostname);
|
||||||
|
if ((farAddress.s_addr == 0) || (farAddress.s_addr == ~0))
|
||||||
if ((farAddress == 0) || (farAddress == ~0))
|
|
||||||
return ENOENT;
|
return ENOENT;
|
||||||
|
|
||||||
if (*++cp2 == '\0')
|
/*
|
||||||
|
* Extract file pathname component
|
||||||
|
*/
|
||||||
|
while (*cp2 == '/')
|
||||||
|
cp2++;
|
||||||
|
if (strcmp (cp2, "BOOTP_FILE") == 0) {
|
||||||
|
cp2 = rtems_bsdnet_bootp_boot_file_name;
|
||||||
|
while (*cp2 == '/')
|
||||||
|
cp2++;
|
||||||
|
}
|
||||||
|
if (*cp2 == '\0')
|
||||||
return ENOENT;
|
return ENOENT;
|
||||||
|
|
||||||
remoteFilename = cp2;
|
remoteFilename = cp2;
|
||||||
if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
|
if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10))
|
||||||
return ENOENT;
|
return ENOENT;
|
||||||
@@ -469,16 +479,13 @@ int rtems_tftp_open(
|
|||||||
/*
|
/*
|
||||||
* 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 EBUSY;
|
return 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
|
||||||
@@ -493,7 +500,6 @@ int rtems_tftp_open(
|
|||||||
}
|
}
|
||||||
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)
|
||||||
@@ -504,7 +510,6 @@ int rtems_tftp_open(
|
|||||||
/*
|
/*
|
||||||
* 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 ENOMEM;
|
return ENOMEM;
|
||||||
@@ -513,7 +518,6 @@ int rtems_tftp_open(
|
|||||||
/*
|
/*
|
||||||
* 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 (;;) {
|
||||||
@@ -536,7 +540,7 @@ int rtems_tftp_open(
|
|||||||
* port on the remote machine.
|
* port on the remote machine.
|
||||||
*/
|
*/
|
||||||
tp->farAddress.sin_family = AF_INET;
|
tp->farAddress.sin_family = AF_INET;
|
||||||
tp->farAddress.sin_addr.s_addr = farAddress;
|
tp->farAddress.sin_addr = farAddress;
|
||||||
tp->farAddress.sin_port = htons (69);
|
tp->farAddress.sin_port = htons (69);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -547,7 +551,14 @@ int rtems_tftp_open(
|
|||||||
/*
|
/*
|
||||||
* Create the request
|
* Create the request
|
||||||
*/
|
*/
|
||||||
|
if ((flags & O_ACCMODE) == O_RDONLY) {
|
||||||
|
tp->writing = 0;
|
||||||
tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ);
|
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;
|
cp1 = (char *) tp->pkbuf.tftpRWRQ.filename_mode;
|
||||||
cp2 = (char *) remoteFilename;
|
cp2 = (char *) remoteFilename;
|
||||||
while ((*cp1++ = *cp2++) != '\0')
|
while ((*cp1++ = *cp2++) != '\0')
|
||||||
@@ -574,7 +585,8 @@ int rtems_tftp_open(
|
|||||||
len = getPacket (tp);
|
len = getPacket (tp);
|
||||||
if (len >= (int) sizeof tp->pkbuf.tftpACK) {
|
if (len >= (int) sizeof tp->pkbuf.tftpACK) {
|
||||||
int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
|
int opcode = ntohs (tp->pkbuf.tftpDATA.opcode);
|
||||||
if ((opcode == TFTP_OPCODE_DATA)
|
if (!tp->writing
|
||||||
|
&& (opcode == TFTP_OPCODE_DATA)
|
||||||
&& (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) {
|
&& (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) {
|
||||||
tp->nused = 0;
|
tp->nused = 0;
|
||||||
tp->blocknum = 1;
|
tp->blocknum = 1;
|
||||||
@@ -587,11 +599,18 @@ int rtems_tftp_open(
|
|||||||
}
|
}
|
||||||
break;
|
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) {
|
if (opcode == TFTP_OPCODE_ERROR) {
|
||||||
tftpSetErrno (tp);
|
int e = tftpErrno (tp);
|
||||||
close (tp->socket);
|
close (tp->socket);
|
||||||
releaseStream (s);
|
releaseStream (s);
|
||||||
return EIO;
|
return e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -604,45 +623,41 @@ int rtems_tftp_open(
|
|||||||
return EIO;
|
return EIO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read from a TFTP stream
|
* Read from a TFTP stream
|
||||||
*/
|
*/
|
||||||
|
static int rtems_tftp_read(
|
||||||
int rtems_tftp_read(
|
|
||||||
rtems_libio_t *iop,
|
rtems_libio_t *iop,
|
||||||
void *buffer,
|
void *buffer,
|
||||||
unsigned32 count
|
unsigned32 count
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
char *bp;
|
char *bp;
|
||||||
struct tftpStream *tp;
|
struct tftpStream *tp = iop->data1;
|
||||||
int retryCount;
|
int retryCount;
|
||||||
int nwant;
|
int nwant;
|
||||||
|
|
||||||
tp = iop->data1;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read till user request is satisfied or EOF is reached
|
* Read till user request is satisfied or EOF is reached
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bp = buffer;
|
bp = buffer;
|
||||||
nwant = count;
|
nwant = count;
|
||||||
while (nwant) {
|
while (nwant) {
|
||||||
if (tp->nleft) {
|
if (tp->nleft) {
|
||||||
int count;
|
int ncopy;
|
||||||
if (nwant < tp->nleft)
|
if (nwant < tp->nleft)
|
||||||
count = nwant;
|
ncopy = nwant;
|
||||||
else
|
else
|
||||||
count = tp->nleft;
|
ncopy = tp->nleft;
|
||||||
memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], count);
|
memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], ncopy);
|
||||||
tp->nused += count;
|
tp->nused += ncopy;
|
||||||
tp->nleft -= count;
|
tp->nleft -= ncopy;
|
||||||
bp += count;
|
bp += ncopy;
|
||||||
nwant -= count;
|
nwant -= ncopy;
|
||||||
if (nwant == 0)
|
if (nwant == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -668,10 +683,8 @@ int rtems_tftp_read(
|
|||||||
set_errno_and_return_minus_one( EIO );
|
set_errno_and_return_minus_one( EIO );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (opcode == TFTP_OPCODE_ERROR) {
|
if (opcode == TFTP_OPCODE_ERROR)
|
||||||
tftpSetErrno (tp);
|
set_errno_and_return_minus_one( tftpErrno (tp) );
|
||||||
return RTEMS_INTERNAL_ERROR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -683,23 +696,57 @@ int rtems_tftp_read(
|
|||||||
set_errno_and_return_minus_one( EIO );
|
set_errno_and_return_minus_one( EIO );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return count - nwant;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX - Eric is this right?
|
* Flush a write buffer and wait for acknowledgement
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
return count - nwant;
|
static int rtems_tftp_flush ( struct tftpStream *tp )
|
||||||
|
{
|
||||||
|
int wlen, rlen;
|
||||||
|
int retryCount = 0;
|
||||||
|
|
||||||
|
wlen = tp->nused + 2 * sizeof (rtems_unsigned16);
|
||||||
|
for (;;) {
|
||||||
|
tp->pkbuf.tftpDATA.opcode = htons (TFTP_OPCODE_DATA);
|
||||||
|
tp->pkbuf.tftpDATA.blocknum = htons (tp->blocknum);
|
||||||
|
if (sendto (tp->socket, (char *)&tp->pkbuf, wlen, 0,
|
||||||
|
(struct sockaddr *)&tp->farAddress,
|
||||||
|
sizeof tp->farAddress) < 0)
|
||||||
|
return EIO;
|
||||||
|
rlen = getPacket (tp);
|
||||||
|
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
|
* Close a TFTP stream
|
||||||
*/
|
*/
|
||||||
int rtems_tftp_close(
|
static int rtems_tftp_close(
|
||||||
rtems_libio_t *iop
|
rtems_libio_t *iop
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
struct tftpStream *tp = iop->data1;;
|
struct tftpStream *tp = iop->data1;;
|
||||||
|
|
||||||
|
if (tp->writing)
|
||||||
|
rtems_tftp_flush (tp);
|
||||||
if (!tp->eof && !tp->firstReply) {
|
if (!tp->eof && !tp->firstReply) {
|
||||||
/*
|
/*
|
||||||
* Tell the other end to stop
|
* Tell the other end to stop
|
||||||
@@ -714,22 +761,62 @@ int rtems_tftp_close(
|
|||||||
return RTEMS_SUCCESSFUL;
|
return RTEMS_SUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtems_tftp_write(
|
static int rtems_tftp_write(
|
||||||
rtems_libio_t *iop,
|
rtems_libio_t *iop,
|
||||||
const void *buffer,
|
const void *buffer,
|
||||||
unsigned32 count
|
unsigned32 count
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return RTEMS_NOT_CONFIGURED;
|
const char *bp;
|
||||||
|
struct tftpStream *tp = iop->data1;
|
||||||
|
int nleft, nfree, ncopy;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Bail out if an error has occurred
|
||||||
|
*/
|
||||||
|
if (!tp->writing)
|
||||||
|
return 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;
|
||||||
|
set_errno_and_return_minus_one (e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtems_device_driver rtems_tftp_control(
|
/*
|
||||||
rtems_device_major_number major,
|
* Dummy version to let fopen(xxxx,"w") work properly.
|
||||||
rtems_device_minor_number minor,
|
*/
|
||||||
void *pargp
|
static int rtems_tftp_ftruncate(
|
||||||
|
rtems_libio_t *iop,
|
||||||
|
off_t count
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return RTEMS_NOT_CONFIGURED;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
rtems_filesystem_node_types_t rtems_tftp_node_type(
|
rtems_filesystem_node_types_t rtems_tftp_node_type(
|
||||||
@@ -768,7 +855,7 @@ rtems_filesystem_file_handlers_r rtems_tftp_handlers = {
|
|||||||
NULL, /* lseek */
|
NULL, /* lseek */
|
||||||
NULL, /* fstat */
|
NULL, /* fstat */
|
||||||
NULL, /* fchmod */
|
NULL, /* fchmod */
|
||||||
NULL, /* ftruncate */
|
rtems_tftp_ftruncate, /* ftruncate */
|
||||||
NULL, /* fpathconf */
|
NULL, /* fpathconf */
|
||||||
NULL, /* fsync */
|
NULL, /* fsync */
|
||||||
NULL, /* fdatasync */
|
NULL, /* fdatasync */
|
||||||
|
|||||||
Reference in New Issue
Block a user