/* * mgmt-cli.c * --------- * Management CLI code. * * Copyright (c) 2016, NORDUnet A/S All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of the NORDUnet nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "stm-init.h" #include "stm-uart.h" #include "stm-led.h" #include "mgmt-cli.h" #include extern uint8_t uart_rx; struct uart_ringbuf_t { uint32_t enabled, ridx, widx, overflow; uint8_t buf[CLI_UART_RECVBUF_SIZE]; }; volatile struct uart_ringbuf_t uart_ringbuf = {1, 0, 0, 0, {0}}; #define RINGBUF_RIDX(rb) (rb.ridx & CLI_UART_RECVBUF_MASK) #define RINGBUF_WIDX(rb) (rb.widx & CLI_UART_RECVBUF_MASK) #define RINGBUF_COUNT(rb) ((unsigned)(rb.widx - rb.ridx)) #define RINGBUF_FULL(rb) (RINGBUF_RIDX(rb) == ((rb.widx + 1) & CLI_UART_RECVBUF_MASK)) #define RINGBUF_READ(rb, dst) {dst = rb.buf[RINGBUF_RIDX(rb)]; rb.buf[RINGBUF_RIDX(rb)] = '.'; rb.ridx++;} #define RINGBUF_WRITE(rb, src) {rb.buf[RINGBUF_WIDX(rb)] = src; rb.widx++;} void uart_cli_print(struct cli_def *cli __attribute__ ((unused)), const char *buf) { char crlf[] = "\r\n"; uart_send_string2(STM_UART_MGMT, buf); uart_send_string2(STM_UART_MGMT, crlf); } int uart_cli_read(struct cli_def *cli __attribute__ ((unused)), void *buf, size_t count) { uint32_t timeout = 0xffffff; /* Always explicitly enable the RX interrupt when we get here. * Prevents us getting stuck waiting for an interrupt that will never come. */ __HAL_UART_FLUSH_DRREGISTER(&huart_mgmt); HAL_UART_Receive_IT(&huart_mgmt, (uint8_t *) &uart_rx, 1); while (count && timeout--) { if (RINGBUF_COUNT(uart_ringbuf)) { RINGBUF_READ(uart_ringbuf, *(uint8_t *) buf); buf++; count--; } else { led_toggle(LED_GREEN); HAL_Delay(10); } } return 1; } int uart_cli_write(struct cli_def *cli __attribute__ ((unused)), const void *buf, size_t count) { uart_send_bytes(STM_UART_MGMT, (uint8_t *) buf, count); return (int) count; } int embedded_cli_loop(struct cli_def *cli) { unsigned char c; int n = 0; static struct cli_loop_ctx ctx; memset(&ctx, 0, sizeof(ctx)); ctx.insertmode = 1; cli->state = CLI_STATE_LOGIN; /* start off in unprivileged mode */ cli_set_privilege(cli, PRIVILEGE_UNPRIVILEGED); cli_set_configmode(cli, MODE_EXEC, NULL); cli_error(cli, "%s", cli->banner); while (1) { cli_loop_start_new_command(cli, &ctx); while (1) { cli_loop_show_prompt(cli, &ctx); n = cli_loop_read_next_char(cli, &ctx, &c); /* cli_print(cli, "Next char: '%c'/%i, ringbuf ridx %i, widx %i (%i/%i) - count %i", c, (int) c, uart_ringbuf.ridx, uart_ringbuf.widx, RINGBUF_RIDX(uart_ringbuf), RINGBUF_WIDX(uart_ringbuf), RINGBUF_COUNT(uart_ringbuf)); */ if (n == CLI_LOOP_CTRL_BREAK) break; if (n == CLI_LOOP_CTRL_CONTINUE) continue; n = cli_loop_process_char(cli, &ctx, c); if (n == CLI_LOOP_CTRL_BREAK) break; if (n == CLI_LOOP_CTRL_CONTINUE) continue; } if (ctx.l < 0) break; /* cli_print(cli, "Process command: '%s'", ctx.cmd); */ n = cli_loop_process_cmd(cli, &ctx); if (n == CLI_LOOP_CTRL_BREAK) break; } return CLI_OK; } /* Interrupt service routine to be called when data has been received on the MGMT UART. */ void mgmt_cli_uart_isr(const uint8_t *buf, size_t count) { if (! uart_ringbuf.enabled) return; while (count) { if (RINGBUF_FULL(uart_ringbuf)) { uart_ringbuf.overflow++; return; } RINGBUF_WRITE(uart_ringbuf, *buf); buf++; count--; } } void mgmt_cli_init(struct cli_def *cli) { cli_init(cli); cli_read_callback(cli, uart_cli_read); cli_write_callback(cli, uart_cli_write); cli_print_callback(cli, uart_cli_print); cli_set_banner(cli, "Cryptech Alpha"); cli_set_hostname(cli, "cryptech"); cli_telnet_protocol(cli, 0); }