/* OpenEZ\serialio\telnet_get.c Copyright (C) 2003 Robert Laughlin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Contact Information: Robert Laughlin, Digital Systems, PO Box 158 Walkersville, MD 21791 address@hidden */ #define DEBUG 1 /**************************************************************** * telnet_get.c ****************************************************************/ #include "OpenEZ\include\stream.h" #include "OpenEZ\include\cfifo.h" #include "OpenEZ\include\OpenEZ.h" extern struct TCB *active_tcb; static void WILL(int i, struct NET_FILE *stream); static void DO(int i, struct NET_FILE *stream); /********************************** * telnet commands * **********************************/ #define tSE 240 // End of subnegotiation parameters. #define tNOP 241 // No operation. #define tDataMark 242 // The data stream portion of a Synch. This should always be accompanied by a TCP Urgent notification. #define tBreak 243 // NVT character BRK. #define tINTER 244 // Interrupt Process The function IP. #define tAbort 245 // Abort output The function AO. #define tSB 250 // Indicates that what follows is subnegotiation of the indicated option. #define tWILL 251 // Indicates the desire to begin performing, or confirmation that you are now performing, the indicated option. #define tWONT 252 // Indicates the refusal to perform, or continue performing, the indicated option. #define tDO 253 // Indicates the request that the other party perform, or confirmation that you are expecting the other party to perform, the indicated option. #define tDONT 254 // Indicates the demand that the other party stop performing, or confirmation that you are no longer expecting the other party to perform, the indicated option. #define tIAC 255 // Data Byte 255. /********************************** * telnet options * **********************************/ #define ECHO 1 // RFC 857 #define SUPPRESS_GO_AHEAD 3 // Suppress Go Ahead. RFC 858 #define tEOF 236 #define SUSP 237 #define ABORT 238 #define TERMINAL_TYPE 24 // RFC 1091 #define LINEMODE 34 #define MODE 1 #define EDIT 1 #define TRAPSIG 2 #define MODE_ACK 4 #define SOFT_TAB 8 #define LIT_ECHO 16 #define FORWARDMASK 2 #define SLC 3 #define SLC_SYNCH 1 #define SLC_BRK 2 #define SLC_IP 3 #define SLC_AO 4 #define SLC_AYT 5 #define SLC_EOR 6 #define SLC_ABORT 7 #define SLC_EOF 8 #define SLC_SUSP 9 #define SLC_EC 10 #define SLC_EL 11 #define SLC_EW 12 #define SLC_RP 13 #define SLC_LNEXT 14 #define SLC_XON 15 #define SLC_XOFF 16 #define SLC_FORW1 17 #define SLC_FORW2 18 #define SLC_MCL 19 #define SLC_MCR 20 #define SLC_MCWL 21 #define SLC_MCWR 22 #define SLC_MCBOL 23 #define SLC_MCEOL 24 #define SLC_INSRT 25 #define SLC_OVER 26 #define SLC_ECR 27 #define SLC_EWR 28 #define SLC_EBOL 29 #define SLC_EEOL 30 #define SLC_DEFAULT 3 #define SLC_VALUE 2 #define SLC_CANTCHANGE 1 #define SLC_NOSUPPORT 0 #define SLC_LEVELBITS 3 #define SLC_ACK 128 #define SLC_FLUSHIN 64 #define SLC_FLUSHOUT 32 int telnet_get(struct NET_FILE *stream) { // get the next char, return -1 if none available int i; if( cfifo_empty( stream->fifo ) ) return -1; i = cfifo_get(stream->fifo); // get next char debug( 8, ("telnet_get, char %d 0x%02X\n", i, i)); switch( stream->telnet_state ) { case 0: // not in a sequence if( i != tIAC ) return i; stream->telnet_state = 1; return -1; case 1: // IAC has been received switch( i ) { case tWILL: stream->telnet_state = 2; // IAC + WILL return -1; case tDO: // DO stream->telnet_state = 3; // IAC + DO return -1; case tDONT: // DONT stream->telnet_state = 7; // IAC + DONT return -1; case tSB: // SB begin sub-negotiation stream->telnet_state = 4; // IAC + SB return -1; } debug( 4, ("telnet_get, unrecognized sequence IAC 0x%02X\n", i)); stream->telnet_state = 0; return -1; case 2: // IAC + WILL has been received switch(i) { case LINEMODE: debug( 4, ("telnet_get, received: IAC WILL LINEMODE, responded with sub-negoiation\n")); fputc(tIAC, (struct FILE *) stream); fputc(tDO, (struct FILE *) stream); fputc(LINEMODE, (struct FILE *) stream); fflush( stream ); fputc(tIAC, (struct FILE *) stream); fputc(tSB, (struct FILE *) stream); fputc(LINEMODE, (struct FILE *) stream); fputc(MODE, (struct FILE *) stream); fputc(EDIT, (struct FILE *) stream); fputc(tIAC, (struct FILE *) stream); fputc(tSE, (struct FILE *) stream); fflush( stream ); fputc(tIAC, (struct FILE *) stream); fputc(tSB, (struct FILE *) stream); fputc(LINEMODE, (struct FILE *) stream); fputc(tDO, (struct FILE *) stream); fputc(FORWARDMASK, (struct FILE *) stream); fputc(0, (struct FILE *) stream); fputc(4, (struct FILE *) stream); fputc(tIAC, (struct FILE *) stream); fputc(tSE, (struct FILE *) stream); fflush( stream ); stream->telnet_state = 0; return -1; case ECHO: debug( 4, ("telnet_get, received: IAC WILL ECHO, responded DO\n")); DO(i, stream); active_tcb->stdin->ioctl &= ~ O_ECHO; // turn off local echo break; case SUPPRESS_GO_AHEAD: // suppress go ahead debug( 4, ("telnet_get, received: IAC WILL SUPPRESS_GO_AHEAD, responded DO\n")); DO(i, stream); break; default: debug( 4, ("telnet_get, received: IAC WILL %d (0x%02X), responded with DONT\n", i, i)); fputc(tIAC, (struct FILE *) stream); fputc(tDONT, (struct FILE *) stream); fputc(i, (struct FILE *) stream); stream->telnet_state = 0; return -1; } case 3: // IAC + DO has been received switch(i) { case SUPPRESS_GO_AHEAD: // suppress go ahead debug( 4, ("telnet_get, received: IAC DO SUPPRESS_GO_AHEAD, responded WILL\n")); WILL(i, stream); break; case TERMINAL_TYPE: debug( 4, ("telnet_get, received: IAC DO TERMINAL_TYPE, responded WILL\n")); WILL(i, stream); break; default: debug( 4, ("telnet_get, received: IAC DO %d (0x%02X), responded WONT\n", i, i)); fputc(tIAC, (struct FILE *) stream); fputc(tWONT, (struct FILE *) stream); fputc(i, (struct FILE *) stream); fflush( stream ); } stream->telnet_state = 0; return -1; case 4: // IAC + SB has been received debug( 4, ("telnet_get, received: IAC SB %d 0x%02X", i, i)); switch(i) { case TERMINAL_TYPE: stream->telnet_state = 6; break; default: stream->telnet_state = 5; break; } stream->telnet_substate = 0; return -1; case 5: // IAC + SB + unknown debug( 4, (" %d x%02X",i, i)); switch( stream->telnet_substate ) { case 0: // waiting for tIAC if( i == tIAC ) stream->telnet_substate = 1; return -1; case 1: // waiting for tIAC if( i == tSE ) { debug( 4, ("\n")); stream->telnet_state = 0; } else stream->telnet_substate = 0; return -1; } case 6: // IAC + SB + TERMINAL_TYPE debug( 4, (" %d x%02X",i, i)); switch( stream->telnet_substate ) { case 0: // waiting for SEND (1) if( i == 1 ) stream->telnet_substate = 1; else { stream->telnet_state = 5; // switch to unknown case stream->telnet_substate = 0; } return -1; case 1: // waiting for IAC if( i == tIAC ) stream->telnet_substate = 2; else { stream->telnet_state = 5; // switch to unknown case stream->telnet_substate = 0; } return -1; case 2: // waiting for SE if( i != tSE ) { stream->telnet_state = 5; // switch to unknown case stream->telnet_substate = 0; return -1; } debug( 4, ("\n")); debug( 4, ("telnet_get, responded: IAC SB TERMINAL_TYPE IS VT100 IAC SE\n")); fputc(tIAC, (struct FILE*) stream); fputc(tSB, (struct FILE*) stream); fputc(TERMINAL_TYPE, (struct FILE*) stream); fputc(0, (struct FILE*) stream); // IS fputc('V', (struct FILE*) stream); fputc('T', (struct FILE*) stream); fputc('1', (struct FILE*) stream); fputc('0', (struct FILE*) stream); fputc('0', (struct FILE*) stream); fputc(tIAC, (struct FILE*) stream); fputc(tSE, (struct FILE*) stream); fflush( stream ); stream->telnet_state = 0; return -1; } case 7: // IAC + DONT has been received switch(i) { default: debug( 4, ("telnet_get, received: IAC DONT %d (0x%02X), responded WONT\n", i, i)); fputc(tIAC, (struct FILE *) stream); fputc(tWONT, (struct FILE *) stream); fputc(i, (struct FILE *) stream); fflush( stream ); } stream->telnet_state = 0; return -1; } // switch( stream->telnet_state ) return -1; } static void WILL(int i, struct NET_FILE *stream) { fputc(tIAC, (struct FILE*) stream); fputc(tWILL, (struct FILE*) stream); fputc(i, (struct FILE*) stream); fflush( stream ); } static void DO(int i, struct NET_FILE *stream) { fputc(tIAC, (struct FILE*) stream); fputc(tDO, (struct FILE*) stream); fputc(i, (struct FILE*) stream); fflush( stream ); }