# apps/telnetd/telnetd.c

    00001 /*
    00002  * Copyright (c) 2003, Adam Dunkels.
    00003  * All rights reserved.
    00004  *
    00005  * Redistribution and use in source and binary forms, with or without
    00006  * modification, are permitted provided that the following conditions
    00007  * are met:
    00008  * 1. Redistributions of source code must retain the above copyright
    00009  *    notice, this list of conditions and the following disclaimer.
    00010  * 2. Redistributions in binary form must reproduce the above copyright
    00011  *    notice, this list of conditions and the following disclaimer in the
    00012  *    documentation and/or other materials provided with the distribution.
    00013  * 3. The name of the author may not be used to endorse or promote
    00014  *    products derived from this software without specific prior
    00015  *    written permission.
    00016  *
    00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
    00018  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
    00019  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
    00021  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
    00023  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
    00025  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
    00026  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    00027  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    00028  *
    00029  * This file is part of the uIP TCP/IP stack
    00030  *
    00031  * $Id: telnetd.c,v 1.2 2006/06/07 09:43:54 adam Exp $
    00032  *
    00033  */
    00034
    00035 #include "uip.h"
    00036 #include "telnetd.h"
    00037 #include "memb.h"
    00038 #include "shell.h"
    00039
    00040 #include <string.h>
    00041
    00042 #define ISO_nl       0x0a
    00043 #define ISO_cr       0x0d
    00044
    00045 struct telnetd_line {
    00046   char line[TELNETD_CONF_LINELEN];
    00047 };
    00048 MEMB(linemem, struct telnetd_line, TELNETD_CONF_NUMLINES);
    00049
    00050 #define STATE_NORMAL 0
    00051 #define STATE_IAC    1
    00052 #define STATE_WILL   2
    00053 #define STATE_WONT   3
    00054 #define STATE_DO     4
    00055 #define STATE_DONT   5
    00056 #define STATE_CLOSE  6
    00057
    00058 static struct telnetd_state s;
    00059
    00060 #define TELNET_IAC   255
    00061 #define TELNET_WILL  251
    00062 #define TELNET_WONT  252
    00063 #define TELNET_DO    253
    00064 #define TELNET_DONT  254
    00065 /*---------------------------------------------------------------------------*/
    00066 static char *
    00067 alloc_line(void)
    00068 {
    00069   return memb_alloc(&linemem);
    00070 }
    00071 /*---------------------------------------------------------------------------*/
    00072 static void
    00073 dealloc_line(char *line)
    00074 {
    00075   memb_free(&linemem, line);
    00076 }
    00077 /*---------------------------------------------------------------------------*/
    00078 void
    00079 shell_quit(char *str)
    00080 {
    00081   s.state = STATE_CLOSE;
    00082 }
    00083 /*---------------------------------------------------------------------------*/
    00084 static void
    00085 sendline(char *line)
    00086 {
    00087   static unsigned int i;
    00088
    00089   for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) {
    00090     if(s.lines[i] == NULL) {
    00091       s.lines[i] = line;
    00092       break;
    00093     }
    00094   }
    00095   if(i == TELNETD_CONF_NUMLINES) {
    00096     dealloc_line(line);
    00097   }
    00098 }
    00099 /*---------------------------------------------------------------------------*/
    00100 void
    00101 shell_prompt(char *str)
    00102 {
    00103   char *line;
    00104   line = alloc_line();
    00105   if(line != NULL) {
    00106     strncpy(line, str, TELNETD_CONF_LINELEN);
    00107     /*    petsciiconv_toascii(line, TELNETD_CONF_LINELEN);*/
    00108     sendline(line);
    00109   }
    00110 }
    00111 /*---------------------------------------------------------------------------*/
    00112 void
    00113 shell_output(char *str1, char *str2)
    00114 {
    00115   static unsigned len;
    00116   char *line;
    00117
    00118   line = alloc_line();
    00119   if(line != NULL) {
    00120     len = strlen(str1);
    00121     strncpy(line, str1, TELNETD_CONF_LINELEN);
    00122     if(len < TELNETD_CONF_LINELEN) {
    00123       strncpy(line + len, str2, TELNETD_CONF_LINELEN - len);
    00124     }
    00125     len = strlen(line);
    00126     if(len < TELNETD_CONF_LINELEN - 2) {
    00127       line[len] = ISO_cr;
    00128       line[len+1] = ISO_nl;
    00129       line[len+2] = 0;
    00130     }
    00131     /*    petsciiconv_toascii(line, TELNETD_CONF_LINELEN);*/
    00132     sendline(line);
    00133   }
    00134 }
    00135 /*---------------------------------------------------------------------------*/
    00136 void
    00137 telnetd_init(void)
    00138 {
    00139   uip_listen(HTONS(23));
    00140   memb_init(&linemem);
    00141   shell_init();
    00142 }
    00143 /*---------------------------------------------------------------------------*/
    00144 static void
    00145 acked(void)
    00146 {
    00147   static unsigned int i;
    00148
    00149   while(s.numsent > 0) {
    00150     dealloc_line(s.lines[0]);
    00151     for(i = 1; i < TELNETD_CONF_NUMLINES; ++i) {
    00152       s.lines[i - 1] = s.lines[i];
    00153     }
    00154     s.lines[TELNETD_CONF_NUMLINES - 1] = NULL;
    00155     --s.numsent;
    00156   }
    00157 }
    00158 /*---------------------------------------------------------------------------*/
    00159 static void
    00160 senddata(void)
    00161 {
    00162   static char *bufptr, *lineptr;
    00163   static int buflen, linelen;
    00164
    00165   bufptr = uip_appdata;
    00166   buflen = 0;
    00167   for(s.numsent = 0; s.numsent < TELNETD_CONF_NUMLINES &&
    00168         s.lines[s.numsent] != NULL ; ++s.numsent) {
    00169     lineptr = s.lines[s.numsent];
    00170     linelen = strlen(lineptr);
    00171     if(linelen > TELNETD_CONF_LINELEN) {
    00172       linelen = TELNETD_CONF_LINELEN;
    00173     }
    00174     if(buflen + linelen < uip_mss()) {
    00175       memcpy(bufptr, lineptr, linelen);
    00176       bufptr += linelen;
    00177       buflen += linelen;
    00178     } else {
    00179       break;
    00180     }
    00181   }
    00182   uip_send(uip_appdata, buflen);
    00183 }
    00184 /*---------------------------------------------------------------------------*/
    00185 static void
    00186 closed(void)
    00187 {
    00188   static unsigned int i;
    00189
    00190   for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) {
    00191     if(s.lines[i] != NULL) {
    00192       dealloc_line(s.lines[i]);
    00193     }
    00194   }
    00195 }
    00196 /*---------------------------------------------------------------------------*/
    00197 static void
    00198 get_char(u8_t c)
    00199 {
    00200   if(c == ISO_cr) {
    00201     return;
    00202   }
    00203
    00204   s.buf[(int)s.bufptr] = c;
    00205   if(s.buf[(int)s.bufptr] == ISO_nl ||
    00206      s.bufptr == sizeof(s.buf) - 1) {
    00207     if(s.bufptr > 0) {
    00208       s.buf[(int)s.bufptr] = 0;
    00209       /*      petsciiconv_topetscii(s.buf, TELNETD_CONF_LINELEN);*/
    00210     }
    00211     shell_input(s.buf);
    00212     s.bufptr = 0;
    00213   } else {
    00214     ++s.bufptr;
    00215   }
    00216 }
    00217 /*---------------------------------------------------------------------------*/
    00218 static void
    00219 sendopt(u8_t option, u8_t value)
    00220 {
    00221   char *line;
    00222   line = alloc_line();
    00223   if(line != NULL) {
    00224     line[0] = TELNET_IAC;
    00225     line[1] = option;
    00226     line[2] = value;
    00227     line[3] = 0;
    00228     sendline(line);
    00229   }
    00230 }
    00231 /*---------------------------------------------------------------------------*/
    00232 static void
    00233 newdata(void)
    00234 {
    00235   u16_t len;
    00236   u8_t c;
    00237   char *dataptr;
    00238
    00239
    00240   len = uip_datalen();
    00241   dataptr = (char *)uip_appdata;
    00242
    00243   while(len > 0 && s.bufptr < sizeof(s.buf)) {
    00244     c = *dataptr;
    00245     ++dataptr;
    00246     --len;
    00247     switch(s.state) {
    00248     case STATE_IAC:
    00249       if(c == TELNET_IAC) {
    00250         get_char(c);
    00251         s.state = STATE_NORMAL;
    00252       } else {
    00253         switch(c) {
    00254         case TELNET_WILL:
    00255           s.state = STATE_WILL;
    00256           break;
    00257         case TELNET_WONT:
    00258           s.state = STATE_WONT;
    00259           break;
    00260         case TELNET_DO:
    00261           s.state = STATE_DO;
    00262           break;
    00263         case TELNET_DONT:
    00264           s.state = STATE_DONT;
    00265           break;
    00266         default:
    00267           s.state = STATE_NORMAL;
    00268           break;
    00269         }
    00270       }
    00271       break;
    00272     case STATE_WILL:
    00273       /* Reply with a DONT */
    00274       sendopt(TELNET_DONT, c);
    00275       s.state = STATE_NORMAL;
    00276       break;
    00277
    00278     case STATE_WONT:
    00279       /* Reply with a DONT */
    00280       sendopt(TELNET_DONT, c);
    00281       s.state = STATE_NORMAL;
    00282       break;
    00283     case STATE_DO:
    00284       /* Reply with a WONT */
    00285       sendopt(TELNET_WONT, c);
    00286       s.state = STATE_NORMAL;
    00287       break;
    00288     case STATE_DONT:
    00289       /* Reply with a WONT */
    00290       sendopt(TELNET_WONT, c);
    00291       s.state = STATE_NORMAL;
    00292       break;
    00293     case STATE_NORMAL:
    00294       if(c == TELNET_IAC) {
    00295         s.state = STATE_IAC;
    00296       } else {
    00297         get_char(c);
    00298       }
    00299       break;
    00300     }
    00301
    00302
    00303   }
    00304
    00305 }
    00306 /*---------------------------------------------------------------------------*/
    00307 void
    00308 telnetd_appcall(void)
    00309 {
    00310   static unsigned int i;
    00311   if(uip_connected()) {
    00312     /*    tcp_markconn(uip_conn, &s);*/
    00313     for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) {
    00314       s.lines[i] = NULL;
    00315     }
    00316     s.bufptr = 0;
    00317     s.state = STATE_NORMAL;
    00318
    00319     shell_start();
    00320   }
    00321
    00322   if(s.state == STATE_CLOSE) {
    00323     s.state = STATE_NORMAL;
    00324     uip_close();
    00325     return;
    00326   }
    00327
    00328   if(uip_closed() ||
    00329      uip_aborted() ||
    00330      uip_timedout()) {
    00331     closed();
    00332   }
    00333
    00334   if(uip_acked()) {
    00335     acked();
    00336   }
    00337
    00338   if(uip_newdata()) {
    00339     newdata();
    00340   }
    00341
    00342   if(uip_rexmit() ||
    00343      uip_newdata() ||
    00344      uip_acked() ||
    00345      uip_connected() ||
    00346      uip_poll()) {
    00347     senddata();
    00348   }
    00349 }
    00350 /*---------------------------------------------------------------------------*/