telnetd.c

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