From f3cc6d4b59d400c3f745bf151d07a706115c4964 Mon Sep 17 00:00:00 2001 From: Abhik Roy Date: Tue, 23 Aug 2022 01:05:30 +0530 Subject: [PATCH] network examples: Multiple ethernet interfaces and VLAN support. Closes https://github.com/espressif/esp-idf/issues/8807 --- examples/network/vlan_support/CMakeLists.txt | 20 ++ examples/network/vlan_support/README.md | 114 ++++++++++ .../network/vlan_support/main/CMakeLists.txt | 2 + .../vlan_support/main/Kconfig.projbuild | 60 ++++++ .../vlan_support/main/eth_vlan_utils.c | 113 ++++++++++ .../vlan_support/main/eth_vlan_utils.h | 50 +++++ .../network/vlan_support/main/vlan_hooks.h | 53 +++++ .../vlan_support/main/vlan_support_main.c | 196 ++++++++++++++++++ .../network/vlan_support/sdkconfig.defaults | 4 + 9 files changed, 612 insertions(+) create mode 100644 examples/network/vlan_support/CMakeLists.txt create mode 100644 examples/network/vlan_support/README.md create mode 100644 examples/network/vlan_support/main/CMakeLists.txt create mode 100644 examples/network/vlan_support/main/Kconfig.projbuild create mode 100644 examples/network/vlan_support/main/eth_vlan_utils.c create mode 100644 examples/network/vlan_support/main/eth_vlan_utils.h create mode 100644 examples/network/vlan_support/main/vlan_hooks.h create mode 100644 examples/network/vlan_support/main/vlan_support_main.c create mode 100644 examples/network/vlan_support/sdkconfig.defaults diff --git a/examples/network/vlan_support/CMakeLists.txt b/examples/network/vlan_support/CMakeLists.txt new file mode 100644 index 000000000000..4ed01ae191c0 --- /dev/null +++ b/examples/network/vlan_support/CMakeLists.txt @@ -0,0 +1,20 @@ +# For more information about build system see +# https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html +# The following five lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.16) + +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/ethernet/basic/components/ethernet_init) +include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +project(vlan_support) + + +# Enabling Vlan by injecting vlan hooks into lwip. +idf_component_get_property(lwip lwip COMPONENT_LIB) +target_compile_options(${lwip} PRIVATE "-I${PROJECT_DIR}/main") + +target_compile_definitions(${lwip} PRIVATE "-DESP_IDF_LWIP_HOOK_FILENAME=\"vlan_hooks.h\"" + "-DETHARP_SUPPORT_VLAN=1" + "-DLWIP_HOOK_VLAN_CHECK=lwip_vlan_check" + "-DLWIP_HOOK_VLAN_SET=lwip_vlan_set") diff --git a/examples/network/vlan_support/README.md b/examples/network/vlan_support/README.md new file mode 100644 index 000000000000..6177d7b93554 --- /dev/null +++ b/examples/network/vlan_support/README.md @@ -0,0 +1,114 @@ +| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 | +| ----------------- | ----- | -------- | -------- | -------- | -------- | + +# Ethernet VLAN Support Example + +See the [README.md](../../ethernet/README.md) file in the upper level [examples](../../ethernet) directory for more information about examples. + +## Overview + +This example demonstrates the creation of one virtual network interface over Ethernet, an additional VLAN interface(disabled by default), and an interface without vlan tag. The work flow of the example could be as follows: + +1. Install Ethernet driver for standard interface and both the virtual network interface. +2. Setup static IP address to both the virtual network interface. +3. Send DHCP requests and wait for a DHCP lease on the standard interface +4. If get IP address successfully, then you will be able to ping the standard interface of the device. +5. The virtual interfaces can be pinged over the configured static IP address. + +Note: The code in vlan_support_main.c can be modified to add more vlan interfaces. The maximum number of interfaces that can be added is specified by the macro `MAX_ETH_NETIF_COUNT`. +## How to use example + +### Hardware Required + +To run this example, it's recommended that you have an official ESP32 Ethernet development board - [ESP32-Ethernet-Kit](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/get-started-ethernet-kit.html). This example should also work for 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chip. + +### Configure the project + +``` +idf.py menuconfig +``` +See common configurations for Ethernet examples from [upper level](../../ethernet/README.md#common-configurations). + +The Virtual network interface is enabled by default. +An additional virtual network interface can also be enabled. +The VLAN tag, Static IP address, network mask and default gateway of these interfaces are also configurable. + +To configure the virtual network interfaces select: +``` +Example Configuration ---> +``` + +### Build, Flash, and Run + +Build the project and flash it to the board, then run monitor tool to view serial output: + +``` +idf.py -p PORT build flash monitor +``` + +(Replace PORT with the name of the serial port to use.) + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects. + +## Example Output + +``` +I (0) cpu_start: Starting scheduler on APP CPU. +I (423) system_api: Base MAC address is not set +I (423) system_api: read default base MAC address from EFUSE +I (443) esp_eth.netif.netif_glue: 24:d7:eb:bb:f2:1b +I (443) esp_eth.netif.netif_glue: ethernet attached to netif +I (443) esp_eth.netif.netif_glue: 24:d7:eb:bb:f2:1b +I (443) esp_eth.netif.netif_glue: ethernet attached to netif +I (453) esp_eth.netif.netif_glue: 24:d7:eb:bb:f2:1b +I (463) esp_eth.netif.netif_glue: ethernet attached to netif +I (3563) eth_vlan_example: Ethernet Started +I (3563) eth_vlan_example: Ethernet Link Up +I (3563) eth_vlan_example: Ethernet HW Addr 24:d7:eb:bb:f2:1b +I (3563) eth_vlan_example: Ethernet interface(24:d7:eb:bb:f2:1b): ETH_VLAN20, Got IP Address +I (3573) eth_vlan_example: ~~~~~~~~~~~ +I (3573) eth_vlan_example: ETHIP:192.168.20.10 +I (3583) eth_vlan_example: ETHMASK:192.168.20.1 +I (3583) eth_vlan_example: ETHGW:255.255.255.0 +I (3593) eth_vlan_example: ~~~~~~~~~~~ +I (3593) esp_netif_handlers: eth ip: 192.168.20.10, mask: 192.168.20.1, gw: 255.255.255.0 +I (3603) eth_vlan_example: Ethernet interface(24:d7:eb:bb:f2:1b): ETH_VLAN30, Got IP Address +I (3613) eth_vlan_example: ~~~~~~~~~~~ +I (3623) eth_vlan_example: ETHIP:192.168.30.10 +I (3623) eth_vlan_example: ETHMASK:192.168.30.1 +I (3633) eth_vlan_example: ETHGW:255.255.255.0 +I (3633) eth_vlan_example: ~~~~~~~~~~~ +I (3643) esp_netif_handlers: eth ip: 192.168.30.10, mask: 192.168.30.1, gw: 255.255.255.0 +I (7943) eth_vlan_example: Ethernet interface(24:d7:eb:bb:f2:1b): ETH_DEF, Got IP Address +I (7943) eth_vlan_example: ~~~~~~~~~~~ +I (7943) eth_vlan_example: ETHIP:192.168.10.100 +I (7943) eth_vlan_example: ETHMASK:255.255.255.0 +I (7953) eth_vlan_example: ETHGW:192.168.10.1 +I (7953) eth_vlan_example: ~~~~~~~~~~~ +I (7963) esp_netif_handlers: eth ip: 192.168.10.100, mask: 255.255.255.0, gw: 192.168.10.1 +``` + +Now you can ping your ESP32 in the terminal. +You can ping the ESP32 VLAN interface from the VLAN interface of your system with default VLAN tag 20. + +## Troubleshooting +### Setup VLAN on Linux +``` +vconfig add eth0 20 +ip addr add 192.168.20.30/24 dev eth0.20 +ip link set eth0.20 up +``` +Replace interface eth0 with your system ethernet interface. +### Setup VLAN on Mac +``` +sudo ifconfig vlan20 create +sudo ifconfig vlan20 vlan 20 vlandev en5 +sudo ifconfig vlan20 inet 192.168.20.30 netmask 255.255.255.0 +``` +Replace interface en5 with your system ethernet interface. + +See common troubleshooting for Ethernet examples from [upper level](../../ethernet/README.md#common-troubleshooting). + +(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.) diff --git a/examples/network/vlan_support/main/CMakeLists.txt b/examples/network/vlan_support/main/CMakeLists.txt new file mode 100644 index 000000000000..ab2281f9d990 --- /dev/null +++ b/examples/network/vlan_support/main/CMakeLists.txt @@ -0,0 +1,2 @@ +idf_component_register(SRCS "vlan_support_main.c" "eth_vlan_utils.c" + INCLUDE_DIRS ".") diff --git a/examples/network/vlan_support/main/Kconfig.projbuild b/examples/network/vlan_support/main/Kconfig.projbuild new file mode 100644 index 000000000000..aa2ad4903fe7 --- /dev/null +++ b/examples/network/vlan_support/main/Kconfig.projbuild @@ -0,0 +1,60 @@ +menu "Example Configuration" + + comment "Virtual Ethernet Interface Configuration" + + config EXAMPLE_ETHERNET_VLAN_ID + int "VLAN identifier" + range 1 4094 + default 20 + help + Set the VLAN Id to the virtual interface + + config EXAMPLE_VLAN_STATIC_IPV4_ADDR + string "IPV4 Address" + default "192.168.20.10" + help + The example will set this IPV4 address to this interface. + + config EXAMPLE_VLAN_STATIC_ADDR_MASK + string "Subnet Mask" + default "255.255.255.0" + + config EXAMPLE_VLAN_STATIC_ADDR_DEF_GW + string "IPV4 Default Gateway" + default "192.168.20.1" + + config EXAMPLE_EXTRA_VLAN_INTERFACE + bool "Additional Vlan Interface" + default n + help + Enables an additional VLAN interface + + if EXAMPLE_EXTRA_VLAN_INTERFACE + config EXAMPLE_EXTRA_ETHERNET_VLAN_ID + int "VLAN identifier" + range 1 4094 + default 30 + depends on EXAMPLE_EXTRA_VLAN_INTERFACE + help + Set the VLAN Id to the additional virtual interface + + config EXAMPLE_EXTRA_VLAN_STATIC_IPV4_ADDR + string "IPV4 Address" + default "192.168.30.10" + depends on EXAMPLE_EXTRA_VLAN_INTERFACE + help + The example will set this IPV4 address to this interface. + + config EXAMPLE_EXTRA_VLAN_STATIC_ADDR_MASK + string "Subnet Mask" + default "255.255.255.0" + depends on EXAMPLE_EXTRA_VLAN_INTERFACE + + config EXAMPLE_EXTRA_VLAN_STATIC_ADDR_DEF_GW + string "IPV4 Default Gateway" + default "192.168.30.1" + depends on EXAMPLE_EXTRA_VLAN_INTERFACE + + endif #EXAMPLE_EXTRA_VLAN_INTERFACE + +endmenu diff --git a/examples/network/vlan_support/main/eth_vlan_utils.c b/examples/network/vlan_support/main/eth_vlan_utils.c new file mode 100644 index 000000000000..49ad7cb38ecd --- /dev/null +++ b/examples/network/vlan_support/main/eth_vlan_utils.c @@ -0,0 +1,113 @@ +/* + * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "esp_netif.h" +#include "esp_eth_netif_glue.h" +#include "esp_netif_net_stack.h" +#include "esp_event.h" +#include "esp_log.h" +#include "esp_check.h" +#include "lwip/esp_netif_net_stack.h" +#include "sdkconfig.h" +#include "lwip/prot/ethernet.h" +#include "lwip/prot/ieee.h" +#include "eth_vlan_utils.h" +#if CONFIG_ESP_NETIF_L2_TAP +#include "esp_vfs_l2tap.h" +#endif + + +/** + * @brief This function gets invoked when Ethernet receive a new packets. + * + * @note This function is to be registered as a callback function which get invoked when Ethernet receive a new packets. + * + * @param eth_handle handle of Ethernet driver + * @param buffer buffer of the received packet + * @param length length of the received packet + * @param priv private pointer + * + * @return + * - ESP_OK: input frame buffer to upper stack successfully + * - ESP_FAIL: error occurred when inputting buffer to upper stack + */ +esp_err_t eth_input_to_netif(esp_eth_handle_t eth_handle, uint8_t *buffer, uint32_t length, void *priv) +{ + struct netif *lwip_netif; + u16_t netif_vlan_id; + struct eth_hdr *ethhdr = (struct eth_hdr *)buffer; + struct eth_vlan_hdr *vlan; + esp_vlan_netifs *vlan_netifs = (esp_vlan_netifs *)priv; + + if (PP_HTONS(ETHTYPE_VLAN) != ethhdr->type) { + // L2 tap after VLAN is not supported. +#if CONFIG_ESP_NETIF_L2_TAP + esp_err_t ret = ESP_OK; + ret = esp_vfs_l2tap_eth_filter(eth_handle, buffer, (size_t *)&length); + if (length == 0) { + return ret; + } +#endif + return esp_netif_receive(vlan_netifs->esp_netif[0], buffer, length, NULL); + } else { + for (int i = 1; i < vlan_netifs->netif_count; i++) { + lwip_netif = esp_netif_get_netif_impl(vlan_netifs->esp_netif[i]); + netif_vlan_id = *((uint16_t *)netif_get_client_data(lwip_netif, LWIP_NETIF_CLIENT_DATA_INDEX_MAX + 1)); + + vlan = (struct eth_vlan_hdr *)(((char *)ethhdr) + SIZEOF_ETH_HDR); + + if (VLAN_ID(vlan) == netif_vlan_id) { + return esp_netif_receive(vlan_netifs->esp_netif[i], buffer, length, NULL); + } + } + + // If the vlan id of the incoming frame doesn't match with any of the interface send it to the default interface. + return esp_netif_receive(vlan_netifs->esp_netif[0], buffer, length, NULL); + } +} + + +/** + * @brief This function creates configuration for esp-netif Ethernet + * + * @param vlan_id handle of Ethernet driver, used to name the interface key. + * @param vlan_eth_cfg_o output parameter returning the esp-netif ethernet configuration. + * + * @return ESP_OK or ESP_FAIL + */ +esp_err_t get_vlan_netif_config(uint16_t vlan_id, esp_netif_config_t *vlan_eth_cfg_o) +{ + // Create new default instance of VLAN esp-netif for Ethernet + char *if_key; + if (asprintf(&if_key, "ETH_VLAN%d", vlan_id) == -1) { + return ESP_FAIL; + } + + esp_netif_inherent_config_t *esp_eth_vlan_base_config = malloc(sizeof(esp_netif_inherent_config_t)); + if (NULL == esp_eth_vlan_base_config) { + return ESP_FAIL; + } + *esp_eth_vlan_base_config = (esp_netif_inherent_config_t)ESP_NETIF_INHERENT_DEFAULT_ETH(); + esp_eth_vlan_base_config->if_key = if_key; + + vlan_eth_cfg_o->base = esp_eth_vlan_base_config; + vlan_eth_cfg_o->driver = NULL; + vlan_eth_cfg_o->stack = ESP_NETIF_NETSTACK_DEFAULT_ETH; + + return ESP_OK; +} + +/** + * @brief This function frees the memory allocated for configuration for esp-netif Ethernet + * + * @param vlan_eth_cfg configuration for esp-netif Ethernet + */ +void free_vlan_config(esp_netif_config_t *vlan_eth_cfg) +{ + if ((NULL != vlan_eth_cfg) && (NULL != vlan_eth_cfg->base)) { + free((void *)(vlan_eth_cfg->base->if_key)); + free((void *)(vlan_eth_cfg->base)); + } +} diff --git a/examples/network/vlan_support/main/eth_vlan_utils.h b/examples/network/vlan_support/main/eth_vlan_utils.h new file mode 100644 index 000000000000..43ebbedb08a2 --- /dev/null +++ b/examples/network/vlan_support/main/eth_vlan_utils.h @@ -0,0 +1,50 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + + +// 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 netif_count; +} esp_vlan_netifs; + + +/** + * @brief This function gets invoked when Ethernet receive a new packets. + * + * @note This function is to be registered as a callback function which get invoked when Ethernet receive a new packets. + * + * @param eth_handle handle of Ethernet driver + * @param buffer buffer of the received packet + * @param length length of the received packet + * @param priv private pointer + * + * @return + * - ESP_OK: input frame buffer to upper stack successfully + * - ESP_FAIL: error occurred when inputting buffer to upper stack + */ +esp_err_t eth_input_to_netif(esp_eth_handle_t eth_handle, uint8_t *buffer, uint32_t length, void *priv); + + +/** + * @brief This function creates configuration for esp-netif Ethernet + * + * @param vlan_id handle of Ethernet driver, used to name the interface key. + * @param vlan_eth_cfg_o output parameter returning the esp-netif ethernet configuration. + * + * @return ESP_OK or ESP_FAIL + */ +esp_err_t get_vlan_netif_config(uint16_t vlan_id, esp_netif_config_t *vlan_eth_cfg_o); + + +/** + * @brief This function frees the memory allocated for configuration for esp-netif Ethernet + * + * @param vlan_eth_cfg configuration for esp-netif Ethernet + */ +void free_vlan_config(esp_netif_config_t *vlan_eth_cfg); diff --git a/examples/network/vlan_support/main/vlan_hooks.h b/examples/network/vlan_support/main/vlan_hooks.h new file mode 100644 index 000000000000..eb97125c6aaf --- /dev/null +++ b/examples/network/vlan_support/main/vlan_hooks.h @@ -0,0 +1,53 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ + +#include "lwip/netif.h" +#include "lwip/pbuf.h" +#include "lwip/prot/ethernet.h" + +/** + * @brief Returns the custom data stored in the supplied `netif` struct representing its vlan tag + * + * @param netif The lwIP network interface on which to send the packet + * @param p The packet to send. pbuf layer must be @ref PBUF_LINK. + * @param src The source MAC address to be copied into the ethernet header + * @param dst The destination MAC address to be copied into the ethernet header + * @param eth_type Ethernet type (@ref lwip_ieee_eth_type) + * + * @return Returns the vlan tag of the interface or -1. + */ +static inline int lwip_vlan_set(struct netif *netif, struct pbuf *p, + const struct eth_addr *src, const struct eth_addr *dst, + u16_t eth_type) +{ + u16_t vlan_id = *((uint16_t *)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_MAX + 1)); + + if (0xFFF == vlan_id) { + return -1; + } else { + return vlan_id; + } +} + +/** + * @brief Checks if the vlan tag in the frame matches the vlan tag of the interface. + * + * @param netif: struct netif on which the packet has been received + * @param eth_hdr: struct eth_hdr of the packet + * @param vlan_hdr: struct eth_vlan_hdr of the packet + * + * @return Returns true if the vlan tag in the frame matches the vlan tag of the interface, else returns false. + */ +static inline bool lwip_vlan_check(struct netif *netif, struct eth_hdr *eth_hdr, struct eth_vlan_hdr *vlan_hdr) +{ + u16_t vlan_id = *((uint16_t *)netif_get_client_data(netif, LWIP_NETIF_CLIENT_DATA_INDEX_MAX + 1)); + + if (vlan_id == VLAN_ID(vlan_hdr)) { + return true; + } + + return false; +} diff --git a/examples/network/vlan_support/main/vlan_support_main.c b/examples/network/vlan_support/main/vlan_support_main.c new file mode 100644 index 000000000000..bae06eeec89a --- /dev/null +++ b/examples/network/vlan_support/main/vlan_support_main.c @@ -0,0 +1,196 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +/* Ethernet Basic Example with an additional VLAN interface. */ +#include +#include +#include +#include "esp_netif.h" +#include "esp_eth.h" +#include "ethernet_init.h" +#include "esp_event.h" +#include "esp_log.h" +#include "eth_vlan_utils.h" +#include "sdkconfig.h" +#include "lwip/prot/ethernet.h" +#include "lwip/prot/ieee.h" +#include "esp_netif_net_stack.h" + + +static const char *TAG = "eth_vlan_example"; + +/** + * @brief Event handler for Ethernet events + * + * @note This function is not required for core functionality. + * + * @param arg + * @param event_base the base ID of the event to register the handler for + * @param event_id the ID of the event with which to unregister the handler + * @param event_data the data, specific to the event occurrence, that gets passed to the handler + */ +void eth_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + uint8_t mac_addr[6] = {0}; + /* we can get the ethernet driver handle from event data */ + esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data; + + switch (event_id) { + case ETHERNET_EVENT_CONNECTED: + esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr); + ESP_LOGI(TAG, "Ethernet Link Up"); + ESP_LOGI(TAG, "Ethernet HW Addr %02x:%02x:%02x:%02x:%02x:%02x", + mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); + break; + case ETHERNET_EVENT_DISCONNECTED: + ESP_LOGI(TAG, "Ethernet Link Down"); + break; + case ETHERNET_EVENT_START: + ESP_LOGI(TAG, "Ethernet Started"); + break; + case ETHERNET_EVENT_STOP: + ESP_LOGI(TAG, "Ethernet Stopped"); + break; + default: + ESP_LOGI(TAG, "Default Event"); + break; + } +} + + +/** + * @brief Event handler for IP_EVENT_ETH_GOT_IP + * + * @note This function is not required for core functionality. + * + * @param arg + * @param event_base the base ID of the event to register the handler for + * @param event_id the ID of the event with which to unregister the handler + * @param event_data the data, specific to the event occurrence, that gets passed to the handler + */ +void got_ip_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) +{ + ip_event_got_ip_t *event = (ip_event_got_ip_t *) event_data; + const esp_netif_ip_info_t *ip_info = &event->ip_info; + u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; + + esp_netif_get_mac(event->esp_netif, hwaddr); + ESP_LOGI(TAG, "Ethernet interface(%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F"): %s, Got IP Address", + hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5], esp_netif_get_ifkey(event->esp_netif)); + ESP_LOGI(TAG, "~~~~~~~~~~~"); + ESP_LOGI(TAG, "ETHIP:" IPSTR, IP2STR(&ip_info->ip)); + ESP_LOGI(TAG, "ETHMASK:" IPSTR, IP2STR(&ip_info->netmask)); + ESP_LOGI(TAG, "ETHGW:" IPSTR, IP2STR(&ip_info->gw)); + ESP_LOGI(TAG, "~~~~~~~~~~~"); +} + + +void app_main(void) +{ + static esp_vlan_netifs vlan_netif_list; + + // Initialize Ethernet driver + uint8_t eth_port_cnt = 0; + esp_eth_handle_t *eth_handle; + ESP_ERROR_CHECK(example_eth_init(ð_handle, ð_port_cnt)); + + // Check or multiple ethernet interface + if (1 < eth_port_cnt) { + ESP_LOGW(TAG, "Multiple Ethernet Interface detected: Only the first initialized interface is going to be used."); + } + + // Initialize TCP/IP network interface (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()); + + // Register user defined event handers + ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, NULL)); + + static uint16_t vlan_id[MAX_ETH_NETIF_COUNT]; + vlan_netif_list.netif_count = 0; + + // Create new default instance of default esp-netif for Ethernet. + // vlan_netif_list.esp_netif[0] must be used as default esp-netif for Ethernet, + // and all untagged and unsupported tagged frames will go to this interface. + esp_netif_config_t eth_cfg = ESP_NETIF_DEFAULT_ETH(); + vlan_netif_list.esp_netif[vlan_netif_list.netif_count] = esp_netif_new(ð_cfg); + + // Attach Ethernet drivers to TCP/IP stack + esp_eth_netif_glue_handle_t eth_glue = esp_eth_new_netif_glue(eth_handle[0]); + ESP_ERROR_CHECK(esp_netif_attach(vlan_netif_list.esp_netif[vlan_netif_list.netif_count], eth_glue)); + + // Set VLAN tag in data of lwip netif. + // VLAN tag 0xFFF can be used to indicate a wildcard match in management operations or filtering database entries. + vlan_id[vlan_netif_list.netif_count] = 0xFFF; + struct netif *lwip_netif = esp_netif_get_netif_impl(vlan_netif_list.esp_netif[vlan_netif_list.netif_count]); + netif_set_client_data(lwip_netif, LWIP_NETIF_CLIENT_DATA_INDEX_MAX + 1, (void *)&vlan_id[vlan_netif_list.netif_count]); + vlan_netif_list.netif_count++; + + + // Create new instance of esp-netif for Ethernet vlan interface + esp_netif_config_t vlan_eth_cfg; + ESP_ERROR_CHECK(get_vlan_netif_config(CONFIG_EXAMPLE_ETHERNET_VLAN_ID, &vlan_eth_cfg)); + vlan_netif_list.esp_netif[vlan_netif_list.netif_count] = esp_netif_new(&vlan_eth_cfg); + free_vlan_config(&vlan_eth_cfg); + + // Attach vlan Ethernet drivers to TCP/IP stack + esp_eth_netif_glue_handle_t vlan_glue = esp_eth_new_netif_glue(eth_handle[0]); + ESP_ERROR_CHECK(esp_netif_attach(vlan_netif_list.esp_netif[vlan_netif_list.netif_count], vlan_glue)); + + // Set VLAN tag in data of lwip netif + vlan_id[vlan_netif_list.netif_count] = CONFIG_EXAMPLE_ETHERNET_VLAN_ID; + lwip_netif = esp_netif_get_netif_impl(vlan_netif_list.esp_netif[vlan_netif_list.netif_count]); + netif_set_client_data(lwip_netif, LWIP_NETIF_CLIENT_DATA_INDEX_MAX + 1, (void *)&vlan_id[vlan_netif_list.netif_count]); + + // Set static IP to the ETH_VLAN interface + esp_netif_dhcpc_stop(vlan_netif_list.esp_netif[vlan_netif_list.netif_count]); + + esp_netif_ip_info_t info_t; + memset(&info_t, 0, sizeof(esp_netif_ip_info_t)); + inet_aton(CONFIG_EXAMPLE_VLAN_STATIC_IPV4_ADDR, &info_t.ip.addr); + inet_aton(CONFIG_EXAMPLE_VLAN_STATIC_ADDR_MASK, &info_t.gw.addr); + inet_aton(CONFIG_EXAMPLE_VLAN_STATIC_ADDR_DEF_GW, &info_t.netmask.addr); + esp_netif_set_ip_info(vlan_netif_list.esp_netif[vlan_netif_list.netif_count], &info_t); + vlan_netif_list.netif_count++; + + + +#if defined(CONFIG_EXAMPLE_EXTRA_VLAN_INTERFACE) + // Create an additional instance of esp-netif for Ethernet vlan interface + ESP_ERROR_CHECK(get_vlan_netif_config(CONFIG_EXAMPLE_EXTRA_ETHERNET_VLAN_ID, &vlan_eth_cfg)); + vlan_netif_list.esp_netif[vlan_netif_list.netif_count] = esp_netif_new(&vlan_eth_cfg); + free_vlan_config(&vlan_eth_cfg); + + // Attach vlan Ethernet drivers to TCP/IP stack + vlan_glue = esp_eth_new_netif_glue(eth_handle[0]); + ESP_ERROR_CHECK(esp_netif_attach(vlan_netif_list.esp_netif[vlan_netif_list.netif_count], vlan_glue)); + + // Set VLAN tag in data of lwip netif + vlan_id[vlan_netif_list.netif_count] = CONFIG_EXAMPLE_EXTRA_ETHERNET_VLAN_ID; + lwip_netif = esp_netif_get_netif_impl(vlan_netif_list.esp_netif[vlan_netif_list.netif_count]); + netif_set_client_data(lwip_netif, LWIP_NETIF_CLIENT_DATA_INDEX_MAX + 1, (void *)&vlan_id[vlan_netif_list.netif_count]); + + // Set static IP to the ETH_VLAN interface + esp_netif_dhcpc_stop(vlan_netif_list.esp_netif[vlan_netif_list.netif_count]); + + memset(&info_t, 0, sizeof(esp_netif_ip_info_t)); + inet_aton(CONFIG_EXAMPLE_EXTRA_VLAN_STATIC_IPV4_ADDR, &info_t.ip.addr); + inet_aton(CONFIG_EXAMPLE_EXTRA_VLAN_STATIC_ADDR_MASK, &info_t.gw.addr); + inet_aton(CONFIG_EXAMPLE_EXTRA_VLAN_STATIC_ADDR_DEF_GW, &info_t.netmask.addr); + esp_netif_set_ip_info(vlan_netif_list.esp_netif[vlan_netif_list.netif_count], &info_t); + vlan_netif_list.netif_count++; +#endif //CONFIG_EXAMPLE_EXTRA_VLAN_INTERFACE + + // Update input path of the ethernet driver + esp_eth_update_input_path(eth_handle[0], eth_input_to_netif, &vlan_netif_list); + + // start Ethernet driver state machine + ESP_ERROR_CHECK(esp_eth_start(eth_handle[0])); +} diff --git a/examples/network/vlan_support/sdkconfig.defaults b/examples/network/vlan_support/sdkconfig.defaults new file mode 100644 index 000000000000..19f33526c067 --- /dev/null +++ b/examples/network/vlan_support/sdkconfig.defaults @@ -0,0 +1,4 @@ +# This file was generated using idf.py save-defconfig. It can be edited manually. +# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration +# +CONFIG_LWIP_NUM_NETIF_CLIENT_DATA=1