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 net_sockaddr addr;
415 net_socklen_t addrlen = sizeof(struct net_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 NET_AF_INET%s)",
446 addr.sa_family == NET_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 int ret;
469 net_socklen_t optlen = sizeof(int);
470
471 if (sh_telnet == NULL) {
472 return;
473 }
474
475 if ((evt->event.revents & ZSOCK_POLLERR) ||
476 (evt->event.revents & ZSOCK_POLLNVAL)) {
477 (void)zsock_getsockopt(evt->event.fd, ZSOCK_SOL_SOCKET,
478 ZSOCK_SO_ERROR, &sock_error, &optlen);
479
480 ret = -sock_error;
481
482 if (ret == -ENETDOWN) {
483 LOG_INF("Network is down");
484 } else {
485 LOG_ERR("Telnet socket %d error (%d)", evt->event.fd, ret);
486 }
487
488 if (evt->event.fd == sh_telnet->fds[SOCK_ID_CLIENT].fd) {
489 telnet_end_client_connection();
490 return;
491 }
492
493 goto error;
494 }
495
496 if (!(evt->event.revents & ZSOCK_POLLIN)) {
497 return;
498 }
499
500 if (evt->event.fd == sh_telnet->fds[SOCK_ID_IPV4_LISTEN].fd) {
501 telnet_accept(&sh_telnet->fds[SOCK_ID_IPV4_LISTEN]);
502 return;
503 } else if (evt->event.fd == sh_telnet->fds[SOCK_ID_IPV6_LISTEN].fd) {
504 telnet_accept(&sh_telnet->fds[SOCK_ID_IPV6_LISTEN]);
505 return;
506 } else if (evt->event.fd == sh_telnet->fds[SOCK_ID_CLIENT].fd) {
507 telnet_recv(&sh_telnet->fds[SOCK_ID_CLIENT]);
508 return;
509 }
510
511 NET_ERR("Unexpected FD received for telnet, restarting service.");
512
513 error:
514 telnet_restart_server();
515 }
516
telnet_setup_server(struct zsock_pollfd * pollfd,net_sa_family_t family,struct net_sockaddr * addr,net_socklen_t addrlen)517 static int telnet_setup_server(struct zsock_pollfd *pollfd, net_sa_family_t family,
518 struct net_sockaddr *addr, net_socklen_t addrlen)
519 {
520 int ret = 0;
521
522 pollfd->fd = zsock_socket(family, NET_SOCK_STREAM, NET_IPPROTO_TCP);
523 if (pollfd->fd < 0) {
524 ret = -errno;
525 LOG_ERR("Failed to create telnet NET_AF_INET%s socket",
526 family == NET_AF_INET ? "" : "6");
527 goto error;
528 }
529
530 if (zsock_bind(pollfd->fd, addr, addrlen) < 0) {
531 ret = -errno;
532 LOG_ERR("Cannot bind on family NET_AF_INET%s (%d)",
533 family == NET_AF_INET ? "" : "6", ret);
534 goto error;
535 }
536
537 if (zsock_listen(pollfd->fd, 1)) {
538 ret = -errno;
539 LOG_ERR("Cannot listen on family NET_AF_INET%s (%d)",
540 family == NET_AF_INET ? "" : "6", ret);
541 goto error;
542 }
543
544 pollfd->events = ZSOCK_POLLIN;
545
546 LOG_DBG("Telnet console enabled on NET_AF_INET%s",
547 family == NET_AF_INET ? "" : "6");
548
549 return 0;
550
551 error:
552 LOG_ERR("Unable to start telnet on NET_AF_INET%s (%d)",
553 family == NET_AF_INET ? "" : "6", ret);
554
555 if (pollfd->fd >= 0) {
556 (void)zsock_close(pollfd->fd);
557 pollfd->fd = -1;
558 }
559
560 return ret;
561 }
562
telnet_init(struct shell_telnet * ctx)563 static int telnet_init(struct shell_telnet *ctx)
564 {
565 int ret;
566
567 if (IS_ENABLED(CONFIG_NET_IPV4)) {
568 struct net_sockaddr_in any_addr4 = {
569 .sin_family = NET_AF_INET,
570 .sin_port = net_htons(TELNET_PORT),
571 .sin_addr = NET_INADDR_ANY_INIT
572 };
573
574 ret = telnet_setup_server(&ctx->fds[SOCK_ID_IPV4_LISTEN],
575 NET_AF_INET, (struct net_sockaddr *)&any_addr4,
576 sizeof(any_addr4));
577 if (ret < 0) {
578 goto error;
579 }
580 }
581
582 if (IS_ENABLED(CONFIG_NET_IPV6)) {
583 struct net_sockaddr_in6 any_addr6 = {
584 .sin6_family = NET_AF_INET6,
585 .sin6_port = net_htons(TELNET_PORT),
586 .sin6_addr = NET_IN6ADDR_ANY_INIT
587 };
588
589 ret = telnet_setup_server(&ctx->fds[SOCK_ID_IPV6_LISTEN],
590 NET_AF_INET6, (struct net_sockaddr *)&any_addr6,
591 sizeof(any_addr6));
592 if (ret < 0) {
593 goto error;
594 }
595 }
596
597 ret = net_socket_service_register(&telnet_server, ctx->fds,
598 ARRAY_SIZE(ctx->fds), NULL);
599 if (ret < 0) {
600 LOG_ERR("Failed to register socket service, %d", ret);
601 goto error;
602 }
603
604 LOG_INF("Telnet shell backend initialized");
605
606 return 0;
607
608 error:
609 if (ctx->fds[SOCK_ID_IPV4_LISTEN].fd >= 0) {
610 (void)zsock_close(ctx->fds[SOCK_ID_IPV4_LISTEN].fd);
611 ctx->fds[SOCK_ID_IPV4_LISTEN].fd = -1;
612 }
613
614 if (ctx->fds[SOCK_ID_IPV6_LISTEN].fd >= 0) {
615 (void)zsock_close(ctx->fds[SOCK_ID_IPV6_LISTEN].fd);
616 ctx->fds[SOCK_ID_IPV6_LISTEN].fd = -1;
617 }
618
619 return ret;
620 }
621
622 /* Shell API */
623
init(const struct shell_transport * transport,const void * config,shell_transport_handler_t evt_handler,void * context)624 static int init(const struct shell_transport *transport,
625 const void *config,
626 shell_transport_handler_t evt_handler,
627 void *context)
628 {
629 int err;
630
631 sh_telnet = (struct shell_telnet *)transport->ctx;
632
633 memset(sh_telnet, 0, sizeof(struct shell_telnet));
634 for (int i = 0; i < ARRAY_SIZE(sh_telnet->fds); i++) {
635 sh_telnet->fds[i].fd = -1;
636 }
637
638 sh_telnet->shell_handler = evt_handler;
639 sh_telnet->shell_context = context;
640
641 err = telnet_init(sh_telnet);
642 if (err != 0) {
643 return err;
644 }
645
646 k_work_init_delayable(&sh_telnet->send_work, telnet_send_prematurely);
647 k_mutex_init(&sh_telnet->rx_lock);
648
649 return 0;
650 }
651
uninit(const struct shell_transport * transport)652 static int uninit(const struct shell_transport *transport)
653 {
654 if (sh_telnet == NULL) {
655 return -ENODEV;
656 }
657
658 return 0;
659 }
660
enable(const struct shell_transport * transport,bool blocking)661 static int enable(const struct shell_transport *transport, bool blocking)
662 {
663 if (sh_telnet == NULL) {
664 return -ENODEV;
665 }
666
667 return 0;
668 }
669
telnet_write(const struct shell_transport * transport,const void * data,size_t length,size_t * cnt)670 static int telnet_write(const struct shell_transport *transport,
671 const void *data, size_t length, size_t *cnt)
672 {
673 struct shell_telnet_line_buf *lb;
674 size_t copy_len;
675 int err;
676 uint32_t timeout;
677 bool was_running;
678
679 if (sh_telnet == NULL) {
680 *cnt = 0;
681 return -ENODEV;
682 }
683
684 if (sh_telnet->fds[SOCK_ID_CLIENT].fd < 0 || sh_telnet->output_lock) {
685 *cnt = length;
686 return 0;
687 }
688
689 *cnt = 0;
690 lb = &sh_telnet->line_out;
691
692 /* Stop the transmission timer, so it does not interrupt the operation.
693 */
694 timeout = k_ticks_to_ms_ceil32(
695 k_work_delayable_remaining_get(&sh_telnet->send_work));
696 was_running = k_work_cancel_delayable_sync(&sh_telnet->send_work,
697 &sh_telnet->work_sync);
698
699 do {
700 if (lb->len + length - *cnt > TELNET_LINE_SIZE) {
701 copy_len = TELNET_LINE_SIZE - lb->len;
702 } else {
703 copy_len = length - *cnt;
704 }
705
706 memcpy(lb->buf + lb->len, (uint8_t *)data + *cnt, copy_len);
707 lb->len += copy_len;
708
709 /* Send the data immediately if the buffer is full or line feed
710 * is recognized.
711 */
712 if (lb->buf[lb->len - 1] == '\n' ||
713 lb->len == TELNET_LINE_SIZE) {
714 err = telnet_send(true);
715 if (err != 0) {
716 *cnt = length;
717 if ((err == -ENOTCONN) || (err == -ENETDOWN)) {
718 LOG_ERR("Network disconnected, shutting down");
719 } else {
720 LOG_ERR("Error %d, shutting down", err);
721 }
722 return 0; /* Return 0 to not trigger ASSERT in shell_ops.c */
723 }
724 }
725
726 *cnt += copy_len;
727 } while (*cnt < length);
728
729 if (lb->len > 0) {
730 /* Check if the timer was already running, initialize otherwise.
731 */
732 timeout = was_running ? timeout : TELNET_TIMEOUT;
733
734 k_work_reschedule(&sh_telnet->send_work, K_MSEC(timeout));
735 }
736
737 sh_telnet->shell_handler(SHELL_TRANSPORT_EVT_TX_RDY,
738 sh_telnet->shell_context);
739
740 return 0;
741 }
742
telnet_read(const struct shell_transport * transport,void * data,size_t length,size_t * cnt)743 static int telnet_read(const struct shell_transport *transport,
744 void *data, size_t length, size_t *cnt)
745 {
746 size_t read_len;
747
748 if (sh_telnet == NULL) {
749 return -ENODEV;
750 }
751
752 if (sh_telnet->fds[SOCK_ID_CLIENT].fd < 0) {
753 goto no_data;
754 }
755
756 k_mutex_lock(&sh_telnet->rx_lock, K_FOREVER);
757
758 if (sh_telnet->rx_len == 0) {
759 k_mutex_unlock(&sh_telnet->rx_lock);
760 goto no_data;
761 }
762
763 read_len = sh_telnet->rx_len;
764 if (read_len > length) {
765 read_len = length;
766 }
767
768 memcpy(data, sh_telnet->rx_buf, read_len);
769 *cnt = read_len;
770
771 sh_telnet->rx_len -= read_len;
772 if (sh_telnet->rx_len > 0) {
773 memmove(sh_telnet->rx_buf, sh_telnet->rx_buf + read_len,
774 sh_telnet->rx_len);
775 }
776
777 k_mutex_unlock(&sh_telnet->rx_lock);
778
779 return 0;
780
781 no_data:
782 *cnt = 0;
783 return 0;
784 }
785
786 const struct shell_transport_api shell_telnet_transport_api = {
787 .init = init,
788 .uninit = uninit,
789 .enable = enable,
790 .write = telnet_write,
791 .read = telnet_read
792 };
793
enable_shell_telnet(void)794 static int enable_shell_telnet(void)
795 {
796 bool log_backend = CONFIG_SHELL_TELNET_INIT_LOG_LEVEL > 0;
797 uint32_t level = (CONFIG_SHELL_TELNET_INIT_LOG_LEVEL > LOG_LEVEL_DBG) ?
798 CONFIG_LOG_MAX_LEVEL : CONFIG_SHELL_TELNET_INIT_LOG_LEVEL;
799 static const struct shell_backend_config_flags cfg_flags =
800 SHELL_DEFAULT_BACKEND_CONFIG_FLAGS;
801
802 return shell_init(&shell_telnet, NULL, cfg_flags, log_backend, level);
803 }
804
805 SYS_INIT(enable_shell_telnet, APPLICATION, CONFIG_SHELL_TELNET_INIT_PRIORITY);
806
shell_backend_telnet_get_ptr(void)807 const struct shell *shell_backend_telnet_get_ptr(void)
808 {
809 return &shell_telnet;
810 }
811