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.

This commit is contained in:
Gregory Nutt 2015-12-07 13:48:06 -06:00
parent 3bd5f60a62
commit 8fdb173090
7 changed files with 231 additions and 107 deletions

View File

@ -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).

11
TODO
View File

@ -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

2
arch

@ -1 +1 @@
Subproject commit 52b36cad744faaef7e67eb25265268a808d9da59
Subproject commit 9d2cde898788481cdd24f92f11fc9617428bcf14

View File

@ -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 */

View File

@ -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 <gnutt@nuttx.org>
@ -46,6 +46,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <stdint.h>
#include <stdbool.h>
@ -63,6 +64,8 @@
#include <nuttx/net/net.h>
#include <nuttx/net/telnet.h>
#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 */

View File

@ -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
****************************************************************************/

View File

@ -42,28 +42,57 @@
#include <nuttx/config.h>
#include <nuttx/net/ioctl.h>
#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 */