diff options
Diffstat (limited to 'c/src/libnetworking/lib/tftpDriver.c')
-rw-r--r-- | c/src/libnetworking/lib/tftpDriver.c | 609 |
1 files changed, 0 insertions, 609 deletions
diff --git a/c/src/libnetworking/lib/tftpDriver.c b/c/src/libnetworking/lib/tftpDriver.c deleted file mode 100644 index cf75623580..0000000000 --- a/c/src/libnetworking/lib/tftpDriver.c +++ /dev/null @@ -1,609 +0,0 @@ -/* - * Trivial File Transfer Protocol (RFC 1350) - * - * Transfer file to/from remote host - * - * W. Eric Norum - * Saskatchewan Accelerator Laboratory - * University of Saskatchewan - * Saskatoon, Saskatchewan, CANADA - * eric@skatter.usask.ca - * - * $Id$ - */ - -#include <stdio.h> -#include <errno.h> -#include <malloc.h> -#include <string.h> -#include <unistd.h> -#include <rtems.h> -#include <rtems/libio.h> -#include <rtems/rtems_bsdnet.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> - -/* - * Range of UDP ports to try - */ -#define UDP_PORT_BASE 3180 - -/* - * Pathname prefix - */ -#define TFTP_PATHNAME_PREFIX "/TFTP/" - -/* - * Default limits - */ -#define PACKET_REPLY_MILLISECONDS 6000 -#define OPEN_RETRY_LIMIT 10 -#define IO_RETRY_LIMIT 10 - -/* - * TFTP opcodes - */ -#define TFTP_OPCODE_RRQ 1 -#define TFTP_OPCODE_WRQ 2 -#define TFTP_OPCODE_DATA 3 -#define TFTP_OPCODE_ACK 4 -#define TFTP_OPCODE_ERROR 5 - -/* - * Largest data transfer - */ -#define TFTP_BUFSIZE 512 - -/* - * Packets transferred between machines - */ -union tftpPacket { - /* - * RRQ/WRQ packet - */ - struct tftpRWRQ { - rtems_unsigned16 opcode; - char filename_mode[TFTP_BUFSIZE]; - } tftpRWRQ; - - /* - * DATA packet - */ - struct tftpDATA { - rtems_unsigned16 opcode; - rtems_unsigned16 blocknum; - rtems_unsigned8 data[TFTP_BUFSIZE]; - } tftpDATA; - - /* - * ACK packet - */ - struct tftpACK { - rtems_unsigned16 opcode; - rtems_unsigned16 blocknum; - } tftpACK; - - /* - * ERROR packet - */ - struct tftpERROR { - rtems_unsigned16 opcode; - rtems_unsigned16 errorCode; - char errorMessage[TFTP_BUFSIZE]; - } tftpERROR; -}; - -/* - * State of each TFTP stream - */ -struct tftpStream { - /* - * Buffer for storing most recently-received packet - */ - union tftpPacket pkbuf; - - /* - * Last block number received - */ - rtems_unsigned16 blocknum; - - /* - * Data transfer socket - */ - int socket; - struct sockaddr_in myAddress; - struct sockaddr_in farAddress; - - /* - * Indices into buffer - */ - int nleft; - int nused; - - /* - * Flags - */ - int firstReply; - int eof; -}; - -/* - * Number of streams open at the same time - */ -static rtems_id tftp_mutex; -static int nStreams; -static struct tftpStream ** volatile tftpStreams; - -/* - * Initialize the TFTP driver - */ -rtems_device_driver rtems_tftp_initialize( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *pargp -) -{ - rtems_status_code sc; - - sc = rtems_semaphore_create (rtems_build_name('T', 'F', 'T', 'P'), - 1, - RTEMS_FIFO | - RTEMS_BINARY_SEMAPHORE | - RTEMS_NO_INHERIT_PRIORITY | - RTEMS_NO_PRIORITY_CEILING | - RTEMS_LOCAL, - 0, - &tftp_mutex); - if (sc != RTEMS_SUCCESSFUL) - return sc; - rtems_io_register_name (TFTP_PATHNAME_PREFIX, major, minor); - return RTEMS_SUCCESSFUL; -} - -/* - * Set error message - * This RTEMS/UNIX error mapping needs to be fixed! - */ -static void -tftpSetErrno (struct tftpStream *tp) -{ - unsigned int tftpError; - static const int errorMap[] = { - 0, - ENOENT, - EPERM, - ENOSPC, - EINVAL, - ENXIO, - EEXIST, - ESRCH, - 0, - }; - - tftpError = ntohs (tp->pkbuf.tftpERROR.errorCode); - if (tftpError < (sizeof errorMap / sizeof errorMap[0])) - errno = errorMap[tftpError]; - else - errno = 1000 + tftpError; -} - -/* - * Send a message to make the other end shut up - */ -static void -sendStifle (struct tftpStream *tp, struct sockaddr_in *to) -{ - int len; - - /* - * Create the error packet (Unknown transfer ID). - */ - tp->pkbuf.tftpERROR.opcode = htons (TFTP_OPCODE_ERROR); - tp->pkbuf.tftpERROR.errorCode = htons (5); - len = sizeof tp->pkbuf.tftpERROR.opcode + - sizeof tp->pkbuf.tftpERROR.errorCode + 1; - len += sprintf (tp->pkbuf.tftpERROR.errorMessage, "GO AWAY"); - - /* - * Send it - */ - sendto (tp->socket, (char *)&tp->pkbuf, len, 0, - (struct sockaddr *)to, sizeof *to); -} - -/* - * Wait for a data packet - */ -static int -getPacket (struct tftpStream *tp) -{ - int len; - struct timeval tv; - - tv.tv_sec = 6; - tv.tv_usec = 0; - setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); - for (;;) { - union { - struct sockaddr s; - struct sockaddr_in i; - } from; - int fromlen = sizeof from; - len = recvfrom (tp->socket, (char *)&tp->pkbuf, - sizeof tp->pkbuf, 0, - &from.s, &fromlen); - if (len < 0) - break; - if (from.i.sin_addr.s_addr == tp->farAddress.sin_addr.s_addr) { - if (tp->firstReply) { - tp->firstReply = 0; - tp->farAddress.sin_port = from.i.sin_port; - } - if (tp->farAddress.sin_port == from.i.sin_port) - break; - } - - /* - * Packet is from someone with whom we are - * not interested. Tell them to go away. - */ - sendStifle (tp, &from.i); - } - tv.tv_sec = 0; - setsockopt (tp->socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv); - return len; -} - -/* - * Send an acknowledgement - */ -static int -sendAck (struct tftpStream *tp) -{ - /* - * Create the acknowledgement - */ - tp->pkbuf.tftpACK.opcode = htons (TFTP_OPCODE_ACK); - tp->pkbuf.tftpACK.blocknum = htons (tp->blocknum); - - /* - * Send it - */ - if (sendto (tp->socket, (char *)&tp->pkbuf, sizeof tp->pkbuf.tftpACK, 0, - (struct sockaddr *)&tp->farAddress, - sizeof tp->farAddress) < 0) - return errno; - return 0; -} - -/* - * Release a stream and clear the pointer to it - */ -static void -releaseStream (int s) -{ - rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); - free (tftpStreams[s]); - tftpStreams[s] = NULL; - rtems_semaphore_release (tftp_mutex); -} - -/* - * 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; - int s; - int len; - char *cp1, *cp2; - char *remoteFilename; - rtems_interval now; - rtems_status_code sc; - - /* - * Read-only for now - */ - if (ap->flags & LIBIO_FLAGS_WRITE) - return RTEMS_NOT_IMPLEMENTED; - - /* - * Pick apart the name into a host:pathname pair - */ - if (strlen (ap->iop->pathname) <= strlen (TFTP_PATHNAME_PREFIX)) - return RTEMS_INVALID_NAME; - cp2 = ap->iop->pathname + strlen (TFTP_PATHNAME_PREFIX); - if (*cp2 == '/') { - farAddress = rtems_bsdnet_bootp_server_address.s_addr; - } - else { - char *hostname; - - cp1 = cp2; - while (*cp2 != '/') { - if (*cp2 == '\0') - return RTEMS_INVALID_NAME; - cp2++; - } - len = cp2 - cp1; - hostname = malloc (len + 1); - if (hostname == NULL) - return RTEMS_NO_MEMORY; - strncpy (hostname, cp1, len); - hostname[len] = '\0'; - farAddress = inet_addr (hostname); - free (hostname); - } - if ((farAddress == 0) || (farAddress == ~0)) - return RTEMS_INVALID_NAME; - if (*++cp2 == '\0') - return RTEMS_INVALID_NAME; - remoteFilename = cp2; - if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10)) - return RTEMS_INVALID_NAME; - - /* - * Find a free stream - */ - sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); - if (sc != RTEMS_SUCCESSFUL) - return sc; - for (s = 0 ; s < nStreams ; s++) { - if (tftpStreams[s] == NULL) - break; - } - if (s == nStreams) { - /* - * Reallocate stream pointers - * Guard against the case where realloc() returns NULL. - */ - struct tftpStream **np; - - np = realloc (tftpStreams, ++nStreams * sizeof *tftpStreams); - if (np == NULL) { - rtems_semaphore_release (tftp_mutex); - return RTEMS_NO_MEMORY; - } - tftpStreams = np; - } - tp = tftpStreams[s] = malloc (sizeof (struct tftpStream)); - rtems_semaphore_release (tftp_mutex); - if (tp == NULL) - return RTEMS_NO_MEMORY; - ap->iop->data0 = s; - ap->iop->data1 = tp; - - /* - * Create the socket - */ - if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) { - releaseStream (s); - return RTEMS_TOO_MANY; - } - - /* - * Bind the socket to a local address - */ - retryCount = 0; - rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now); - for (;;) { - int try = (now + retryCount) % 10; - - tp->myAddress.sin_family = AF_INET; - tp->myAddress.sin_port = htons (UDP_PORT_BASE + nStreams * try + minor); - tp->myAddress.sin_addr.s_addr = htonl (INADDR_ANY); - if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0) - break; - if (++retryCount == 10) { - close (tp->socket); - releaseStream (minor); - return RTEMS_RESOURCE_IN_USE; - } - } - - /* - * Set the UDP destination to the TFTP server - * port on the remote machine. - */ - tp->farAddress.sin_family = AF_INET; - tp->farAddress.sin_addr.s_addr = farAddress; - tp->farAddress.sin_port = htons (69); - - /* - * Start the transfer - */ - tp->firstReply = 1; - for (;;) { - /* - * Create the request - */ - tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ); - cp1 = tp->pkbuf.tftpRWRQ.filename_mode; - cp2 = remoteFilename; - while ((*cp1++ = *cp2++) != '\0') - continue; - cp2 = "octet"; - while ((*cp1++ = *cp2++) != '\0') - continue; - len = cp1 - (char *)&tp->pkbuf.tftpRWRQ; - - /* - * Send the request - */ - if (sendto (tp->socket, (char *)&tp->pkbuf, len, 0, - (struct sockaddr *)&tp->farAddress, - sizeof tp->farAddress) < 0) { - close (tp->socket); - releaseStream (minor); - return RTEMS_UNSATISFIED; - } - - /* - * Get reply - */ - len = getPacket (tp); - if (len >= (int) sizeof tp->pkbuf.tftpACK) { - int opcode = ntohs (tp->pkbuf.tftpDATA.opcode); - if ((opcode == TFTP_OPCODE_DATA) - && (ntohs (tp->pkbuf.tftpDATA.blocknum) == 1)) { - tp->nused = 0; - tp->blocknum = 1; - tp->nleft = len - 2 * sizeof (rtems_unsigned16); - tp->eof = (tp->nleft < TFTP_BUFSIZE); - if (sendAck (tp) != 0) { - close (tp->socket); - releaseStream (minor); - return RTEMS_UNSATISFIED; - } - break; - } - if (opcode == TFTP_OPCODE_ERROR) { - tftpSetErrno (tp); - close (tp->socket); - releaseStream (ap->iop->data0); - return RTEMS_INTERNAL_ERROR; - } - } - - /* - * Keep trying - */ - if (++retryCount >= OPEN_RETRY_LIMIT) { - close (tp->socket); - releaseStream (minor); - return RTEMS_UNSATISFIED; - } - } - return RTEMS_SUCCESSFUL; -} - -/* - * Read from a TFTP stream - */ -rtems_device_driver rtems_tftp_read( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *pargp -) -{ - rtems_libio_rw_args_t *ap = pargp; - char *bp; - struct tftpStream *tp; - int retryCount; - int nwant; - - tp = ap->iop->data1; - - /* - * Read till user request is satisfied or EOF is reached - */ - bp = ap->buffer; - nwant = ap->count; - while (nwant) { - if (tp->nleft) { - int count; - if (nwant < tp->nleft) - count = nwant; - else - count = tp->nleft; - memcpy (bp, &tp->pkbuf.tftpDATA.data[tp->nused], count); - tp->nused += count; - tp->nleft -= count; - bp += count; - nwant -= count; - if (nwant == 0) - break; - } - if (tp->eof) - break; - - /* - * Wait for the next packet - */ - retryCount = 0; - for (;;) { - int len = getPacket (tp); - if (len >= (int)sizeof tp->pkbuf.tftpACK) { - int opcode = ntohs (tp->pkbuf.tftpDATA.opcode); - rtems_unsigned16 nextBlock = tp->blocknum + 1; - if ((opcode == TFTP_OPCODE_DATA) - && (ntohs (tp->pkbuf.tftpDATA.blocknum) == nextBlock)) { - tp->nused = 0; - tp->nleft = len - 2 * sizeof (rtems_unsigned16); - tp->eof = (tp->nleft < TFTP_BUFSIZE); - tp->blocknum++; - if (sendAck (tp) != 0) - return RTEMS_IO_ERROR; - break; - } - if (opcode == TFTP_OPCODE_ERROR) { - tftpSetErrno (tp); - return RTEMS_INTERNAL_ERROR; - } - } - - /* - * Keep trying? - */ - if (++retryCount == IO_RETRY_LIMIT) - return RTEMS_IO_ERROR; - if (sendAck (tp) != 0) - return RTEMS_IO_ERROR; - } - } - ap->bytes_moved = ap->count - nwant; - return RTEMS_SUCCESSFUL; -} - -/* - * Close a TFTP stream - */ -rtems_device_driver rtems_tftp_close( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *pargp -) -{ - rtems_libio_open_close_args_t *ap = pargp; - struct tftpStream *tp = ap->iop->data1;; - - if (!tp->eof && !tp->firstReply) { - /* - * Tell the other end to stop - */ - rtems_interval ticksPerSecond; - sendStifle (tp, &tp->farAddress); - rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &ticksPerSecond); - rtems_task_wake_after (1 + ticksPerSecond / 10); - } - close (tp->socket); - releaseStream (ap->iop->data0); - return RTEMS_SUCCESSFUL; -} - -rtems_device_driver rtems_tftp_write( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *pargp -) -{ - return RTEMS_NOT_CONFIGURED; -} - -rtems_device_driver rtems_tftp_control( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *pargp -) -{ - return RTEMS_NOT_CONFIGURED; -} |