From 8fdb1730902ad5ecb690719884467e9a2ed57b0a Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Mon, 7 Dec 2015 13:48:06 -0600 Subject: [PATCH] drivers/net/telnet.c: Now works like the loop device. A new interface called telnet_initialize() registers a telnet session "factory" device at /dev/telnet. Via ioctl, the factory device can create instances of the telnet character devices at /dev/telnetN to support Telnet sessions. --- ChangeLog | 5 + TODO | 11 +- arch | 2 +- drivers/loop/loop.c | 5 +- drivers/net/telnet.c | 263 +++++++++++++++++++++++++------------ include/nuttx/net/ioctl.h | 5 + include/nuttx/net/telnet.h | 47 +++++-- 7 files changed, 231 insertions(+), 107 deletions(-) diff --git a/ChangeLog b/ChangeLog index 62d48e9351..72b4ddf0c8 100755 --- a/ChangeLog +++ b/ChangeLog @@ -11222,4 +11222,9 @@ * configs/: Update all configurations that use the Telnet daemon; those configurations now need to separately enable the Telnet drvier (2015-12-07). + * drivers/net/telnet.c: Now works like the loop device. A new interface + called telnet_initialize() registers a telnet session "factory" + device at /dev/telnet. Via ioctl, the factory device can create + instances of the telnet character devices at /dev/telnetN to support + Telnet sessions (2015-12-07). diff --git a/TODO b/TODO index 46882e7781..98ea6fe312 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ -NuttX TODO List (Last updated November 28, 2015) +NuttX TODO List (Last updated December 7, 2015) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This file summarizes known NuttX bugs, limitations, inconsistencies with @@ -14,6 +14,7 @@ nuttx/ (3) Signals (sched/signal, arch/) (2) pthreads (sched/pthread) (0) Message Queues (sched/mqueue) + (7) Kernel/Protected Build (4) C++ Support (6) Binary loaders (binfmt/) (11) Network (net/, drivers/net) @@ -461,14 +462,6 @@ o Kernel/Protected Build Status: Open Priority: Medium/High - Title: TELNETD PARTITIONING. - Description: Telnetd is implemented as a driver that resides in the apps/ - directory. In the kernel/protected build modes, the driver - logic must be moved into the kernel part of the build (nuttx/, - although the application level interfaces must stay in apps/). - Status: Open - Priority: Medium - Title: NxTERM PARTITIONING. Description: NxTerm is implemented (correctly) as a driver that resides in the nuttx/ directory. However, the user interfaces must be diff --git a/arch b/arch index 52b36cad74..9d2cde8987 160000 --- a/arch +++ b/arch @@ -1 +1 @@ -Subproject commit 52b36cad744faaef7e67eb25265268a808d9da59 +Subproject commit 9d2cde898788481cdd24f92f11fc9617428bcf14 diff --git a/drivers/loop/loop.c b/drivers/loop/loop.c index 1345b5417d..19cd75d62c 100644 --- a/drivers/loop/loop.c +++ b/drivers/loop/loop.c @@ -63,7 +63,7 @@ static int loop_ioctl(FAR struct file *filep, int cmd, unsigned long arg); * Private Data ****************************************************************************/ -static const struct file_operations loop_fops = +static const struct file_operations g_loop_fops = { 0, /* open */ 0, /* close */ @@ -154,6 +154,7 @@ static int loop_ioctl(FAR struct file *filep, int cmd, unsigned long arg) default: ret = -ENOTTY; + break; } return ret; @@ -173,7 +174,7 @@ static int loop_ioctl(FAR struct file *filep, int cmd, unsigned long arg) void loop_register(void) { - (void)register_driver("/dev/loop", &loop_fops, 0666, NULL); + (void)register_driver("/dev/loop", &g_loop_fops, 0666, NULL); } #endif /* CONFIG_DEV_LOOP */ diff --git a/drivers/net/telnet.c b/drivers/net/telnet.c index b935a5b457..505a01cb94 100644 --- a/drivers/net/telnet.c +++ b/drivers/net/telnet.c @@ -1,5 +1,5 @@ /**************************************************************************** - * apps/netutils/telnet_driver.c + * drivers/net/telnet.c * * Copyright (C) 2007, 2009, 2011-2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt @@ -46,6 +46,7 @@ #include #include +#include #include #include @@ -63,6 +64,8 @@ #include #include +#ifdef CONFIG_NETDEV_TELNET + /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ @@ -128,7 +131,7 @@ struct telnet_dev_s struct telnet_common_s { sem_t tc_exclsem; /* Enforces exclusive access to 'minor' */ - int tc_minor; /* The next minor number to use */ + uint16_t tc_minor; /* The next minor number to use */ }; /**************************************************************************** @@ -152,13 +155,24 @@ static bool telnet_putchar(FAR struct telnet_dev_s *priv, uint8_t ch, static void telnet_sendopt(FAR struct telnet_dev_s *priv, uint8_t option, uint8_t value); -/* Character driver methods */ +/* Telnet character driver methods */ static int telnet_open(FAR struct file *filep); static int telnet_close(FAR struct file *filep); static ssize_t telnet_read(FAR struct file *, FAR char *, size_t); static ssize_t telnet_write(FAR struct file *, FAR const char *, size_t); -static int telnet_ioctl(FAR struct file *filep, int cmd, + +/* Telnet session creation */ + +static int telnet_session(FAR struct telnet_session_s *session); + +/* Telnet factory driver methods */ + +static ssize_t factory_read(FAR struct file *filep, FAR char *buffer, + size_t buflen); +static ssize_t factory_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen); +static int common_ioctl(FAR struct file *filep, int cmd, unsigned long arg); /**************************************************************************** @@ -167,14 +181,27 @@ static int telnet_ioctl(FAR struct file *filep, int cmd, static const struct file_operations g_telnet_fops = { - telnet_open, /* open */ - telnet_close, /* close */ - telnet_read, /* read */ - telnet_write, /* write */ - 0, /* seek */ - telnet_ioctl /* ioctl */ + telnet_open, /* open */ + telnet_close, /* close */ + telnet_read, /* read */ + telnet_write, /* write */ + 0, /* seek */ + common_ioctl /* ioctl */ #ifndef CONFIG_DISABLE_POLL - , 0 /* poll */ + , 0 /* poll */ +#endif +}; + +static const struct file_operations g_factory_fops = +{ + 0, /* open */ + 0, /* close */ + factory_read, /* read */ + factory_write, /* write */ + 0, /* seek */ + common_ioctl /* ioctl */ +#ifndef CONFIG_DISABLE_POLL + , 0 /* poll */ #endif }; @@ -712,70 +739,27 @@ static ssize_t telnet_write(FAR struct file *filep, FAR const char *buffer, size } /**************************************************************************** - * Name: telnet_poll - ****************************************************************************/ - -static int telnet_ioctl(FAR struct file *filep, int cmd, unsigned long arg) -{ -#if 0 /* No ioctl commands are yet supported */ - struct inode *inode = filep->f_inode; - struct cdcacm_dev_s *priv = inode->i_private; - int ret = OK; - - switch (cmd) - { - /* Add ioctl commands here */ - - default: - ret = -ENOTTY; - break; - } - - return ret; -#else - return -ENOTTY; -#endif -} - -/**************************************************************************** - * Name: telnet_poll - ****************************************************************************/ - -#if 0 /* Not used by this driver */ -static int telnet_poll(FAR struct file *filep, FAR struct pollfd *fds, - bool setup) -{ - FAR struct inode *inode = filep->f_inode; - FAR struct telnet_dev_s *priv = inode->i_private; -} -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: telnet_driver + * Name: telnet_session * * Description: * Create a character driver to "wrap" the telnet session. This function * will select and return a unique path for the new telnet device. * * Parameters: - * sd - The socket descriptor that represents the new telnet connection. + * session - On input, contains the socket descriptor that represents the + * new telnet connection. On output, it holds the path to the new Telnet driver. * * Return: - * An allocated string represent the full path to the created driver. The - * receiver of the string must de-allocate this memory when it is no longer - * needed. NULL is returned on a failure. + * Zero (OK) on success; a negated errno value on failure. * ****************************************************************************/ -FAR char *telnet_driver(int sd) +static int telnet_session(FAR struct telnet_session_s *session) { FAR struct telnet_dev_s *priv; FAR struct socket *psock; - FAR char *devpath = NULL; + struct stat statbuf; + uint16_t start; int ret; /* Allocate instance data for this driver */ @@ -784,7 +768,7 @@ FAR char *telnet_driver(int sd) if (!priv) { nlldbg("Failed to allocate the driver data structure\n"); - return NULL; + return -ENOMEM; } /* Initialize the allocated driver instance */ @@ -801,10 +785,11 @@ FAR char *telnet_driver(int sd) * instance resided in the daemon's task group`). */ - psock = sockfd_socket(sd); + psock = sockfd_socket(session->ts_sd); if (!psock) { - nlldbg("Failed to convert sd=%d to a socket structure\n", sd); + nlldbg("Failed to convert sd=%d to a socket structure\n", session->ts_sd); + ret = -EINVAL; goto errout_with_dev; } @@ -815,51 +800,157 @@ FAR char *telnet_driver(int sd) goto errout_with_dev; } - /* And close the original */ - - psock_close(psock); - - /* Allocate a unique minor device number of the telnet drvier */ + /* Allocate a unique minor device number of the telnet drvier. + * Get exclusive access to the minor counter. + */ do { ret = sem_wait(&g_telnet_common.tc_exclsem); if (ret < 0 && errno != -EINTR) { - goto errout_with_dev; + goto errout_with_clone; } } while (ret < 0); - priv->td_minor = g_telnet_common.tc_minor; - g_telnet_common.tc_minor++; - sem_post(&g_telnet_common.tc_exclsem); + /* Loop until the device name is verified to be unique. */ - /* Create a path and name for the driver. */ - - ret = asprintf(&devpath, TELNETD_DEVFMT, priv->td_minor); - if (ret < 0) + start = g_telnet_common.tc_minor; + do { - nlldbg("Failed to allocate the driver path\n"); - goto errout_with_dev; + /* Get the next candiate minor number */ + + priv->td_minor = g_telnet_common.tc_minor; + g_telnet_common.tc_minor++; + + snprintf(session->ts_devpath, TELNET_DEVPATH_MAX, TELNETD_DEVFMT, + priv->td_minor); + + ret = stat(session->ts_devpath, &statbuf); + DEBUGASSERT(ret >= 0 || errno == ENOENT); + } + while (ret >= 0 && start != g_telnet_common.tc_minor); + + if (ret >= 0) + { + nlldbg("ERROR: Too many sessions\n"); + ret = -ENFILE; + goto errout_with_semaphore; } /* Register the driver */ - ret = register_driver(devpath, &g_telnet_fops, 0666, priv); + ret = register_driver(session->ts_devpath, &g_telnet_fops, 0666, priv); if (ret < 0) { - nlldbg("Failed to register the driver %s: %d\n", devpath, ret); - goto errout_with_devpath; + nlldbg("ERROR: Failed to register the driver %s: %d\n", + session->ts_devpath, ret); + goto errout_with_semaphore; } + /* Close the original psoock (keeping the clone) */ + + psock_close(psock); + /* Return the path to the new telnet driver */ - return devpath; + sem_post(&g_telnet_common.tc_exclsem); + return OK; + +errout_with_semaphore: + sem_post(&g_telnet_common.tc_exclsem); + +errout_with_clone: + psock_close(&priv->td_psock); -errout_with_devpath: - free(devpath); errout_with_dev: free(priv); - return NULL; + return ret; } + +/**************************************************************************** + * Name: factory_read + ****************************************************************************/ + +static ssize_t factory_read(FAR struct file *filep, FAR char *buffer, + size_t len) +{ + return 0; /* Return EOF */ +} + +/**************************************************************************** + * Name: factory_write + ****************************************************************************/ + +static ssize_t factory_write(FAR struct file *filep, FAR const char *buffer, + size_t len) +{ + return len; /* Say that everything was written */ +} + +/**************************************************************************** + * Name: common_ioctl + ****************************************************************************/ + +static int common_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + int ret; + + switch (cmd) + { + /* Command: SIOCTELNET + * Description: Create a Telnet sessions. + * Argument: A pointer to a write-able instance of struct + * telnet_session_s. + * Dependencies: CONFIG_NETDEV_TELNET + */ + + case SIOCTELNET: + { + FAR struct telnet_session_s *session = + (FAR struct telnet_session_s *)((uintptr_t)arg); + + if (session == NULL) + { + ret = -EINVAL; + } + else + { + ret = telnet_session(session); + } + } + break; + + default: + ret = -ENOTTY; + break; + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: telnet_initialize + * + * Description: + * Create the Telnet factory at /dev/telnet. + * + * Parameters: + * None + * + * Return: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int telnet_initialize(void) +{ + return register_driver("/dev/telnet", &g_factory_fops, 0666, NULL); +} + +#endif /* CONFIG_NETDEV_TELNET */ diff --git a/include/nuttx/net/ioctl.h b/include/nuttx/net/ioctl.h index 5b617314d7..4a13ed523f 100644 --- a/include/nuttx/net/ioctl.h +++ b/include/nuttx/net/ioctl.h @@ -175,6 +175,11 @@ #define SIOCINQ _SIOC(0x004f) /* Returns the amount of queued unread * data in the receive */ +/* Telnet driver ************************************************************/ + +#define SIOCTELNET _SIOC(0x0050) /* Create a Telnet sessions. + * See include/nuttx/net/telnet.h */ + /**************************************************************************** * Type Definitions ****************************************************************************/ diff --git a/include/nuttx/net/telnet.h b/include/nuttx/net/telnet.h index 6820260fad..c7184c6d6b 100644 --- a/include/nuttx/net/telnet.h +++ b/include/nuttx/net/telnet.h @@ -42,28 +42,57 @@ #include +#include + +#ifdef CONFIG_NETDEV_TELNET + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* The minimum size of a device name. Big enough to hold /dev/telnet65535. */ + +#define TELNET_DEVPATH_MAX 18 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* NETDEV ioctl command: + * + * Command: SIOCTELNET + * Description: Create a Telnet sessions. + * Argument: A pointer to a write-able instance of struct telnet_session_s. + * Dependencies: CONFIG_NETDEV_TELNET + */ + +struct telnet_session_s +{ + int ts_sd; /* Socket descriptor for session. */ + char ts_devpath[TELNET_DEVPATH_MAX]; /* Path to new session driver */ +}; + /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** - * Name: telnet_driver + * Name: telnet_initialize * * Description: - * Create a character driver to "wrap" the telnet session. This function - * will select and return a unique path for the new telnet device. + * Create the Telnet factory at /dev/telnet. * * Parameters: - * sd - The socket descriptor that represents the new telnet connection. + * None * * Return: - * An allocated string represent the full path to the created driver. The - * receiver of the string must de-allocate this memory when it is no longer - * needed. NULL is returned on a failure. + * Zero (OK) on success; a negated errno value on failure. * ****************************************************************************/ -FAR char *telnet_driver(int sd); +#ifdef __KERNEL__ +int telnet_initialize(void); +#endif +#endif /* CONFIG_NETDEV_TELNET */ #endif /* __INCLUDE_NUTTX_NET_TELNET_H */ -