summaryrefslogtreecommitdiffstats
path: root/c/src/libnetworking/rtems_telnetd
diff options
context:
space:
mode:
Diffstat (limited to 'c/src/libnetworking/rtems_telnetd')
-rw-r--r--c/src/libnetworking/rtems_telnetd/Makefile.am44
-rw-r--r--c/src/libnetworking/rtems_telnetd/README28
-rw-r--r--c/src/libnetworking/rtems_telnetd/icmds.c48
-rw-r--r--c/src/libnetworking/rtems_telnetd/pty.c408
-rw-r--r--c/src/libnetworking/rtems_telnetd/pty.h63
-rw-r--r--c/src/libnetworking/rtems_telnetd/telnetd.c132
-rw-r--r--c/src/libnetworking/rtems_telnetd/telnetd.h35
7 files changed, 758 insertions, 0 deletions
diff --git a/c/src/libnetworking/rtems_telnetd/Makefile.am b/c/src/libnetworking/rtems_telnetd/Makefile.am
new file mode 100644
index 0000000000..a5d0480722
--- /dev/null
+++ b/c/src/libnetworking/rtems_telnetd/Makefile.am
@@ -0,0 +1,44 @@
+##
+## $Id$
+##
+
+AUTOMAKE_OPTIONS = foreign 1.4
+
+include_rtemsdir = $(includedir)/rtems
+
+LIBNAME = libtelnetd-tmp
+LIB = $(ARCH)/$(LIBNAME).a
+
+C_FILES = pty.c telnetd.c icmds.c
+C_O_FILES = $(C_FILES:%.c=$(ARCH)/%.o)
+
+include_rtems_HEADERS = pty.h telnetd.h
+
+OBJS = $(C_O_FILES)
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
+include $(top_srcdir)/../../../automake/compile.am
+include $(top_srcdir)/../../../automake/lib.am
+
+$(PROJECT_INCLUDE)/rtems:
+ @$(mkinstalldirs) $@
+$(PROJECT_INCLUDE)/rtems/%.h: %.h
+ $(INSTALL_DATA) $< $@
+
+#
+# (OPTIONAL) Add local stuff here using +=
+#
+
+$(LIB): $(OBJS)
+ $(make-library)
+
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems \
+ $(include_rtems_HEADERS:%=$(PROJECT_INCLUDE)/rtems/%)
+
+all-local: $(ARCH) $(PREINSTALL_FILES) $(OBJS) $(LIB)
+
+.PRECIOUS: $(LIB)
+
+EXTRA_DIST = README pty.c telnetd.c pty.h icmds.c telnetd.h
+
+include $(top_srcdir)/../../../automake/local.am
diff --git a/c/src/libnetworking/rtems_telnetd/README b/c/src/libnetworking/rtems_telnetd/README
new file mode 100644
index 0000000000..0c964c412d
--- /dev/null
+++ b/c/src/libnetworking/rtems_telnetd/README
@@ -0,0 +1,28 @@
+#
+# $Id$
+#
+
+Author: fernando.ruiz@ctv.es (correo@fernando-ruiz.com)
+
+This directory contains a telnetd server
+primary features:
+
+ + create a user shell pseudo-terminal task.
+
+This code has not been extensively tested. It is provided as a tool
+for RTEMS users to open more shell tcp/ip pseudo-terminal.
+Suggestions and comments are appreciated.
+
+Read libmisc/shell for more information.
+
+NOTES:
+
+1. OOB not yet implemented. Only a reduced negotiation is implemented.
+
+2. If you have tcp/ip inited you can start telnetd daemon.
+ You need register pseudo-terminals driver into device drivers table.
+ 16 ptyX termios device terminales are created into /dev/.
+ Calling rtems_initialize_telnetd() starts the daemon.
+ Enjoy it.
+
+FUTURE:
diff --git a/c/src/libnetworking/rtems_telnetd/icmds.c b/c/src/libnetworking/rtems_telnetd/icmds.c
new file mode 100644
index 0000000000..1ac6820f39
--- /dev/null
+++ b/c/src/libnetworking/rtems_telnetd/icmds.c
@@ -0,0 +1,48 @@
+#include <rtems/shell.h>
+#include <rtems/rtems_bsdnet.h>
+/*+++++++++++++++++++++++++++++++++++++++++++++*/
+int main_inet(int argc,char * argv[]) {
+ rtems_bsdnet_show_inet_routes ();
+ return 0;
+}
+/*+++++++++++++++++++++++++++++++++++++++++++++*/
+int main_mbuf(int argc,char * argv[]) {
+ rtems_bsdnet_show_mbuf_stats ();
+ return 0;
+}
+/*+++++++++++++++++++++++++++++++++++++++++++++*/
+int main_if(int argc,char * argv[]) {
+ rtems_bsdnet_show_if_stats ();
+ return 0;
+}
+/*+++++++++++++++++++++++++++++++++++++++++++++*/
+int main_ip(int argc,char * argv[]) {
+ rtems_bsdnet_show_ip_stats ();
+ return 0;
+}
+/*+++++++++++++++++++++++++++++++++++++++++++++*/
+int main_icmp(int argc,char * argv[]) {
+ rtems_bsdnet_show_icmp_stats ();
+ return 0;
+}
+/*+++++++++++++++++++++++++++++++++++++++++++++*/
+int main_tcp(int argc,char * argv[]) {
+ rtems_bsdnet_show_tcp_stats ();
+ return 0;
+}
+/*+++++++++++++++++++++++++++++++++++++++++++++*/
+int main_udp(int argc,char * argv[]) {
+ rtems_bsdnet_show_udp_stats ();
+ return 0;
+}
+/*+++++++++++++++++++++++++++++++++++++++++++++*/
+void register_icmds(void) {
+ shell_add_cmd("inet" ,"net","inet routes" ,main_inet);
+ shell_add_cmd("mbuf" ,"net","mbuf stats" ,main_mbuf);
+ shell_add_cmd("if" ,"net","if stats" ,main_if );
+ shell_add_cmd("ip" ,"net","ip stats" ,main_ip );
+ shell_add_cmd("icmp" ,"net","icmp stats" ,main_icmp);
+ shell_add_cmd("tcp" ,"net","tcp stats" ,main_tcp );
+ shell_add_cmd("udp" ,"net","udp stats" ,main_udp );
+}
+
diff --git a/c/src/libnetworking/rtems_telnetd/pty.c b/c/src/libnetworking/rtems_telnetd/pty.c
new file mode 100644
index 0000000000..a18b286922
--- /dev/null
+++ b/c/src/libnetworking/rtems_telnetd/pty.c
@@ -0,0 +1,408 @@
+/*
+ * /dev/ptyXX (A first version for pseudo-terminals)
+ *
+ * Author: Fernando RUIZ CASAS (fernando.ruiz@ctv.es)
+ * May 2001
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id$
+ */
+/*-----------------------------------------*/
+#include <termios.h>
+#include <rtems.h>
+#include <rtems/libio.h>
+#include <bsp.h>
+#include <rtems/pty.h>
+/*-----------------------------------------*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+/*-----------------------------------------*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+/*-----------------------------------------*/
+#define printk printf
+/*-----------------------------------------*/
+#define IAC_ESC 255
+#define IAC_DONT 254
+#define IAC_DO 253
+#define IAC_WONT 252
+#define IAC_WILL 251
+#define IAC_SB 250
+#define IAC_GA 249
+#define IAC_EL 248
+#define IAC_EC 247
+#define IAC_AYT 246
+#define IAC_AO 245
+#define IAC_IP 244
+#define IAC_BRK 243
+#define IAC_DMARK 242
+#define IAC_NOP 241
+#define IAC_SE 240
+#define IAC_EOR 239
+
+struct pty_tt;
+typedef struct pty_tt pty_t;
+
+struct pty_tt {
+ char *devname;
+ struct rtems_termios_tty *ttyp;
+ tcflag_t c_cflag;
+ int opened;
+ int socket;
+
+ int last_cr;
+ int iac_mode;
+};
+
+
+int ptys_initted=FALSE;
+pty_t ptys[MAX_PTYS];
+
+/* This procedure returns the devname for a pty slot free.
+ * If not slot availiable (field socket>=0)
+ * then the socket argument is closed
+ */
+
+char * get_pty(int socket) {
+ int ndx;
+ if (!ptys_initted) return NULL;
+ for (ndx=0;ndx<MAX_PTYS;ndx++) {
+ if (ptys[ndx].socket<0) {
+ ptys[ndx].socket=socket;
+ return ptys[ndx].devname;
+ };
+ };
+ close(socket);
+ return NULL;
+}
+
+
+/*-----------------------------------------------------------*/
+/*
+ * The NVT terminal is negociated in PollRead and PollWrite
+ * with every BYTE sendded or received.
+ * A litle status machine in the pty_read_byte(int minor)
+ *
+ */
+const char IAC_AYT_RSP[]="\r\nAYT? Yes, RTEMS-SHELL is here\r\n";
+const char IAC_BRK_RSP[]="<*Break*>";
+const char IAC_IP_RSP []="<*Interrupt*>";
+
+
+static
+int send_iac(int minor,unsigned char mode,unsigned char option) {
+ unsigned char buf[3];
+ buf[0]=IAC_ESC;
+ buf[1]=mode;
+ buf[2]=option;
+ return write(ptys[minor].socket,buf,sizeof(buf));
+}
+
+int read_pty(int minor) { /* Characters writed in the client side*/
+ unsigned char value;
+ int count;
+ int result;
+ count=read(ptys[minor].socket,&value,sizeof(value));
+ if (count<1) {
+ fclose(stdin);
+ fclose(stdout);
+ fclose(stderr);
+ /* If you don't read from the socket the system ends the task */
+ rtems_task_delete(RTEMS_SELF);
+ };
+ switch(ptys[minor].iac_mode) {
+ case IAC_ESC:
+ ptys[minor].iac_mode=0;
+ switch(value) {
+ case IAC_ESC :
+ return IAC_ESC;
+ case IAC_DONT:
+ case IAC_DO :
+ case IAC_WONT:
+ case IAC_WILL:
+ ptys[minor].iac_mode=value;
+ return -1;
+ case IAC_SB :
+ return -100;
+ case IAC_GA :
+ return -1;
+ case IAC_EL :
+ return 0x03; /* Ctrl-C*/
+ case IAC_EC :
+ return '\b';
+ case IAC_AYT :
+ write(ptys[minor].socket,IAC_AYT_RSP,strlen(IAC_AYT_RSP));
+ return -1;
+ case IAC_AO :
+ return -1;
+ case IAC_IP :
+ write(ptys[minor].socket,IAC_IP_RSP,strlen(IAC_IP_RSP));
+ return -1;
+ case IAC_BRK :
+ write(ptys[minor].socket,IAC_BRK_RSP,strlen(IAC_BRK_RSP));
+ return -1;
+ case IAC_DMARK:
+ return -2;
+ case IAC_NOP :
+ return -1;
+ case IAC_SE :
+ return -101;
+ case IAC_EOR :
+ return -102;
+ default :
+ return -1;
+ };
+ break;
+ case IAC_WILL:
+ ptys[minor].iac_mode=0;
+ if (value==34){send_iac(minor,IAC_DONT, 34); /*LINEMODE*/
+ send_iac(minor,IAC_DO , 1);} else /*ECHO */
+ {send_iac(minor,IAC_DONT,value);};
+ return -1;
+ case IAC_DONT:
+ ptys[minor].iac_mode=0;
+ return -1;
+ case IAC_DO :
+ ptys[minor].iac_mode=0;
+ if (value==3) {send_iac(minor,IAC_WILL, 3);} else /* GO AHEAD*/
+ if (value==1) { } else /* ECHO */
+ {send_iac(minor,IAC_WONT,value);};
+ return -1;
+ case IAC_WONT:
+ ptys[minor].iac_mode=0;
+ if (value==1) {send_iac(minor,IAC_WILL, 1);} else /* ECHO */
+ {send_iac(minor,IAC_WONT,value);};
+ return -1;
+ default:
+ ptys[minor].iac_mode=0;
+ if (value==IAC_ESC) {
+ ptys[minor].iac_mode=value;
+ return -1;
+ } else {
+ result=value;
+ if ((value=='\n') && (ptys[minor].last_cr)) result=-1;
+ ptys[minor].last_cr=(value=='\r');
+ return result;
+ };
+ };
+
+}
+
+/*-----------------------------------------------------------*/
+static int ptySetAttributes(int minor,const struct termios *t);
+static int ptyPollInitialize(int major,int minor,void * arg) ;
+static int ptyShutdown(int major,int minor,void * arg) ;
+static int ptyPollWrite(int minor, const char * buf,int len) ;
+static int ptyPollRead(int minor) ;
+const rtems_termios_callbacks * pty_get_termios_handlers(int polled) ;
+/*-----------------------------------------------------------*/
+/* Set the 'Hardware' */
+/*-----------------------------------------------------------*/
+static int
+ptySetAttributes(int minor,const struct termios *t) {
+ if (minor<MAX_PTYS) {
+ ptys[minor].c_cflag=t->c_cflag;
+ } else {
+ return -1;
+ };
+ return 0;
+}
+/*-----------------------------------------------------------*/
+static int
+ptyPollInitialize(int major,int minor,void * arg) {
+ rtems_libio_open_close_args_t * args = arg;
+ struct termios t;
+ if (minor<MAX_PTYS) {
+ if (ptys[minor].socket<0) return -1;
+ ptys[minor].opened=TRUE;
+ ptys[minor].ttyp=args->iop->data1;
+ t.c_cflag=B9600|CS8;/* termios default */
+ return ptySetAttributes(minor,&t);
+ } else {
+ return -1;
+ };
+}
+/*-----------------------------------------------------------*/
+static int
+ptyShutdown(int major,int minor,void * arg) {
+ if (minor<MAX_PTYS) {
+ ptys[minor].opened=FALSE;
+ if (ptys[minor].socket>=0) close(ptys[minor].socket);
+ ptys[minor].socket=-1;
+ chown(ptys[minor].devname,2,0);
+ } else {
+ return -1;
+ };
+ return 0;
+}
+/*-----------------------------------------------------------*/
+/* Write Characters into pty device */
+/*-----------------------------------------------------------*/
+static int
+ptyPollWrite(int minor, const char * buf,int len) {
+ int count;
+ if (minor<MAX_PTYS) {
+ if (ptys[minor].socket<0) return -1;
+ count=write(ptys[minor].socket,buf,len);
+ } else {
+ count=-1;
+ };
+ return count;
+}
+/*-----------------------------------------------------------*/
+static int
+ptyPollRead(int minor) {
+ int result;
+ if (minor<MAX_PTYS) {
+ if (ptys[minor].socket<0) return -1;
+ result=read_pty(minor);
+ return result;
+ };
+ return -1;
+}
+/*-----------------------------------------------------------*/
+static const rtems_termios_callbacks pty_poll_callbacks = {
+ ptyPollInitialize, /* FirstOpen*/
+ ptyShutdown, /* LastClose*/
+ ptyPollRead, /* PollRead */
+ ptyPollWrite, /* Write */
+ ptySetAttributes, /* setAttributes */
+ NULL, /* stopRemoteTX */
+ NULL, /* StartRemoteTX */
+ 0 /* outputUsesInterrupts */
+};
+/*-----------------------------------------------------------*/
+const rtems_termios_callbacks * pty_get_termios_handlers(int polled) {
+ return &pty_poll_callbacks;
+}
+/*-----------------------------------------------------------*/
+void init_ptys(void) {
+ int ndx;
+ for (ndx=0;ndx<MAX_PTYS;ndx++) {
+ ptys[ndx].devname=malloc(strlen("/dev/ptyXX")+1);
+ sprintf(ptys[ndx].devname,"/dev/pty%X",ndx);
+ ptys[ndx].ttyp=NULL;
+ ptys[ndx].c_cflag=CS8|B9600;
+ ptys[ndx].socket=-1;
+ ptys[ndx].opened=FALSE;
+
+ };
+ ptys_initted=TRUE;
+}
+
+
+/*-----------------------------------------------------------*/
+/* pty_initialize
+ *
+ * This routine initializes the pty IO driver.
+ *
+ * Input parameters: NONE
+ *
+ * Output parameters: NONE
+ *
+ * Return values:
+ */
+/*-----------------------------------------------------------*/
+rtems_device_driver pty_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg
+)
+{
+ int ndx;
+ rtems_status_code status ;
+
+ /*
+ * Set up ptys
+ */
+
+ init_ptys();
+
+ /*
+ * Register the devices
+ */
+ for (ndx=0;ndx<MAX_PTYS;ndx++) {
+ status = rtems_io_register_name(ptys[ndx].devname, major, ndx);
+ if (status != RTEMS_SUCCESSFUL)
+ rtems_fatal_error_occurred(status);
+ chmod(ptys[ndx].devname,0660);
+ chown(ptys[ndx].devname,2,0); /* tty,root*/
+ };
+ printk("Device: /dev/pty%X../dev/pty%X (%d)pseudo-terminals registered.\n",0,MAX_PTYS-1,MAX_PTYS);
+
+ return RTEMS_SUCCESSFUL;
+}
+
+
+/*
+ * Open entry point
+ */
+
+rtems_device_driver pty_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ rtems_status_code sc ;
+ sc = rtems_termios_open(major,minor,arg,pty_get_termios_handlers(FALSE));
+ return sc;
+}
+
+/*
+ * Close entry point
+ */
+
+rtems_device_driver pty_close(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return rtems_termios_close(arg);
+}
+
+/*
+ * read bytes from the pty
+ */
+
+rtems_device_driver pty_read(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return rtems_termios_read(arg);
+}
+
+/*
+ * write bytes to the pty
+ */
+
+rtems_device_driver pty_write(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return rtems_termios_write(arg);
+}
+
+/*
+ * IO Control entry point
+ */
+
+rtems_device_driver pty_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg
+)
+{
+ return rtems_termios_ioctl(arg);
+}
diff --git a/c/src/libnetworking/rtems_telnetd/pty.h b/c/src/libnetworking/rtems_telnetd/pty.h
new file mode 100644
index 0000000000..2c1367101d
--- /dev/null
+++ b/c/src/libnetworking/rtems_telnetd/pty.h
@@ -0,0 +1,63 @@
+/*
+ * /dev/ptyXX (A first version for pseudo-terminals)
+ *
+ * Author: Fernando RUIZ CASAS (fernando.ruiz@ctv.es)
+ * May 2001
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id$
+ */
+
+#ifndef __PTY_H
+#define __PTY_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems.h>
+
+#ifndef MAX_PTYS
+#define MAX_PTYS 16
+#endif
+
+char * get_pty(int socket);
+
+rtems_device_driver pty_initialize(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg);
+rtems_device_driver pty_open(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg);
+rtems_device_driver pty_close(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg);
+rtems_device_driver pty_read(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg);
+rtems_device_driver pty_write(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg);
+rtems_device_driver pty_control(
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void * arg);
+
+
+#define PTY_DRIVER_TABLE_ENTRY \
+ { pty_initialize , pty_open , pty_close , \
+ pty_read , pty_write , pty_control }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/c/src/libnetworking/rtems_telnetd/telnetd.c b/c/src/libnetworking/rtems_telnetd/telnetd.c
new file mode 100644
index 0000000000..ce7c5c118d
--- /dev/null
+++ b/c/src/libnetworking/rtems_telnetd/telnetd.c
@@ -0,0 +1,132 @@
+/***********************************************************/
+/*
+ *
+ * The telnet DAEMON
+ *
+ * Author: 17,may 2001
+ *
+ * WORK: fernando.ruiz@ctv.es
+ * HOME: correo@fernando-ruiz.com
+ *
+ * After start the net you can start this daemon.
+ * It uses the previously inited pseudo-terminales (pty.c)
+ * getting a new terminal with getpty(). This function
+ * gives a terminal name passing a opened socket like parameter.
+ *
+ * With register_telnetd() you add a new command in the shell to start
+ * this daemon interactively. (Login in /dev/console of course)
+ *
+ * Sorry but OOB is not still implemented. (This is the first version)
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems.h>
+#include <rtems/error.h>
+#include <rtems/pty.h>
+#include <rtems/shell.h>
+#include <rtems/telnetd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+/***********************************************************/
+rtems_id telnetd_task_id =0;
+rtems_unsigned32 telnetd_stack_size =16384;
+rtems_task_priority telnetd_task_priority=100;
+/***********************************************************/
+rtems_task rtems_task_telnetd(rtems_task_argument task_argument) {
+ int des_socket,
+ acp_socket;
+ struct sockaddr_in srv;
+ char * devname;
+ int i=1;
+ int size_adr;
+ if ((des_socket=socket(PF_INET,SOCK_STREAM,0))<0) {
+ perror("telnetd:socket");
+ rtems_task_delete(RTEMS_SELF);
+ };
+ setsockopt(des_socket,SOL_SOCKET,0,&i,sizeof(i));
+ memset(&srv,0,sizeof(srv));
+ srv.sin_family=AF_INET;
+ srv.sin_port=htons(23);
+ size_adr=sizeof(srv);
+ if ((bind(des_socket,(struct sockaddr *)&srv,size_adr))<0) {
+ perror("telnetd:bind");
+ close(des_socket);
+ rtems_task_delete(RTEMS_SELF);
+ };
+ if ((listen(des_socket,5))<0) {
+ perror("telnetd:listen");
+ close(des_socket);
+ rtems_task_delete(RTEMS_SELF);
+ };
+ do {
+ acp_socket=accept(des_socket,(struct sockaddr*)&srv,&size_adr);
+ if (acp_socket<0) {
+ perror("telnetd:accept");
+ break;
+ };
+ if ((devname = get_pty(acp_socket)) ) {
+ shell_init(&devname[5],
+ telnetd_stack_size,
+ telnetd_task_priority,
+ devname,B9600|CS8,FALSE);
+ } else {
+ close(acp_socket);
+ };
+ } while(1);
+ close(des_socket);
+ rtems_task_delete(RTEMS_SELF);
+}
+/***********************************************************/
+int rtems_initialize_telnetd(void) {
+ void register_icmds(void);
+ rtems_status_code sc;
+
+ register_icmds(); /* stats for tcp/ip */
+
+ if (telnetd_task_id ) return RTEMS_RESOURCE_IN_USE;
+ if (telnetd_stack_size<=0 ) telnetd_stack_size =16384;
+ if (telnetd_task_priority<=2) telnetd_task_priority=100;
+ sc=rtems_task_create(new_rtems_name("tlnd"),
+ 100,RTEMS_MINIMUM_STACK_SIZE,
+ RTEMS_DEFAULT_MODES,
+ RTEMS_DEFAULT_ATTRIBUTES,
+ &telnetd_task_id);
+ if (sc!=RTEMS_SUCCESSFUL) {
+ rtems_error(sc,"creating task telnetd");
+ return (int)sc;
+ };
+ sc=rtems_task_start(telnetd_task_id,
+ rtems_task_telnetd,
+ (rtems_task_argument)NULL);
+ if (sc!=RTEMS_SUCCESSFUL) {
+ rtems_error(sc,"starting task telnetd");
+ };
+ return (int)sc;
+}
+/***********************************************************/
+int main_telnetd(int argc,char * argv[]) {
+ rtems_status_code sc;
+ if (telnetd_task_id) {
+ printf("ERROR:telnetd already started\n");
+ return 1;
+ };
+ if (argc>1) telnetd_stack_size =str2int(argv[1]);
+ if (argc>2) telnetd_task_priority=str2int(argv[2]);
+ sc=rtems_initialize_telnetd();
+ if (sc!=RTEMS_SUCCESSFUL) return sc;
+ printf("rtems_telnetd() started with stacksize=%u,priority=%d\n",
+ telnetd_stack_size,telnetd_task_priority);
+ return 0;
+}
+/***********************************************************/
+int register_telnetd(void) {
+ shell_add_cmd("telnetd","telnet","telnetd [stacksize [tsk_priority]]",main_telnetd);
+ return 0;
+}
+/***********************************************************/
diff --git a/c/src/libnetworking/rtems_telnetd/telnetd.h b/c/src/libnetworking/rtems_telnetd/telnetd.h
new file mode 100644
index 0000000000..1bb99ebc1b
--- /dev/null
+++ b/c/src/libnetworking/rtems_telnetd/telnetd.h
@@ -0,0 +1,35 @@
+/*
+ * (A first version for telnetd)
+ *
+ * Author: Fernando RUIZ CASAS (fernando.ruiz@ctv.es)
+ * May 2001
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * rtems_initialize_telnetd() starts the daemon.
+ * main_telnetd() is the main_proc for the command telnetd in the shell
+ * register_telnetd() add a new command in the shell to start
+ * interactively the telnetd daemon.
+ *
+ * $Id$
+ */
+
+#ifndef __TELNETD_H
+#define __TELNETD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int rtems_initialize_telnetd(void);
+int main_telnetd(int argc,char * argv[]);
+int register_telnetd(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+