From d5fec7888e92964bc35bc92519aff32d3b242157 Mon Sep 17 00:00:00 2001 From: Abhik Roy Date: Sat, 29 Jul 2023 00:08:33 +1000 Subject: [PATCH] feat(common): Console for runtime network interface configuration and monitoring --- .../console_cmd_ifconfig/CMakeLists.txt | 4 + .../console_cmd_ifconfig/Kconfig.projbuild | 18 + components/console_cmd_ifconfig/LICENSE | 1 + components/console_cmd_ifconfig/README.md | 57 ++ .../console_cmd_ifconfig/console_connect.c | 96 +++ .../console_cmd_ifconfig/console_ifconfig.c | 558 ++++++++++++++++++ .../console_cmd_ifconfig/console_ifconfig.h | 7 + .../console_cmd_ifconfig/idf_component.yml | 8 + .../include/console_connect.h | 7 + 9 files changed, 756 insertions(+) create mode 100644 components/console_cmd_ifconfig/CMakeLists.txt create mode 100644 components/console_cmd_ifconfig/Kconfig.projbuild create mode 100644 components/console_cmd_ifconfig/LICENSE create mode 100644 components/console_cmd_ifconfig/README.md create mode 100644 components/console_cmd_ifconfig/console_connect.c create mode 100644 components/console_cmd_ifconfig/console_ifconfig.c create mode 100644 components/console_cmd_ifconfig/console_ifconfig.h create mode 100644 components/console_cmd_ifconfig/idf_component.yml create mode 100644 components/console_cmd_ifconfig/include/console_connect.h diff --git a/components/console_cmd_ifconfig/CMakeLists.txt b/components/console_cmd_ifconfig/CMakeLists.txt new file mode 100644 index 0000000000..6be427437a --- /dev/null +++ b/components/console_cmd_ifconfig/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "console_connect.c" "console_ifconfig.c" + INCLUDE_DIRS "include" + REQUIRES "ethernet_init" + PRIV_REQUIRES esp_netif console nvs_flash esp_eth) diff --git a/components/console_cmd_ifconfig/Kconfig.projbuild b/components/console_cmd_ifconfig/Kconfig.projbuild new file mode 100644 index 0000000000..e93b6a1ea7 --- /dev/null +++ b/components/console_cmd_ifconfig/Kconfig.projbuild @@ -0,0 +1,18 @@ +menu "Enable console commands" + + orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps" + + config EXAMPLE_CMD_QUIT + bool + prompt "quit" + default y + config EXAMPLE_CMD_IFCONFIG + bool + prompt "ifconfig" + default y + config EXAMPLE_CMD_PING + bool + prompt "ping" + default n + +endmenu diff --git a/components/console_cmd_ifconfig/LICENSE b/components/console_cmd_ifconfig/LICENSE new file mode 100644 index 0000000000..b91d006974 --- /dev/null +++ b/components/console_cmd_ifconfig/LICENSE @@ -0,0 +1 @@ +console_cmd_ifconfig/LICENSE diff --git a/components/console_cmd_ifconfig/README.md b/components/console_cmd_ifconfig/README.md new file mode 100644 index 0000000000..f304b6b7ca --- /dev/null +++ b/components/console_cmd_ifconfig/README.md @@ -0,0 +1,57 @@ +# Console command ifconfig +The component offers a console that enables runtime network interface configuration and monitoring for any example project. + +## API + +### Steps to enable console in an example code: +1. Add this component to your project using the command: + ```bash + idf.py add-dependency + ``` +2. In the main file of the example, add the following line: + ```c + #include "console_connect.h" + ``` +3. Ensure esp-netif is initialized and default event loop is created in your app_main(): + ```c + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + ``` +4. In your app_main() function, add the following line as the last line: + ```c + example_start_networking_console(NULL, NULL); + ``` +5. Optionally, you can add a user-defined command: + ```c + example_start_networking_console("user_cmd", usr_cmd_hndl); + ``` + In the above line, "user_cmd" is a string representing the user-defined command name, and usr_cmd_hndl is the command callback function with the prototype. + ```c + int usr_cmd_hndl(int argc, char **argv) + ``` + + +## Suported commands: + +### Ifconfig: +* **ifconfig help:** Prints the help text for all ifconfig commands +* **ifconfig netif create/destroy \/\:** Create or destroy a network interface with the specified ethernet handle or interface name +* **ifconfig eth show:** Display a list of available ethernet handle +* **ifconfig:** Display a list of all esp_netif interfaces along with their information. +* **ifconfig \:** Provide the details of the named interface. +* **ifconfig \ default:** Set the specified interface as the default interface. +* **ifconfig \ ip6:** Enable IPv6 on the specified interface. +* **ifconfig up:** Enable the specified interface. +* **ifconfig down:** Disable the specified interface. +* **ifconfig \ link \:** Enable or disable the link of the specified interface. +* **ifconfig \ ip \:** Set the IPv4 address of the specified interface. +* **ifconfig \ mask \:** Set the subnet mask of the specified interface. +* **ifconfig \ gw \:** Set the default gateway of the specified interface. +* **ifconfig \ napt \:** Enable or disable Network Address and Port Translation (NAPT) on the specified interface. +* **ifconfig \ dhcp server \:** Enable or disable the DHCP server on the specified interface. (Note: DHCP server is not supported yet) +* **ifconfig \ dhcp client \:** Enable or disable the DHCP client on the specified interface. + +Note: Disabling the DHCP server and client enables the use of static IP configuration. + +### Quit: +**quit:** Quits the Console application. diff --git a/components/console_cmd_ifconfig/console_connect.c b/components/console_cmd_ifconfig/console_connect.c new file mode 100644 index 0000000000..6290a8dea2 --- /dev/null +++ b/components/console_cmd_ifconfig/console_connect.c @@ -0,0 +1,96 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "sdkconfig.h" +#include "lwip/inet.h" +#include "lwip/netdb.h" +#include "lwip/sockets.h" +#include "esp_netif.h" +#include "esp_console.h" +#include "esp_event.h" +#include "nvs_flash.h" +#include "argtable3/argtable3.h" +#include "esp_log.h" +#include "esp_netif_net_stack.h" +#include "lwip/ip6.h" +#include "lwip/opt.h" +#if IP_NAPT +#include "lwip/lwip_napt.h" +#endif +#include "console_connect.h" +#include "console_ifconfig.h" + +static const char *TAG = "console_connect"; + +static esp_console_repl_t *s_repl = NULL; + +/* handle 'quit' command */ +static int do_cmd_quit(int argc, char **argv) +{ + printf("Bye Bye\n\r\n"); + s_repl->del(s_repl); + return 0; +} + +static esp_console_cmd_t register_quit(void) +{ + esp_console_cmd_t command = { + .command = "quit", + .help = "Quit REPL environment", + .func = &do_cmd_quit + }; + return command; +} + + +esp_err_t example_start_networking_console(char *usr_cmd, int (*usr_cmd_hndl)(int argc, char **argv)) +{ + esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT(); + esp_console_cmd_t command; + + // Initialize TCP/IP network interface aka the esp-netif (should be called only once in application) + //ESP_ERROR_CHECK(esp_netif_init()); + // Create default event loop that running in background + //ESP_ERROR_CHECK(esp_event_loop_create_default()); + + // install console REPL environment +#if CONFIG_ESP_CONSOLE_UART + esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &s_repl)); +#endif + +#if CONFIG_EXAMPLE_CMD_IFCONFIG + /* register command `ifconfig` */ + command = register_ifconfig(); + if (esp_console_cmd_register(&command)) { + ESP_LOGE(TAG, "Unable to register ifconfig"); + } +#endif + +#if CONFIG_EXAMPLE_CMD_QUIT + /* register command `quit` */ + command = register_quit(); + if (esp_console_cmd_register(&command)) { + ESP_LOGE(TAG, "Unable to register quit"); + } +#endif + + /* Register command from caller */ + if ((usr_cmd_hndl != NULL) && (usr_cmd != NULL)) { + esp_console_cmd_t command = { + .command = usr_cmd, + .help = "user command", + .func = usr_cmd_hndl + }; + if (esp_console_cmd_register(&command) != ESP_OK) { + ESP_LOGE(TAG, "Unable to register user command"); + } + } + + // start console REPL + return esp_console_start_repl(s_repl); +} diff --git a/components/console_cmd_ifconfig/console_ifconfig.c b/components/console_cmd_ifconfig/console_ifconfig.c new file mode 100644 index 0000000000..f40bf548b2 --- /dev/null +++ b/components/console_cmd_ifconfig/console_ifconfig.c @@ -0,0 +1,558 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include "sdkconfig.h" +#include "lwip/inet.h" +#include "lwip/netdb.h" +#include "lwip/sockets.h" +#include "esp_netif.h" +#include "esp_eth.h" +#include "esp_console.h" +#include "esp_event.h" +#include "nvs_flash.h" +#include "argtable3/argtable3.h" +#include "esp_log.h" +#include "esp_netif_net_stack.h" +#include "lwip/ip6.h" +#include "lwip/opt.h" +#include "ethernet_init.h" +#if IP_NAPT +#include "lwip/lwip_napt.h" +#endif + + +typedef struct netif_op_ netif_op; + +typedef struct netif_op_ { + char *name; + esp_err_t (*operation)(netif_op *self, int argc, char *argv[], esp_netif_t *esp_netif); + int arg_cnt; + int start_index; + char *help; + int netif_flag; +} netif_op; + +esp_err_t ifcfg_help_op(netif_op *self, int argc, char *argv[], esp_netif_t *esp_netif); +esp_err_t ifcfg_print_op(netif_op *self, int argc, char *argv[], esp_netif_t *esp_netif); +esp_err_t ifcfg_lwip_op(netif_op *self, int argc, char *argv[], esp_netif_t *esp_netif); +esp_err_t ifcfg_basic_op(netif_op *self, int argc, char *argv[], esp_netif_t *esp_netif); +esp_err_t ifcfg_ip_op(netif_op *self, int argc, char *argv[], esp_netif_t *esp_netif); +esp_err_t ifcfg_napt_op(netif_op *self, int argc, char *argv[], esp_netif_t *esp_netif); +esp_err_t ifcfg_dhcp_op(netif_op *self, int argc, char *argv[], esp_netif_t *esp_netif); +esp_err_t ifcfg_netif_op(netif_op *self, int argc, char *argv[], esp_netif_t *esp_netif); +esp_err_t ifcfg_eth_op(netif_op *self, int argc, char *argv[], esp_netif_t *esp_netif); + +static const char *TAG = "console_ifconfig"; + +netif_op cmd_list[] = { + {.name = "help", .operation = ifcfg_help_op, .arg_cnt = 2, .start_index = 1, .netif_flag = false, .help = "ifconfig help: Prints the help text for all ifconfig commands"}, + {.name = "netif", .operation = ifcfg_netif_op, .arg_cnt = 4, .start_index = 1, .netif_flag = false, .help = "ifconfig netif create/destroy /: Create or destroy a network interface with the specified ethernet handle or interface name"}, + {.name = "eth", .operation = ifcfg_eth_op, .arg_cnt = 3, .start_index = 1, .netif_flag = false, .help = "ifconfig eth show: Display a list of available ethernet handle"}, + {.name = "ifconfig", .operation = ifcfg_print_op, .arg_cnt = 1, .start_index = 0, .netif_flag = false, .help = "ifconfig: Display a list of all esp_netif interfaces along with their information"}, + {.name = "ifconfig", .operation = ifcfg_print_op, .arg_cnt = 2, .start_index = 0, .netif_flag = true, .help = "ifconfig : Provide the details of the named interface"}, + {.name = "default", .operation = ifcfg_basic_op, .arg_cnt = 3, .start_index = 2, .netif_flag = true, .help = "ifconfig default: Set the specified interface as the default interface"}, + {.name = "ip6", .operation = ifcfg_basic_op, .arg_cnt = 3, .start_index = 2, .netif_flag = true, .help = "ifconfig ip6: Enable IPv6 on the specified interface"}, + {.name = "up", .operation = ifcfg_lwip_op, .arg_cnt = 3, .start_index = 2, .netif_flag = true, .help = "ifconfig up: Enable the specified interface"}, + {.name = "down", .operation = ifcfg_lwip_op, .arg_cnt = 3, .start_index = 2, .netif_flag = true, .help = "ifconfig down: Disable the specified interface"}, + {.name = "link", .operation = ifcfg_lwip_op, .arg_cnt = 4, .start_index = 2, .netif_flag = true, .help = "ifconfig link : Enable or disable the link of the specified interface"}, + {.name = "ip", .operation = ifcfg_ip_op, .arg_cnt = 4, .start_index = 2, .netif_flag = true, .help = "ifconfig ip : Set the IPv4 address of the specified interface"}, + {.name = "mask", .operation = ifcfg_ip_op, .arg_cnt = 4, .start_index = 2, .netif_flag = true, .help = "ifconfig mask : Set the subnet mask of the specified interface"}, + {.name = "gw", .operation = ifcfg_ip_op, .arg_cnt = 4, .start_index = 2, .netif_flag = true, .help = "ifconfig gw : Set the default gateway of the specified interface"}, + {.name = "napt", .operation = ifcfg_napt_op, .arg_cnt = 4, .start_index = 2, .netif_flag = true, .help = "ifconfig napt : Enable or disable NAPT on the specified interface."}, + {.name = "dhcp", .operation = ifcfg_dhcp_op, .arg_cnt = 5, .start_index = 2, .netif_flag = true, .help = "ifconfig dhcp server : Enable or disable the DHCP server.(Note: DHCP server is not supported yet)\n ifconfig dhcp client : Enable or disable the DHCP client\nNote: Disabling the DHCP server and client enables the use of static IP configuration."}, +}; + + +esp_err_t ifcfg_help_op(netif_op *self, int argc, char *argv[], esp_netif_t *esp_netif) +{ + int cmd_count = sizeof(cmd_list) / sizeof(cmd_list[0]); + + for (int i = 0; i < cmd_count; i++) { + if ((cmd_list[i].help != NULL) && (strlen(cmd_list[i].help) != 0)) { + printf(" %s\n", cmd_list[i].help); + } + } + + return ESP_OK; +} + + +esp_netif_t *get_esp_netif_from_ifname(char *if_name) +{ + esp_netif_t *esp_netif = NULL; + esp_err_t ret = ESP_FAIL; + char interface[10]; + + /* Get interface details and own global ipv6 address */ + for (int i = 0; i < esp_netif_get_nr_of_ifs(); ++i) { + esp_netif = esp_netif_next(esp_netif); + ret = esp_netif_get_netif_impl_name(esp_netif, interface); + + if ((ESP_FAIL == ret) || (NULL == esp_netif)) { + ESP_LOGE(TAG, "No interface available"); + return NULL; + } + + if (!strcmp(interface, if_name)) { + return esp_netif; + } + } + + return NULL; +} + + +esp_err_t ifcfg_basic_op(netif_op *self, int argc, char *argv[], esp_netif_t *esp_netif) +{ + /* Set Default */ + if (!strcmp("default", argv[self->start_index])) { + esp_netif_set_default_netif(esp_netif); + return ESP_OK; + } + + /* Enable IPv6 on this interface */ + if (!strcmp("ip6", argv[self->start_index])) { + ESP_ERROR_CHECK(esp_netif_create_ip6_linklocal(esp_netif)); + return ESP_OK; + } + + return ESP_FAIL; +} + + +esp_err_t ifcfg_lwip_op(netif_op *self, int argc, char *argv[], esp_netif_t *esp_netif) +{ + struct netif *lwip_netif = esp_netif_get_netif_impl(esp_netif); + if (NULL == lwip_netif) { + ESP_LOGE(TAG, "lwip interface %s not available", argv[1]); + return ESP_OK; + } + + /* Enable/Disable Interface */ + if (!strcmp("up", argv[self->start_index])) { + netif_set_up(lwip_netif); + return ESP_OK; + } + + if (!strcmp("down", argv[self->start_index])) { + netif_set_down(lwip_netif); + return ESP_OK; + } + + /* Enable/Disable link */ + if (!strcmp("link", argv[self->start_index])) { + + if (!strcmp("up", argv[self->start_index + 1])) { + netif_set_link_up(lwip_netif); + } + + if (!strcmp("down", argv[self->start_index + 1])) { + netif_set_down(lwip_netif); + netif_set_link_down(lwip_netif); + } + + return ESP_OK; + } + + return ESP_FAIL; +} + + +esp_err_t ifcfg_ip_op(netif_op *self, int argc, char *argv[], esp_netif_t *esp_netif) +{ + esp_netif_ip_info_t ip_info; + + esp_netif_dhcpc_stop(esp_netif); + memset(&ip_info, 0, sizeof(esp_netif_ip_info_t)); + esp_netif_get_ip_info(esp_netif, &ip_info); + + if (!strcmp("ip", argv[self->start_index])) { + ESP_LOGI(TAG, "Setting ip: %s", argv[self->start_index + 1]); + + inet_aton(argv[self->start_index + 1], &ip_info.ip.addr); + esp_netif_set_ip_info(esp_netif, &ip_info); + return ESP_OK; + } + + if (!strcmp("mask", argv[self->start_index])) { + ESP_LOGI(TAG, "Setting mask: %s", argv[self->start_index + 1]); + + inet_aton(argv[self->start_index + 1], &ip_info.netmask.addr); + esp_netif_set_ip_info(esp_netif, &ip_info); + return ESP_OK; + } + + if (!strcmp("gw", argv[self->start_index])) { + ESP_LOGI(TAG, "Setting gw: %s", argv[self->start_index + 1]); + + inet_aton(argv[self->start_index + 1], &ip_info.gw.addr); + esp_netif_set_ip_info(esp_netif, &ip_info); + return ESP_OK; + } + + return ESP_FAIL; +} + + +#if IP_NAPT +esp_err_t set_napt(char *if_name, bool state) +{ + esp_netif_t *esp_netif = NULL; + esp_err_t ret = ESP_FAIL; + char interface[10]; + + /* Get interface details and own global ipv6 address */ + for (int i = 0; i < esp_netif_get_nr_of_ifs(); ++i) { + esp_netif = esp_netif_next(esp_netif); + + ret = esp_netif_get_netif_impl_name(esp_netif, interface); + if ((ESP_FAIL == ret) || (NULL == esp_netif)) { + ESP_LOGE(TAG, "No interface available"); + return ESP_FAIL; + } + + if (!strcmp(interface, if_name)) { + struct netif *lwip_netif = esp_netif_get_netif_impl(esp_netif); + ip_napt_enable_netif(lwip_netif, state); + return ESP_OK; + } + } + + return ESP_FAIL; +} +#endif + + +esp_err_t ifcfg_napt_op(netif_op *self, int argc, char *argv[], esp_netif_t *esp_netif) +{ +#if IP_NAPT + if (!strcmp("napt", argv[self->start_index])) { + + ESP_LOGI(TAG, "Setting napt %s on %s", argv[self->start_index + 1], argv[1]); + if (!strcmp(argv[self->start_index + 1], "enable")) { + return set_napt(argv[1], true); + } else if (!strcmp(argv[self->start_index + 1], "disable")) { + return set_napt(argv[1], false); + } else { + ESP_LOGI(TAG, "Invalid argument: %s", argv[self->start_index + 1]); + } + + return ESP_FAIL; + } +#endif + ESP_LOGE(TAG, "NAPT not enabled in menuconfig"); + return ESP_OK; +} + + +esp_err_t ifcfg_dhcp_op(netif_op *self, int argc, char *argv[], esp_netif_t *esp_netif) +{ + /* Server */ + if (!strcmp("server", argv[self->start_index + 1])) { + if (!strcmp("enable", argv[self->start_index + 2])) { + ESP_LOGW(TAG, "DHCP Server configuration is not supported yet."); // TBD + //esp_netif_dhcps_start(esp_netif); + return ESP_OK; + } else if (!strcmp("disable", argv[self->start_index + 2])) { + ESP_LOGW(TAG, "DHCP Server configuration is not supported yet."); // TBD + //esp_netif_dhcps_stop(esp_netif); + return ESP_OK; + } else { + ESP_LOGE(TAG, "Invalid argument"); + return ESP_FAIL; + } + } + + /* Client */ + if (!strcmp("client", argv[self->start_index + 1])) { + if (!strcmp("enable", argv[self->start_index + 2])) { + esp_netif_dhcpc_start(esp_netif); + return ESP_OK; + } else if (!strcmp("disable", argv[self->start_index + 2])) { + esp_netif_dhcpc_stop(esp_netif); + return ESP_OK; + } else { + ESP_LOGE(TAG, "Invalid argument"); + return ESP_FAIL; + } + } + + return ESP_FAIL; +} + + +void print_iface_details(esp_netif_t *esp_netif) +{ + esp_netif_ip_info_t ip_info; + uint8_t mac[NETIF_MAX_HWADDR_LEN]; + char interface[10]; + int ip6_addrs_count = 0; + esp_ip6_addr_t ip6[LWIP_IPV6_NUM_ADDRESSES]; + esp_err_t ret = ESP_FAIL; + esp_netif_dhcp_status_t status; + + struct netif *lwip_netif = esp_netif_get_netif_impl(esp_netif); + + /* Print Interface Name and Number */ + ret = esp_netif_get_netif_impl_name(esp_netif, interface); + if ((ESP_FAIL == ret) || (NULL == esp_netif)) { + ESP_LOGE(TAG, "No interface available"); + return; + } + + if (esp_netif_get_default_netif() == esp_netif) { + ESP_LOGI(TAG, "Interface Name: %s (DEF)", interface); + } else { + ESP_LOGI(TAG, "Interface Name: %s", interface); + } + ESP_LOGI(TAG, "Interface Number: %d", lwip_netif->num); + + /* Print MAC address */ + esp_netif_get_mac(esp_netif, mac); + ESP_LOGI(TAG, "MAC: %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], + mac[2], mac[3], mac[4], mac[5]); + + /* Print DHCP status */ + if (ESP_OK == esp_netif_dhcps_get_status(esp_netif, &status)) { + ESP_LOGI(TAG, "DHCP Server Status: %d", status); + } else if ((ESP_OK == esp_netif_dhcpc_get_status(esp_netif, &status))) { + if (ESP_NETIF_DHCP_STOPPED == status) { + ESP_LOGI(TAG, "Static IP"); + } else { + ESP_LOGI(TAG, "DHCP Client Status: %s", status ? "enabled" : "disabled"); + } + } + + /* Print IP Info */ + esp_netif_get_ip_info(esp_netif, &ip_info); + ESP_LOGI(TAG, "IP: " IPSTR ", MASK: " IPSTR ", GW: " IPSTR, IP2STR(&(ip_info.ip)), IP2STR(&(ip_info.netmask)), IP2STR(&(ip_info.gw))); + +#if IP_NAPT + /* Print NAPT status*/ + ESP_LOGI(TAG, "NAPT: %s", lwip_netif->napt ? "enabled" : "disabled"); +#endif + + /* Print IPv6 Address */ + ip6_addrs_count = esp_netif_get_all_ip6(esp_netif, ip6); + for (int j = 0; j < ip6_addrs_count; ++j) { + ESP_LOGI(TAG, "IPv6 address: " IPV6STR, IPV62STR(ip6[j])); + } + + /* Print Interface and Link Status*/ + ESP_LOGI(TAG, "Interface Status: %s", esp_netif_is_netif_up(esp_netif) ? "UP" : "DOWN"); + ESP_LOGI(TAG, "Link Status: %s\n", netif_is_link_up(lwip_netif) ? "UP" : "DOWN"); + +} + + +esp_err_t ifcfg_print_op(netif_op *self, int argc, char *argv[], esp_netif_t *esp_netif) +{ + /* Print interface details */ + if (2 == argc) { + print_iface_details(esp_netif); + return ESP_OK; + } + + /* Get interface details and own global ipv6 address of all interfaces */ + for (int i = 0; i < esp_netif_get_nr_of_ifs(); ++i) { + esp_netif = esp_netif_next(esp_netif); + print_iface_details(esp_netif); + } + + return ESP_OK; +} + + +/* Maximum number of interface that can be added */ +#define MAX_ETH_NETIF_COUNT (10) + +typedef struct { + esp_netif_t *esp_netif[MAX_ETH_NETIF_COUNT]; + uint8_t created_flag[MAX_ETH_NETIF_COUNT]; + uint8_t netif_count; +} esp_netif_list; + +uint8_t eth_init_flag = false; +uint8_t eth_port_cnt = 0; +esp_eth_handle_t *eth_handle = NULL; + + +esp_err_t get_netif_config(uint16_t id, esp_netif_config_t *eth_cfg_o) +{ + /* Create new default instance of esp-netif for Ethernet */ + char *if_key; + if (asprintf(&if_key, "IFC_ETH%d", id) == -1) { + return ESP_FAIL; + } + + esp_netif_inherent_config_t *esp_eth_base_config = malloc(sizeof(esp_netif_inherent_config_t)); + if (NULL == esp_eth_base_config) { + return ESP_FAIL; + } + *esp_eth_base_config = (esp_netif_inherent_config_t)ESP_NETIF_INHERENT_DEFAULT_ETH(); + esp_eth_base_config->if_key = if_key; + + eth_cfg_o->base = esp_eth_base_config; + eth_cfg_o->driver = NULL; + eth_cfg_o->stack = ESP_NETIF_NETSTACK_DEFAULT_ETH; + + return ESP_OK; +} + + +void free_config(esp_netif_config_t *eth_cfg) +{ + if ((NULL != eth_cfg) && (NULL != eth_cfg->base)) { + free((void *)(eth_cfg->base->if_key)); + free((void *)(eth_cfg->base)); + } +} + + +esp_err_t ifcfg_netif_op(netif_op *self, int argc, char *argv[], esp_netif_t *esp_netif) +{ + static esp_netif_list netif_list; + int eth_handle_id = atoi(argv[self->start_index + 2]); + + if (!strcmp(argv[self->start_index + 1], "create")) { + /* Validate ethernet handle */ + if ((eth_handle_id + 1 > eth_port_cnt) || (eth_handle_id < 0)) { + ESP_LOGE(TAG, "Invalid ethernet handle: %s", argv[self->start_index + 2]); + return ESP_FAIL; + } + esp_netif_config_t eth_cfg = ESP_NETIF_DEFAULT_ETH(); + ESP_ERROR_CHECK(get_netif_config(eth_handle_id, ð_cfg)); + for (int i = 0; i < MAX_ETH_NETIF_COUNT; i++) { + if (netif_list.created_flag[i] == 0) { + esp_netif = esp_netif_new(ð_cfg); + if (esp_netif == NULL) { + ESP_LOGE(TAG, "Interface with key %s already exists", argv[self->start_index + 2]); + return ESP_FAIL; + } + netif_list.esp_netif[i] = esp_netif; + netif_list.created_flag[i] = 1; + netif_list.netif_count++; + + esp_eth_netif_glue_handle_t eth_glue = esp_eth_new_netif_glue(eth_handle[eth_handle_id]); + if (eth_glue == NULL) { + ESP_LOGE(TAG, "%s: eth_glue is NULL", __func__); + } + ESP_ERROR_CHECK(esp_netif_attach(netif_list.esp_netif[i], eth_glue)); + + sleep(10); + + // start Ethernet driver state machine + ESP_ERROR_CHECK(esp_eth_start(eth_handle[eth_handle_id])); + + free_config(ð_cfg); + break; + } + } + + return ESP_OK; + } else if (!strcmp(argv[self->start_index + 1], "destroy")) { + esp_netif = get_esp_netif_from_ifname(argv[self->start_index + 2]); + if (NULL == esp_netif) { + ESP_LOGE(TAG, "interface %s not available", argv[1]); + return ESP_FAIL; + } + + for (int i = 0; i < MAX_ETH_NETIF_COUNT; i++) { + if (esp_netif == netif_list.esp_netif[i]) { + netif_list.created_flag[i] = 0; + break; + } + } + esp_netif_destroy(esp_netif); + netif_list.netif_count--; + + return ESP_OK; + } + + return ESP_FAIL; +} + + +esp_err_t ifcfg_eth_op(netif_op *self, int argc, char *argv[], esp_netif_t *esp_netif) +{ + if (!strcmp(argv[self->start_index + 1], "show")) { + + /* Check if ethernet is initialized */ + if (eth_init_flag == false) { + // Initialize Ethernet driver + if (ethernet_init(ð_handle, ð_port_cnt) != ESP_OK) { + ESP_LOGE(TAG, "Unable to initialize ethernet"); + return ESP_FAIL; + } + eth_init_flag = true; + } + + /* Display available ethernet handles */ + for (int i = 0; i < eth_port_cnt; i++) { + printf("ethernet handle id: %d\n", i); + } + + } + + return ESP_OK; +} + + +/* handle 'ifconfig' command */ +static int do_cmd_ifconfig(int argc, char **argv) +{ + esp_netif_t *esp_netif = NULL; + int cmd_count = sizeof(cmd_list) / sizeof(cmd_list[0]); + netif_op cmd; + + for (int i = 0; i < cmd_count; i++) { + cmd = cmd_list[i]; + + if (argc < cmd.start_index + 1) { + continue; + } + + if (!strcmp(cmd.name, argv[cmd.start_index])) { + + /* Get interface for eligible commands */ + if (cmd.netif_flag == true) { + esp_netif = get_esp_netif_from_ifname(argv[1]); + if (NULL == esp_netif) { + ESP_LOGE(TAG, "interface %s not available", argv[1]); + return 0; + } + } + + if (cmd.arg_cnt == argc) { + if (cmd.operation != NULL) { + if (cmd.operation(&cmd, argc, argv, esp_netif) != ESP_OK) { + ESP_LOGE(TAG, "Usage:\n%s", cmd.help); + return 0; + } + + } + return 0; + } + } + } + + ESP_LOGE(TAG, "Command not available"); + + return 1; +} + + +esp_console_cmd_t register_ifconfig(void) +{ + esp_console_cmd_t command = { + .command = "ifconfig", + .help = "Command for network interface configuration and monitoring\nFor more info run 'ifconfig help'", + .func = &do_cmd_ifconfig + }; + + return command; +} diff --git a/components/console_cmd_ifconfig/console_ifconfig.h b/components/console_cmd_ifconfig/console_ifconfig.h new file mode 100644 index 0000000000..8feacfc318 --- /dev/null +++ b/components/console_cmd_ifconfig/console_ifconfig.h @@ -0,0 +1,7 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +esp_console_cmd_t register_ifconfig(void); diff --git a/components/console_cmd_ifconfig/idf_component.yml b/components/console_cmd_ifconfig/idf_component.yml new file mode 100644 index 0000000000..f935a0c289 --- /dev/null +++ b/components/console_cmd_ifconfig/idf_component.yml @@ -0,0 +1,8 @@ +version: 0.0.4 +url: https://github.com/espressif-abhikroy/esp-protocols/tree/components/console_cmd_ifconfig/components/console_cmd_ifconfig +description: The component offers a console that enables runtime network interface configuration and monitoring. +dependencies: + idf: + version: '>=4.1' + ethernet_init: + version: '>=0.0.1' diff --git a/components/console_cmd_ifconfig/include/console_connect.h b/components/console_cmd_ifconfig/include/console_connect.h new file mode 100644 index 0000000000..20ad6dfc6d --- /dev/null +++ b/components/console_cmd_ifconfig/include/console_connect.h @@ -0,0 +1,7 @@ + +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +esp_err_t example_start_networking_console(char *usr_cmd, int (*usr_cmd_hndl)(int argc, char **argv));