1 /* 2 * Copyright (c) 2003, Adam Dunkels. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote 14 * products derived from this software without specific prior 15 * written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * This file is part of the uIP TCP/IP stack 30 * 31 * $Id: telnetd.c,v 1.2 2006/06/07 09:43:54 adam Exp $ 32 * 33 */ 34 35 #include "uip.h" 36 #include "telnetd.h" 37 #include "memb.h" 38 #include "shell.h" 39 40 #include <string.h> 41 42 #define ISO_nl 0x0a 43 #define ISO_cr 0x0d 44 45 struct telnetd_line { 46 char line[TELNETD_CONF_LINELEN]; 47 }; 48 MEMB(linemem, struct telnetd_line, TELNETD_CONF_NUMLINES); 49 50 #define STATE_NORMAL 0 51 #define STATE_IAC 1 52 #define STATE_WILL 2 53 #define STATE_WONT 3 54 #define STATE_DO 4 55 #define STATE_DONT 5 56 #define STATE_CLOSE 6 57 58 static struct telnetd_state s; 59 60 #define TELNET_IAC 255 61 #define TELNET_WILL 251 62 #define TELNET_WONT 252 63 #define TELNET_DO 253 64 #define TELNET_DONT 254 65 /*---------------------------------------------------------------------------*/ 66 static char * 67 alloc_line(void) 68 { 69 return memb_alloc(&linemem); 70 } 71 /*---------------------------------------------------------------------------*/ 72 static void 73 dealloc_line(char *line) 74 { 75 memb_free(&linemem, line); 76 } 77 /*---------------------------------------------------------------------------*/ 78 void 79 shell_quit(char *str) 80 { 81 s.state = STATE_CLOSE; 82 } 83 /*---------------------------------------------------------------------------*/ 84 static void 85 sendline(char *line) 86 { 87 static unsigned int i; 88 89 for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) { 90 if(s.lines[i] == NULL) { 91 s.lines[i] = line; 92 break; 93 } 94 } 95 if(i == TELNETD_CONF_NUMLINES) { 96 dealloc_line(line); 97 } 98 } 99 /*---------------------------------------------------------------------------*/ 100 void 101 shell_prompt(char *str) 102 { 103 char *line; 104 line = alloc_line(); 105 if(line != NULL) { 106 strncpy(line, str, TELNETD_CONF_LINELEN); 107 /* petsciiconv_toascii(line, TELNETD_CONF_LINELEN);*/ 108 sendline(line); 109 } 110 } 111 /*---------------------------------------------------------------------------*/ 112 void 113 shell_output(char *str1, char *str2) 114 { 115 static unsigned len; 116 char *line; 117 118 line = alloc_line(); 119 if(line != NULL) { 120 len = strlen(str1); 121 strncpy(line, str1, TELNETD_CONF_LINELEN); 122 if(len < TELNETD_CONF_LINELEN) { 123 strncpy(line + len, str2, TELNETD_CONF_LINELEN - len); 124 } 125 len = strlen(line); 126 if(len < TELNETD_CONF_LINELEN - 2) { 127 line[len] = ISO_cr; 128 line[len+1] = ISO_nl; 129 line[len+2] = 0; 130 } 131 /* petsciiconv_toascii(line, TELNETD_CONF_LINELEN);*/ 132 sendline(line); 133 } 134 } 135 /*---------------------------------------------------------------------------*/ 136 void 137 telnetd_init(void) 138 { 139 uip_listen(HTONS(23)); 140 memb_init(&linemem); 141 shell_init(); 142 } 143 /*---------------------------------------------------------------------------*/ 144 static void 145 acked(void) 146 { 147 static unsigned int i; 148 149 while(s.numsent > 0) { 150 dealloc_line(s.lines[0]); 151 for(i = 1; i < TELNETD_CONF_NUMLINES; ++i) { 152 s.lines[i - 1] = s.lines[i]; 153 } 154 s.lines[TELNETD_CONF_NUMLINES - 1] = NULL; 155 --s.numsent; 156 } 157 } 158 /*---------------------------------------------------------------------------*/ 159 static void 160 senddata(void) 161 { 162 static char *bufptr, *lineptr; 163 static int buflen, linelen; 164 165 bufptr = uip_appdata; 166 buflen = 0; 167 for(s.numsent = 0; s.numsent < TELNETD_CONF_NUMLINES && 168 s.lines[s.numsent] != NULL ; ++s.numsent) { 169 lineptr = s.lines[s.numsent]; 170 linelen = strlen(lineptr); 171 if(linelen > TELNETD_CONF_LINELEN) { 172 linelen = TELNETD_CONF_LINELEN; 173 } 174 if(buflen + linelen < uip_mss()) { 175 memcpy(bufptr, lineptr, linelen); 176 bufptr += linelen; 177 buflen += linelen; 178 } else { 179 break; 180 } 181 } 182 uip_send(uip_appdata, buflen); 183 } 184 /*---------------------------------------------------------------------------*/ 185 static void 186 closed(void) 187 { 188 static unsigned int i; 189 190 for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) { 191 if(s.lines[i] != NULL) { 192 dealloc_line(s.lines[i]); 193 } 194 } 195 } 196 /*---------------------------------------------------------------------------*/ 197 static void 198 get_char(u8_t c) 199 { 200 if(c == ISO_cr) { 201 return; 202 } 203 204 s.buf[(int)s.bufptr] = c; 205 if(s.buf[(int)s.bufptr] == ISO_nl || 206 s.bufptr == sizeof(s.buf) - 1) { 207 if(s.bufptr > 0) { 208 s.buf[(int)s.bufptr] = 0; 209 /* petsciiconv_topetscii(s.buf, TELNETD_CONF_LINELEN);*/ 210 } 211 shell_input(s.buf); 212 s.bufptr = 0; 213 } else { 214 ++s.bufptr; 215 } 216 } 217 /*---------------------------------------------------------------------------*/ 218 static void 219 sendopt(u8_t option, u8_t value) 220 { 221 char *line; 222 line = alloc_line(); 223 if(line != NULL) { 224 line[0] = TELNET_IAC; 225 line[1] = option; 226 line[2] = value; 227 line[3] = 0; 228 sendline(line); 229 } 230 } 231 /*---------------------------------------------------------------------------*/ 232 static void 233 newdata(void) 234 { 235 u16_t len; 236 u8_t c; 237 char *dataptr; 238 239 240 len = uip_datalen(); 241 dataptr = (char *)uip_appdata; 242 243 while(len > 0 && s.bufptr < sizeof(s.buf)) { 244 c = *dataptr; 245 ++dataptr; 246 --len; 247 switch(s.state) { 248 case STATE_IAC: 249 if(c == TELNET_IAC) { 250 get_char(c); 251 s.state = STATE_NORMAL; 252 } else { 253 switch(c) { 254 case TELNET_WILL: 255 s.state = STATE_WILL; 256 break; 257 case TELNET_WONT: 258 s.state = STATE_WONT; 259 break; 260 case TELNET_DO: 261 s.state = STATE_DO; 262 break; 263 case TELNET_DONT: 264 s.state = STATE_DONT; 265 break; 266 default: 267 s.state = STATE_NORMAL; 268 break; 269 } 270 } 271 break; 272 case STATE_WILL: 273 /* Reply with a DONT */ 274 sendopt(TELNET_DONT, c); 275 s.state = STATE_NORMAL; 276 break; 277 278 case STATE_WONT: 279 /* Reply with a DONT */ 280 sendopt(TELNET_DONT, c); 281 s.state = STATE_NORMAL; 282 break; 283 case STATE_DO: 284 /* Reply with a WONT */ 285 sendopt(TELNET_WONT, c); 286 s.state = STATE_NORMAL; 287 break; 288 case STATE_DONT: 289 /* Reply with a WONT */ 290 sendopt(TELNET_WONT, c); 291 s.state = STATE_NORMAL; 292 break; 293 case STATE_NORMAL: 294 if(c == TELNET_IAC) { 295 s.state = STATE_IAC; 296 } else { 297 get_char(c); 298 } 299 break; 300 } 301 302 303 } 304 305 } 306 /*---------------------------------------------------------------------------*/ 307 void 308 telnetd_appcall(void) 309 { 310 static unsigned int i; 311 if(uip_connected()) { 312 /* tcp_markconn(uip_conn, &s);*/ 313 for(i = 0; i < TELNETD_CONF_NUMLINES; ++i) { 314 s.lines[i] = NULL; 315 } 316 s.bufptr = 0; 317 s.state = STATE_NORMAL; 318 319 shell_start(); 320 } 321 322 if(s.state == STATE_CLOSE) { 323 s.state = STATE_NORMAL; 324 uip_close(); 325 return; 326 } 327 328 if(uip_closed() || 329 uip_aborted() || 330 uip_timedout()) { 331 closed(); 332 } 333 334 if(uip_acked()) { 335 acked(); 336 } 337 338 if(uip_newdata()) { 339 newdata(); 340 } 341 342 if(uip_rexmit() || 343 uip_newdata() || 344 uip_acked() || 345 uip_connected() || 346 uip_poll()) { 347 senddata(); 348 } 349 } 350 /*---------------------------------------------------------------------------*/ 351