From c1a37d3e949c7be87cf90f0872030518f20eec01 Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Thu, 4 Feb 1999 14:54:31 +0000 Subject: Debugged and now works except for handling of minor number. --- c/src/libnetworking/lib/tftpDriver.c | 742 ++++++++++++++++++++--------------- 1 file changed, 429 insertions(+), 313 deletions(-) (limited to 'c/src/libnetworking/lib/tftpDriver.c') diff --git a/c/src/libnetworking/lib/tftpDriver.c b/c/src/libnetworking/lib/tftpDriver.c index e9564110f5..cc179bf2de 100644 --- a/c/src/libnetworking/lib/tftpDriver.c +++ b/c/src/libnetworking/lib/tftpDriver.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -139,35 +140,65 @@ struct tftpStream { /* * Number of streams open at the same time */ + static rtems_id tftp_mutex; static int nStreams; static struct tftpStream ** volatile tftpStreams; -typedef struct { - rtems_id tftp_mutex; - int nStreams; - struct tftpStream ** volatile tftpStreams; - rtems_filesystem_mount_table_entry_t *mt_entry; -} tftp_fs_info; +typedef const char *tftp_node; +extern rtems_filesystem_operations_table rtems_tftp_ops; +extern rtems_filesystem_file_handlers_r rtems_tftp_handlers; + +/* + * 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( rtems_filesystem_mount_table_entry_t *temp_mt_entry ) { - tftp_fs_info *fs_info; 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 )); - if ( !fs_info ) - set_errno_and_return_minus_one( ENOMEM ); + temp_mt_entry->fs_info = NULL; + temp_mt_entry->mt_fs_root.node_access = NULL; + + /* + * These need to be looked at for full POSIX semantics. + */ + + temp_mt_entry->pathconf_limits_and_options = rtems_tftp_limits_and_options; - temp_mt_entry->fs_info = fs_info; - temp_mt_entry->mt_fs_root.node_access = fs_info; + /* + * Now allocate a semaphore for mutual exclusion. + * + * NOTE: This could be in an fsinfo for this filesystem type. + */ sc = rtems_semaphore_create ( rtems_build_name('T', 'F', 'T', 'P'), @@ -178,11 +209,11 @@ int rtems_tftp_mount_me( RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL, 0, - &fs_info->tftp_mutex + &tftp_mutex ); if (sc != RTEMS_SUCCESSFUL) - set_errno_and_return_minus_one( ENOMEM ); /* ??? */ + set_errno_and_return_minus_one( ENOMEM ); return 0; } @@ -190,18 +221,28 @@ int rtems_tftp_mount_me( /* * 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 -) + +int rtems_bsdnet_initialize_tftp_filesystem () { + 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" ); -/* XXX change to a mount */ - rtems_io_register_name (TFTP_PATHNAME_PREFIX, major, minor); - return RTEMS_SUCCESSFUL; + return status; } /* @@ -338,344 +379,376 @@ int rtems_tftp_evaluate_for_make( const char **name /* OUT */ ) { - set_errno_and_return_minus_one( EIO ); + set_errno_and_return_minus_one( EIO ); } + /* * XXX - Fix return values. */ -int TFTP_eval_path( +int rtems_tftp_eval_path( const char *pathname, /* IN */ int flags, /* IN */ rtems_filesystem_location_info_t *pathloc /* IN/OUT */ ) { - rtems_unsigned32 farAddress; - int len; - const char *remoteFilename; - tftp_fs_info *fs_info; - const char *cp1, *cp2; - - fs_info = pathloc->node_access; + /* + * Read-only for now + */ + + if ( (flags & O_WRONLY) == O_WRONLY ) + set_errno_and_return_minus_one( ENOENT ); - /* - * Pick apart the name into a host:pathname pair - */ - /* - * XXX - I think this is handled by the caller of - * the evaluate routine. ? Am I starting at the right - * place? - */ + /* + * 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. + */ - cp2 = pathname+1; - - 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; + pathloc->node_access = (void * ) pathname; + pathloc->handlers = &rtems_tftp_handlers; return 0; } -/* - * Open a TFTP stream - */ -rtems_device_driver rtems_tftp_open( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *pargp + +int rtems_tftp_open( + rtems_libio_t *iop, + const char *new_name, + unsigned32 flag, + unsigned32 mode ) { - 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; + struct tftpStream *tp; + int retryCount; + rtems_unsigned32 farAddress; + int s; + int len; + char *cp1; + char *cp2; + char *remoteFilename; + rtems_interval now; + rtems_status_code sc; + /* + * This came from the evaluate path. + */ - /* - * 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; + cp2 = iop->file_info; + if (*cp2 == '/') { + farAddress = rtems_bsdnet_bootp_server_address.s_addr; + } + else { + char *hostname; + + cp1 = cp2; + while (*cp2 != '/') { + if (*cp2 == '\0') + set_errno_and_return_minus_one( ENOENT ); + cp2++; + } + + len = cp2 - cp1; + hostname = malloc (len + 1); + if (hostname == NULL) + set_errno_and_return_minus_one( ENOMEM ); + + strncpy (hostname, cp1, len); + hostname[len] = '\0'; + farAddress = inet_addr (hostname); + free (hostname); + } + + if ((farAddress == 0) || (farAddress == ~0)) + set_errno_and_return_minus_one( ENOENT ); + + if (*++cp2 == '\0') + set_errno_and_return_minus_one( ENOENT ); + + remoteFilename = cp2; + if (strlen (remoteFilename) > (TFTP_BUFSIZE - 10)) + set_errno_and_return_minus_one( ENOENT ); - 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; + /* + * Find a free stream + */ - /* - * Create the socket - */ - if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) { - releaseStream (s); - return RTEMS_TOO_MANY; - } + sc = rtems_semaphore_obtain (tftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + if (sc != RTEMS_SUCCESSFUL) + set_errno_and_return_minus_one( EBUSY ); + + 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); + set_errno_and_return_minus_one( ENOMEM ); + } + tftpStreams = np; + } + + tp = tftpStreams[s] = malloc (sizeof (struct tftpStream)); + rtems_semaphore_release (tftp_mutex); + if (tp == NULL) + set_errno_and_return_minus_one( ENOMEM ); + iop->data0 = s; + iop->data1 = tp; - /* - * 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; + /* + * Create the socket + */ - 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; - } - } + if ((tp->socket = socket (AF_INET, SOCK_DGRAM, 0)) < 0) { + releaseStream (s); + set_errno_and_return_minus_one( ENOMEM ); + } - /* - * 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); + /* + * Bind the socket to a local address + */ - /* - * 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; + retryCount = 0; + rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now); + for (;;) { + int try = (now + retryCount) % 10; + + tp->myAddress.sin_family = AF_INET; + /* + * 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); + if (bind (tp->socket, (struct sockaddr *)&tp->myAddress, sizeof tp->myAddress) >= 0) + break; + if (++retryCount == 10) { + close (tp->socket); + /* + * XXX Eric .. how do we get the minor information to release this??? + releaseStream (minor); + */ + set_errno_and_return_minus_one( EBUSY ); + } + } - /* - * 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; - } + /* + * 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); - /* - * 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; - } - } + /* + * Start the transfer + */ + tp->firstReply = 1; + for (;;) { + /* + * Create the request + */ + tp->pkbuf.tftpRWRQ.opcode = htons (TFTP_OPCODE_RRQ); + /* + * XXX Eric .. is this cast taking the const off right? + */ + + cp1 = (char *) tp->pkbuf.tftpRWRQ.filename_mode; + cp2 = (char *) remoteFilename; + while ((*cp1++ = *cp2++) != '\0') + continue; + cp2 = "octet"; + while ((*cp1++ = *cp2++) != '\0') + continue; + len = cp1 - (char *)&tp->pkbuf.tftpRWRQ; + + /* + * Send the request + */ + if (sendto (tp->socket, (char *)&tp->pkbuf, len, 0, + (struct sockaddr *)&tp->farAddress, + sizeof tp->farAddress) < 0) { + close (tp->socket); + /* + * XXX Eric .. how do we get the minor information to release this??? + releaseStream (minor); + */ + set_errno_and_return_minus_one( EIO ); + } + + /* + * 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); + /* + * XXX Eric .. how do we get the minor information to release this??? + releaseStream (minor); + */ + + set_errno_and_return_minus_one( EIO ); + } + break; + } + if (opcode == TFTP_OPCODE_ERROR) { + tftpSetErrno (tp); + close (tp->socket); + /* + * XXX Eric .. how do we get the minor information to release this??? + * releaseStream (minor); + */ + set_errno_and_return_minus_one( EIO ); + } + } + + /* + * Keep trying + */ + if (++retryCount >= OPEN_RETRY_LIMIT) { + close (tp->socket); + /* + * XXX Eric .. how do we get the minor information to release this??? + releaseStream (minor); + */ + set_errno_and_return_minus_one( EIO ); + } + } - /* - * Keep trying - */ - if (++retryCount >= OPEN_RETRY_LIMIT) { - close (tp->socket); - releaseStream (minor); - return RTEMS_UNSATISFIED; - } - } - return RTEMS_SUCCESSFUL; + return 0; } /* * Read from a TFTP stream */ -rtems_device_driver rtems_tftp_read( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *pargp + +int rtems_tftp_read( + rtems_libio_t *iop, + void *buffer, + unsigned32 count ) { - rtems_libio_rw_args_t *ap = pargp; - char *bp; - struct tftpStream *tp; - int retryCount; - int nwant; + char *bp; + struct tftpStream *tp; + int retryCount; + int nwant; - tp = ap->iop->data1; + tp = 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; - } - } + /* + * Read till user request is satisfied or EOF is reached + */ - /* - * 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; + bp = buffer; + nwant = 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) + set_errno_and_return_minus_one( EIO ); + break; + } + if (opcode == TFTP_OPCODE_ERROR) { + tftpSetErrno (tp); + return RTEMS_INTERNAL_ERROR; + } + } + + /* + * Keep trying? + */ + if (++retryCount == IO_RETRY_LIMIT) + set_errno_and_return_minus_one( EIO ); + if (sendAck (tp) != 0) + set_errno_and_return_minus_one( EIO ); + } + } + + /* + * XXX - Eric is this right? + * + */ + return count - nwant; } /* * Close a TFTP stream */ -rtems_device_driver rtems_tftp_close( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *pargp +int rtems_tftp_close( + rtems_libio_t *iop ) { - 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; + struct tftpStream *tp = 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 (iop->data0); + return RTEMS_SUCCESSFUL; } -rtems_device_driver rtems_tftp_write( - rtems_device_major_number major, - rtems_device_minor_number minor, - void *pargp +int rtems_tftp_write( + rtems_libio_t *iop, + const void *buffer, + unsigned32 count ) { - return RTEMS_NOT_CONFIGURED; + return RTEMS_NOT_CONFIGURED; } rtems_device_driver rtems_tftp_control( @@ -684,5 +757,48 @@ rtems_device_driver rtems_tftp_control( void *pargp ) { - 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, +}; -- cgit v1.2.3