1 /*
2  * Copyright 2013 Tenkiv, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5  * the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10  * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11  * specific language governing permissions and limitations under the License.
12  */
13 
14 /**
15  * @file TelnetServer.c
16  * @brief Implements a control interface for the Tekdaqc via the Telnet protocol.
17  *
18  * Implements a control interface for the Tekdaqc via the Telnet protocol. Only a single connection
19  * is allowed at a time. Any attempts to connect while an active connection is present will result in
20  * an error message from the board.
21  *
22  * This file based on the Telnet server implementation in the TI Stellaris example Cave Adventure game,
23  * in particular, the methods for processing the Telnet state machine.
24  *
25  * @author Jared Woolston (jwoolston@tenkiv.com)
26  * @since v1.0.0.0
27  */
28 
29 /*--------------------------------------------------------------------------------------------------------*/
30 /* INCLUDES */
31 /*--------------------------------------------------------------------------------------------------------*/
32 #include "lwip/opt.h"
33 #include "lwip/apps/telnetserver.h"
34 #include "lwip/debug.h"
35 #include "lwip/stats.h"
36 #include "lwip/tcp.h"
37 #include <stdio.h>
38 #include <inttypes.h>
39 #define PRINT_TAG "TELNETD"
40 /*--------------------------------------------------------------------------------------------------------*/
41 /* PRIVATE DEFINES */
42 /*--------------------------------------------------------------------------------------------------------*/
43 #define SIZE_TOSTRING_BUFFER 512U
44 
45 #define TELNET_PORT 23U
46 
47 #define ERROR_MESSAGE_HEADER "\n\r--------------------\n\rError Message\n\r\tMessage: %s\n\r--------------------\n\r\x1E"
48 #define STATUS_MESSAGE_HEADER "\n\r--------------------\n\rStatus Message\n\r\tMessage: %s\n\r--------------------\n\r\x1E"
49 #define DEBUG_MESSAGE_HEADER "\n\r--------------------\n\rDebug Message\n\r\tMessage: %s\n\r--------------------\n\r\x1E"
50 #define COMMAND_DATA_MESSAGE_HEADER "\n\r--------------------\n\rCommand Data Message\n\r\tMessage: %s\n\r--------------------\n\r\x1E"
51 
52 //#define TELNET_DEBUG
53 //#define TELNET_CHAR_DEBUG
54 /*--------------------------------------------------------------------------------------------------------*/
55 /* PRIVATE VARIABLES */
56 /*--------------------------------------------------------------------------------------------------------*/
57 
58 /**
59  * @internal
60  * @brief Pointer to the TCP port being used for the Telnet server.
61  */
62 static struct tcp_pcb *telnet_pcb;
63 
64 /**
65  * @internal
66  * @brief Pointer to the current Telnet server.
67  */
68 static TelnetServer_t telnet_server;
69 
70 /**
71  * @internal
72  * @brief Indicates the connection status of the telnet server.
73  */
74 static bool IsConnected = false;
75 
76 /**
77  * @internal
78  * @brief Buffer for printing the TOSTRING_BUFFER with additional formatting.
79  */
80 static char MESSAGE_BUFFER[SIZE_TOSTRING_BUFFER];
81 
82 /**
83  * @internal
84  * @brief The error message provided when an attempt is made to play the game when
85  *         it is already being played over a different interface.
86  */
87 static const char ErrorMessage[53] =
88 		"The Tekdaqc is already in use...try again later!\r\n";
89 
90 /**
91  * @internal
92  * @brief The initialization sequence sent to a remote telnet client when it first connects to the telnet server.
93  */
94 static const char TelnetInit[] = { TELNET_IAC, TELNET_DO,
95 TELNET_OPT_SUPPRESS_GA, TELNET_IAC, TELNET_WILL, TELNET_OPT_ECHO };
96 
97 /**
98  * @internal
99  * @brief This telnet server will always suppress go ahead generation, regardless of this setting.
100  */
101 static TelnetOpts_t TelnetOptions[] = { { .option = TELNET_OPT_SUPPRESS_GA,
102                 .flags = (0x01 << OPT_FLAG_WILL) }, { .option = TELNET_OPT_ECHO,
103                 .flags = (1 << OPT_FLAG_DO) } };
104 
105 /*--------------------------------------------------------------------------------------------------------*/
106 /* PRIVATE FUNCTION PROTOTYPES */
107 /*--------------------------------------------------------------------------------------------------------*/
108 
109 /**
110  * @brief Called when the lwIP TCP/IP stack has an incoming connection request on the telnet port.
111  */
112 static err_t TelnetAccept(void *arg, struct tcp_pcb *pcb, err_t err);
113 
114 /**
115  * @brief Called when the lwIP TCP/IP stack has an incoming packet to be processed.
116  */
117 static err_t TelnetReceive(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);
118 
119 /**
120  * @brief Called when the lwIP TCP/IP stack has received an acknowledge for data that has been transmitted.
121  */
122 static err_t TelnetSent(void *arg, struct tcp_pcb *pcb, u16_t len);
123 
124 /**
125  * @brief Called when the lwIP TCP/IP stack has detected an error.
126  */
127 static void TelnetError(void *arg, err_t err);
128 
129 /**
130  * @brief Clears the internal message string buffer.
131  */
132 static void ClearToMessageBuffer(void);
133 
134 /**
135  * @brief Creates an initalizes a Telnet server.
136  */
137 static TelnetServer_t* CreateTelnetServer(void);
138 
139 /*--------------------------------------------------------------------------------------------------------*/
140 /* PRIVATE METHODS */
141 /*--------------------------------------------------------------------------------------------------------*/
142 
143 /*
144  * @internal
145  * This function is called when the lwIP TCP/IP stack has an incoming
146  * connection request on the telnet port.
147  *
148  * @param arg void* Argument pointer passed to the handler by the lwIP stack.
149  * @param pcb tcp_pcb* struct The PCB structure this callback is for.
150  * @param err lwIP err_t with the current error status.
151  * @retval err lwIP err_t with the result of the this function.
152  */
TelnetAccept(void * arg,struct tcp_pcb * pcb,err_t err)153 static err_t TelnetAccept(void *arg, struct tcp_pcb *pcb, err_t err) {
154 #ifdef TELNET_DEBUG
155     LOGD(PRINT_TAG, "[Telnet Server] Incoming connection requested on Telnet port.\n\r");
156 #endif
157     err_t ret_err;
158 
159     LWIP_UNUSED_ARG(arg);
160     LWIP_UNUSED_ARG(err);
161 
162     /* Check if already connected. */
163     if (TelnetIsConnected() == true) {
164         /* There is already a connected client, so refuse this connection with
165 	   a message indicating this fact. */
166 #ifdef TELNET_DEBUG
167         LOGD(PRINT_TAG, "[Telnet Server] A connection was attempted while an active connection is open.\n\r");
168 #endif
169         tcp_accepted(pcb);
170         tcp_arg(pcb, NULL);
171         tcp_sent(pcb, TelnetSent);
172         tcp_write(pcb, ErrorMessage, sizeof(ErrorMessage), 1);
173             tcp_output(pcb);
174             /* Temporarily accept this connection until the message is transmitted. */
175             return (ERR_OK);
176         }
177 
178         /* Setup the TCP connection priority. */
179         tcp_setprio(pcb, TCP_PRIO_MIN);
180 
181         CreateTelnetServer();
182 #ifdef TELNET_DEBUG
183         LOGD(PRINT_TAG, "[Telnet Server] Initializing telnet server.\n\r");
184 #endif
185         tcp_nagle_enable(pcb);
186         telnet_server.pcb = pcb;
187         telnet_server.pcb->so_options |= SOF_KEEPALIVE;
188         telnet_server.pcb->keep_idle = 300000UL; // 5 Minutes
189         telnet_server.pcb->keep_intvl = 1000UL; // 1 Second
190         telnet_server.pcb->keep_cnt = 9; // 9 Consecutive failures terminate
191 
192         /* Mark that a client has connected. */
193         IsConnected = true;
194         /* Accept this connection. */
195         tcp_accepted(pcb);
196 #ifdef TELNET_DEBUG
197         LOGD(PRINT_TAG, "[Telnet Server] An incoming connection was accepted.\n\r");
198 #endif
199 
200         /* Setup the TCP callback argument. */
201         tcp_arg(pcb, &telnet_server);
202 
203         /* Initialize lwIP tcp_recv callback function for pcb  */
204         tcp_recv(pcb, TelnetReceive);
205 
206         /* Initialize lwIP tcp_err callback function for pcb  */
207         tcp_err(pcb, TelnetError);
208 
209         /* Initialize lwIP tcp_poll callback function for pcb */
210         tcp_poll(pcb, TelnetPoll, 1);
211 
212         /* Setup the TCP sent callback function. */
213         tcp_sent(pcb, TelnetSent);
214         /* Initialize the count of outstanding bytes.  The initial byte acked as
215          part of the SYN -> SYN/ACK sequence is included so that the byte count
216          works out correctly at the end. */
217         telnet_server.outstanding = sizeof(TelnetInit) + 1;
218         /* Do not close the telnet connection until requested. */
219         telnet_server.close = 0;
220 #ifdef TELNET_DEBUG
221         LOGD(PRINT_TAG, "[Telnet Server] Writing the init messages\n\r");
222 #endif
223         /* Send the telnet initialization string. */
224         tcp_write(pcb, TelnetInit, sizeof(TelnetInit), 1);
225         tcp_output(pcb);
226 
227         TelnetWriteDebugMessage("[TELNET] Telnet Server Connected. Welcome.");
228 
229 #ifdef TELNET_DEBUG
230         LOGD(PRINT_TAG, "[Telnet Server] Telnet Server Connected. Welcome.\n\r");
231 #endif
232         /* Return a success code. */
233         ret_err = ERR_OK;
234         return ret_err;
235 }
236 
237 /*
238  * @internal
239  * This function is called when the lwIP TCP/IP stack has an incoming packet to
240  * be processed.
241  *
242  * @param arg void* Argument pointer passed to the handler by the lwIP stack.
243  * @param pcb tcp_pcb* struct The PCB structure this callback is for.
244  * @param p pbuf* struct The data buffer from the lwIP stack.
245  * @param err lwIP err_t with the current error status.
246  * @retval err lwIP err_t with the result of the this function.
247  */
TelnetReceive(void * arg,struct tcp_pcb * pcb,struct pbuf * p,err_t err)248 static err_t TelnetReceive(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) {
249     struct pbuf *q;
250     unsigned long ulIdx;
251     unsigned char *pucData;
252     TelnetServer_t* server;
253     if (arg != NULL) {
254         server = (TelnetServer_t*) arg;
255 
256         /* Process the incoming packet. */
257         if ((err == ERR_OK) && (p != NULL)) {
258 #ifdef TELNET_DEBUG
259             LOGD(PRINT_TAG, "[Telnet Server] Processing received packet.\n\r");
260 #endif
261             /* Accept the packet from TCP. */
262             tcp_recved(pcb, p->tot_len);
263             /* Loop through the pbufs in this packet. */
264             for (q = p, pucData = (unsigned char*) q->payload; q != NULL; q = q->next) {
265                 /* Loop through the bytes in this pbuf. */
266                 for (ulIdx = 0; ulIdx < q->len; ulIdx++) {
267                     /* Process this character. */
268                     TelnetProcessCharacter(pucData[ulIdx]);
269                 }
270             }
271 
272             /* Free the pbuf. */
273             pbuf_free(p);
274         } else if ((err == ERR_OK) && (p == NULL)) {
275             /* If a null packet is passed in, close the connection. */
276             server->length = 0;
277             TelnetClose();
278         }
279     } else {
280 #ifdef TELNET_DEBUG
281         LOGD(PRINT_TAG, "[Telnet Server] Could not cast receive args to telnet server struct because they were null.\n\r");
282         return ERR_VAL;
283 #endif
284     }
285     /* Return okay. */
286     return (ERR_OK);
287 }
288 
289 /**
290  * @internal
291  * This function is called when the lwIP TCP/IP stack has received an
292  * acknowledge for data that has been transmitted.
293  *
294  * @param arg void* Argument pointer passed to the handler by the lwIP stack.
295  * @param pcb tcp_pcb* struct The PCB structure this callback is for.
296  * @param len u16_t The number of bytes which were sent.
297  * @retval err lwIP err_t with the result of the this function.
298  */
TelnetSent(void * arg,struct tcp_pcb * pcb,u16_t len)299 static err_t TelnetSent(void *arg, struct tcp_pcb *pcb, u16_t len)
300 {
301     /* See if this is for the game connection or for a secondary connection. */
302     if (arg) {
303         TelnetServer_t* server = (TelnetServer_t*) arg;
304 #ifdef TELNET_DEBUG
305         LOGD(PRINT_TAG, "[Telnet Server] Sent packet was acknowledged.\n\r");
306 #endif
307         /* Decrement the count of outstanding bytes. */
308         server->outstanding -= len;
309     } else {
310         /* See if this is the ACK for the error message. */
311         if (len == sizeof(ErrorMessage)) {
312             /* Close this telnet connection now that the error message has been transmitted. */
313             tcp_sent(pcb, 0);
314             tcp_close(pcb);
315         }
316     }
317     /* Return OK. */
318     return (ERR_OK);
319 }
320 
321 /**
322  * @internal
323  * This function implements the tcp_err callback function (called when a fatal
324  * tcp_connection error occurs. As soon as this function is called, the Telnet
325  * server is invalid and should not be used anymore.
326  *
327  * @param  arg Pointer to argument parameter
328  * @param  err Not used
329  * @retval None
330  */
TelnetError(void * arg,err_t err)331 static void TelnetError(void *arg, err_t err)
332 {
333     LWIP_UNUSED_ARG(err);
334     //#ifdef TELNET_DEBUG
335     LOGD(PRINT_TAG, "[Telnet Server] Telnet error received: %i\n\r", err);
336     //#endif
337     TelnetServer_t* server;
338     server = (TelnetServer_t*) arg;
339     if (server != NULL) {
340         /* free es structure */
341         mem_free(server);
342     }
343     IsConnected = false;
344 }
345 
346 /**
347  * @internal
348  * Creates and initializes a Telnet server.
349  *
350  * @param none
351  * @retval TelnetServer_t* The structure used to represent the current server.
352  */
CreateTelnetServer(void)353 static TelnetServer_t* CreateTelnetServer(void)
354 {
355 #ifdef TELNET_DEBUG
356     LOGD(PRINT_TAG, "[Telnet Server] Allocating memory for server.\n\r");
357 #endif
358     /* Allocate structure server to maintain Telnet connection information */
359     IsConnected = false;
360     telnet_server.halt = false;
361     telnet_server.recvWrite = 0;
362     telnet_server.recvRead = 0;
363     telnet_server.previous = 0;
364     telnet_server.length = 0;
365     for (int i = 0; i < TELNET_BUFFER_LENGTH; ++i) {
366         telnet_server.recvBuffer[i] = 0;
367     }
368     return &telnet_server;
369 }
370 
371 /**
372  * @internal
373  * Clears the internal message string buffer.
374  *
375  * @param none
376  * @retval none
377  */
ClearToMessageBuffer(void)378 static void ClearToMessageBuffer(void) {
379     for (int i = 0; i < SIZE_TOSTRING_BUFFER; ++i) {
380         MESSAGE_BUFFER[i] = '\0';
381     }
382 }
383 
384 /**
385  * Initializes the provided TelnetServer_t struct with default values and creates a TCP port for it.
386  *
387  * @param none
388  * @retval none
389  */
InitializeTelnetServer(void)390 TelnetStatus_t InitializeTelnetServer(void) {
391     telnet_server.length = 0;
392     telnet_server.outstanding = 0;
393     for (uint_fast16_t i = 0; i < sizeof(telnet_server.buffer); ++i) {
394         telnet_server.buffer[i] = 0;
395     }
396     /* Create a new tcp pcb */
397 #ifdef TELNET_DEBUG
398     LOGD(PRINT_TAG, "[Telnet Server] Creating TCP port for Telnet server.\n\r");
399 #endif
400     telnet_pcb = tcp_new();
401 
402     if (telnet_pcb != NULL) {
403 #ifdef TELNET_DEBUG
404         LOGD(PRINT_TAG, "[Telnet Server] Successfully created Telnet TCP port.\n\r");
405 #endif
406         err_t err;
407         /* Bind telnet to port TELNET_PORT */
408         err = tcp_bind(telnet_pcb, IP_ADDR_ANY, TELNET_PORT);
409 
410         if (err == ERR_OK) {
411             /* Start tcp listening for Telnet PCB */
412             telnet_pcb = tcp_listen(telnet_pcb);
413 #ifdef TELNET_DEBUG
414             LOGD(PRINT_TAG, "[Telnet Server] Now listening for incoming connections on port %i\n\r", TELNET_PORT);
415 #endif
416             /* Initialize LwIP tcp_accept callback function */
417             tcp_accept(telnet_pcb, TelnetAccept);
418             return TELNET_OK;
419         } else {
420             /* Deallocate the pcb */
421             memp_free(MEMP_TCP_PCB, telnet_pcb);
422 #ifdef TELNET_DEBUG
423             LOGD(PRINT_TAG, "[Telnet Server] Can not bind pcb\n\r");
424 #endif
425             return TELNET_ERR_BIND;
426         }
427     } else {
428 #ifdef TELNET_DEBUG
429         LOGD(PRINT_TAG, "[Telnet Server] Can not create new TCP port.\n\r");
430 #endif
431         return TELNET_ERR_PCBCREATE;
432     }
433 }
434 
435 /**
436  * This function is called when the the TCP connection should be closed.
437  *
438  * @param none
439  * @retval none
440  */
TelnetClose(void)441 void TelnetClose(void) {
442     LOGD(PRINT_TAG, "Closing telnet connection.\n\r");
443     struct tcp_pcb *pcb = telnet_server.pcb;
444 
445     /* Remove all callbacks */
446     tcp_arg(pcb, NULL);
447     tcp_sent(pcb, NULL);
448     tcp_recv(pcb, NULL);
449     tcp_err(pcb, NULL);
450     tcp_poll(pcb, NULL, 0);
451 
452     /* Clear the telnet data structure pointer, to indicate that there is no longer a connection. */
453     telnet_server.pcb = 0;
454 
455     /* Close tcp connection */
456     tcp_close(pcb);
457     IsConnected = false;
458 
459     /* Re-initialize the Telnet Server */
460     InitializeTelnetServer();
461 }
462 
463 /**
464  * Returns the connection status of the Telnet server. Since this implementation supports only
465  * one client at a time, this method can be used to determine if an incoming request can be honored
466  * as well as allowing other parts of the program to adjust their behavior depending on if a client
467  * is connected.
468  *
469  * @param none
470  * @retval bool TRUE if the telnet server has an active connection.
471  */
TelnetIsConnected(void)472 bool TelnetIsConnected(void) {
473     return (IsConnected);
474 }
475 
476 /**
477  * Called by the lwIP stack when there is data to send/receive to/from the Telnet server.
478  *
479  * @param arg void* to argument passed to callback by lwIP stack.
480  * @param tpcb tcp_pcb* To the tcp_pcb struct for the current tcp connection.
481  * @retval err_t The error/status code.
482  */
TelnetPoll(void * arg,struct tcp_pcb * tpcb)483 err_t TelnetPoll(void *arg, struct tcp_pcb *tpcb) {
484     err_t ret_err;
485     TelnetServer_t* server;
486     server = (TelnetServer_t*) arg;
487 
488     if (server != NULL) {
489         unsigned long length = server->length;
490         if ((server->pcb != NULL) && (length != 0)) {
491        	/* Write the data from the transmit buffer. */
492         tcp_write(server->pcb, server->buffer, length, 1);
493 
494         /* Increment the count of outstanding bytes. */
495         server->outstanding += length;
496 
497         /* Output the telnet data. */
498         tcp_output(server->pcb);
499 
500         /* Reset the size of the data in the transmit buffer. */
501         server->length = 0;
502     }
503     /* See if the telnet connection should be closed; this will only occur once
504 	   all transmitted data has been ACKed by the client (so that some or all
505 	   of the final message is not lost). */
506     if (server->pcb && (server->outstanding == 0) && (server->close != 0)) {
507 #ifdef TELNET_DEBUG
508         LOGD(PRINT_TAG, "[Telnet Server] Telnet server should be closed.\n\r");
509 #endif
510         TelnetClose();
511     }
512         ret_err = ERR_OK;
513     } else {
514 #ifdef TELNET_DEBUG
515         LOGD(PRINT_TAG, "[Telnet Server] Cannot process poll request due to null server structure.\n\r");
516 #endif
517         /* Nothing to be done */
518         tcp_abort(tpcb);
519         ret_err = ERR_ABRT;
520     }
521     return ret_err;
522 }
523 
524 /**
525  * Writes a character into the telnet receive buffer.
526  *
527  * @param character char The character to write.
528  * @retval none
529  */
TelnetRecvBufferWrite(char character)530 void TelnetRecvBufferWrite(char character) {
531     unsigned long ulWrite;
532     /* Ignore this character if it is the NULL character. */
533     if (character == 0) {
534 #ifdef TELNET_CHAR_DEBUG
535         LOGD(PRINT_TAG, "[Telnet Server] Ignorning NULL character.\n\r");
536 #endif
537         return;
538     }
539 
540     /* Ignore this character if it is the second part of a CR/LF or LF/CR sequence. */
541     if (((character == '\r') && (telnet_server.previous == '\n'))
542         || ((character == '\n') && (telnet_server.previous == '\r'))) {
543         return;
544     }
545 
546     /* Store this character into the receive buffer if there is space for it. */
547     ulWrite = telnet_server.recvWrite;
548     if (((ulWrite + 1) % sizeof(telnet_server.recvBuffer))
549          != telnet_server.recvRead) {
550         telnet_server.recvBuffer[ulWrite] = character;
551         telnet_server.recvWrite = (ulWrite + 1) % sizeof(telnet_server.recvBuffer);
552 #ifdef TELNET_CHAR_DEBUG
553         for (int i = 0; i <= telnet_server.recvWrite; ++i) {
554             LOGD(PRINT_TAG, "%c", telnet_server.recvBuffer[i]);
555         }
556         LOGD(PRINT_TAG, "\n\r");
557 #endif
558     } else {
559 #ifdef TELNET_DEBUG
560         LOGD(PRINT_TAG, "[Telnet Server] Could not store new character because buffer was full.\n\r");
561 #endif
562     }
563 
564     /* Save this character as the previously received telnet character. */
565     telnet_server.previous = character;
566 }
567 
568 /**
569  * Reads a character from the telnet interface.
570  *
571  * @param none
572  * @retval char The character read from the telnet interface.
573  */
TelnetRead(void)574 char TelnetRead(void) {
575     if (TelnetIsConnected() == true) {
576         uint32_t read;
577         char ret;
578         /* Return a NULL if there is no data in the receive buffer. */
579         read = telnet_server.recvRead;
580         if (read == telnet_server.recvWrite) {
581             return (0);
582         }
583         /* Read the next byte from the receive buffer. */
584         ret = telnet_server.recvBuffer[read];
585         telnet_server.recvRead = (read + 1) % sizeof(telnet_server.recvBuffer);
586         /* Return the byte that was read. */
587         return (ret);
588     } else {
589         return 0;
590     }
591 }
592 
593 /**
594  * Writes a character to the telnet interface.
595  *
596  * @param character const char The character to write to the interface.
597  * @retval none
598  */
TelnetWrite(const char character)599 void TelnetWrite(const char character) {
600     if (TelnetIsConnected() == true) {
601         /* Delay until there is some space in the output buffer.  The buffer is not
602            completly filled here to leave some room for the processing of received
603            telnet commands. */
604         while (telnet_server.length > (sizeof(telnet_server.buffer) - 32)) {
605 #ifdef TELNET_DEBUG
606             LOGD(PRINT_TAG, "[Telnet Server] Telnet buffer is full!\n\r");
607 #endif
608             /* Handle periodic timers for LwIP */
609             aos_msleep(200);
610             //LwIP_Periodic_Handle(GetLocalTime());
611         }
612 
613         /* Write this character into the output buffer. */
614         telnet_server.buffer[telnet_server.length++] = character;
615     }
616 }
617 
618 /**
619  * Writes a string to the specified Telnet server. Disables Ethernet
620  * interrupts during this process in order to prevent an intervening
621  * interrupt from corrupting the output buffer.
622  *
623  * @param string char* Pointer to a C-String to write to the interface.
624  * @retval none
625  */
TelnetWriteString(char * string)626 void TelnetWriteString(char* string) {
627     if (TelnetIsConnected() == true) {
628 #if 0
629         Eth_EXTI_Disable();
630 #endif
631         while (*string) {
632             TelnetWrite(*string);
633             ++string;
634         }
635 #if 0
636         Eth_EXTI_Enable();
637 #endif
638     }
639 }
640 
641 /**
642  * This function will handle a WILL request for a telnet option.  If it is an
643  * option that is known by the telnet server, a DO response will be generated
644  * if the option is not already enabled.  For unknown options, a DONT response
645  * will always be generated.
646  *
647  * The response (if any) is written into the telnet transmit buffer.
648  *
649  * @param option char Option for the WILL command.
650  * @retval none
651  */
TelnetProcessWill(char option)652 void TelnetProcessWill(char option) {
653     unsigned long ulIdx;
654 #ifdef TELNET_CHAR_DEBUG
655     LOGD(PRINT_TAG, "[Telnet Server] Processing WILL command with option: %c/0x%02X\n\r", option, option);
656 #endif
657     /* Loop through the known options. */
658     for (ulIdx = 0; ulIdx < (sizeof(TelnetOptions) / sizeof(TelnetOptions[0])); ulIdx++) {
659         /* See if this option matches the option in question. */
660         if (TelnetOptions[ulIdx].option == option) {
661             /* See if the WILL flag for this option has already been set. */
662             if (((TelnetOptions[ulIdx].flags >> OPT_FLAG_WILL) & 0x01) == 0) {
663                 /* Set the WILL flag for this option. */
664                 TelnetOptions[ulIdx].flags = (TelnetOptions[ulIdx].flags & 0xFD)
665                                               | (0x01 << OPT_FLAG_WILL);
666                 /* Send a DO response to this option. */
667                 telnet_server.buffer[telnet_server.length++] = TELNET_IAC;
668                 telnet_server.buffer[telnet_server.length++] = TELNET_DO;
669                 telnet_server.buffer[telnet_server.length++] = option;
670             }
671             /* Return without any further processing. */
672             return;
673         }
674     }
675 
676     /* This option is not recognized, so send a DONT response. */
677     telnet_server.buffer[telnet_server.length++] = TELNET_IAC;
678     telnet_server.buffer[telnet_server.length++] = TELNET_DONT;
679     telnet_server.buffer[telnet_server.length++] = option;
680 }
681 
682 /**
683  * This function will handle a WONT request for a telnet option.  If it is an
684  * option that is known by the telnet server, a DONT response will be generated
685  * if the option is not already disabled.  For unknown options, a DONT response
686  * will always be generated.
687  *
688  * The response (if any) is written into the telnet transmit buffer.
689  *
690  * @param server Pointer to the server to process.
691  * @param option char Option for the WONT command.
692  * @retval none
693  */
TelnetProcessWont(char option)694 void TelnetProcessWont(char option) {
695     unsigned long ulIdx;
696 #ifdef TELNET_CHAR_DEBUG
697     LOGD(PRINT_TAG, "[Telnet Server] Processing WONT command with option: %c/0x%02X\n\r", option, option);
698 #endif
699     /* Loop through the known options. */
700     for (ulIdx = 0; ulIdx < (sizeof(TelnetOptions) / sizeof(TelnetOptions[0])); ulIdx++) {
701         /* See if this option matches the option in question. */
702         if (TelnetOptions[ulIdx].option == option) {
703             /* See if the WILL flag for this option is currently set. */
704             if (((TelnetOptions[ulIdx].flags >> OPT_FLAG_WILL) & 0x01) == 1) {
705                 /* Clear the WILL flag for this option. */
706                 TelnetOptions[ulIdx].flags = (TelnetOptions[ulIdx].flags & 0xFD)
707                                               | 0x00;
708                 /* Send a DONT response to this option. */
709                 telnet_server.buffer[telnet_server.length++] = TELNET_IAC;
710                 telnet_server.buffer[telnet_server.length++] = TELNET_DONT;
711                 telnet_server.buffer[telnet_server.length++] = option;
712             }
713             /* Return without any further processing. */
714             return;
715         }
716     }
717 
718     /* This option is not recognized, so send a DONT response. */
719     telnet_server.buffer[telnet_server.length++] = TELNET_IAC;
720     telnet_server.buffer[telnet_server.length++] = TELNET_DONT;
721     telnet_server.buffer[telnet_server.length++] = option;
722 }
723 
724 /**
725  * This function will handle a DO request for a telnet option.  If it is an
726  * option that is known by the telnet server, a WILL response will be generated
727  * if the option is not already enabled.  For unknown options, a WONT response
728  * will always be generated.
729  *
730  * The response (if any) is written into the telnet transmit buffer.
731  *
732  * @param option char Option for the DO command.
733  * @return none
734  */
TelnetProcessDo(char option)735 void TelnetProcessDo(char option) {
736     unsigned long ulIdx;
737 #ifdef TELNET_CHAR_DEBUG
738     LOGD(PRINT_TAG, "[Telnet Server] Processing DO command with option: %c/0x%02X\n\r", option, option);
739 #endif
740     /* Loop through the known options. */
741     for (ulIdx = 0; ulIdx < (sizeof(TelnetOptions) / sizeof(TelnetOptions[0])); ulIdx++) {
742         /* See if this option matches the option in question. */
743         if (TelnetOptions[ulIdx].option == option) {
744             /* See if the DO flag for this option has already been set. */
745             if (((TelnetOptions[ulIdx].flags >> OPT_FLAG_DO) & 0x01) == 0) {
746            	    /* Set the DO flag for this option. */
747            	    TelnetOptions[ulIdx].flags = (TelnetOptions[ulIdx].flags & 0xFB)
748                                               | (0x01 << OPT_FLAG_DO);
749            	    /* Send a WILL response to this option. */
750                	telnet_server.buffer[telnet_server.length++] = TELNET_IAC;
751            	    telnet_server.buffer[telnet_server.length++] = TELNET_WILL;
752                	telnet_server.buffer[telnet_server.length++] = option;
753             }
754             /* Return without any further processing. */
755             return;
756         }
757     }
758 
759     // This option is not recognized, so send a WONT response.
760     telnet_server.buffer[telnet_server.length++] = TELNET_IAC;
761     telnet_server.buffer[telnet_server.length++] = TELNET_WONT;
762     telnet_server.buffer[telnet_server.length++] = option;
763 }
764 
765 /**
766  * This funciton will handle a DONT request for a telnet option.  If it is an
767  * option that is known by the telnet server, a WONT response will be generated
768  * if the option is not already disabled.  For unknown options, a WONT resopnse
769  * will always be generated.
770  *
771  * The response (if any) is written into the telnet transmit buffer.
772  *
773  * @param option char Option for the DONT command.
774  * @return none
775  */
TelnetProcessDont(char option)776 void TelnetProcessDont(char option) {
777     unsigned long ulIdx;
778 #ifdef TELNET_CHAR_DEBUG
779     LOGD(PRINT_TAG, "[Telnet Server] Processing DONT command with option: %c/0x%02X\n\r", option, option);
780 #endif
781     /* Loop through the known options. */
782     for (ulIdx = 0; ulIdx < (sizeof(TelnetOptions) / sizeof(TelnetOptions[0])); ulIdx++) {
783         /* See if this option matches the option in question. */
784         if (TelnetOptions[ulIdx].option == option) {
785             /* See if the DO flag for this option is currently set. */
786             if (((TelnetOptions[ulIdx].flags >> OPT_FLAG_DO) & 0x01) == 1) {
787                 /* Clear the DO flag for this option. */
788            	    TelnetOptions[ulIdx].flags = (TelnetOptions[ulIdx].flags & 0xFB)
789                                               | 0x00;
790        	        /* Send a WONT response to this option. */
791            	    telnet_server.buffer[telnet_server.length++] = TELNET_IAC;
792            	    telnet_server.buffer[telnet_server.length++] = TELNET_WONT;
793        	        telnet_server.buffer[telnet_server.length++] = option;
794            	}
795        	    /* Return without any further processing. */
796        	    return;
797         }
798     }
799 
800     /* This option is not recognized, so send a WONT response. */
801     telnet_server.buffer[telnet_server.length++] = TELNET_IAC;
802     telnet_server.buffer[telnet_server.length++] = TELNET_WONT;
803     telnet_server.buffer[telnet_server.length++] = option;
804 }
805 
806 /*
807  * This function processes a character received from the telnet port, handling
808  * the interpretation of telnet commands (as indicated by the telnet interpret
809  * as command (IAC) byte).
810  *
811  * @param character char The character to process.
812  * @retval none
813  */
TelnetProcessCharacter(char character)814 void TelnetProcessCharacter(char character) {
815 #ifdef TELNET_CHAR_DEBUG
816     LOGD(PRINT_TAG, "[Telnet Server] Processing Character: %c/0x%02X\n\r", character, character);
817 #endif
818     /* Determine the current state of the telnet command parser. */
819     switch (telnet_server.state) {
820     /* The normal state of the parser, were each character is either sent
821      to the UART or is a telnet IAC character. */
822     case STATE_NORMAL: {
823         /* See if this character is the IAC character. */
824         if (character == TELNET_IAC) {
825             /* Skip this character and go to the IAC state. */
826             telnet_server.state = STATE_IAC;
827         } else {
828             /* Write this character to the receive buffer. */
829             TelnetRecvBufferWrite(character);
830             /* Echo this character */
831             TelnetWrite(character);                    //Echo the character back
832         }
833         break;
834     }
835     /* The previous character was the IAC character. */
836     case STATE_IAC: {
837         /* Determine how to interpret this character. */
838         switch (character) {
839         /* See if this character is also an IAC character. */
840         case TELNET_IAC: {
841             /* Write 0xff to the receive buffer. */
842             TelnetRecvBufferWrite(0xff);
843             /* Switch back to normal mode. */
844             telnet_server.state = STATE_NORMAL;
845             /* This character has been handled. */
846             break;
847         }
848         /* See if this character is the WILL request. */
849         case TELNET_WILL: {
850             /* Switch to the WILL mode; the next character will have
851              the option in question. */
852             telnet_server.state = STATE_WILL;
853             /* This character has been handled. */
854             break;
855         }
856         /* See if this character is the WONT request. */
857         case TELNET_WONT: {
858             /* Switch to the WONT mode; the next character will have
859              the option in question. */
860             telnet_server.state = STATE_WONT;
861             /* This character has been handled. */
862             break;
863         }
864     	/* See if this character is the DO request. */
865         case TELNET_DO: {
866        	    /* Switch to the DO mode; the next character will have the
867        	      option in question. */
868        	    telnet_server.state = STATE_DO;
869        	    /* This character has been handled. */
870             break;
871         }
872        	/* See if this character is the DONT request. */
873         case TELNET_DONT: {
874        	    /* Switch to the DONT mode; the next character will have
875        	     the option in question. */
876             telnet_server.state = STATE_DONT;
877        	    /* This character has been handled. */
878             break;
879         }
880         /* See if this character is the AYT request. */
881         case TELNET_AYT: {
882             /* Send a short string back to the client so that it knows
883              that the server is still alive. */
884             telnet_server.buffer[telnet_server.length++] = '\r';
885             telnet_server.buffer[telnet_server.length++] = '\n';
886             telnet_server.buffer[telnet_server.length++] = '[';
887             telnet_server.buffer[telnet_server.length++] = 'Y';
888             telnet_server.buffer[telnet_server.length++] = 'e';
889             telnet_server.buffer[telnet_server.length++] = 's';
890             telnet_server.buffer[telnet_server.length++] = ']';
891             telnet_server.buffer[telnet_server.length++] = '\r';
892             telnet_server.buffer[telnet_server.length++] = '\n';
893             /* Switch back to normal mode. */
894             telnet_server.state = STATE_NORMAL;
895             /* This character has been handled. */
896             break;
897         }
898         /* Explicitly ignore the GA and NOP request, plus provide a
899          catch-all ignore for unrecognized requests. */
900         case TELNET_GA:
901         case TELNET_NOP:
902         default: {
903             /* Switch back to normal mode. */
904             telnet_server.state = STATE_NORMAL;
905             /* This character has been handled. */
906             break;
907         }
908         }
909         /* This state has been handled. */
910         break;
911 	}
912     /* The previous character sequence was IAC WILL. */
913     case STATE_WILL: {
914         /* Process the WILL request on this option. */
915         TelnetProcessWill(character);
916         /* Switch back to normal mode. */
917         telnet_server.state = STATE_NORMAL;
918         /* This state has been handled. */
919         break;
920     }
921     /* The previous character sequence was IAC WONT. */
922     case STATE_WONT: {
923         /* Process the WONT request on this option. */
924         TelnetProcessWont(character);
925         /* Switch back to normal mode. */
926         telnet_server.state = STATE_NORMAL;
927         /* This state has been handled. */
928         break;
929     }
930     /* The previous character sequence was IAC DO. */
931     case STATE_DO: {
932         /* Process the DO request on this option. */
933         TelnetProcessDo(character);
934         /* Switch back to normal mode. */
935         telnet_server.state = STATE_NORMAL;
936         /* This state has been handled. */
937         break;
938     }
939     /* The previous character sequence was IAC DONT. */
940     case STATE_DONT: {
941         /* Process the DONT request on this option. */
942         TelnetProcessDont(character);
943         /* Switch back to normal mode. */
944         telnet_server.state = STATE_NORMAL;
945         /* This state has been handled. */
946         break;
947     }
948     /* A catch-all for unknown states.  This should never be reached, but
949       is provided just in case it is ever needed. */
950     default: {
951         /* Switch back to normal mode. */
952         telnet_server.state = STATE_NORMAL;
953         /* This state has been handled. */
954         break;
955     }
956     }
957 }
958 
959 /**
960  * Print a message to the telnet connection formatted as an error.
961  *
962  * @param message char* Pointer to the string to send
963  * @retval none
964  */
TelnetWriteErrorMessage(char * message)965 void TelnetWriteErrorMessage(char* message) {
966     if (TelnetIsConnected() == true) {
967         ClearToMessageBuffer();
968         char* character = message;
969         while (*character) {
970             character++;
971         }
972         uint16_t n = snprintf(MESSAGE_BUFFER, sizeof(MESSAGE_BUFFER),
973         ERROR_MESSAGE_HEADER, message);
974         if (n > 0) {
975             TelnetWriteString(MESSAGE_BUFFER);
976         }
977     }
978 }
979 
980 /**
981  * Print a message to the telnet connection formatted as a status.
982  *
983  * @param message char* Pointer to the string to send
984  * @retval none
985  */
TelnetWriteStatusMessage(char * message)986 void TelnetWriteStatusMessage(char* message) {
987     if (TelnetIsConnected() == true) {
988         ClearToMessageBuffer();
989         uint8_t count = 0;
990         char* character = message;
991         while (*character) {
992             ++character;
993             ++count;
994         }
995         uint16_t n = snprintf(MESSAGE_BUFFER, sizeof(MESSAGE_BUFFER),
996         STATUS_MESSAGE_HEADER, message);
997         if (n > 0) {
998             TelnetWriteString(MESSAGE_BUFFER);
999         }
1000     }
1001 }
1002 
1003 /**
1004  * Print a message to the telnet connection formatted as a debug.
1005  *
1006  * @param message char* Pointer to the string to send
1007  * @retval none
1008  */
TelnetWriteDebugMessage(char * message)1009 void TelnetWriteDebugMessage(char* message) {
1010     if (TelnetIsConnected() == true) {
1011         ClearToMessageBuffer();
1012         uint8_t count = 0;
1013         char* character = message;
1014         while (*character) {
1015             ++character;
1016             ++count;
1017         }
1018         uint16_t n = snprintf(MESSAGE_BUFFER, sizeof(MESSAGE_BUFFER),
1019         DEBUG_MESSAGE_HEADER, message);
1020         if (n > 0) {
1021             TelnetWriteString(MESSAGE_BUFFER);
1022         }
1023     }
1024 }
1025 
1026 /**
1027  * Print a message to the telnet connection formatted as a command data.
1028  *
1029  * @param message char* Pointer to the string to send
1030  * @retval none
1031  */
TelnetWriteCommandDataMessage(char * message)1032 void TelnetWriteCommandDataMessage(char* message) {
1033     if (TelnetIsConnected() == true) {
1034         ClearToMessageBuffer();
1035         uint8_t count = 0;
1036         char* character = message;
1037         while (*character) {
1038             ++character;
1039             ++count;
1040         }
1041         uint16_t n = snprintf(MESSAGE_BUFFER, sizeof(MESSAGE_BUFFER),
1042         COMMAND_DATA_MESSAGE_HEADER, message);
1043         if (n > 0) {
1044             TelnetWriteString(MESSAGE_BUFFER);
1045         }
1046     }
1047 }
1048