• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3  * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this list of
9  *    conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12  *    of conditions and the following disclaimer in the documentation and/or other materials
13  *    provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16  *    to endorse or promote products derived from this software without specific prior written
17  *    permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "telnet_dev.h"
33 #ifdef LOSCFG_NET_TELNET
34 #include "unistd.h"
35 #include "stdlib.h"
36 #include "sys/ioctl.h"
37 #include "sys/types.h"
38 #include "pthread.h"
39 
40 #include "los_printf.h"
41 #ifdef LOSCFG_BASE_CORE_SWTMR_ENABLE
42 #include "los_swtmr_pri.h"
43 #endif
44 #include "los_sched_pri.h"
45 #include "console.h"
46 #include "lwip/opt.h"
47 #include "lwip/sockets.h"
48 #include "telnet_pri.h"
49 
50 #include "fs/driver.h"
51 
52 /* event: there are more commands left in the FIFO to run */
53 #define TELNET_EVENT_MORE_CMD   0x01
54 #define TELNET_DEV_DRV_MODE     0666
55 
56 STATIC TELNET_DEV_S g_telnetDev;
57 STATIC EVENT_CB_S *g_event;
58 STATIC struct Vnode *g_currentVnode;
59 
GetTelnetDevByFile(const struct file * file,BOOL isOpenOp)60 STATIC INLINE TELNET_DEV_S *GetTelnetDevByFile(const struct file *file, BOOL isOpenOp)
61 {
62     struct Vnode *telnetInode = NULL;
63     TELNET_DEV_S *telnetDev = NULL;
64 
65     if (file == NULL) {
66         return NULL;
67     }
68     telnetInode = file->f_vnode;
69     if (telnetInode == NULL) {
70         return NULL;
71     }
72     /*
73      * Check if the f_vnode is valid here for non-open ops (open is supposed to get invalid f_vnode):
74      * when telnet is disconnected, there still may be 'TelentShellTask' tasks trying to write
75      * to the file, but the file has illegal f_vnode because the file is used by others.
76      */
77     if (!isOpenOp) {
78         if (telnetInode != g_currentVnode) {
79             return NULL;
80         }
81     }
82     telnetDev = (TELNET_DEV_S *)((struct drv_data*)telnetInode->data)->priv;
83     return telnetDev;
84 }
85 
86 /*
87  * Description : When receive user's input commands, first copy commands to the FIFO of the telnet device.
88  *               Then, notify a command resolver task (an individual shell task) to take out and run commands.
89  * Return      : -1                   --- On failure
90  *               Non-negative integer --- length of written commands
91  */
TelnetTx(const CHAR * buf,UINT32 bufLen)92 INT32 TelnetTx(const CHAR *buf, UINT32 bufLen)
93 {
94     UINT32 i;
95     TELNET_DEV_S *telnetDev = NULL;
96 
97     TelnetLock();
98 
99     telnetDev = &g_telnetDev;
100     if ((buf == NULL) || (telnetDev->cmdFifo == NULL)) {
101         TelnetUnlock();
102         return -1;
103     }
104 
105     /* size limited */
106     if (bufLen > telnetDev->cmdFifo->fifoNum) {
107         bufLen = telnetDev->cmdFifo->fifoNum;
108     }
109 
110     if (bufLen == 0) {
111         TelnetUnlock();
112         return 0;
113     }
114 
115     /* copy commands to the fifo of the telnet device */
116     for (i = 0; i < bufLen; i++) {
117         telnetDev->cmdFifo->rxBuf[telnetDev->cmdFifo->rxIndex] = *buf;
118         telnetDev->cmdFifo->rxIndex++;
119         telnetDev->cmdFifo->rxIndex %= FIFO_MAX;
120         buf++;
121     }
122     telnetDev->cmdFifo->fifoNum -= bufLen;
123 
124     if (telnetDev->eventPend) {
125         /* signal that there are some works to do */
126         (VOID)LOS_EventWrite(&telnetDev->eventTelnet, TELNET_EVENT_MORE_CMD);
127     }
128     /* notify the command resolver task */
129     notify_poll(&telnetDev->wait);
130     TelnetUnlock();
131 
132     return (INT32)bufLen;
133 }
134 
135 /*
136  * Description : When open the telnet device, init the FIFO, wait queue etc.
137  */
TelnetOpen(struct file * file)138 STATIC INT32 TelnetOpen(struct file *file)
139 {
140     struct wait_queue_head *wait = NULL;
141     TELNET_DEV_S *telnetDev = NULL;
142 
143     TelnetLock();
144 
145     telnetDev = GetTelnetDevByFile(file, TRUE);
146     if (telnetDev == NULL) {
147         TelnetUnlock();
148         return -1;
149     }
150 
151     if (telnetDev->cmdFifo == NULL) {
152         wait = &telnetDev->wait;
153         (VOID)LOS_EventInit(&telnetDev->eventTelnet);
154         g_event = &telnetDev->eventTelnet;
155         telnetDev->cmdFifo = (TELNTE_FIFO_S *)malloc(sizeof(TELNTE_FIFO_S));
156         if (telnetDev->cmdFifo == NULL) {
157             TelnetUnlock();
158             return -1;
159         }
160         (VOID)memset_s(telnetDev->cmdFifo, sizeof(TELNTE_FIFO_S), 0, sizeof(TELNTE_FIFO_S));
161         telnetDev->cmdFifo->fifoNum = FIFO_MAX;
162         LOS_ListInit(&wait->poll_queue);
163     }
164     g_currentVnode = file->f_vnode;
165     TelnetUnlock();
166     return 0;
167 }
168 
169 /*
170  * Description : When close the telnet device, free the FIFO, wait queue etc.
171  */
TelnetClose(struct file * file)172 STATIC INT32 TelnetClose(struct file *file)
173 {
174     struct wait_queue_head *wait = NULL;
175     TELNET_DEV_S *telnetDev = NULL;
176 
177     TelnetLock();
178 
179     telnetDev = GetTelnetDevByFile(file, FALSE);
180     if (telnetDev != NULL) {
181         wait = &telnetDev->wait;
182         LOS_ListDelete(&wait->poll_queue);
183         free(telnetDev->cmdFifo);
184         telnetDev->cmdFifo = NULL;
185         (VOID)LOS_EventDestroy(&telnetDev->eventTelnet);
186         g_event = NULL;
187     }
188     g_currentVnode = NULL;
189     TelnetUnlock();
190     return 0;
191 }
192 
193 /*
194  * Description : When a command resolver task tries to read the telnet device,
195  *               this method is called, and it will take out user's commands from the FIFO to run.
196  * Return      : -1                   --- On failure
197  *               Non-negative integer --- length of commands taken out from the FIFO of the telnet device.
198  */
TelnetRead(struct file * file,CHAR * buf,size_t bufLen)199 STATIC ssize_t TelnetRead(struct file *file, CHAR *buf, size_t bufLen)
200 {
201     UINT32 i;
202     TELNET_DEV_S *telnetDev = NULL;
203 
204     TelnetLock();
205 
206     telnetDev = GetTelnetDevByFile(file, FALSE);
207     if ((buf == NULL) || (telnetDev == NULL) || (telnetDev->cmdFifo == NULL)) {
208         TelnetUnlock();
209         return -1;
210     }
211 
212     if (telnetDev->eventPend) {
213         TelnetUnlock();
214         (VOID)LOS_EventRead(g_event, TELNET_EVENT_MORE_CMD, LOS_WAITMODE_OR, LOS_WAIT_FOREVER);
215         TelnetLock();
216     }
217 
218     if (bufLen > (FIFO_MAX - telnetDev->cmdFifo->fifoNum)) {
219         bufLen = FIFO_MAX - telnetDev->cmdFifo->fifoNum;
220     }
221 
222     for (i = 0; i < bufLen; i++) {
223         *buf++ = telnetDev->cmdFifo->rxBuf[telnetDev->cmdFifo->rxOutIndex++];
224         if (telnetDev->cmdFifo->rxOutIndex >= FIFO_MAX) {
225             telnetDev->cmdFifo->rxOutIndex = 0;
226         }
227     }
228     telnetDev->cmdFifo->fifoNum += bufLen;
229     /* check if no more commands left to run */
230     if (telnetDev->cmdFifo->fifoNum == FIFO_MAX) {
231         (VOID)LOS_EventClear(&telnetDev->eventTelnet, ~TELNET_EVENT_MORE_CMD);
232     }
233 
234     TelnetUnlock();
235     return (ssize_t)bufLen;
236 }
237 
238 /*
239  * Description : When a command resolver task tries to write command results to the telnet device,
240  *               just use lwIP send function to send out results.
241  * Return      : -1                   --- buffer is NULL
242  *               Non-negative integer --- length of written data, maybe 0.
243  */
TelnetWrite(struct file * file,const CHAR * buf,const size_t bufLen)244 STATIC ssize_t TelnetWrite(struct file *file, const CHAR *buf, const size_t bufLen)
245 {
246     INT32 ret = 0;
247     TELNET_DEV_S *telnetDev = NULL;
248 
249     TelnetLock();
250 
251     telnetDev = GetTelnetDevByFile(file, FALSE);
252     if ((buf == NULL) || (telnetDev == NULL) || (telnetDev->cmdFifo == NULL)) {
253         TelnetUnlock();
254         return -1;
255     }
256 
257     if (OS_INT_ACTIVE) {
258         TelnetUnlock();
259         return ret;
260     }
261 
262     if (!OsPreemptable()) {
263         TelnetUnlock();
264         return ret;
265     }
266 
267     if (telnetDev->clientFd != 0) {
268 #ifdef LOSCFG_BASE_CORE_SWTMR_ENABLE
269          /* DO NOT call blocking API in software timer task */
270         if (OsIsSwtmrTask(OsCurrTaskGet())) {
271             TelnetUnlock();
272             return ret;
273         }
274 #endif
275         ret = send(telnetDev->clientFd, buf, bufLen, 0);
276     }
277     TelnetUnlock();
278     return ret;
279 }
280 
TelnetIoctl(struct file * file,const INT32 cmd,unsigned long arg)281 STATIC INT32 TelnetIoctl(struct file *file, const INT32 cmd, unsigned long arg)
282 {
283     TELNET_DEV_S *telnetDev = NULL;
284 
285     TelnetLock();
286 
287     telnetDev = GetTelnetDevByFile(file, FALSE);
288     if (telnetDev == NULL) {
289         TelnetUnlock();
290         return -1;
291     }
292 
293     if (cmd == CFG_TELNET_EVENT_PEND) {
294         if (arg == 0) {
295             telnetDev->eventPend = FALSE;
296             (VOID)LOS_EventWrite(&(telnetDev->eventTelnet), TELNET_EVENT_MORE_CMD);
297             (VOID)LOS_EventClear(&(telnetDev->eventTelnet), ~TELNET_EVENT_MORE_CMD);
298         } else {
299             telnetDev->eventPend = TRUE;
300         }
301     } else if (cmd == CFG_TELNET_SET_FD) {
302         if (arg >= (FD_SETSIZE - 1)) {
303             TelnetUnlock();
304             return -1;
305         }
306         telnetDev->clientFd = (INT32)arg;
307     }
308     TelnetUnlock();
309     return 0;
310 }
311 
TelnetPoll(struct file * file,poll_table * table)312 STATIC INT32 TelnetPoll(struct file *file, poll_table *table)
313 {
314     TELNET_DEV_S *telnetDev = NULL;
315 
316     TelnetLock();
317 
318     telnetDev = GetTelnetDevByFile(file, FALSE);
319     if ((telnetDev == NULL) || (telnetDev->cmdFifo == NULL)) {
320         TelnetUnlock();
321         return -1;
322     }
323 
324     poll_wait(file, &telnetDev->wait, table);
325 
326     /* check if there are some commands to run */
327     if (telnetDev->cmdFifo->fifoNum != FIFO_MAX) {
328         TelnetUnlock();
329         return POLLIN | POLLRDNORM;
330     }
331     TelnetUnlock();
332     return 0;
333 }
334 
335 STATIC const struct file_operations_vfs g_telnetOps = {
336     TelnetOpen,
337     TelnetClose,
338     TelnetRead,
339     TelnetWrite,
340     NULL,
341     TelnetIoctl,
342     NULL,
343 #ifndef CONFIG_DISABLE_POLL
344     TelnetPoll,
345 #endif
346     NULL,
347 };
348 
349 /* Once the telnet server stopped, remove the telnet device file. */
TelnetedUnregister(VOID)350 INT32 TelnetedUnregister(VOID)
351 {
352     free(g_telnetDev.cmdFifo);
353     g_telnetDev.cmdFifo = NULL;
354     (VOID)unregister_driver(TELNET);
355 
356     return 0;
357 }
358 
359 /* Once the telnet server started, setup the telnet device file. */
TelnetedRegister(VOID)360 INT32 TelnetedRegister(VOID)
361 {
362     INT32 ret;
363 
364     g_telnetDev.id = 0;
365     g_telnetDev.cmdFifo = NULL;
366     g_telnetDev.eventPend = TRUE;
367 
368     ret = register_driver(TELNET, &g_telnetOps, TELNET_DEV_DRV_MODE, &g_telnetDev);
369     if (ret != 0) {
370         PRINT_ERR("Telnet register driver error.\n");
371     }
372     return ret;
373 }
374 
375 /* When a telnet client connection established, update the output console for tasks. */
TelnetDevInit(INT32 clientFd)376 INT32 TelnetDevInit(INT32 clientFd)
377 {
378     INT32 ret;
379 
380     if (clientFd < 0) {
381         PRINT_ERR("Invalid telnet clientFd.\n");
382         return -1;
383     }
384     ret = system_console_init(TELNET);
385     if (ret != 0) {
386         PRINT_ERR("Telnet console init error.\n");
387         return ret;
388     }
389     ret = ioctl(STDIN_FILENO, CFG_TELNET_SET_FD, clientFd);
390     if (ret != 0) {
391         PRINT_ERR("Telnet device ioctl error.\n");
392         (VOID)system_console_deinit(TELNET);
393     }
394     return ret;
395 }
396 
397 /* When closing the telnet client connection, reset the output console for tasks. */
TelnetDevDeinit(VOID)398 INT32 TelnetDevDeinit(VOID)
399 {
400     INT32 ret;
401 
402     ret = system_console_deinit(TELNET);
403     if (ret != 0) {
404         PRINT_ERR("Telnet console deinit error.\n");
405     }
406     return ret;
407 }
408 #endif
409 
410