1 /*
2 * Copyright (c) 2017 Intel Corporation
3 * Copyright (c) 2019 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr/init.h>
9
10 #include <zephyr/logging/log.h>
11 #include <zephyr/net/socket.h>
12 #include <zephyr/net/socket_service.h>
13 #include <zephyr/shell/shell_telnet.h>
14
15 #include "shell_telnet_protocol.h"
16
17 SHELL_TELNET_DEFINE(shell_transport_telnet);
18 SHELL_DEFINE(shell_telnet, CONFIG_SHELL_PROMPT_TELNET, &shell_transport_telnet,
19 CONFIG_SHELL_TELNET_LOG_MESSAGE_QUEUE_SIZE,
20 CONFIG_SHELL_TELNET_LOG_MESSAGE_QUEUE_TIMEOUT,
21 SHELL_FLAG_OLF_CRLF);
22
23 LOG_MODULE_REGISTER(shell_telnet, CONFIG_SHELL_TELNET_LOG_LEVEL);
24
25 struct shell_telnet *sh_telnet;
26
27 /* Various definitions mapping the TELNET service configuration options */
28 #define TELNET_PORT CONFIG_SHELL_TELNET_PORT
29 #define TELNET_LINE_SIZE CONFIG_SHELL_TELNET_LINE_BUF_SIZE
30 #define TELNET_TIMEOUT CONFIG_SHELL_TELNET_SEND_TIMEOUT
31
32 #define TELNET_MIN_COMMAND_LEN 2
33 #define TELNET_WILL_DO_COMMAND_LEN 3
34
35 #define SOCK_ID_IPV4_LISTEN 0
36 #define SOCK_ID_IPV6_LISTEN 1
37 #define SOCK_ID_CLIENT 2
38 #define SOCK_ID_MAX 3
39
40 /* Basic TELNET implementation. */
41
42 static void telnet_server_cb(struct net_socket_service_event *evt);
43 static int telnet_init(struct shell_telnet *ctx);
44
45 NET_SOCKET_SERVICE_SYNC_DEFINE_STATIC(telnet_server, telnet_server_cb,
46 SHELL_TELNET_POLLFD_COUNT);
47
48
telnet_end_client_connection(void)49 static void telnet_end_client_connection(void)
50 {
51 int ret;
52
53 (void)zsock_close(sh_telnet->fds[SOCK_ID_CLIENT].fd);
54
55 sh_telnet->fds[SOCK_ID_CLIENT].fd = -1;
56 sh_telnet->output_lock = false;
57
58 k_work_cancel_delayable_sync(&sh_telnet->send_work,
59 &sh_telnet->work_sync);
60
61 ret = net_socket_service_register(&telnet_server, sh_telnet->fds,
62 ARRAY_SIZE(sh_telnet->fds), NULL);
63 if (ret < 0) {
64 LOG_ERR("Failed to register socket service, %d", ret);
65 }
66 }
67
telnet_command_send_reply(uint8_t * msg,uint16_t len)68 static void telnet_command_send_reply(uint8_t *msg, uint16_t len)
69 {
70 if (sh_telnet->fds[SOCK_ID_CLIENT].fd < 0) {
71 return;
72 }
73
74 while (len > 0) {
75 int ret;
76
77 ret = zsock_send(sh_telnet->fds[SOCK_ID_CLIENT].fd, msg, len, 0);
78 if (ret < 0) {
79 LOG_ERR("Failed to send command %d, shutting down", ret);
80 telnet_end_client_connection();
81 break;
82 }
83
84 msg += ret;
85 len -= ret;
86 }
87 }
88
telnet_reply_ay_command(void)89 static void telnet_reply_ay_command(void)
90 {
91 static const char alive[] = "Zephyr at your service\r\n";
92
93 telnet_command_send_reply((uint8_t *)alive, strlen(alive));
94 }
95
telnet_echo_set(const struct shell * sh,bool val)96 static int telnet_echo_set(const struct shell *sh, bool val)
97 {
98 int ret = shell_echo_set(sh_telnet->shell_context, val);
99
100 if (ret < 0) {
101 LOG_ERR("Failed to set echo to: %d, err: %d", val, ret);
102 }
103 return ret;
104 }
105
telnet_reply_dont_command(struct telnet_simple_command * cmd)106 static void telnet_reply_dont_command(struct telnet_simple_command *cmd)
107 {
108 switch (cmd->opt) {
109 case NVT_OPT_ECHO:
110 {
111 int ret = telnet_echo_set(sh_telnet->shell_context, false);
112
113 if (ret >= 0) {
114 cmd->op = NVT_CMD_WILL_NOT;
115 } else {
116 cmd->op = NVT_CMD_WILL;
117 }
118 break;
119 }
120 default:
121 cmd->op = NVT_CMD_WILL_NOT;
122 break;
123 }
124
125 telnet_command_send_reply((uint8_t *)cmd,
126 sizeof(struct telnet_simple_command));
127 }
128
telnet_reply_do_command(struct telnet_simple_command * cmd)129 static void telnet_reply_do_command(struct telnet_simple_command *cmd)
130 {
131 switch (cmd->opt) {
132 case NVT_OPT_SUPR_GA:
133 cmd->op = NVT_CMD_WILL;
134 break;
135 case NVT_OPT_ECHO:
136 {
137 int ret = telnet_echo_set(sh_telnet->shell_context, true);
138
139 if (ret >= 0) {
140 cmd->op = NVT_CMD_WILL;
141 } else {
142 cmd->op = NVT_CMD_WILL_NOT;
143 }
144 break;
145 }
146 default:
147 cmd->op = NVT_CMD_WILL_NOT;
148 break;
149 }
150
151 telnet_command_send_reply((uint8_t *)cmd,
152 sizeof(struct telnet_simple_command));
153 }
154
telnet_reply_command(struct telnet_simple_command * cmd)155 static void telnet_reply_command(struct telnet_simple_command *cmd)
156 {
157 if (!cmd->iac) {
158 return;
159 }
160
161 switch (cmd->op) {
162 case NVT_CMD_AO:
163 /* OK, no output then */
164 sh_telnet->output_lock = true;
165 sh_telnet->line_out.len = 0;
166 k_work_cancel_delayable_sync(&sh_telnet->send_work,
167 &sh_telnet->work_sync);
168 break;
169 case NVT_CMD_AYT:
170 telnet_reply_ay_command();
171 break;
172 case NVT_CMD_DO:
173 telnet_reply_do_command(cmd);
174 break;
175 case NVT_CMD_DO_NOT:
176 telnet_reply_dont_command(cmd);
177 break;
178 default:
179 LOG_DBG("Operation %u not handled", cmd->op);
180 break;
181 }
182 }
183
telnet_send(bool block)184 static int telnet_send(bool block)
185 {
186 int ret;
187 uint8_t *msg = sh_telnet->line_out.buf;
188 uint16_t len = sh_telnet->line_out.len;
189
190 if (sh_telnet->line_out.len == 0) {
191 return 0;
192 }
193
194 if (sh_telnet->fds[SOCK_ID_CLIENT].fd < 0) {
195 return -ENOTCONN;
196 }
197
198 while (len > 0) {
199 ret = zsock_send(sh_telnet->fds[SOCK_ID_CLIENT].fd, msg, len,
200 block ? 0 : ZSOCK_MSG_DONTWAIT);
201 if (!block && (ret < 0) && (errno == EAGAIN)) {
202 /* Not all data was sent - move the remaining data and
203 * update length.
204 */
205 memmove(sh_telnet->line_out.buf, msg, len);
206 sh_telnet->line_out.len = len;
207 return -EAGAIN;
208 }
209
210 if (ret < 0) {
211 ret = -errno;
212 LOG_ERR("Failed to send %d, shutting down", -ret);
213 telnet_end_client_connection();
214 return ret;
215 }
216
217 msg += ret;
218 len -= ret;
219 }
220
221 /* We reinitialize the line buffer */
222 sh_telnet->line_out.len = 0;
223
224 return 0;
225 }
226
telnet_send_prematurely(struct k_work * work)227 static void telnet_send_prematurely(struct k_work *work)
228 {
229 int ret;
230
231 /* Use non-blocking send to prevent system workqueue blocking. */
232 ret = telnet_send(false);
233 if (ret == -EAGAIN) {
234 /* Not all data was sent, reschedule the work. */
235 k_work_reschedule(&sh_telnet->send_work, K_MSEC(TELNET_TIMEOUT));
236 }
237 }
238
telnet_command_length(uint8_t op)239 static int telnet_command_length(uint8_t op)
240 {
241 if (op == NVT_CMD_SB || op == NVT_CMD_WILL || op == NVT_CMD_WILL_NOT ||
242 op == NVT_CMD_DO || op == NVT_CMD_DO_NOT) {
243 return TELNET_WILL_DO_COMMAND_LEN;
244 }
245
246 return TELNET_MIN_COMMAND_LEN;
247 }
248
telnet_handle_command(struct telnet_simple_command * cmd)249 static inline int telnet_handle_command(struct telnet_simple_command *cmd)
250 {
251 /* Commands are two or three bytes. */
252 if (cmd->iac != NVT_CMD_IAC) {
253 return 0;
254 }
255
256 if (IS_ENABLED(CONFIG_SHELL_TELNET_SUPPORT_COMMAND)) {
257 LOG_DBG("Got a command %u/%u/%u", cmd->iac, cmd->op, cmd->opt);
258 telnet_reply_command(cmd);
259 }
260
261 if (cmd->op == NVT_CMD_SB) {
262 /* TODO Add subnegotiation support. */
263 return -EOPNOTSUPP;
264 }
265
266 return 0;
267 }
268
telnet_recv(struct zsock_pollfd * pollfd)269 static void telnet_recv(struct zsock_pollfd *pollfd)
270 {
271 struct telnet_simple_command *cmd =
272 (struct telnet_simple_command *)sh_telnet->cmd_buf;
273 size_t len, off, buf_left, cmd_total_len;
274 uint8_t *buf;
275 int ret;
276
277 k_mutex_lock(&sh_telnet->rx_lock, K_FOREVER);
278
279 buf_left = sizeof(sh_telnet->rx_buf) - sh_telnet->rx_len;
280 if (buf_left == 0) {
281 /* No space left to read TCP stream, try again later. */
282 k_mutex_unlock(&sh_telnet->rx_lock);
283 k_msleep(10);
284 return;
285 }
286
287 buf = sh_telnet->rx_buf + sh_telnet->rx_len;
288
289 ret = zsock_recv(pollfd->fd, buf, buf_left, 0);
290 if (ret < 0) {
291 LOG_DBG("Telnet client error %d", ret);
292 goto error;
293 } else if (ret == 0) {
294 LOG_DBG("Telnet client closed connection");
295 goto error;
296 }
297
298 off = 0;
299 len = ret;
300 cmd_total_len = 0;
301 /* Filter out and process commands from the data buffer. */
302 while (off < len) {
303 if (sh_telnet->cmd_len > 0) {
304 /* Command mode */
305 if (sh_telnet->cmd_len == 1) {
306 /* Operation */
307 cmd->op = *(buf + off);
308 sh_telnet->cmd_len++;
309 cmd_total_len++;
310 off++;
311
312 if (telnet_command_length(cmd->op) >
313 TELNET_MIN_COMMAND_LEN) {
314 continue;
315 }
316 } else if (sh_telnet->cmd_len == 2) {
317 /* Option */
318 cmd->opt = *(buf + off);
319 sh_telnet->cmd_len++;
320 cmd_total_len++;
321 off++;
322 }
323
324 ret = telnet_handle_command(cmd);
325 if (ret < 0) {
326 goto error;
327 } else {
328 LOG_DBG("Handled command");
329 }
330
331 memset(cmd, 0, sizeof(*cmd));
332 sh_telnet->cmd_len = 0;
333
334 continue;
335 }
336
337 if (*(buf + off) == NVT_CMD_IAC) {
338 cmd->iac = *(buf + off);
339 sh_telnet->cmd_len++;
340 cmd_total_len++;
341 off++;
342 continue;
343 }
344
345 /* Data byte, remove command bytes from the buffer, if any. */
346 if (cmd_total_len > 0) {
347 size_t data_off = off;
348
349 off -= cmd_total_len;
350 len -= cmd_total_len;
351 cmd_total_len = 0;
352
353 memmove(buf + off, buf + data_off, len);
354 }
355
356 off++;
357 }
358
359 if (cmd_total_len > 0) {
360 /* In case the buffer ended with command, trim the buffer size
361 * here.
362 */
363 len -= cmd_total_len;
364 }
365
366 if (len == 0) {
367 k_mutex_unlock(&sh_telnet->rx_lock);
368 return;
369 }
370
371 sh_telnet->rx_len += len;
372
373 k_mutex_unlock(&sh_telnet->rx_lock);
374
375 sh_telnet->shell_handler(SHELL_TRANSPORT_EVT_RX_RDY,
376 sh_telnet->shell_context);
377
378 return;
379
380 error:
381 k_mutex_unlock(&sh_telnet->rx_lock);
382 telnet_end_client_connection();
383 }
384
telnet_restart_server(void)385 static void telnet_restart_server(void)
386 {
387 int ret;
388
389 if (sh_telnet->fds[SOCK_ID_IPV4_LISTEN].fd >= 0) {
390 (void)zsock_close(sh_telnet->fds[SOCK_ID_IPV4_LISTEN].fd);
391 sh_telnet->fds[SOCK_ID_IPV4_LISTEN].fd = -1;
392 }
393
394 if (sh_telnet->fds[SOCK_ID_IPV6_LISTEN].fd >= 0) {
395 (void)zsock_close(sh_telnet->fds[SOCK_ID_IPV6_LISTEN].fd);
396 sh_telnet->fds[SOCK_ID_IPV6_LISTEN].fd = -1;
397 }
398
399 if (sh_telnet->fds[SOCK_ID_CLIENT].fd >= 0) {
400 (void)zsock_close(sh_telnet->fds[SOCK_ID_CLIENT].fd);
401 sh_telnet->fds[SOCK_ID_CLIENT].fd = -1;
402 }
403
404 ret = telnet_init(sh_telnet);
405 if (ret < 0) {
406 LOG_ERR("Telnet fatal error, failed to restart server (%d)", ret);
407 (void)net_socket_service_unregister(&telnet_server);
408 }
409 }
410
telnet_accept(struct zsock_pollfd * pollfd)411 static void telnet_accept(struct zsock_pollfd *pollfd)
412 {
413 int sock, ret = 0;
414 struct sockaddr addr;
415 socklen_t addrlen = sizeof(struct sockaddr);
416
417 sock = zsock_accept(pollfd->fd, &addr, &addrlen);
418 if (sock < 0) {
419 ret = -errno;
420 NET_ERR("Telnet accept error (%d)", ret);
421 return;
422 }
423
424 if (sh_telnet->fds[SOCK_ID_CLIENT].fd > 0) {
425 /* Too many connections. */
426 ret = 0;
427 NET_ERR("Telnet client already connected.");
428 goto error;
429 }
430
431 sh_telnet->fds[SOCK_ID_CLIENT].fd = sock;
432 sh_telnet->fds[SOCK_ID_CLIENT].events = ZSOCK_POLLIN;
433 sh_telnet->rx_len = 0;
434 sh_telnet->cmd_len = 0;
435 sh_telnet->line_out.len = 0;
436
437 ret = net_socket_service_register(&telnet_server, sh_telnet->fds,
438 ARRAY_SIZE(sh_telnet->fds), NULL);
439 if (ret < 0) {
440 LOG_ERR("Failed to register socket service, (%d)", ret);
441 sh_telnet->fds[SOCK_ID_CLIENT].fd = -1;
442 goto error;
443 }
444
445 LOG_DBG("Telnet client connected (family AF_INET%s)",
446 addr.sa_family == AF_INET ? "" : "6");
447
448 /* Disable echo - if command handling is enabled we reply that we
449 * support echo.
450 */
451 (void)telnet_echo_set(sh_telnet->shell_context, false);
452
453 return;
454
455 error:
456 if (sock > 0) {
457 (void)zsock_close(sock);
458 }
459
460 if (ret < 0) {
461 telnet_restart_server();
462 }
463 }
464
telnet_server_cb(struct net_socket_service_event * evt)465 static void telnet_server_cb(struct net_socket_service_event *evt)
466 {
467 int sock_error;
468 socklen_t optlen = sizeof(int);
469
470 if (sh_telnet == NULL) {
471 return;
472 }
473
474 if ((evt->event.revents & ZSOCK_POLLERR) ||
475 (evt->event.revents & ZSOCK_POLLNVAL)) {
476 (void)zsock_getsockopt(evt->event.fd, SOL_SOCKET,
477 SO_ERROR, &sock_error, &optlen);
478 NET_ERR("Telnet socket %d error (%d)", evt->event.fd, sock_error);
479
480 if (evt->event.fd == sh_telnet->fds[SOCK_ID_CLIENT].fd) {
481 telnet_end_client_connection();
482 return;
483 }
484
485 goto error;
486 }
487
488 if (!(evt->event.revents & ZSOCK_POLLIN)) {
489 return;
490 }
491
492 if (evt->event.fd == sh_telnet->fds[SOCK_ID_IPV4_LISTEN].fd) {
493 telnet_accept(&sh_telnet->fds[SOCK_ID_IPV4_LISTEN]);
494 return;
495 } else if (evt->event.fd == sh_telnet->fds[SOCK_ID_IPV6_LISTEN].fd) {
496 telnet_accept(&sh_telnet->fds[SOCK_ID_IPV6_LISTEN]);
497 return;
498 } else if (evt->event.fd == sh_telnet->fds[SOCK_ID_CLIENT].fd) {
499 telnet_recv(&sh_telnet->fds[SOCK_ID_CLIENT]);
500 return;
501 }
502
503 NET_ERR("Unexpected FD received for telnet, restarting service.");
504
505 error:
506 telnet_restart_server();
507 }
508
telnet_setup_server(struct zsock_pollfd * pollfd,sa_family_t family,struct sockaddr * addr,socklen_t addrlen)509 static int telnet_setup_server(struct zsock_pollfd *pollfd, sa_family_t family,
510 struct sockaddr *addr, socklen_t addrlen)
511 {
512 int ret = 0;
513
514 pollfd->fd = zsock_socket(family, SOCK_STREAM, IPPROTO_TCP);
515 if (pollfd->fd < 0) {
516 ret = -errno;
517 LOG_ERR("Failed to create telnet AF_INET%s socket",
518 family == AF_INET ? "" : "6");
519 goto error;
520 }
521
522 if (zsock_bind(pollfd->fd, addr, addrlen) < 0) {
523 ret = -errno;
524 LOG_ERR("Cannot bind on family AF_INET%s (%d)",
525 family == AF_INET ? "" : "6", ret);
526 goto error;
527 }
528
529 if (zsock_listen(pollfd->fd, 1)) {
530 ret = -errno;
531 LOG_ERR("Cannot listen on family AF_INET%s (%d)",
532 family == AF_INET ? "" : "6", ret);
533 goto error;
534 }
535
536 pollfd->events = ZSOCK_POLLIN;
537
538 LOG_DBG("Telnet console enabled on AF_INET%s",
539 family == AF_INET ? "" : "6");
540
541 return 0;
542
543 error:
544 LOG_ERR("Unable to start telnet on AF_INET%s (%d)",
545 family == AF_INET ? "" : "6", ret);
546
547 if (pollfd->fd >= 0) {
548 (void)zsock_close(pollfd->fd);
549 pollfd->fd = -1;
550 }
551
552 return ret;
553 }
554
telnet_init(struct shell_telnet * ctx)555 static int telnet_init(struct shell_telnet *ctx)
556 {
557 int ret;
558
559 if (IS_ENABLED(CONFIG_NET_IPV4)) {
560 struct sockaddr_in any_addr4 = {
561 .sin_family = AF_INET,
562 .sin_port = htons(TELNET_PORT),
563 .sin_addr = INADDR_ANY_INIT
564 };
565
566 ret = telnet_setup_server(&ctx->fds[SOCK_ID_IPV4_LISTEN],
567 AF_INET, (struct sockaddr *)&any_addr4,
568 sizeof(any_addr4));
569 if (ret < 0) {
570 goto error;
571 }
572 }
573
574 if (IS_ENABLED(CONFIG_NET_IPV6)) {
575 struct sockaddr_in6 any_addr6 = {
576 .sin6_family = AF_INET6,
577 .sin6_port = htons(TELNET_PORT),
578 .sin6_addr = IN6ADDR_ANY_INIT
579 };
580
581 ret = telnet_setup_server(&ctx->fds[SOCK_ID_IPV6_LISTEN],
582 AF_INET6, (struct sockaddr *)&any_addr6,
583 sizeof(any_addr6));
584 if (ret < 0) {
585 goto error;
586 }
587 }
588
589 ret = net_socket_service_register(&telnet_server, ctx->fds,
590 ARRAY_SIZE(ctx->fds), NULL);
591 if (ret < 0) {
592 LOG_ERR("Failed to register socket service, %d", ret);
593 goto error;
594 }
595
596 LOG_INF("Telnet shell backend initialized");
597
598 return 0;
599
600 error:
601 if (ctx->fds[SOCK_ID_IPV4_LISTEN].fd >= 0) {
602 (void)zsock_close(ctx->fds[SOCK_ID_IPV4_LISTEN].fd);
603 ctx->fds[SOCK_ID_IPV4_LISTEN].fd = -1;
604 }
605
606 if (ctx->fds[SOCK_ID_IPV6_LISTEN].fd >= 0) {
607 (void)zsock_close(ctx->fds[SOCK_ID_IPV6_LISTEN].fd);
608 ctx->fds[SOCK_ID_IPV6_LISTEN].fd = -1;
609 }
610
611 return ret;
612 }
613
614 /* Shell API */
615
init(const struct shell_transport * transport,const void * config,shell_transport_handler_t evt_handler,void * context)616 static int init(const struct shell_transport *transport,
617 const void *config,
618 shell_transport_handler_t evt_handler,
619 void *context)
620 {
621 int err;
622
623 sh_telnet = (struct shell_telnet *)transport->ctx;
624
625 memset(sh_telnet, 0, sizeof(struct shell_telnet));
626 for (int i = 0; i < ARRAY_SIZE(sh_telnet->fds); i++) {
627 sh_telnet->fds[i].fd = -1;
628 }
629
630 sh_telnet->shell_handler = evt_handler;
631 sh_telnet->shell_context = context;
632
633 err = telnet_init(sh_telnet);
634 if (err != 0) {
635 return err;
636 }
637
638 k_work_init_delayable(&sh_telnet->send_work, telnet_send_prematurely);
639 k_mutex_init(&sh_telnet->rx_lock);
640
641 return 0;
642 }
643
uninit(const struct shell_transport * transport)644 static int uninit(const struct shell_transport *transport)
645 {
646 if (sh_telnet == NULL) {
647 return -ENODEV;
648 }
649
650 return 0;
651 }
652
enable(const struct shell_transport * transport,bool blocking)653 static int enable(const struct shell_transport *transport, bool blocking)
654 {
655 if (sh_telnet == NULL) {
656 return -ENODEV;
657 }
658
659 return 0;
660 }
661
telnet_write(const struct shell_transport * transport,const void * data,size_t length,size_t * cnt)662 static int telnet_write(const struct shell_transport *transport,
663 const void *data, size_t length, size_t *cnt)
664 {
665 struct shell_telnet_line_buf *lb;
666 size_t copy_len;
667 int err;
668 uint32_t timeout;
669 bool was_running;
670
671 if (sh_telnet == NULL) {
672 *cnt = 0;
673 return -ENODEV;
674 }
675
676 if (sh_telnet->fds[SOCK_ID_CLIENT].fd < 0 || sh_telnet->output_lock) {
677 *cnt = length;
678 return 0;
679 }
680
681 *cnt = 0;
682 lb = &sh_telnet->line_out;
683
684 /* Stop the transmission timer, so it does not interrupt the operation.
685 */
686 timeout = k_ticks_to_ms_ceil32(
687 k_work_delayable_remaining_get(&sh_telnet->send_work));
688 was_running = k_work_cancel_delayable_sync(&sh_telnet->send_work,
689 &sh_telnet->work_sync);
690
691 do {
692 if (lb->len + length - *cnt > TELNET_LINE_SIZE) {
693 copy_len = TELNET_LINE_SIZE - lb->len;
694 } else {
695 copy_len = length - *cnt;
696 }
697
698 memcpy(lb->buf + lb->len, (uint8_t *)data + *cnt, copy_len);
699 lb->len += copy_len;
700
701 /* Send the data immediately if the buffer is full or line feed
702 * is recognized.
703 */
704 if (lb->buf[lb->len - 1] == '\n' ||
705 lb->len == TELNET_LINE_SIZE) {
706 err = telnet_send(true);
707 if (err != 0) {
708 *cnt = length;
709 if ((err == -ENOTCONN) || (err == -ENETDOWN)) {
710 LOG_ERR("Network disconnected, shutting down");
711 } else {
712 LOG_ERR("Error %d, shutting down", err);
713 }
714 return 0; /* Return 0 to not trigger ASSERT in shell_ops.c */
715 }
716 }
717
718 *cnt += copy_len;
719 } while (*cnt < length);
720
721 if (lb->len > 0) {
722 /* Check if the timer was already running, initialize otherwise.
723 */
724 timeout = was_running ? timeout : TELNET_TIMEOUT;
725
726 k_work_reschedule(&sh_telnet->send_work, K_MSEC(timeout));
727 }
728
729 sh_telnet->shell_handler(SHELL_TRANSPORT_EVT_TX_RDY,
730 sh_telnet->shell_context);
731
732 return 0;
733 }
734
telnet_read(const struct shell_transport * transport,void * data,size_t length,size_t * cnt)735 static int telnet_read(const struct shell_transport *transport,
736 void *data, size_t length, size_t *cnt)
737 {
738 size_t read_len;
739
740 if (sh_telnet == NULL) {
741 return -ENODEV;
742 }
743
744 if (sh_telnet->fds[SOCK_ID_CLIENT].fd < 0) {
745 goto no_data;
746 }
747
748 k_mutex_lock(&sh_telnet->rx_lock, K_FOREVER);
749
750 if (sh_telnet->rx_len == 0) {
751 k_mutex_unlock(&sh_telnet->rx_lock);
752 goto no_data;
753 }
754
755 read_len = sh_telnet->rx_len;
756 if (read_len > length) {
757 read_len = length;
758 }
759
760 memcpy(data, sh_telnet->rx_buf, read_len);
761 *cnt = read_len;
762
763 sh_telnet->rx_len -= read_len;
764 if (sh_telnet->rx_len > 0) {
765 memmove(sh_telnet->rx_buf, sh_telnet->rx_buf + read_len,
766 sh_telnet->rx_len);
767 }
768
769 k_mutex_unlock(&sh_telnet->rx_lock);
770
771 return 0;
772
773 no_data:
774 *cnt = 0;
775 return 0;
776 }
777
778 const struct shell_transport_api shell_telnet_transport_api = {
779 .init = init,
780 .uninit = uninit,
781 .enable = enable,
782 .write = telnet_write,
783 .read = telnet_read
784 };
785
enable_shell_telnet(void)786 static int enable_shell_telnet(void)
787 {
788 bool log_backend = CONFIG_SHELL_TELNET_INIT_LOG_LEVEL > 0;
789 uint32_t level = (CONFIG_SHELL_TELNET_INIT_LOG_LEVEL > LOG_LEVEL_DBG) ?
790 CONFIG_LOG_MAX_LEVEL : CONFIG_SHELL_TELNET_INIT_LOG_LEVEL;
791 static const struct shell_backend_config_flags cfg_flags =
792 SHELL_DEFAULT_BACKEND_CONFIG_FLAGS;
793
794 return shell_init(&shell_telnet, NULL, cfg_flags, log_backend, level);
795 }
796
797 SYS_INIT(enable_shell_telnet, APPLICATION, CONFIG_SHELL_TELNET_INIT_PRIORITY);
798
shell_backend_telnet_get_ptr(void)799 const struct shell *shell_backend_telnet_get_ptr(void)
800 {
801 return &shell_telnet;
802 }
803