blob: 6531de0e88e86d10ba504e3b5e6ea43835da6054 [file] [log] [blame]
adamdunkelsb9614dc2004-08-09 20:33:51 +00001#include "contiki.h"
2#include "loader.h"
3#include "memb.h"
4#include "ctk-term.h"
5#include "ctk-term-conf.h"
6
7/*-----------------------------------------------------------------------------------*/
8/*
9 * #defines and enums
10 */
11/*-----------------------------------------------------------------------------------*/
12/* Telnet special characters */
13#define TN_NULL 0
14#define TN_BL 7
15#define TN_BS 8
16#define TN_HT 9
17#define TN_LF 10
18#define TN_VT 11
19#define TN_FF 12
20#define TN_CR 13
21
22/* Commands preceeded by TN_IAC */
23#define TN_SE 240
24#define TN_NOP 241
25#define TN_DM 242
26#define TN_BRK 243
27#define TN_IP 244
28#define TN_AO 245
29#define TN_AYT 246
30#define TN_EC 247
31#define TN_EL 248
32#define TN_GA 249
33#define TN_SB 250
34#define TN_WILL 251
35#define TN_WONT 252
36#define TN_DO 253
37#define TN_DONT 254
38#define TN_IAC 255
39
40#define TNO_BIN 0
41#define TNO_ECHO 1
42#define TNO_SGA 3
43#define TNO_NAWS 31
44
45/* Telnet parsing states */
46enum {
47 TNS_IDLE,
48 TNS_IAC,
49 TNS_OPT,
50 TNS_SB,
51 TNS_SBIAC
52};
53
54/* Telnet option negotiation states */
55enum {
56 TNOS_NO,
57 TNOS_WANTNO_EMPTY,
58 TNOS_WANTNO_OPPOSITE,
59 TNOS_WANTYES_EMPTY,
60 TNOS_WANTYES_OPPOSITE,
61 TNOS_YES
62};
63
64/* Telnet session states */
65enum {
66 TTS_FREE, /* Not allocated */
67 TTS_IDLE, /* No data to send and nothing sent */
68 TTS_SEND_TNDATA, /* Sending telnet data */
69 TTS_SEND_APPDATA /* Sending data from upper layers */
70};
71
72/* Number of options supported (we only need ECHO(1) and SGA(3) options) */
73#define TNSM_MAX_OPTIONS 4
74
75/* Max option replies in output queue */
76#define TNQLEN 20
77
78/* Number of option buffer */
79#define OPTION_POOL_SIZE 20
80
81/* Maximum number of telnet sessions */
82#ifdef CTK_TERM_CONF_MAX_TELNET_CLIENTS
83#define NUM_CONNS CTK_TERM_CONF_MAX_TELNET_CLIENTS
84#else
85#define NUM_CONNS 1
86#endif
87
88#ifdef CTK_TERM_CONF_TELNET_PORT
89#define PORT CTK_TERM_CONF_TELNET_PORT
90#else
91#define PORT 23
92#endif
93
94/*-----------------------------------------------------------------------------------*/
95/*
96 * Structures
97 */
98/*-----------------------------------------------------------------------------------*/
99/* Telnet option state structure */
100struct TNOption {
101 unsigned char state;
102 unsigned char wants;
103};
104
105/* Telnet handling state structure */
106struct TNSMState
107{
108 struct TNOption myOpt[TNSM_MAX_OPTIONS];
109 struct TNOption hisOpt[TNSM_MAX_OPTIONS];
110 unsigned char cmd;
111 unsigned char state;
112};
113
114/* Telnet session state */
115struct telnet_state
116{
117 unsigned char state;
118 unsigned char* sendq[TNQLEN];
119 struct TNSMState tnsm;
120 struct ctk_term_state* termstate;
121};
122
123/*-----------------------------------------------------------------------------------*/
124/*
125 * Local variables
126 */
127/*-----------------------------------------------------------------------------------*/
128/*static DISPATCHER_UIPCALL(ctk_termtelnet_appcall, state);*/
129static void ctk_termtelnet_appcall(void *state);
130
131EK_EVENTHANDLER(eventhandler, ev, data);
132EK_PROCESS(p, "CTK telnet server", EK_PRIO_NORMAL,
133 eventhandler, NULL, NULL);
134/*static struct dispatcher_proc p =
135 {DISPATCHER_PROC("CTK telnet server", NULL, NULL,
136 ctk_termtelnet_appcall)};*/
137
138static ek_id_t id = EK_ID_NONE;
139
140/* Option negotiation buffer pool */
141MEMB(telnetbuf, 3, OPTION_POOL_SIZE);
142
143static int i,j;
144static struct telnet_state states[NUM_CONNS];
145
146/*-----------------------------------------------------------------------------------*/
147/*
148 * Send an option reply on a connection
149 */
150/*-----------------------------------------------------------------------------------*/
151static void
152Reply(struct telnet_state* tns, unsigned char cmd, unsigned char opt)
153{
154 unsigned char* buf = (unsigned char*)memb_alloc(&telnetbuf);
155 if (buf != 0) {
156 buf[0]=TN_IAC;
157 buf[1]=cmd;
158 buf[2]=opt;
159 for (i=0; i < TNQLEN; i++) {
160 if (tns->sendq[i] == 0) {
161 tns->sendq[i] = buf;
162 return;
163 }
164 }
165 /* Queue is full. Drop it */
166 memb_free(&telnetbuf, (char*)buf);
167 }
168}
169
170/*-----------------------------------------------------------------------------------*/
171/*
172 * Prepare for enabling one of remote side options.
173 */
174/*-----------------------------------------------------------------------------------*/
175static void
176EnableHisOpt(struct telnet_state* tns, unsigned char opt)
177{
178 switch(tns->tnsm.hisOpt[opt].state) {
179 case TNOS_NO:
180 tns->tnsm.hisOpt[opt].wants = 1;
181 tns->tnsm.hisOpt[opt].state = TNOS_WANTYES_EMPTY;
182 Reply(tns, TN_DO, opt);
183 break;
184 case TNOS_WANTNO_EMPTY:
185 tns->tnsm.hisOpt[opt].state = TNOS_WANTNO_OPPOSITE;
186 break;
187 case TNOS_WANTNO_OPPOSITE:
188 break;
189 case TNOS_WANTYES_EMPTY:
190 tns->tnsm.hisOpt[opt].state = TNOS_YES;
191 break;
192 case TNOS_WANTYES_OPPOSITE:
193 tns->tnsm.hisOpt[opt].state = TNOS_WANTYES_EMPTY;
194 break;
195 case TNOS_YES:
196 break;
197 }
198}
199
200/*-----------------------------------------------------------------------------------*/
201/*
202 * Prepare for enabling one of my options
203 */
204/*-----------------------------------------------------------------------------------*/
205static void
206EnableMyOpt(struct telnet_state* tns, unsigned char opt)
207{
208 if (opt < TNSM_MAX_OPTIONS) {
209 switch(tns->tnsm.myOpt[opt].state) {
210 case TNOS_NO:
211 tns->tnsm.myOpt[opt].wants = 1;
212 tns->tnsm.myOpt[opt].state = TNOS_WANTYES_EMPTY;
213 Reply(tns, TN_WILL, opt);
214 break;
215 case TNOS_WANTNO_EMPTY:
216 tns->tnsm.myOpt[opt].state = TNOS_WANTNO_OPPOSITE;
217 break;
218 case TNOS_WANTNO_OPPOSITE:
219 break;
220 case TNOS_WANTYES_EMPTY:
221 tns->tnsm.myOpt[opt].state = TNOS_YES;
222 break;
223 case TNOS_WANTYES_OPPOSITE:
224 tns->tnsm.myOpt[opt].state = TNOS_WANTYES_EMPTY;
225 break;
226 case TNOS_YES:
227 break;
228 }
229 }
230}
231
232/*-----------------------------------------------------------------------------------*/
233/*
234 * Implementation of option negotiation using the Q-method
235 */
236/*-----------------------------------------------------------------------------------*/
237static void
238HandleCommand(struct telnet_state* tns, unsigned char cmd, unsigned char opt)
239{
240 if (opt < TNSM_MAX_OPTIONS) {
241 /* Handling according to RFC 1143 "Q Method" */
242 switch(cmd) {
243 case TN_WILL:
244 switch(tns->tnsm.hisOpt[opt].state) {
245 case TNOS_NO:
246 if (tns->tnsm.hisOpt[opt].wants) {
247 tns->tnsm.hisOpt[opt].state = TNOS_YES;
248 Reply(tns, TN_DO, opt);
249 }
250 else {
251 Reply(tns, TN_DONT, opt);
252 }
253 break;
254 case TNOS_WANTNO_EMPTY:
255 tns->tnsm.hisOpt[opt].state = TNOS_NO;
256 break;
257 case TNOS_WANTNO_OPPOSITE:
258 tns->tnsm.hisOpt[opt].state = TNOS_YES;
259 break;
260 case TNOS_WANTYES_EMPTY:
261 tns->tnsm.hisOpt[opt].state = TNOS_YES;
262 break;
263 case TNOS_WANTYES_OPPOSITE:
264 tns->tnsm.hisOpt[opt].state = TNOS_WANTNO_EMPTY;
265 Reply(tns, TN_DONT, opt);
266 break;
267 case TNOS_YES:
268 break;
269 }
270 break;
271 case TN_WONT:
272 switch(tns->tnsm.hisOpt[opt].state) {
273 case TNOS_NO:
274 break;
275 case TNOS_WANTNO_EMPTY:
276 case TNOS_WANTYES_EMPTY:
277 case TNOS_WANTYES_OPPOSITE:
278 tns->tnsm.hisOpt[opt].state = TNOS_NO;
279 break;
280 case TNOS_WANTNO_OPPOSITE:
281 tns->tnsm.hisOpt[opt].state = TNOS_WANTYES_EMPTY;
282 Reply(tns, TN_DO, opt);
283 break;
284 case TNOS_YES:
285 tns->tnsm.hisOpt[opt].state = TNOS_NO;
286 Reply(tns, TN_DONT, opt);
287 break;
288 }
289 break;
290 case TN_DO:
291 switch(tns->tnsm.myOpt[opt].state) {
292 case TNOS_NO:
293 if (tns->tnsm.myOpt[opt].wants) {
294 tns->tnsm.myOpt[opt].state = TNOS_YES;
295 Reply(tns, TN_WILL, opt);
296 }
297 else {
298 Reply(tns, TN_WONT, opt);
299 }
300 break;
301 case TNOS_WANTNO_EMPTY:
302 tns->tnsm.myOpt[opt].state = TNOS_NO;
303 break;
304 case TNOS_WANTNO_OPPOSITE:
305 tns->tnsm.myOpt[opt].state = TNOS_YES;
306 break;
307 case TNOS_WANTYES_EMPTY:
308 tns->tnsm.myOpt[opt].state = TNOS_YES;
309 break;
310 case TNOS_WANTYES_OPPOSITE:
311 tns->tnsm.myOpt[opt].state = TNOS_WANTNO_EMPTY;
312 Reply(tns, TN_WONT, opt);
313 break;
314 case TNOS_YES:
315 break;
316 }
317 break;
318 case TN_DONT:
319 switch(tns->tnsm.myOpt[opt].state) {
320 case TNOS_NO:
321 break;
322 case TNOS_WANTNO_EMPTY:
323 case TNOS_WANTYES_EMPTY:
324 case TNOS_WANTYES_OPPOSITE:
325 tns->tnsm.myOpt[opt].state = TNOS_NO;
326 break;
327 case TNOS_WANTNO_OPPOSITE:
328 tns->tnsm.myOpt[opt].state = TNOS_WANTYES_EMPTY;
329 Reply(tns, TN_WILL, opt);
330 break;
331 case TNOS_YES:
332 tns->tnsm.myOpt[opt].state = TNOS_NO;
333 Reply(tns, TN_WONT, opt);
334 break;
335 }
336 break;
337 }
338 }
339 else {
340 switch(cmd) {
341 case TN_WILL:
342 Reply(tns, TN_DONT, opt);
343 break;
344 case TN_WONT:
345 break;
346 case TN_DO:
347 Reply(tns, TN_WONT, opt);
348 break;
349 case TN_DONT:
350 break;
351 }
352 }
353}
354
355/*-----------------------------------------------------------------------------------*/
356/*
357 * Telnet data parsing
358 */
359/*-----------------------------------------------------------------------------------*/
360static unsigned char
361parse_input(struct telnet_state* tns, unsigned char b)
362{
363 unsigned char ret = 0;
364 switch(tns->tnsm.state) {
365 case TNS_IDLE:
366 if (b == TN_IAC) tns->tnsm.state = TNS_IAC;
367 else ret = 1;
368 break;
369 case TNS_IAC:
370 switch(b) {
371 case TN_SE:
372 case TN_NOP:
373 case TN_DM:
374 case TN_BRK:
375 case TN_IP:
376 case TN_AO:
377 case TN_AYT:
378 case TN_EC:
379 case TN_EL:
380 case TN_GA:
381 tns->tnsm.state = TNS_IDLE;
382 break;
383 case TN_SB:
384 tns->tnsm.state = TNS_SB;
385 break;
386 case TN_WILL:
387 case TN_WONT:
388 case TN_DO:
389 case TN_DONT:
390 tns->tnsm.cmd = b;
391 tns->tnsm.state = TNS_OPT;
392 break;
393 case TN_IAC:
394 tns->tnsm.state = TNS_IDLE;
395 ret = 1;
396 break;
397 default:
398 /* Drop unknown IACs */
399 tns->tnsm.state = TNS_IDLE;
400 break;
401 }
402 break;
403 case TNS_OPT:
404 HandleCommand(tns, tns->tnsm.cmd, b);
405 tns->tnsm.state = TNS_IDLE;
406 break;
407 case TNS_SB:
408 if (b == TN_IAC) {
409 tns->tnsm.state = TNS_SBIAC;
410 }
411 break;
412 case TNS_SBIAC:
413 if (b == TN_IAC) {
414 tns->tnsm.state = TNS_SB;
415 }
416 else if (b == TN_SE) {
417 tns->tnsm.state = TNS_IDLE;
418 }
419 else {
420 tns->tnsm.state = TNS_IDLE;
421 }
422 break;
423 }
424 return ret;
425}
426
427/*-----------------------------------------------------------------------------------*/
428/*
429 * Initialize telnet machine
430 */
431/*-----------------------------------------------------------------------------------*/
432static void
433telnet_init(struct telnet_state* tns)
434{
435 int i;
436 for (i = 0; i < TNSM_MAX_OPTIONS; i++) {
437 tns->tnsm.myOpt[i].state = TNOS_NO;
438 tns->tnsm.myOpt[i].wants = 0;
439 tns->tnsm.hisOpt[i].state = TNOS_NO;
440 tns->tnsm.hisOpt[i].wants = 0;
441 }
442 tns->tnsm.state = TNS_IDLE;
443}
444
445
446/*-----------------------------------------------------------------------------------*/
447/*
448 * Allocate a telnet session structure (including terminal state)
449 */
450/*-----------------------------------------------------------------------------------*/
451static struct telnet_state*
452alloc_state()
453{
454 for (i=0; i < NUM_CONNS; i++) {
455 if (states[i].state == TTS_FREE) {
456 states[i].termstate = ctk_term_alloc_state();
457 if (states[i].termstate != NULL) {
458 for (j = 0; j < TNQLEN; j++) {
459 states[i].sendq[j] = 0;
460 }
461 telnet_init(&states[i]);
462 states[i].state = TTS_IDLE;
463 return &(states[i]);
464 }
465 }
466 }
467 return NULL;
468}
469
470/*-----------------------------------------------------------------------------------*/
471/*
472 * Free a telnet session structure (including terminal state)
473 */
474/*-----------------------------------------------------------------------------------*/
475static void
476free_state(struct telnet_state* tns)
477{
478 if (tns != NULL) {
479 ctk_term_dealloc_state(tns->termstate);
480 tns->state = TTS_FREE;
481 }
482}
483
484/*-----------------------------------------------------------------------------------*/
485/*
486 * A packet is successfully sent
487 */
488/*-----------------------------------------------------------------------------------*/
489static void
490acked(struct telnet_state* tns)
491{
492 /* Were we sending a telnet option packet? */
493 if (tns->state == TTS_SEND_TNDATA) {
494 /* Yes, free it and update queue */
495 if (tns->sendq[0] != 0) {
496 memb_free(&telnetbuf, (char*)(tns->sendq[0]));
497 for (i=1; i < TNQLEN; i++) {
498 tns->sendq[i-1] = tns->sendq[i];
499 }
500 tns->sendq[TNQLEN-1] = 0;
501 /* No options left. Go idle */
502 if (tns->sendq[0] == 0) {
503 tns->state = TTS_IDLE;
504 }
505 }
506 }
507 /* Or were we sending application date ? */
508 else if (tns->state == TTS_SEND_APPDATA) {
509 /* Inform application that data is sent successfully */
510 ctk_term_sent(tns->termstate);
511 tns->state = TTS_IDLE;
512 }
513}
514
515/*-----------------------------------------------------------------------------------*/
516/*
517 * Send data on a connections
518 */
519/*-----------------------------------------------------------------------------------*/
520static void
521senddata(struct telnet_state* tns)
522{
523 /* Check if there are any option packets to send */
524 if (tns->state == TTS_IDLE || tns->state == TTS_SEND_TNDATA) {
525 if (tns->sendq[0] != 0) {
526 tns->state = TTS_SEND_TNDATA;
527 uip_send(tns->sendq[0],3);
528 }
529 }
530 /* Check if terminal wants to send any data */
531 if (tns->state == TTS_IDLE || tns->state == TTS_SEND_APPDATA) {
532 u16_t len = ctk_term_send(tns->termstate, (unsigned char*)uip_appdata, (unsigned short)uip_mss());
533 if (len > 0) {
534 tns->state = TTS_SEND_APPDATA;
535 uip_send(uip_appdata, len);
536 }
537 }
538}
539
540/*-----------------------------------------------------------------------------------*/
541/*
542 * uIP callback
543 */
544/*-----------------------------------------------------------------------------------*/
545static void
546ctk_termtelnet_appcall(void *state)
547{
548 struct telnet_state *tns;
549
550 tns = (struct telnet_state*)(state);
551
552 if(uip_connected()) {
553 if(tns == NULL) {
554 tns = alloc_state();
555 if(tns == NULL) {
556 uip_close();
557 return;
558 }
559 tcp_markconn(uip_conn, (void *)tns);
560 }
561 /* Try to negotiate some options */
562 EnableHisOpt(tns, TNO_SGA);
563 EnableMyOpt(tns,TNO_SGA);
564 EnableMyOpt(tns,TNO_ECHO);
565 /* Request update of screen */
566 ctk_term_redraw(tns->termstate);
567 senddata(tns);
568 } else if(uip_closed() || uip_aborted()) {
569 free_state(tns);
570 return;
571 }
572
573 if (uip_acked()) {
574 acked(tns);
575 }
576
577 if (uip_newdata()) {
578 for(j = 0; j < uip_datalen(); j++) {
579 if (parse_input(tns, uip_appdata[j])) {
580 /* Pass it uppwards */
581 ctk_term_input(tns->termstate, uip_appdata[j]);
582 }
583 }
584 }
585
586 if(uip_rexmit() ||
587 uip_newdata() ||
588 uip_acked()) {
589 senddata(tns);
590 } else if(uip_poll()) {
591 if (tns->state == TTS_IDLE) {
592 senddata(tns);
593 }
594 }
595}
596/*-----------------------------------------------------------------------------------*/
597/*
598 * Init function
599 */
600/*-----------------------------------------------------------------------------------*/
601LOADER_INIT_FUNC(ctk_termtelnet_init, arg)
602{
603 arg_free(arg);
604 if(id == EK_ID_NONE) {
605 memb_init(&telnetbuf);
606 for (i=0; i < NUM_CONNS; i++) {
607 states[i].state = TTS_FREE;
608 }
609 id = ek_start(&p);
610 }
611}
612/*-----------------------------------------------------------------------------------*/
613EK_EVENTHANDLER(eventhandler, ev, data)
614{
615 if(ev == EK_EVENT_INIT) {
616 tcp_listen(HTONS(PORT));
617 } else if(ev == tcpip_event) {
618 ctk_termtelnet_appcall(data);
619 }
620}