10d163575Sopenharmony_ci/* 20d163575Sopenharmony_ci * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. 30d163575Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. 40d163575Sopenharmony_ci * 50d163575Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification, 60d163575Sopenharmony_ci * are permitted provided that the following conditions are met: 70d163575Sopenharmony_ci * 80d163575Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, this list of 90d163575Sopenharmony_ci * conditions and the following disclaimer. 100d163575Sopenharmony_ci * 110d163575Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, this list 120d163575Sopenharmony_ci * of conditions and the following disclaimer in the documentation and/or other materials 130d163575Sopenharmony_ci * provided with the distribution. 140d163575Sopenharmony_ci * 150d163575Sopenharmony_ci * 3. Neither the name of the copyright holder nor the names of its contributors may be used 160d163575Sopenharmony_ci * to endorse or promote products derived from this software without specific prior written 170d163575Sopenharmony_ci * permission. 180d163575Sopenharmony_ci * 190d163575Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 200d163575Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 210d163575Sopenharmony_ci * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 220d163575Sopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 230d163575Sopenharmony_ci * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 240d163575Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 250d163575Sopenharmony_ci * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 260d163575Sopenharmony_ci * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 270d163575Sopenharmony_ci * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 280d163575Sopenharmony_ci * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 290d163575Sopenharmony_ci * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 300d163575Sopenharmony_ci */ 310d163575Sopenharmony_ci 320d163575Sopenharmony_ci#include "telnet_loop.h" 330d163575Sopenharmony_ci#ifdef LOSCFG_NET_TELNET 340d163575Sopenharmony_ci#include "stdio.h" 350d163575Sopenharmony_ci#include "stdlib.h" 360d163575Sopenharmony_ci#include "unistd.h" 370d163575Sopenharmony_ci#include "pthread.h" 380d163575Sopenharmony_ci#include "netinet/tcp.h" 390d163575Sopenharmony_ci#include "sys/select.h" 400d163575Sopenharmony_ci#include "sys/types.h" 410d163575Sopenharmony_ci#include "sys/prctl.h" 420d163575Sopenharmony_ci 430d163575Sopenharmony_ci#include "los_task.h" 440d163575Sopenharmony_ci#include "linux/atomic.h" 450d163575Sopenharmony_ci#include "lwip/sockets.h" 460d163575Sopenharmony_ci#include "lwip/inet.h" 470d163575Sopenharmony_ci#include "lwip/netif.h" 480d163575Sopenharmony_ci#include "console.h" 490d163575Sopenharmony_ci#ifdef LOSCFG_SHELL 500d163575Sopenharmony_ci#include "shell.h" 510d163575Sopenharmony_ci#include "shcmd.h" 520d163575Sopenharmony_ci#endif 530d163575Sopenharmony_ci#include "telnet_pri.h" 540d163575Sopenharmony_ci#include "telnet_dev.h" 550d163575Sopenharmony_ci 560d163575Sopenharmony_ci 570d163575Sopenharmony_ci/* TELNET commands in RFC854 */ 580d163575Sopenharmony_ci#define TELNET_SB 250 /* Indicates that what follows is subnegotiation of the indicated option */ 590d163575Sopenharmony_ci#define TELNET_WILL 251 /* Indicates the desire to perform the indicated option */ 600d163575Sopenharmony_ci#define TELNET_DO 253 /* Indicates the request for the other party to perform the indicated option */ 610d163575Sopenharmony_ci#define TELNET_IAC 255 /* Interpret as Command */ 620d163575Sopenharmony_ci 630d163575Sopenharmony_ci/* telnet options in IANA */ 640d163575Sopenharmony_ci#define TELNET_ECHO 1 /* Echo */ 650d163575Sopenharmony_ci#define TELNET_SGA 3 /* Suppress Go Ahead */ 660d163575Sopenharmony_ci#define TELNET_NAWS 31 /* Negotiate About Window Size */ 670d163575Sopenharmony_ci#define TELNET_NOP 0xf1 /* Unassigned in IANA, putty use this to keepalive */ 680d163575Sopenharmony_ci 690d163575Sopenharmony_ci#define LEN_IAC_CMD 2 /* Only 2 char: |IAC|cmd| */ 700d163575Sopenharmony_ci#define LEN_IAC_CMD_OPT 3 /* Only 3 char: |IAC|cmd|option| */ 710d163575Sopenharmony_ci#define LEN_IAC_CMD_NAWS 9 /* NAWS: |IAC|SB|NAWS|x1|x2|x3|x4|IAC|SE| */ 720d163575Sopenharmony_ci 730d163575Sopenharmony_ci/* server/client settings */ 740d163575Sopenharmony_ci#define TELNET_TASK_STACK_SIZE 0x2000 750d163575Sopenharmony_ci#define TELNET_TASK_PRIORITY 9 760d163575Sopenharmony_ci 770d163575Sopenharmony_ci/* server settings */ 780d163575Sopenharmony_ci#define TELNET_LISTEN_BACKLOG 128 790d163575Sopenharmony_ci#define TELNET_ACCEPT_INTERVAL 200 800d163575Sopenharmony_ci 810d163575Sopenharmony_ci/* client settings */ 820d163575Sopenharmony_ci#define TELNET_CLIENT_POLL_TIMEOUT 2000 830d163575Sopenharmony_ci#define TELNET_CLIENT_READ_BUF_SIZE 256 840d163575Sopenharmony_ci#define TELNET_CLIENT_READ_FILTER_BUF_SIZE (8 * 1024) 850d163575Sopenharmony_ci 860d163575Sopenharmony_ci/* limitation: only support 1 telnet client connection */ 870d163575Sopenharmony_ciSTATIC volatile INT32 g_telnetClientFd = -1; /* client fd */ 880d163575Sopenharmony_ci 890d163575Sopenharmony_ci/* limitation: only support 1 telnet server */ 900d163575Sopenharmony_ciSTATIC volatile INT32 g_telnetListenFd = -1; /* listen fd of telnetd */ 910d163575Sopenharmony_ci 920d163575Sopenharmony_ci/* each bit for a client connection, although only support 1 connection for now */ 930d163575Sopenharmony_ciSTATIC volatile UINT32 g_telnetMask = 0; 940d163575Sopenharmony_ci/* taskID of telnetd */ 950d163575Sopenharmony_ciSTATIC atomic_t g_telnetTaskId = 0; 960d163575Sopenharmony_ci/* protect listenFd, clientFd etc. */ 970d163575Sopenharmony_cipthread_mutex_t g_telnetMutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; 980d163575Sopenharmony_ci 990d163575Sopenharmony_ciVOID TelnetLock(VOID) 1000d163575Sopenharmony_ci{ 1010d163575Sopenharmony_ci (VOID)pthread_mutex_lock(&g_telnetMutex); 1020d163575Sopenharmony_ci} 1030d163575Sopenharmony_ci 1040d163575Sopenharmony_ciVOID TelnetUnlock(VOID) 1050d163575Sopenharmony_ci{ 1060d163575Sopenharmony_ci (VOID)pthread_mutex_unlock(&g_telnetMutex); 1070d163575Sopenharmony_ci} 1080d163575Sopenharmony_ci 1090d163575Sopenharmony_ci/* filter out iacs from client stream */ 1100d163575Sopenharmony_ciSTATIC UINT8 *ReadFilter(const UINT8 *src, UINT32 srcLen, UINT32 *dstLen) 1110d163575Sopenharmony_ci{ 1120d163575Sopenharmony_ci STATIC UINT8 buf[TELNET_CLIENT_READ_FILTER_BUF_SIZE]; 1130d163575Sopenharmony_ci UINT8 *dst = buf; 1140d163575Sopenharmony_ci UINT32 left = srcLen; 1150d163575Sopenharmony_ci 1160d163575Sopenharmony_ci while (left > 0) { 1170d163575Sopenharmony_ci if (*src != TELNET_IAC) { 1180d163575Sopenharmony_ci *dst = *src; 1190d163575Sopenharmony_ci dst++; 1200d163575Sopenharmony_ci src++; 1210d163575Sopenharmony_ci left--; 1220d163575Sopenharmony_ci continue; 1230d163575Sopenharmony_ci } 1240d163575Sopenharmony_ci 1250d163575Sopenharmony_ci /* 1260d163575Sopenharmony_ci * if starting with IAC, filter out IAC as following 1270d163575Sopenharmony_ci * |IAC| --> skip 1280d163575Sopenharmony_ci * |IAC|NOP|... --> ... : skip for putty keepalive etc. 1290d163575Sopenharmony_ci * |IAC|x| --> skip 1300d163575Sopenharmony_ci * |IAC|IAC|x|... --> |IAC|... : skip for literal cmds 1310d163575Sopenharmony_ci * |IAC|SB|NAWS|x1|x2|x3|x4|IAC|SE|... --> ... : skip NAWS(unsupported) 1320d163575Sopenharmony_ci * |IAC|x|x|... --> ... : skip unsupported IAC 1330d163575Sopenharmony_ci */ 1340d163575Sopenharmony_ci if (left == 1) { 1350d163575Sopenharmony_ci break; 1360d163575Sopenharmony_ci } 1370d163575Sopenharmony_ci /* left no less than 2 */ 1380d163575Sopenharmony_ci if (*(src + 1) == TELNET_NOP) { 1390d163575Sopenharmony_ci src += LEN_IAC_CMD; 1400d163575Sopenharmony_ci left -= LEN_IAC_CMD; 1410d163575Sopenharmony_ci continue; 1420d163575Sopenharmony_ci } 1430d163575Sopenharmony_ci if (left == LEN_IAC_CMD) { 1440d163575Sopenharmony_ci break; 1450d163575Sopenharmony_ci } 1460d163575Sopenharmony_ci /* left no less than 3 */ 1470d163575Sopenharmony_ci if (*(src + 1) == TELNET_IAC) { 1480d163575Sopenharmony_ci *dst = TELNET_IAC; 1490d163575Sopenharmony_ci dst++; 1500d163575Sopenharmony_ci src += LEN_IAC_CMD; 1510d163575Sopenharmony_ci left -= LEN_IAC_CMD; 1520d163575Sopenharmony_ci continue; 1530d163575Sopenharmony_ci } 1540d163575Sopenharmony_ci if ((*(src + 1) == TELNET_SB) && (*(src + LEN_IAC_CMD) == TELNET_NAWS)) { 1550d163575Sopenharmony_ci if (left > LEN_IAC_CMD_NAWS) { 1560d163575Sopenharmony_ci src += LEN_IAC_CMD_NAWS; 1570d163575Sopenharmony_ci left -= LEN_IAC_CMD_NAWS; 1580d163575Sopenharmony_ci continue; 1590d163575Sopenharmony_ci } 1600d163575Sopenharmony_ci break; 1610d163575Sopenharmony_ci } 1620d163575Sopenharmony_ci src += LEN_IAC_CMD_OPT; 1630d163575Sopenharmony_ci left -= LEN_IAC_CMD_OPT; 1640d163575Sopenharmony_ci } 1650d163575Sopenharmony_ci 1660d163575Sopenharmony_ci if (dstLen != NULL) { 1670d163575Sopenharmony_ci *dstLen = dst - buf; 1680d163575Sopenharmony_ci } 1690d163575Sopenharmony_ci return buf; 1700d163575Sopenharmony_ci} 1710d163575Sopenharmony_ci 1720d163575Sopenharmony_ci/* 1730d163575Sopenharmony_ci * Description : Write data to fd. 1740d163575Sopenharmony_ci * Input : fd --- the fd to write. 1750d163575Sopenharmony_ci * : src --- data pointer. 1760d163575Sopenharmony_ci * : srcLen --- data length. 1770d163575Sopenharmony_ci * Return : length of written data. 1780d163575Sopenharmony_ci */ 1790d163575Sopenharmony_ciSTATIC ssize_t WriteToFd(INT32 fd, const CHAR *src, size_t srcLen) 1800d163575Sopenharmony_ci{ 1810d163575Sopenharmony_ci size_t sizeLeft; 1820d163575Sopenharmony_ci ssize_t sizeWritten; 1830d163575Sopenharmony_ci 1840d163575Sopenharmony_ci sizeLeft = srcLen; 1850d163575Sopenharmony_ci while (sizeLeft > 0) { 1860d163575Sopenharmony_ci sizeWritten = write(fd, src, sizeLeft); 1870d163575Sopenharmony_ci if (sizeWritten < 0) { 1880d163575Sopenharmony_ci /* last write failed */ 1890d163575Sopenharmony_ci if (sizeLeft == srcLen) { 1900d163575Sopenharmony_ci /* nothing was written in any loop */ 1910d163575Sopenharmony_ci return -1; 1920d163575Sopenharmony_ci } else { 1930d163575Sopenharmony_ci /* something was written in previous loop */ 1940d163575Sopenharmony_ci break; 1950d163575Sopenharmony_ci } 1960d163575Sopenharmony_ci } else if (sizeWritten == 0) { 1970d163575Sopenharmony_ci break; 1980d163575Sopenharmony_ci } 1990d163575Sopenharmony_ci sizeLeft -= (size_t)sizeWritten; 2000d163575Sopenharmony_ci src += sizeWritten; 2010d163575Sopenharmony_ci } 2020d163575Sopenharmony_ci 2030d163575Sopenharmony_ci return (ssize_t)(srcLen - sizeLeft); 2040d163575Sopenharmony_ci} 2050d163575Sopenharmony_ci 2060d163575Sopenharmony_ci/* Try to remove the client device if there is any client connection */ 2070d163575Sopenharmony_ciSTATIC VOID TelnetClientClose(VOID) 2080d163575Sopenharmony_ci{ 2090d163575Sopenharmony_ci /* check if there is any client connection */ 2100d163575Sopenharmony_ci if (g_telnetMask == 0) { 2110d163575Sopenharmony_ci return; 2120d163575Sopenharmony_ci } 2130d163575Sopenharmony_ci (VOID)TelnetDevDeinit(); 2140d163575Sopenharmony_ci g_telnetMask = 0; 2150d163575Sopenharmony_ci printf("telnet client disconnected.\n"); 2160d163575Sopenharmony_ci} 2170d163575Sopenharmony_ci 2180d163575Sopenharmony_ci/* Release the client and server fd */ 2190d163575Sopenharmony_ciSTATIC VOID TelnetRelease(VOID) 2200d163575Sopenharmony_ci{ 2210d163575Sopenharmony_ci if (g_telnetClientFd >= 0) { 2220d163575Sopenharmony_ci (VOID)close(g_telnetClientFd); 2230d163575Sopenharmony_ci g_telnetClientFd = -1; 2240d163575Sopenharmony_ci } 2250d163575Sopenharmony_ci 2260d163575Sopenharmony_ci if (g_telnetListenFd >= 0) { 2270d163575Sopenharmony_ci (VOID)close(g_telnetListenFd); 2280d163575Sopenharmony_ci g_telnetListenFd = -1; 2290d163575Sopenharmony_ci } 2300d163575Sopenharmony_ci} 2310d163575Sopenharmony_ci 2320d163575Sopenharmony_ci/* Stop telnet server */ 2330d163575Sopenharmony_ciSTATIC VOID TelnetdDeinit(VOID) 2340d163575Sopenharmony_ci{ 2350d163575Sopenharmony_ci if (atomic_read(&g_telnetTaskId) == 0) { 2360d163575Sopenharmony_ci PRINTK("telnet server is not running!\n"); 2370d163575Sopenharmony_ci return; 2380d163575Sopenharmony_ci } 2390d163575Sopenharmony_ci 2400d163575Sopenharmony_ci TelnetRelease(); 2410d163575Sopenharmony_ci (VOID)TelnetedUnregister(); 2420d163575Sopenharmony_ci atomic_set(&g_telnetTaskId, 0); 2430d163575Sopenharmony_ci PRINTK("telnet server closed.\n"); 2440d163575Sopenharmony_ci} 2450d163575Sopenharmony_ci 2460d163575Sopenharmony_ci/* 2470d163575Sopenharmony_ci * Description : Setup the listen fd for telnetd with specific port. 2480d163575Sopenharmony_ci * Input : port --- the port at which telnet server listens. 2490d163575Sopenharmony_ci * Return : -1 --- on error 2500d163575Sopenharmony_ci * : non-negative --- listen fd if OK 2510d163575Sopenharmony_ci */ 2520d163575Sopenharmony_ciSTATIC INT32 TelnetdInit(UINT16 port) 2530d163575Sopenharmony_ci{ 2540d163575Sopenharmony_ci INT32 listenFd; 2550d163575Sopenharmony_ci INT32 reuseAddr = 1; 2560d163575Sopenharmony_ci struct sockaddr_in inTelnetAddr; 2570d163575Sopenharmony_ci 2580d163575Sopenharmony_ci listenFd = socket(AF_INET, SOCK_STREAM, 0); 2590d163575Sopenharmony_ci if (listenFd == -1) { 2600d163575Sopenharmony_ci PRINT_ERR("TelnetdInit : socket error.\n"); 2610d163575Sopenharmony_ci goto ERR_OUT; 2620d163575Sopenharmony_ci } 2630d163575Sopenharmony_ci 2640d163575Sopenharmony_ci /* reuse listen port */ 2650d163575Sopenharmony_ci if (setsockopt(listenFd, SOL_SOCKET, SO_REUSEADDR, &reuseAddr, sizeof(reuseAddr)) != 0) { 2660d163575Sopenharmony_ci PRINT_ERR("TelnetdInit : setsockopt REUSEADDR error.\n"); 2670d163575Sopenharmony_ci goto ERR_CLOSE_FD; 2680d163575Sopenharmony_ci } 2690d163575Sopenharmony_ci 2700d163575Sopenharmony_ci (VOID)memset_s(&inTelnetAddr, sizeof(struct sockaddr_in), 0, sizeof(struct sockaddr_in)); 2710d163575Sopenharmony_ci inTelnetAddr.sin_family = AF_INET; 2720d163575Sopenharmony_ci inTelnetAddr.sin_addr.s_addr = INADDR_ANY; 2730d163575Sopenharmony_ci inTelnetAddr.sin_port = htons(port); 2740d163575Sopenharmony_ci 2750d163575Sopenharmony_ci if (bind(listenFd, (const struct sockaddr *)&inTelnetAddr, sizeof(struct sockaddr_in)) == -1) { 2760d163575Sopenharmony_ci PRINT_ERR("TelnetdInit : bind error.\n"); 2770d163575Sopenharmony_ci goto ERR_CLOSE_FD; 2780d163575Sopenharmony_ci } 2790d163575Sopenharmony_ci 2800d163575Sopenharmony_ci if (listen(listenFd, TELNET_LISTEN_BACKLOG) == -1) { 2810d163575Sopenharmony_ci PRINT_ERR("TelnetdInit : listen error.\n"); 2820d163575Sopenharmony_ci goto ERR_CLOSE_FD; 2830d163575Sopenharmony_ci } 2840d163575Sopenharmony_ci 2850d163575Sopenharmony_ci return listenFd; 2860d163575Sopenharmony_ci 2870d163575Sopenharmony_ciERR_CLOSE_FD: 2880d163575Sopenharmony_ci (VOID)close(listenFd); 2890d163575Sopenharmony_ciERR_OUT: 2900d163575Sopenharmony_ci return -1; 2910d163575Sopenharmony_ci} 2920d163575Sopenharmony_ci 2930d163575Sopenharmony_ciSTATIC INT32 TelnetClientPrepare(INT32 clientFd) 2940d163575Sopenharmony_ci{ 2950d163575Sopenharmony_ci INT32 keepAlive = TELNET_KEEPALIVE; 2960d163575Sopenharmony_ci INT32 keepIdle = TELNET_KEEPIDLE; 2970d163575Sopenharmony_ci INT32 keepInterval = TELNET_KEEPINTV; 2980d163575Sopenharmony_ci INT32 keepCnt = TELNET_KEEPCNT; 2990d163575Sopenharmony_ci const UINT8 doEcho[] = { TELNET_IAC, TELNET_DO, TELNET_ECHO }; 3000d163575Sopenharmony_ci const UINT8 doNaws[] = { TELNET_IAC, TELNET_DO, TELNET_NAWS }; 3010d163575Sopenharmony_ci const UINT8 willEcho[] = { TELNET_IAC, TELNET_WILL, TELNET_ECHO }; 3020d163575Sopenharmony_ci const UINT8 willSga[] = { TELNET_IAC, TELNET_WILL, TELNET_SGA }; 3030d163575Sopenharmony_ci 3040d163575Sopenharmony_ci if (g_telnetListenFd == -1) { 3050d163575Sopenharmony_ci return -1; 3060d163575Sopenharmony_ci } 3070d163575Sopenharmony_ci g_telnetClientFd = clientFd; 3080d163575Sopenharmony_ci if (TelnetDevInit(clientFd) != 0) { 3090d163575Sopenharmony_ci g_telnetClientFd = -1; 3100d163575Sopenharmony_ci return -1; 3110d163575Sopenharmony_ci } 3120d163575Sopenharmony_ci g_telnetMask = 1; 3130d163575Sopenharmony_ci 3140d163575Sopenharmony_ci /* negotiate with client */ 3150d163575Sopenharmony_ci (VOID)WriteToFd(clientFd, (CHAR *)doEcho, sizeof(doEcho)); 3160d163575Sopenharmony_ci (VOID)WriteToFd(clientFd, (CHAR *)doNaws, sizeof(doNaws)); 3170d163575Sopenharmony_ci (VOID)WriteToFd(clientFd, (CHAR *)willEcho, sizeof(willEcho)); 3180d163575Sopenharmony_ci (VOID)WriteToFd(clientFd, (CHAR *)willSga, sizeof(willSga)); 3190d163575Sopenharmony_ci 3200d163575Sopenharmony_ci /* enable TCP keepalive to check whether telnet link is alive */ 3210d163575Sopenharmony_ci if (setsockopt(clientFd, SOL_SOCKET, SO_KEEPALIVE, (VOID *)&keepAlive, sizeof(keepAlive)) < 0) { 3220d163575Sopenharmony_ci PRINT_ERR("telnet setsockopt SO_KEEPALIVE error.\n"); 3230d163575Sopenharmony_ci } 3240d163575Sopenharmony_ci if (setsockopt(clientFd, IPPROTO_TCP, TCP_KEEPIDLE, (VOID *)&keepIdle, sizeof(keepIdle)) < 0) { 3250d163575Sopenharmony_ci PRINT_ERR("telnet setsockopt TCP_KEEPIDLE error.\n"); 3260d163575Sopenharmony_ci } 3270d163575Sopenharmony_ci if (setsockopt(clientFd, IPPROTO_TCP, TCP_KEEPINTVL, (VOID *)&keepInterval, sizeof(keepInterval)) < 0) { 3280d163575Sopenharmony_ci PRINT_ERR("telnet setsockopt TCP_KEEPINTVL error.\n"); 3290d163575Sopenharmony_ci } 3300d163575Sopenharmony_ci if (setsockopt(clientFd, IPPROTO_TCP, TCP_KEEPCNT, (VOID *)&keepCnt, sizeof(keepCnt)) < 0) { 3310d163575Sopenharmony_ci PRINT_ERR("telnet setsockopt TCP_KEEPCNT error.\n"); 3320d163575Sopenharmony_ci } 3330d163575Sopenharmony_ci return 0; 3340d163575Sopenharmony_ci} 3350d163575Sopenharmony_ci 3360d163575Sopenharmony_ciSTATIC VOID *TelnetClientLoop(VOID *arg) 3370d163575Sopenharmony_ci{ 3380d163575Sopenharmony_ci struct pollfd pollFd; 3390d163575Sopenharmony_ci INT32 ret; 3400d163575Sopenharmony_ci INT32 nRead; 3410d163575Sopenharmony_ci UINT32 len; 3420d163575Sopenharmony_ci UINT8 buf[TELNET_CLIENT_READ_BUF_SIZE]; 3430d163575Sopenharmony_ci UINT8 *cmdBuf = NULL; 3440d163575Sopenharmony_ci INT32 clientFd = (INT32)(UINTPTR)arg; 3450d163575Sopenharmony_ci 3460d163575Sopenharmony_ci (VOID)prctl(PR_SET_NAME, "TelnetClientLoop", 0, 0, 0); 3470d163575Sopenharmony_ci TelnetLock(); 3480d163575Sopenharmony_ci if (TelnetClientPrepare(clientFd) != 0) { 3490d163575Sopenharmony_ci TelnetUnlock(); 3500d163575Sopenharmony_ci (VOID)close(clientFd); 3510d163575Sopenharmony_ci return NULL; 3520d163575Sopenharmony_ci } 3530d163575Sopenharmony_ci TelnetUnlock(); 3540d163575Sopenharmony_ci 3550d163575Sopenharmony_ci while (1) { 3560d163575Sopenharmony_ci pollFd.fd = clientFd; 3570d163575Sopenharmony_ci pollFd.events = POLLIN | POLLRDHUP; 3580d163575Sopenharmony_ci pollFd.revents = 0; 3590d163575Sopenharmony_ci 3600d163575Sopenharmony_ci ret = poll(&pollFd, 1, TELNET_CLIENT_POLL_TIMEOUT); 3610d163575Sopenharmony_ci if (ret < 0) { 3620d163575Sopenharmony_ci break; 3630d163575Sopenharmony_ci } 3640d163575Sopenharmony_ci if (ret == 0) { 3650d163575Sopenharmony_ci continue; 3660d163575Sopenharmony_ci } 3670d163575Sopenharmony_ci /* connection reset, maybe keepalive failed or reset by peer */ 3680d163575Sopenharmony_ci if ((UINT16)pollFd.revents & (POLLERR | POLLHUP | POLLRDHUP)) { 3690d163575Sopenharmony_ci break; 3700d163575Sopenharmony_ci } 3710d163575Sopenharmony_ci 3720d163575Sopenharmony_ci if ((UINT16)pollFd.revents & POLLIN) { 3730d163575Sopenharmony_ci nRead = read(clientFd, buf, sizeof(buf)); 3740d163575Sopenharmony_ci if (nRead <= 0) { 3750d163575Sopenharmony_ci /* telnet client shutdown */ 3760d163575Sopenharmony_ci break; 3770d163575Sopenharmony_ci } 3780d163575Sopenharmony_ci cmdBuf = ReadFilter(buf, (UINT32)nRead, &len); 3790d163575Sopenharmony_ci if (len > 0) { 3800d163575Sopenharmony_ci (VOID)TelnetTx((CHAR *)cmdBuf, len); 3810d163575Sopenharmony_ci } 3820d163575Sopenharmony_ci } 3830d163575Sopenharmony_ci } 3840d163575Sopenharmony_ci TelnetLock(); 3850d163575Sopenharmony_ci TelnetClientClose(); 3860d163575Sopenharmony_ci (VOID)close(clientFd); 3870d163575Sopenharmony_ci clientFd = -1; 3880d163575Sopenharmony_ci g_telnetClientFd = -1; 3890d163575Sopenharmony_ci TelnetUnlock(); 3900d163575Sopenharmony_ci return NULL; 3910d163575Sopenharmony_ci} 3920d163575Sopenharmony_ci 3930d163575Sopenharmony_ciSTATIC VOID TelnetClientTaskAttr(pthread_attr_t *threadAttr) 3940d163575Sopenharmony_ci{ 3950d163575Sopenharmony_ci (VOID)pthread_attr_init(threadAttr); 3960d163575Sopenharmony_ci threadAttr->inheritsched = PTHREAD_EXPLICIT_SCHED; 3970d163575Sopenharmony_ci threadAttr->schedparam.sched_priority = TELNET_TASK_PRIORITY; 3980d163575Sopenharmony_ci threadAttr->detachstate = PTHREAD_CREATE_DETACHED; 3990d163575Sopenharmony_ci (VOID)pthread_attr_setstacksize(threadAttr, TELNET_TASK_STACK_SIZE); 4000d163575Sopenharmony_ci} 4010d163575Sopenharmony_ci 4020d163575Sopenharmony_ci/* 4030d163575Sopenharmony_ci * Description : Handle the client connection request. 4040d163575Sopenharmony_ci * Create a client connection if permitted. 4050d163575Sopenharmony_ci * Return : 0 --- please continue the server accept loop 4060d163575Sopenharmony_ci * : -1 --- please stop the server accept loop. 4070d163575Sopenharmony_ci */ 4080d163575Sopenharmony_ciSTATIC INT32 TelnetdAcceptClient(INT32 clientFd, const struct sockaddr_in *inTelnetAddr) 4090d163575Sopenharmony_ci{ 4100d163575Sopenharmony_ci INT32 ret = 0; 4110d163575Sopenharmony_ci pthread_t tmp; 4120d163575Sopenharmony_ci pthread_attr_t useAttr; 4130d163575Sopenharmony_ci 4140d163575Sopenharmony_ci TelnetClientTaskAttr(&useAttr); 4150d163575Sopenharmony_ci 4160d163575Sopenharmony_ci if (clientFd < 0) { 4170d163575Sopenharmony_ci ret = -1; 4180d163575Sopenharmony_ci goto ERROUT; 4190d163575Sopenharmony_ci } 4200d163575Sopenharmony_ci 4210d163575Sopenharmony_ci TelnetLock(); 4220d163575Sopenharmony_ci 4230d163575Sopenharmony_ci if (g_telnetListenFd == -1) { 4240d163575Sopenharmony_ci /* server already has been closed, so quit this task now */ 4250d163575Sopenharmony_ci ret = -1; 4260d163575Sopenharmony_ci goto ERROUT_UNLOCK; 4270d163575Sopenharmony_ci } 4280d163575Sopenharmony_ci 4290d163575Sopenharmony_ci if (g_telnetClientFd >= 0) { 4300d163575Sopenharmony_ci /* already connected and support only one */ 4310d163575Sopenharmony_ci goto ERROUT_UNLOCK; 4320d163575Sopenharmony_ci } 4330d163575Sopenharmony_ci 4340d163575Sopenharmony_ci g_telnetClientFd = clientFd; 4350d163575Sopenharmony_ci 4360d163575Sopenharmony_ci if (pthread_create(&tmp, &useAttr, TelnetClientLoop, (VOID *)(UINTPTR)clientFd) != 0) { 4370d163575Sopenharmony_ci PRINT_ERR("Failed to create client handle task\n"); 4380d163575Sopenharmony_ci g_telnetClientFd = -1; 4390d163575Sopenharmony_ci goto ERROUT_UNLOCK; 4400d163575Sopenharmony_ci } 4410d163575Sopenharmony_ci TelnetUnlock(); 4420d163575Sopenharmony_ci return ret; 4430d163575Sopenharmony_ci 4440d163575Sopenharmony_ciERROUT_UNLOCK: 4450d163575Sopenharmony_ci (VOID)close(clientFd); 4460d163575Sopenharmony_ci clientFd = -1; 4470d163575Sopenharmony_ci TelnetUnlock(); 4480d163575Sopenharmony_ciERROUT: 4490d163575Sopenharmony_ci return ret; 4500d163575Sopenharmony_ci} 4510d163575Sopenharmony_ci 4520d163575Sopenharmony_ci/* 4530d163575Sopenharmony_ci * Waiting for client's connection. Only allow 1 connection, and others will be discarded. 4540d163575Sopenharmony_ci */ 4550d163575Sopenharmony_ciSTATIC VOID TelnetdAcceptLoop(INT32 listenFd) 4560d163575Sopenharmony_ci{ 4570d163575Sopenharmony_ci INT32 clientFd = -1; 4580d163575Sopenharmony_ci struct sockaddr_in inTelnetAddr; 4590d163575Sopenharmony_ci INT32 len = sizeof(inTelnetAddr); 4600d163575Sopenharmony_ci 4610d163575Sopenharmony_ci TelnetLock(); 4620d163575Sopenharmony_ci g_telnetListenFd = listenFd; 4630d163575Sopenharmony_ci 4640d163575Sopenharmony_ci while (g_telnetListenFd >= 0) { 4650d163575Sopenharmony_ci TelnetUnlock(); 4660d163575Sopenharmony_ci 4670d163575Sopenharmony_ci (VOID)memset_s(&inTelnetAddr, sizeof(inTelnetAddr), 0, sizeof(inTelnetAddr)); 4680d163575Sopenharmony_ci clientFd = accept(listenFd, (struct sockaddr *)&inTelnetAddr, (socklen_t *)&len); 4690d163575Sopenharmony_ci if (TelnetdAcceptClient(clientFd, &inTelnetAddr) == 0) { 4700d163575Sopenharmony_ci /* 4710d163575Sopenharmony_ci * Sleep sometime before next loop: mostly we already have one connection here, 4720d163575Sopenharmony_ci * and the next connection will be declined. So don't waste our cpu. 4730d163575Sopenharmony_ci */ 4740d163575Sopenharmony_ci LOS_Msleep(TELNET_ACCEPT_INTERVAL); 4750d163575Sopenharmony_ci } else { 4760d163575Sopenharmony_ci return; 4770d163575Sopenharmony_ci } 4780d163575Sopenharmony_ci TelnetLock(); 4790d163575Sopenharmony_ci } 4800d163575Sopenharmony_ci TelnetUnlock(); 4810d163575Sopenharmony_ci} 4820d163575Sopenharmony_ci 4830d163575Sopenharmony_ciSTATIC INT32 TelnetdMain(VOID) 4840d163575Sopenharmony_ci{ 4850d163575Sopenharmony_ci INT32 sock; 4860d163575Sopenharmony_ci INT32 ret; 4870d163575Sopenharmony_ci 4880d163575Sopenharmony_ci sock = TelnetdInit(TELNETD_PORT); 4890d163575Sopenharmony_ci if (sock == -1) { 4900d163575Sopenharmony_ci PRINT_ERR("telnet init error.\n"); 4910d163575Sopenharmony_ci return -1; 4920d163575Sopenharmony_ci } 4930d163575Sopenharmony_ci 4940d163575Sopenharmony_ci TelnetLock(); 4950d163575Sopenharmony_ci ret = TelnetedRegister(); 4960d163575Sopenharmony_ci TelnetUnlock(); 4970d163575Sopenharmony_ci 4980d163575Sopenharmony_ci if (ret != 0) { 4990d163575Sopenharmony_ci PRINT_ERR("telnet register error.\n"); 5000d163575Sopenharmony_ci (VOID)close(sock); 5010d163575Sopenharmony_ci return -1; 5020d163575Sopenharmony_ci } 5030d163575Sopenharmony_ci 5040d163575Sopenharmony_ci PRINTK("start telnet server successfully, waiting for connection.\n"); 5050d163575Sopenharmony_ci TelnetdAcceptLoop(sock); 5060d163575Sopenharmony_ci return 0; 5070d163575Sopenharmony_ci} 5080d163575Sopenharmony_ci 5090d163575Sopenharmony_ci/* 5100d163575Sopenharmony_ci * Try to create telnetd task. 5110d163575Sopenharmony_ci */ 5120d163575Sopenharmony_ciSTATIC VOID TelnetdTaskInit(VOID) 5130d163575Sopenharmony_ci{ 5140d163575Sopenharmony_ci UINT32 ret; 5150d163575Sopenharmony_ci TSK_INIT_PARAM_S initParam = {0}; 5160d163575Sopenharmony_ci 5170d163575Sopenharmony_ci initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)TelnetdMain; 5180d163575Sopenharmony_ci initParam.uwStackSize = TELNET_TASK_STACK_SIZE; 5190d163575Sopenharmony_ci initParam.pcName = "TelnetServer"; 5200d163575Sopenharmony_ci initParam.usTaskPrio = TELNET_TASK_PRIORITY; 5210d163575Sopenharmony_ci initParam.uwResved = LOS_TASK_STATUS_DETACHED; 5220d163575Sopenharmony_ci 5230d163575Sopenharmony_ci if (atomic_read(&g_telnetTaskId) != 0) { 5240d163575Sopenharmony_ci PRINT_ERR("telnet server is already running!\n"); 5250d163575Sopenharmony_ci return; 5260d163575Sopenharmony_ci } 5270d163575Sopenharmony_ci 5280d163575Sopenharmony_ci ret = LOS_TaskCreate((UINT32 *)&g_telnetTaskId, &initParam); 5290d163575Sopenharmony_ci if (ret != LOS_OK) { 5300d163575Sopenharmony_ci PRINT_ERR("failed to create telnet server task!\n"); 5310d163575Sopenharmony_ci } 5320d163575Sopenharmony_ci} 5330d163575Sopenharmony_ci 5340d163575Sopenharmony_ci/* 5350d163575Sopenharmony_ci * Try to destroy telnetd task. 5360d163575Sopenharmony_ci */ 5370d163575Sopenharmony_ciSTATIC VOID TelnetdTaskDeinit(VOID) 5380d163575Sopenharmony_ci{ 5390d163575Sopenharmony_ci if (atomic_read(&g_telnetTaskId) == 0) { 5400d163575Sopenharmony_ci PRINTK("telnet server is not running, please start up telnet server first.\n"); 5410d163575Sopenharmony_ci return; 5420d163575Sopenharmony_ci } 5430d163575Sopenharmony_ci 5440d163575Sopenharmony_ci TelnetLock(); 5450d163575Sopenharmony_ci TelnetClientClose(); 5460d163575Sopenharmony_ci TelnetdDeinit(); 5470d163575Sopenharmony_ci TelnetUnlock(); 5480d163575Sopenharmony_ci} 5490d163575Sopenharmony_ci 5500d163575Sopenharmony_ciSTATIC VOID TelnetUsage(VOID) 5510d163575Sopenharmony_ci{ 5520d163575Sopenharmony_ci PRINTK("Usage: telnet [OPTION]...\n"); 5530d163575Sopenharmony_ci PRINTK("Start or close telnet server.\n\n"); 5540d163575Sopenharmony_ci PRINTK(" on Init the telnet server\n"); 5550d163575Sopenharmony_ci PRINTK(" off Deinit the telnet server\n"); 5560d163575Sopenharmony_ci} 5570d163575Sopenharmony_ci 5580d163575Sopenharmony_ciINT32 TelnetCmd(UINT32 argc, const CHAR **argv) 5590d163575Sopenharmony_ci{ 5600d163575Sopenharmony_ci if (argc != 1) { 5610d163575Sopenharmony_ci TelnetUsage(); 5620d163575Sopenharmony_ci return 0; 5630d163575Sopenharmony_ci } 5640d163575Sopenharmony_ci 5650d163575Sopenharmony_ci if (strcmp(argv[0], "on") == 0) { 5660d163575Sopenharmony_ci /* telnet on: try to start telnet server task */ 5670d163575Sopenharmony_ci TelnetdTaskInit(); 5680d163575Sopenharmony_ci return 0; 5690d163575Sopenharmony_ci } 5700d163575Sopenharmony_ci if (strcmp(argv[0], "off") == 0) { 5710d163575Sopenharmony_ci /* telnet off: try to stop clients, then stop server task */ 5720d163575Sopenharmony_ci TelnetdTaskDeinit(); 5730d163575Sopenharmony_ci return 0; 5740d163575Sopenharmony_ci } 5750d163575Sopenharmony_ci 5760d163575Sopenharmony_ci TelnetUsage(); 5770d163575Sopenharmony_ci return 0; 5780d163575Sopenharmony_ci} 5790d163575Sopenharmony_ci 5800d163575Sopenharmony_ci#ifdef LOSCFG_SHELL_CMD_DEBUG 5810d163575Sopenharmony_ciSHELLCMD_ENTRY(telnet_shellcmd, CMD_TYPE_EX, "telnet", 1, (CmdCallBackFunc)TelnetCmd); 5820d163575Sopenharmony_ci#endif /* LOSCFG_SHELL_CMD_DEBUG */ 5830d163575Sopenharmony_ci#endif 5840d163575Sopenharmony_ci 585