balbekova пре 6 година
родитељ
комит
edfb336c4c
2 измењених фајлова са 423 додато и 219 уклоњено
  1. 404 217
      modules/Telnet_Server/telnet_server.c
  2. 19 2
      modules/Telnet_Server/telnet_server.h

+ 404 - 217
modules/Telnet_Server/telnet_server.c

@@ -28,17 +28,74 @@
 #include "web_params_api.h"
 
 
+#define ISO_nl       0x0a
+#define ISO_cr       0x0d
+
+//
+// States
+//
+
+#define STATE_NORMAL 0
+#define STATE_IAC    1
+#define STATE_OPT    2
+#define STATE_SB     3
+#define STATE_OPTDAT 4
+#define STATE_SE     5
+#define STATE_CLOSE	 6
+
+//
+// Special telnet characters
+//
+
+#define TELNET_SE    240   // End of subnegotiation parameters
+#define TELNET_NOP   241   // No operation
+#define TELNET_MARK  242   // Data mark
+#define TELNET_BRK   243   // Break
+#define TELNET_IP    244   // Interrupt process
+#define TELNET_AO    245   // Abort output
+#define TELNET_AYT   246   // Are you there
+#define TELNET_EC    247   // Erase character
+#define TELNET_EL    248   // Erase line
+#define TELNET_GA    249   // Go ahead
+#define TELNET_SB    250   // Start of subnegotiation parameters
+#define TELNET_WILL  251   // Will option code
+#define TELNET_WONT  252   // Won't option code
+#define TELNET_DO    253   // Do option code
+#define TELNET_DONT  254   // Don't option code
+#define TELNET_IAC   255   // Interpret as command
+
+//
+// Telnet options
+//
+#define TELOPT_TRANSMIT_BINARY      0  // Binary Transmission (RFC856)
+#define TELOPT_ECHO                 1  // Echo (RFC857)
+#define TELOPT_SUPPRESS_GO_AHEAD    3  // Suppress Go Ahead (RFC858)
+#define TELOPT_STATUS               5  // Status (RFC859)
+#define TELOPT_TIMING_MARK          6  // Timing Mark (RFC860)
+#define TELOPT_NAOCRD              10  // Output Carriage-Return Disposition (RFC652)
+#define TELOPT_NAOHTS              11  // Output Horizontal Tab Stops (RFC653)
+#define TELOPT_NAOHTD              12  // Output Horizontal Tab Stop Disposition (RFC654)
+#define TELOPT_NAOFFD              13  // Output Formfeed Disposition (RFC655)
+#define TELOPT_NAOVTS              14  // Output Vertical Tabstops (RFC656)
+#define TELOPT_NAOVTD              15  // Output Vertical Tab Disposition (RFC657)
+#define TELOPT_NAOLFD              16  // Output Linefeed Disposition (RFC658)
+#define TELOPT_EXTEND_ASCII        17  // Extended ASCII (RFC698)
+#define TELOPT_TERMINAL_TYPE       24  // Terminal Type (RFC1091)
+#define TELOPT_NAWS                31  // Negotiate About Window Size (RFC1073)
+#define TELOPT_TERMINAL_SPEED      32  // Terminal Speed (RFC1079)
+#define TELOPT_TOGGLE_FLOW_CONTROL 33  // Remote Flow Control (RFC1372)
+#define TELOPT_LINEMODE            34  // Linemode (RFC1184)
+#define TELOPT_AUTHENTICATION      37  // Authentication (RFC1416)
+
 
-/* Dimensions the buffer into which input characters are placed. */
-#define cmdMAX_INPUT_SIZE	144
 /* Repeat Login timeout, 1 seconds */
 #define REPEAT_SENSOR_INFO_TIME		configTICK_RATE_HZ*1*1
 
 /* Set option to drop old connection if the new one is accepted */
 #define TCP_DROP_PREV_CONNECTION    0
 
-static portBASE_TYPE FreeRTOS_CLIAuthProcess( const int8_t * const pcCommandInput, int8_t * pcWriteBuffer, uint8_t num_conn  );
-static portBASE_TYPE FreeRTOS_ChangePWDProcess( const int8_t * const pcCommandInput, int8_t * pcWriteBuffer, uint8_t num_conn  );
+static portBASE_TYPE FreeRTOS_CLIAuthProcess( int8_t * pcWriteBuffer, telnetd_state_t *s  );
+static portBASE_TYPE FreeRTOS_ChangePWDProcess( int8_t * pcWriteBuffer, telnetd_state_t *s  );
 void SensorInfoTimerCallback(TimerHandle_t pxTimer);
 
 TimerHandle_t RepeatSensorInfoTimer;
@@ -47,9 +104,8 @@ state_telnet_server_t telnetState = TELNET_AUTH;
 uint8_t id_change_pwd = 0;
 user_level_t telnet_code_auth = USER;
 
-auth_telnet_server_t auth_tlnt_srvr_param[NUMBER_TELNET_CONNECT];
+telnetd_state_t auth_tlnt_srvr_param[NUMBER_TELNET_CONNECT];
 
-static int32_t lClientFd;
 static int32_t lSocket;
 static int8_t *pcOutputString;
 static bool flagTelnetChange = false;
@@ -61,11 +117,262 @@ static struct sockaddr_in sa;
 extern bool white_list_check(uint32_t check_remote_addr);
 #endif
 
+const int8_t * const pcWarningMessage = ( const int8_t * ) "Количество соединенений превышено. Данное соединение будет закрыто\r\n";
+#ifdef HARDWARE_BT6708
+const int8_t * const pcWelcomeMessage = ( const int8_t * ) "BT6708 command server - connection accepted.\r\nlogin:";
+#else
+const int8_t * const pcWelcomeMessage = ( const int8_t * ) "BT6706 command server - connection accepted.\r\nlogin:";
+#endif
+static const int8_t * const pcEndOfCommandOutputString = ( int8_t * ) "\r\n[Нажмите клавишу ENTER для повторного выполнения предыдущей команды]\r\n>";
+
 /**
   * @brief  Общая структура настроек
   */
 extern SETTINGS_t sSettings;
 
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Close a telnet session.
+ *
+ * This function can be called from a telnet command in order to close
+ * the connection.
+ *
+ * \param s The connection which is to be closed.
+ *
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+telnetd_close(telnetd_state_t *s)
+{
+  s->state = STATE_CLOSE;
+}
+
+static void telnetd_input(telnetd_state_t *s)
+{
+	portBASE_TYPE xReturned;
+
+	switch(s->telnetState){
+		case TELNET_AUTH:
+		case TELNET_AUTH_PASSW:
+			if(FreeRTOS_CLIAuthProcess(pcOutputString, s)){
+				send( s->num_connect, pcOutputString, strlen( ( const char * ) pcOutputString ), 0 );
+				memset( s->buf, 0x00, cmdMAX_INPUT_SIZE );
+			}
+			else{
+				s->state = STATE_CLOSE;
+			}
+			break;
+		case TELNET_CMD:
+			/* The input string has been terminated.  Was the
+			input a quit command? */
+			if( strcmp( "quit", ( const char * ) s->buf ) == 0 )
+			{
+				s->state = STATE_CLOSE;
+			}
+			else
+			{
+				/* The input string was not a quit command.
+				Pass the string to the command interpreter. */
+
+				/* See if the command is empty, indicating that the last command is
+				to be executed again. */
+				if( s->bufptr == 0 )
+				{
+					strcpy( s->buf, s->prev_cmd );
+				}
+
+				/* Transmit a line separator, just to make the
+				output easier to read. */
+				lwip_send( s->num_connect, "\r\n", strlen( "\r\n" ), 0 );
+
+				do
+				{
+					/* Ensure there is not a string lingering in
+					the output buffer. */
+					pcOutputString[ 0 ] = 0x00;
+					xReturned = FreeRTOS_CLIProcessCommand( s->buf, pcOutputString, configCOMMAND_INT_MAX_OUTPUT_SIZE );
+					s->telnetState = telnetState;
+					send( s->num_connect, pcOutputString, strlen( ( const char * ) pcOutputString ), 0 );
+
+				} while( xReturned != pdFALSE );
+
+				if( strcmp( "sensor info", ( const char * ) s->buf ) == 0 ){
+					strcpy( s->prev_cmd, s->buf );
+					memset( s->buf, 0x00, cmdMAX_INPUT_SIZE );
+					xTimerStart(RepeatSensorInfoTimer, 0);
+				}
+				else{
+
+					/* All the strings generated by the input
+					command have been sent.  Clear the input
+					string ready to receive the next command.
+					Remember the command that was just processed
+					first in case it is to be processed again. */
+					strcpy( s->prev_cmd, s->buf );
+					memset( s->buf, 0x00, cmdMAX_INPUT_SIZE );
+					if(s->telnetState != TELNET_CHANGE_PWD)
+						send( s->num_connect, pcEndOfCommandOutputString, strlen( ( const char * ) pcEndOfCommandOutputString ), 0 );
+				}
+			}
+			break;
+		case TELNET_CHANGE_PWD:
+		case TELNET_CHANGE_PWD_ACK:
+			FreeRTOS_ChangePWDProcess(pcOutputString, s);
+			send( s->num_connect, pcOutputString, strlen( ( const char * ) pcOutputString ), 0 );
+			memset( s->buf, 0x00, cmdMAX_INPUT_SIZE );
+			break;
+
+	}
+}
+
+/*-----------------------------------------------------------------------------------*/
+static void getchar(telnetd_state_t *s)
+{
+  if(s->buf[s->bufptr] == ISO_nl ||
+	s->buf[s->bufptr] == 0) {
+	s->bufptr = 0;
+    return;
+  }
+
+  if(s->buf[s->bufptr] == ISO_cr ||
+     s->bufptr == sizeof(s->buf) - 1) {
+    if(s->bufptr > 0) {
+      s->buf[s->bufptr] = 0;
+    }
+    telnetd_input(s);
+    s->bufptr = 0;
+  } else if( s->buf[s->bufptr] == '\b' || s->buf[s->bufptr] == 0x7f)
+	{
+		/* Backspace was pressed.  Erase the last
+		character in the string - if any. */
+	  	s->buf[s->bufptr] = '\0';
+		if( s->bufptr > 0 )
+		{
+			s->bufptr--;
+			s->buf[s->bufptr] = '\0';
+		}
+	}
+  else {
+    ++s->bufptr;
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+static void sendopt(telnetd_state_t *s, u8_t code, u8_t option)
+{
+	unsigned char buf[3];
+	buf[0] = TELNET_IAC;
+	buf[1] = code;
+	buf[2] = option;
+    send( s->num_connect, buf, 3, 0 );
+}
+
+void parseopt(telnetd_state_t *ts, uint8_t code, uint8_t option)
+{
+
+  switch (option) {
+    case TELOPT_ECHO:
+    case TELOPT_SUPPRESS_GO_AHEAD:
+    case TELOPT_LINEMODE:
+    case TELOPT_NAWS:
+      break;
+
+    case TELOPT_TIMING_MARK:
+
+    	xTimerStop(RepeatSensorInfoTimer, 0);
+		sendopt(ts, TELNET_WILL, TELOPT_TIMING_MARK);
+		sendopt(ts, TELNET_MARK, 0);
+		if(ts->telnetState != TELNET_CHANGE_PWD && ts->telnetState != TELNET_CHANGE_PWD_ACK)
+			send( ts->num_connect, pcEndOfCommandOutputString, strlen( ( const char * ) pcEndOfCommandOutputString ), 0 );
+    	break;
+
+    default:
+      if (code == TELNET_WILL || code == TELNET_WONT) {
+        sendopt(ts, TELNET_DONT, option);
+      } else {
+        sendopt(ts, TELNET_WONT, option);
+      }
+      break;
+  }
+}
+
+static void parseoptdat(telnetd_state_t *ts, int option, unsigned char *data, uint8_t len) {
+
+  switch (option) {
+    case TELOPT_NAWS:
+      break;
+
+    case TELOPT_TERMINAL_SPEED:
+      break;
+
+    case TELOPT_TERMINAL_TYPE:
+      break;
+  }
+}
+
+/*-----------------------------------------------------------------------------------*/
+static void newdata(telnetd_state_t *s)
+{
+	char c;
+
+    c = s->buf[s->bufptr];
+    switch(s->state) {
+    case STATE_IAC:
+    	switch (c) {
+		  case TELNET_IAC:
+			s->state = STATE_NORMAL;
+			break;
+
+		  case TELNET_WILL:
+		  case TELNET_WONT:
+		  case TELNET_DO:
+		  case TELNET_DONT:
+			s->code = c;
+			s->state = STATE_OPT;
+			break;
+
+		  case TELNET_SB:
+			s->state = STATE_SB;
+			break;
+
+		  default:
+			s->state = STATE_NORMAL;
+			break;
+		}
+      break;
+	case STATE_OPT:
+		parseopt(s, s->code, c);
+		s->state = STATE_NORMAL;
+		break;
+
+	case STATE_SB:
+		s->code = c;
+		s->optlen = 0;
+		s->state = STATE_OPTDAT;
+		break;
+
+	case STATE_OPTDAT:
+		if (c == TELNET_IAC) {
+		  s->state = STATE_SE;
+		} else if (s->optlen < sizeof(s->optdata)) {
+		  s->optdata[s->optlen++] = c;
+		}
+		break;
+
+	case STATE_SE:
+		if (c == TELNET_SE) parseoptdat(s, s->code, s->optdata, s->optlen);
+		s->state = STATE_NORMAL;
+		break;
+    case STATE_NORMAL:
+      if(c == TELNET_IAC) {
+    	  s->state = STATE_IAC;
+      } else {
+    	  getchar(s);
+      }
+      break;
+    }
+
+}
+
 /*-----------------------------------------------------------*/
 
 /* Stop server */
@@ -135,20 +442,9 @@ void vBasicSocketsCommandInterpreterTask( void *pvParameters )
 	int32_t lBytes, lAddrLen = sizeof( struct sockaddr_in );
 	struct sockaddr_in sLocalAddr;
 	struct sockaddr_in client_addr;
-	const int8_t * const pcWarningMessage = ( const int8_t * ) "Количество соединенений превышено. Данное соединение будет закрыто\r\n";
-#ifdef HARDWARE_BT6708
-	const int8_t * const pcWelcomeMessage = ( const int8_t * ) "BT6708 command server - connection accepted.\r\nlogin:";
-#else
-	const int8_t * const pcWelcomeMessage = ( const int8_t * ) "BT6706 command server - connection accepted.\r\nlogin:";
-#endif
-	static const int8_t * const pcEndOfCommandOutputString = ( int8_t * ) "\r\n[Нажмите клавишу ENTER для повторного выполнения предыдущей команды]\r\n>";
-	int8_t cInChar, cInputIndex;
-	static int8_t cInputString[ cmdMAX_INPUT_SIZE ] = { 0 }, cLastInputString[ cmdMAX_INPUT_SIZE ] = { 0 };
-	portBASE_TYPE xReturned;
 	int new_sd;
     int desc_ready, rc;
     struct timeval timeout;
-    bool close_conn;
     uint16_t port;
     bool enabled;
     bool firstrun = true;
@@ -276,19 +572,32 @@ void vBasicSocketsCommandInterpreterTask( void *pvParameters )
 #ifdef HARDWARE_BT6708
 						lwip_getpeername(new_sd, &sa_temp, &len);
 #endif
-						//recv( new_sd, cInputString, 27, 0 );
-						recv( new_sd, cInputString, 1, 0 );
+					//	recv( new_sd, &auth_tlnt_srvr_param[cur_cnt].buf, 27, 0 );
+						// Send initial options
 						if(cnt_conn < NUMBER_TELNET_CONNECT){
 							for(uint8_t k = 0; k < NUMBER_TELNET_CONNECT; k ++){
 								if(auth_tlnt_srvr_param[k].active_conn == false){
 									auth_tlnt_srvr_param[k].active_conn = true;
 									auth_tlnt_srvr_param[k].num_connect = new_sd;
 									auth_tlnt_srvr_param[k].telnetState = TELNET_AUTH;
+									auth_tlnt_srvr_param[k].state = STATE_NORMAL;
 #ifdef HARDWARE_BT6708
 									auth_tlnt_srvr_param[k].flagWhiteListTelnet = white_list_check(sa_temp.sin_addr.s_addr);
 #elif HARDWARE_BT6706
 									auth_tlnt_srvr_param[k].flagWhiteListTelnet = true;
 #endif
+									while(recv( new_sd, &auth_tlnt_srvr_param[k].buf[auth_tlnt_srvr_param[k].bufptr], 1,  MSG_DONTWAIT ) > 0){
+										newdata(&auth_tlnt_srvr_param[k]);
+										vTaskDelay(5);
+									}
+									sendopt(&auth_tlnt_srvr_param[k], TELNET_WILL, TELOPT_SUPPRESS_GO_AHEAD);
+									sendopt(&auth_tlnt_srvr_param[k], TELNET_DO, TELOPT_ECHO);
+									sendopt(&auth_tlnt_srvr_param[k], TELNET_DO, TELOPT_LINEMODE);
+									vTaskDelay(50);
+									while(recv( new_sd, &auth_tlnt_srvr_param[k].buf[auth_tlnt_srvr_param[k].bufptr], 1,  MSG_DONTWAIT ) > 0){
+										newdata(&auth_tlnt_srvr_param[k]);
+										vTaskDelay(5);
+									}
 									send( new_sd, pcWelcomeMessage, strlen( ( const char * ) pcWelcomeMessage ), 0 );
 									break;
 								}
@@ -304,8 +613,6 @@ void vBasicSocketsCommandInterpreterTask( void *pvParameters )
 							}
 						}
 
-						cInputIndex = 0;
-						memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
 #if TCP_DROP_PREV_CONNECTION
                     /* Close previous active connection */
                     if (active_sd != -1 && active_sd != new_sd) {
@@ -332,7 +639,6 @@ void vBasicSocketsCommandInterpreterTask( void *pvParameters )
 				/* existing connection must be readable             */
 				else {
 					DBG printf("  Descriptor %d is readable\n", i);
-					close_conn = false;
 
 					for(cur_cnt = 0; cur_cnt < NUMBER_TELNET_CONNECT; cur_cnt ++){
 						if(auth_tlnt_srvr_param[cur_cnt].num_connect == i){
@@ -356,147 +662,15 @@ void vBasicSocketsCommandInterpreterTask( void *pvParameters )
 					/* recv fails with EWOULDBLOCK.  If any other */
 					/* failure occurs, we will close the          */
 					/* connection.                                */
-					if ((lBytes = recv(i, &cInChar, sizeof( cInChar ), 0 )) > 0) {
-
-						if( lBytes > 0L )
-						{
-							if( cInChar == '\n' )
-							{
-								switch(auth_tlnt_srvr_param[cur_cnt].telnetState){
-								case TELNET_AUTH:
-									if(FreeRTOS_CLIAuthProcess(cInputString, pcOutputString, cur_cnt)){
-										send( i, pcOutputString, strlen( ( const char * ) pcOutputString ), 0 );
-										cInputIndex = 0;
-										memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
-									}
-									else{
-										/* Set lBytes to 0 to close the connection. */
-										lBytes = 0L;
-									}
-									break;
-								case TELNET_CMD:
-									/* The input string has been terminated.  Was the
-									input a quit command? */
-									if( strcmp( "quit", ( const char * ) cInputString ) == 0 )
-									{
-										/* Set lBytes to 0 to close the connection. */
-										lBytes = 0L;
-									}
-									else
-									{
-										/* The input string was not a quit command.
-										Pass the string to the command interpreter. */
-
-										/* See if the command is empty, indicating that the last command is
-										to be executed again. */
-										if( cInputIndex == 0 )
-										{
-											strcpy( ( char * ) cInputString, ( char * ) cLastInputString );
-										}
-
-										/* Transmit a line separator, just to make the
-										output easier to read. */
-										lwip_send( i, "\r\n", strlen( "\r\n" ), 0 );
-
-										do
-										{
-											/* Ensure there is not a string lingering in
-											the output buffer. */
-											pcOutputString[ 0 ] = 0x00;
-											xReturned = FreeRTOS_CLIProcessCommand( cInputString, pcOutputString, configCOMMAND_INT_MAX_OUTPUT_SIZE );
-											auth_tlnt_srvr_param[cur_cnt].telnetState = telnetState;
-											send( i, pcOutputString, strlen( ( const char * ) pcOutputString ), 0 );
-
-										} while( xReturned != pdFALSE );
-
-										if( strcmp( "sensor info", ( const char * ) cInputString ) == 0 ){
-											strcpy( ( char * ) cLastInputString, ( char * ) cInputString );
-											cInputIndex = 0;
-											memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
-											lClientFd = i;
-											xTimerStart(RepeatSensorInfoTimer, 0);
-										}
-										else{
-
-											/* All the strings generated by the input
-											command have been sent.  Clear the input
-											string ready to receive the next command.
-											Remember the command that was just processed
-											first in case it is to be processed again. */
-											strcpy( ( char * ) cLastInputString, ( char * ) cInputString );
-											cInputIndex = 0;
-											memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
-											if(auth_tlnt_srvr_param[cur_cnt].telnetState != TELNET_CHANGE_PWD)
-												send( i, pcEndOfCommandOutputString, strlen( ( const char * ) pcEndOfCommandOutputString ), 0 );
-										}
-									}
-									break;
-								case TELNET_CHANGE_PWD:
-									FreeRTOS_ChangePWDProcess(cInputString, pcOutputString, cur_cnt);
-									send( i, pcOutputString, strlen( ( const char * ) pcOutputString ), 0 );
-									cInputIndex = 0;
-									memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
-									break;
+					if ((lBytes = recv(i, &auth_tlnt_srvr_param[cur_cnt].buf[auth_tlnt_srvr_param[cur_cnt].bufptr], 1, 0 )) > 0) {
 
-								}
-
-							}
-							else
-							{
-								if( cInChar == '\r' )
-								{
-									/* Ignore the character. */
-								}
-								else if( cInChar == '\b' )
-								{
-									/* Backspace was pressed.  Erase the last
-									character in the string - if any. */
-									if( cInputIndex > 0 )
-									{
-										cInputIndex--;
-										cInputString[ cInputIndex ] = '\0';
-									}
-								}
-								else if( cInChar == '\t' ){
-									/*FreeRTOS_CLICompleteCMDCommand(cInputString, pcOutputString);
-									strcpy((char *)cInputString, (char *)pcOutputString);
-									send( i, pcOutputString, strlen( ( const char * ) pcOutputString ), 0 );*/
-								}
-								else
-								{
-									/* A character was entered.  Add it to the string
-									entered so far.  When a \n is entered the complete
-									string will be passed to the command interpreter. */
-									if( cInputIndex < cmdMAX_INPUT_SIZE )
-									{
-										cInputString[ cInputIndex ] = cInChar;
-										cInputIndex++;
-									}
-									if( strcmp( "\377\364\377\375\006", ( const char * ) cInputString ) == 0 ){
-										xTimerStop(RepeatSensorInfoTimer, 0);
-										cInputIndex = 0;
-										memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
-										cInputString[0] = 255;
-										cInputString[1] = 251;
-										cInputString[2] = 6;
-										cInputString[3] = 255;
-										cInputString[4] = 242;
-										//if(telnetState[i] != TELNET_CHANGE_PWD)
-											//lwip_send( lClientFd, pcEndOfCommandOutputString, strlen( ( const char * ) pcEndOfCommandOutputString ), 0 );
-										send( i, cInputString, strlen( ( const char * ) cInputString ), 0 );
-										memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
-										if(auth_tlnt_srvr_param[cur_cnt].telnetState != TELNET_CHANGE_PWD)
-											send( i, pcEndOfCommandOutputString, strlen( ( const char * ) pcEndOfCommandOutputString ), 0 );
-									}
-								}
-							}
-						}
+							newdata(&auth_tlnt_srvr_param[cur_cnt]);
 					}
 
 					if (lBytes < 0) {
 						if (errno != EWOULDBLOCK){
 							DBG printf("  recv() failed\n");
-							close_conn = true;
+							auth_tlnt_srvr_param[cur_cnt].state = STATE_CLOSE;
 						}
 					}
 
@@ -504,7 +678,7 @@ void vBasicSocketsCommandInterpreterTask( void *pvParameters )
 					/* closed by the client                       */
 					if (lBytes == 0) {
 						DBG printf("  Connection closed\n");
-						close_conn = true;
+						auth_tlnt_srvr_param[cur_cnt].state = STATE_CLOSE;
 					}
 
 					/* If the close_conn flag was turned on, we need */
@@ -514,7 +688,8 @@ void vBasicSocketsCommandInterpreterTask( void *pvParameters )
 					/* determining the new maximum descriptor value  */
 					/* based on the bits that are still turned on in */
 					/* the master set.                               */
-					if (close_conn) {
+					if (auth_tlnt_srvr_param[cur_cnt].state == STATE_CLOSE) {
+						auth_tlnt_srvr_param[cur_cnt].state = STATE_NORMAL;
 						auth_tlnt_srvr_param[cur_cnt].num_connect = 0;
 						auth_tlnt_srvr_param[cur_cnt].active_conn = false;
 						auth_tlnt_srvr_param[cur_cnt].telnetState = TELNET_AUTH;
@@ -532,7 +707,6 @@ void vBasicSocketsCommandInterpreterTask( void *pvParameters )
 			}
 		}
     }
-
 }
 
 void telnet_server_init(void) {
@@ -556,44 +730,52 @@ void SensorInfoTimerCallback(TimerHandle_t pxTimer) {
 		the output buffer. */
 		pcOutputString[ 0 ] = 0x00;
 		xReturned = FreeRTOS_CLIProcessCommand( "sensor info", pcOutputString, configCOMMAND_INT_MAX_OUTPUT_SIZE );
-		lwip_send( lClientFd, pcOutputString, strlen( ( const char * ) pcOutputString ), 0 );
+		for(uint8_t i = 0; i < NUMBER_TELNET_CONNECT; i++){
+			if(auth_tlnt_srvr_param[i].active_conn){
+				lwip_send( auth_tlnt_srvr_param[i].num_connect, pcOutputString, strlen( ( const char * ) pcOutputString ), 0 );
+			}
+		}
 
 	} while( xReturned != pdFALSE );
 	xTimerStart(RepeatSensorInfoTimer, 0);
 }
 
-static portBASE_TYPE FreeRTOS_CLIAuthProcess( const int8_t * const pcCommandInput, int8_t * pcWriteBuffer, uint8_t num_conn  )
+static portBASE_TYPE FreeRTOS_CLIAuthProcess( int8_t * pcWriteBuffer, telnetd_state_t *s  )
 {
 	portBASE_TYPE xReturn = pdTRUE;
 	uint32_t len;
 	uint8_t valueLen, user_id;
 	char WebPassword[MAX_WEB_PASSWD_LEN];
 	char WebLogin[MAX_WEB_LOGIN_LEN];
-	static uint8_t login_err[NUMBER_TELNET_CONNECT] = {0};
-	static uint8_t telnet_state_auth[NUMBER_TELNET_CONNECT] = {0};
-	static char login[NUMBER_TELNET_CONNECT][cmdMAX_INPUT_SIZE] = { 0 };
 	char password[cmdMAX_INPUT_SIZE] = { 0 };
 	const int8_t * const pcPSWHeader = ( int8_t * ) "\r\npassword:";
 	const int8_t * const pcLoginHeader = ( int8_t * ) "\r\nlogin:";
 
 	memset(pcWriteBuffer, 0, configCOMMAND_INT_MAX_OUTPUT_SIZE);
 
-	if(telnet_state_auth[num_conn] == 0){
-		telnet_state_auth[num_conn] = 1;
-		memset(&login[num_conn][0], 0, cmdMAX_INPUT_SIZE);
-		len = strlen((char *)pcCommandInput);
-		strncpy(&login[num_conn][0], (char *)pcCommandInput, len);
-		strncpy( ( char * ) pcWriteBuffer, ( const char * ) pcPSWHeader, strlen( ( char * ) pcPSWHeader ) );
-		xReturn = pdTRUE;
-	}
-	else{
+	switch(s->telnetState){
+	case TELNET_AUTH:
+		memset(s->login, 0, MAX_WEB_LOGIN_LEN);
+		len = strlen(s->buf);
+		if(len < MAX_WEB_LOGIN_LEN){
+			strncpy(s->login, s->buf, len);
+			sendopt(s, TELNET_WILL, TELOPT_ECHO);
+			strncpy( ( char * ) pcWriteBuffer, ( const char * ) pcPSWHeader, strlen( ( char * ) pcPSWHeader ) );
+			s->telnetState = TELNET_AUTH_PASSW;
+			xReturn = pdTRUE;
+		}
+		else{
+			xReturn = pdFALSE;
+		}
+		break;
+	case TELNET_AUTH_PASSW:
+		sendopt(s, TELNET_WONT, TELOPT_ECHO);
 		memset(name_login_telnet, 0, 50);
-		telnet_state_auth[num_conn] = 0;
-		memset(password, 0, cmdMAX_INPUT_SIZE);
-		len = strlen((char *)pcCommandInput);
-		strncpy(password, (char *)pcCommandInput, len);
+		memset(password, 0, MAX_WEB_PASSWD_LEN);
+		len = strlen(s->buf);
+		strncpy(password, s->buf, len);
 #ifdef HARDWARE_BT6708
-		if(!auth_tlnt_srvr_param[num_conn].flagWhiteListTelnet){
+		if(!s->flagWhiteListTelnet){
 			xReturn = pdFALSE;
 		}
 		else
@@ -605,14 +787,14 @@ static portBASE_TYPE FreeRTOS_CLIAuthProcess( const int8_t * const pcCommandInpu
 				GetUserPassword(user_id, WebPassword, &valueLen);
 
 				/* Check login and password */
-				if ((strncmp(WebLogin, &login[num_conn][0], MAX_WEB_LOGIN_LEN) == 0) &&
+				if ((strncmp(WebLogin, s->login, MAX_WEB_LOGIN_LEN) == 0) &&
 					(strncmp(WebPassword, password, MAX_WEB_PASSWD_LEN) == 0)) {
 
 					/* Login and pass are valid */
-					auth_tlnt_srvr_param[num_conn].telnet_code_auth = user_id;
-					login_err[num_conn] = 0;
+					s->telnet_code_auth = user_id;
+					s->login_err = 0;
 					strcpy( ( char * ) pcWriteBuffer, "\r\nАвторизация успешно пройдена\r\n>" );
-					auth_tlnt_srvr_param[num_conn].telnetState = TELNET_CMD;
+					s->telnetState = TELNET_CMD;
 					switch (user_id) {
 					  case 0:
 						  snprintf(name_login_telnet, sizeof(name_login_telnet), "Администратор");
@@ -633,69 +815,74 @@ static portBASE_TYPE FreeRTOS_CLIAuthProcess( const int8_t * const pcCommandInpu
 				}
 			}
 		}
-		if(xReturn == pdFALSE){
-			if(login_err[num_conn] < 4){
-				login_err[num_conn] ++;
+		break;
+	default:
+		xReturn = pdFALSE;
+		s->telnetState = TELNET_AUTH;
+		return xReturn;
+		break;
+	}
+
+	if(xReturn == pdFALSE){
+		s->telnetState = TELNET_AUTH;
+		if(s->login_err < 4){
+			s->login_err ++;
 #ifdef HARDWARE_BT6708
-				if(!auth_tlnt_srvr_param[num_conn].flagWhiteListTelnet)
-					strcpy( ( char * ) pcWriteBuffer, "\r\nДоступ запрешен! Ваш IP-адрес находится вне диапазона доверительных хостов\r\n" );
-				else
+			if(!s->flagWhiteListTelnet)
+				strcpy( ( char * ) pcWriteBuffer, "\r\nДоступ запрешен! Ваш IP-адрес находится вне диапазона доверительных хостов\r\n" );
+			else
 #endif
-					strcpy( ( char * ) pcWriteBuffer, "\r\nОшибка авторизации\r\n" );
-				strncat( ( char * ) pcWriteBuffer, ( const char * ) pcLoginHeader, strlen( ( char * ) pcLoginHeader ) );
-				xReturn = pdTRUE;
-			}
-			else{
-				login_err[num_conn] = 0;
-				xReturn = pdFALSE;
-			}
+				strcpy( ( char * ) pcWriteBuffer, "\r\nОшибка авторизации\r\n" );
+			strncat( ( char * ) pcWriteBuffer, ( const char * ) pcLoginHeader, strlen( ( char * ) pcLoginHeader ) );
+			xReturn = pdTRUE;
+		}
+		else{
+			s->login_err = 0;
+			xReturn = pdFALSE;
 		}
 	}
 
-
 	return xReturn;
 }
 
-static portBASE_TYPE FreeRTOS_ChangePWDProcess( const int8_t * const pcCommandInput, int8_t * pcWriteBuffer, uint8_t num_conn  )
+static portBASE_TYPE FreeRTOS_ChangePWDProcess( int8_t * pcWriteBuffer, telnetd_state_t *s  )
 {
 	portBASE_TYPE xReturn = pdTRUE;
 	uint32_t len;
-	static uint8_t telnet_state_change_pwd = 0;
-	static char password[ MAX_WEB_LOGIN_LEN ] = { 0 };
-	char password2[ MAX_WEB_LOGIN_LEN ] = { 0 };
+	static char password[ MAX_WEB_PASSWD_LEN ] = { 0 };
+	char password2[ MAX_WEB_PASSWD_LEN ] = { 0 };
 	const int8_t * const pcNewPSWHeader = ( int8_t * ) "\r\nВведите повторно новый пароль:";
 
 	memset(pcWriteBuffer, 0, configCOMMAND_INT_MAX_OUTPUT_SIZE);
 
-	if(telnet_state_change_pwd == 0){
-		telnet_state_change_pwd = 1;
-		memset(password, 0, MAX_WEB_LOGIN_LEN);
-		len = strlen((char *)pcCommandInput);
-		if(len >= MAX_WEB_LOGIN_LEN){
+	len = strlen(s->buf);
+	if(s->telnetState == TELNET_CHANGE_PWD){
+		memset(password, 0, MAX_WEB_PASSWD_LEN);
+		if(len >= MAX_WEB_PASSWD_LEN){
 			strcpy( ( char * ) pcWriteBuffer, "\r\nОшибка при вводе нового пароля\r\n>" );
-			auth_tlnt_srvr_param[num_conn].telnetState = TELNET_CMD;
+			s->telnetState = TELNET_CMD;
 		}
 		else{
-			if(!control_string_en_digit((char *)pcCommandInput, len)){
+			if(!control_string_en_digit(s->buf, len)){
 				strcpy( ( char * ) pcWriteBuffer, "\r\nОшибка при вводе нового пароля\r\n>" );
-				auth_tlnt_srvr_param[num_conn].telnetState = TELNET_CMD;
+				s->telnetState = TELNET_CMD;
 			}
 			else{
-				strncpy(password, (char *)pcCommandInput, len);
+				strncpy(password, s->buf, len);
 				strncpy( ( char * ) pcWriteBuffer, ( const char * ) pcNewPSWHeader, strlen( ( char * ) pcNewPSWHeader ) );
+				s->telnetState = TELNET_CHANGE_PWD_ACK;
 			}
 		}
 	}
 	else{
-		telnet_state_change_pwd = 0;
+		s->telnetState = TELNET_CHANGE_PWD;
 		memset(password2, 0, cmdMAX_INPUT_SIZE);
-		len = strlen((char *)pcCommandInput);
 		if(len >= MAX_WEB_LOGIN_LEN){
 			strcpy( ( char * ) pcWriteBuffer, "\r\nОшибка при вводе нового пароля\r\n>" );
-			auth_tlnt_srvr_param[num_conn].telnetState = TELNET_CMD;
+			s->telnetState = TELNET_CMD;
 		}
 		else{
-			strncpy(password2, (char *)pcCommandInput, len);
+			strncpy(password2, s->buf, len);
 
 			if (strncmp(password, password2, MAX_WEB_PASSWD_LEN) == 0) {
 				memcpy(sSettings.sAuth[id_change_pwd].password, password, 11);
@@ -703,12 +890,12 @@ static portBASE_TYPE FreeRTOS_ChangePWDProcess( const int8_t * const pcCommandIn
 				HTTP_SaveSettings();
 				log_event_data(LOG_PSW_CHANGE, name_login_telnet);
 				strcpy( ( char * ) pcWriteBuffer, "\r\nПароль успешно изменен\r\n>" );
-				auth_tlnt_srvr_param[num_conn].telnetState = TELNET_CMD;
+				s->telnetState = TELNET_CMD;
 				xReturn = pdTRUE;
 			}
 			else{
 				strcpy( ( char * ) pcWriteBuffer, "\r\nОшибка при вводе нового пароля\r\n>" );
-				auth_tlnt_srvr_param[num_conn].telnetState = TELNET_CMD;
+				s->telnetState = TELNET_CMD;
 			}
 		}
 	}

+ 19 - 2
modules/Telnet_Server/telnet_server.h

@@ -10,22 +10,39 @@
 
 #include "settings_api.h"
 
+/* Dimensions the buffer into which input characters are placed. */
+#define cmdMAX_INPUT_SIZE			144
+
 /*Number of connection*/
 #define NUMBER_TELNET_CONNECT		5
 
 typedef enum{
 	TELNET_AUTH = 0,
+	TELNET_AUTH_PASSW,
 	TELNET_CMD,
-	TELNET_CHANGE_PWD
+	TELNET_CHANGE_PWD,
+	TELNET_CHANGE_PWD_ACK
 }state_telnet_server_t;
 
+/**
+ * A telnet connection structure.
+ */
 typedef struct{
+	uint8_t state;
+	uint8_t code;
+	char buf[cmdMAX_INPUT_SIZE];
+	char bufptr;
+	char prev_cmd[cmdMAX_INPUT_SIZE];
+	unsigned char optdata[cmdMAX_INPUT_SIZE];
+	uint8_t optlen;
 	state_telnet_server_t telnetState;
 	user_level_t telnet_code_auth;
+	char login[MAX_WEB_LOGIN_LEN];
+	uint8_t login_err;
 	uint8_t num_connect;
 	bool active_conn;
 	bool flagWhiteListTelnet;
-}auth_telnet_server_t;
+}telnetd_state_t;
 
 
 void telnet_server_init(void);