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 *
alloc_line(void)67 alloc_line(void)
68 {
69 return memb_alloc(&linemem);
70 }
71 /*---------------------------------------------------------------------------*/
72 static void
dealloc_line(char * line)73 dealloc_line(char *line)
74 {
75 memb_free(&linemem, line);
76 }
77 /*---------------------------------------------------------------------------*/
78 void
shell_quit(char * str)79 shell_quit(char *str)
80 {
81 s.state = STATE_CLOSE;
82 }
83 /*---------------------------------------------------------------------------*/
84 static void
sendline(char * line)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
shell_prompt(char * str)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
shell_output(char * str1,char * str2)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
telnetd_init(void)137 telnetd_init(void)
138 {
139 uip_listen(HTONS(23));
140 memb_init(&linemem);
141 shell_init();
142 }
143 /*---------------------------------------------------------------------------*/
144 static void
acked(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
senddata(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
closed(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
get_char(u8_t c)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
sendopt(u8_t option,u8_t value)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
newdata(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
telnetd_appcall(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