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