From 05993b5090989e0673a0bb4266c1d234e51d48de Mon Sep 17 00:00:00 2001 From: Ondrej Kosta Date: Wed, 12 Aug 2026 12:39:21 +0200 Subject: [PATCH] feat(examples): add Ethernet sublayer example and update PTP Add a dedicated sublayer example under examples/ethernet and enable sublayer usage in the PTP example. --- docs/en/api-reference/network/esp_eth.rst | 14 ++ docs/zh_CN/api-reference/network/esp_eth.rst | 14 ++ examples/ethernet/.build-test-rules.yml | 11 ++ examples/ethernet/README.md | 2 + examples/ethernet/ptp/main/ptp_main.c | 20 ++- examples/ethernet/sublayer/CMakeLists.txt | 8 + examples/ethernet/sublayer/README.md | 55 +++++++ .../ethernet/sublayer/main/CMakeLists.txt | 3 + .../ethernet/sublayer/main/Kconfig.projbuild | 22 +++ .../main/ethernet_sublayer_example_main.c | 143 ++++++++++++++++++ .../ethernet/sublayer/main/idf_component.yml | 3 + .../ethernet/sublayer/pytest_eth_sublayer.py | 26 ++++ .../ethernet/sublayer/sdkconfig.ci.defaults | 4 + .../sublayer/sdkconfig.ci.defaults_esp32p4 | 4 + .../sublayer/sdkconfig.ci.defaults_esp32s31 | 4 + examples/ethernet/sublayer/sdkconfig.defaults | 5 + 16 files changed, 337 insertions(+), 1 deletion(-) create mode 100644 examples/ethernet/sublayer/CMakeLists.txt create mode 100644 examples/ethernet/sublayer/README.md create mode 100644 examples/ethernet/sublayer/main/CMakeLists.txt create mode 100644 examples/ethernet/sublayer/main/Kconfig.projbuild create mode 100644 examples/ethernet/sublayer/main/ethernet_sublayer_example_main.c create mode 100644 examples/ethernet/sublayer/main/idf_component.yml create mode 100644 examples/ethernet/sublayer/pytest_eth_sublayer.py create mode 100644 examples/ethernet/sublayer/sdkconfig.ci.defaults create mode 100644 examples/ethernet/sublayer/sdkconfig.ci.defaults_esp32p4 create mode 100644 examples/ethernet/sublayer/sdkconfig.ci.defaults_esp32s31 create mode 100644 examples/ethernet/sublayer/sdkconfig.defaults diff --git a/docs/en/api-reference/network/esp_eth.rst b/docs/en/api-reference/network/esp_eth.rst index f19183a92f0..b89b807a21c 100644 --- a/docs/en/api-reference/network/esp_eth.rst +++ b/docs/en/api-reference/network/esp_eth.rst @@ -683,6 +683,20 @@ The majority of PHY management functionality required by the ESP-IDF Ethernet dr Once you finish the new custom PHY driver implementation, consider sharing it among other users via `ESP Component Registry `_. +.. _ethernet-sublayer: + +Ethernet Sublayer +^^^^^^^^^^^^^^^^^ + +The Ethernet sublayer is an optional layer between one physical Ethernet driver (``esp_eth_handle_t``) and one or more ``esp_netif`` instances. It owns the driver RX input path, distributes Ethernet events to attached interfaces, and can perform mid-path frame processing such as 802.1Q VLAN multiplexing and demultiplexing. + +.. note:: + The Ethernet sublayer is an **experimental** feature. Enable :menuitem:`CONFIG_IDF_EXPERIMENTAL_FEATURES` and :menuitem:`CONFIG_ETH_SUBLAYER_SUPPORT` to use it. The API is under active development and may change in future ESP-IDF releases without a deprecation period. + +For architecture details, configuration, and usage guidance, see :component_file:`esp_eth/src/sublayer/README.md`. + +A working demonstration is available in :example:`ethernet/sublayer`, which shares one Ethernet driver between an untagged ``esp_netif`` and a tagged VLAN ``esp_netif``. + .. ---------------------------- API Reference ---------------------------------- API Reference diff --git a/docs/zh_CN/api-reference/network/esp_eth.rst b/docs/zh_CN/api-reference/network/esp_eth.rst index af51e757c87..aa48dcb9c8e 100644 --- a/docs/zh_CN/api-reference/network/esp_eth.rst +++ b/docs/zh_CN/api-reference/network/esp_eth.rst @@ -683,6 +683,20 @@ ESP-IDF 以太网驱动程序所需的大部分 PHY 管理功能都已涵盖在 实现新的自定义 PHY 驱动程序后,你可以通过 `乐鑫组件注册表 `_ 将驱动分享给其他用户。 +.. _ethernet-sublayer: + +以太网子层 +^^^^^^^^^^ + +以太网子层是位于一个物理以太网驱动程序(``esp_eth_handle_t``)与一个或多个 ``esp_netif`` 实例之间的可选层。它负责拥有驱动程序的 RX 输入路径,将以太网事件分发给所连接的接口,并可执行路径中的帧处理,例如 802.1Q VLAN 复用与解复用。 + +.. note:: + 以太网子层是一项**实验性**功能。需启用 :menuitem:`CONFIG_IDF_EXPERIMENTAL_FEATURES` 和 :menuitem:`CONFIG_ETH_SUBLAYER_SUPPORT` 后方可使用。该 API 仍在积极开发中,未来 ESP-IDF 版本中可能会在不经过弃用周期的情况下发生变更。 + +有关架构细节、配置和使用指南,请参阅 :component_file:`esp_eth/src/sublayer/README.md`。 + +可参考 :example:`ethernet/sublayer` 中的示例,该示例演示了如何在一个未打标签的 ``esp_netif`` 和一个带标签的 VLAN ``esp_netif`` 之间共享同一个以太网驱动程序。 + .. ---------------------------- API Reference ---------------------------------- API 参考 diff --git a/examples/ethernet/.build-test-rules.yml b/examples/ethernet/.build-test-rules.yml index 324366ca33d..1e27da54276 100644 --- a/examples/ethernet/.build-test-rules.yml +++ b/examples/ethernet/.build-test-rules.yml @@ -36,3 +36,14 @@ examples/ethernet/ptp: depends_components: - esp_eth - esp_netif + +examples/ethernet/sublayer: + enable: + - if: INCLUDE_DEFAULT == 1 + disable: + - if: IDF_TARGET not in ["esp32", "esp32p4", "esp32s31"] + depends_components: + - esp_eth + - esp_netif + - lwip + - esp_driver_gpio diff --git a/examples/ethernet/README.md b/examples/ethernet/README.md index 8a73c60c532..91e5e102d45 100644 --- a/examples/ethernet/README.md +++ b/examples/ethernet/README.md @@ -9,6 +9,8 @@ Ethernet examples demonstrate basic features related to Ethernet layer, such as: * basic Ethernet initialization and binding to IP stack via ESP-NETIF +* experimental Ethernet netif sublayer (untagged + VLAN interfaces on one driver) + * tools for performance measurement, i.e. `iperf` * hardware time synchronization diff --git a/examples/ethernet/ptp/main/ptp_main.c b/examples/ethernet/ptp/main/ptp_main.c index 581891e9563..c397100780d 100644 --- a/examples/ethernet/ptp/main/ptp_main.c +++ b/examples/ethernet/ptp/main/ptp_main.c @@ -59,8 +59,21 @@ void init_ethernet_and_netif(void) esp_netif_base_config.route_prio -= i*5; esp_netif_t *eth_netif = esp_netif_new(&esp_netif_config); +#if CONFIG_ETH_SUBLAYER_SUPPORT + ESP_LOGI(TAG, "Using Ethernet sublayer"); + esp_eth_sublayer_config_t sub_config = { + .eth_handle = eth_handles[i], + }; + esp_eth_sublayer_handle_t eth_sublayer = NULL; + ESP_ERROR_CHECK(esp_eth_sublayer_new(&sub_config, ð_sublayer)); + esp_eth_sublayer_vlan_handle_t eth_netif_untag = NULL; + ESP_ERROR_CHECK(esp_eth_sublayer_vlan_add(eth_sublayer, ESP_ETH_SUBLAYER_UNTAGGED_VID, ð_netif_untag)); + // attach Ethernet driver to TCP/IP stack + ESP_ERROR_CHECK(esp_netif_attach(eth_netif, eth_netif_untag)); +#else // attach Ethernet driver to TCP/IP stack ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handles[i]))); +#endif } for (int i = 0; i < eth_port_cnt; i++) { @@ -127,7 +140,12 @@ void app_main(void) ptp_deamon_start(); #if CONFIG_EXAMPLE_PTP_PULSE_EMAC_PPS - esp_eth_handle_t eth_handle = esp_netif_get_io_driver(esp_netif_get_handle_from_ifkey(ETH_IF_KEY)); + esp_netif_iodriver_handle netif_iodriver = esp_netif_get_io_driver(esp_netif_get_handle_from_ifkey(ETH_IF_KEY)); +#if CONFIG_ETH_SUBLAYER_SUPPORT + esp_eth_handle_t eth_handle = esp_eth_sublayer_vlan_get_eth_handle(netif_iodriver); +#else + esp_eth_handle_t eth_handle = (esp_eth_handle_t)netif_iodriver; +#endif esp_eth_mac_t *mac; ESP_ERROR_CHECK(esp_eth_get_mac_instance(eth_handle, &mac)); ESP_ERROR_CHECK(esp_eth_mac_set_pps_out_gpio(mac, CONFIG_EXAMPLE_PTP_PULSE_GPIO)); diff --git a/examples/ethernet/sublayer/CMakeLists.txt b/examples/ethernet/sublayer/CMakeLists.txt new file mode 100644 index 00000000000..4058da1ed16 --- /dev/null +++ b/examples/ethernet/sublayer/CMakeLists.txt @@ -0,0 +1,8 @@ +# The following 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.22) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +# "Trim" the build. Include the minimal set of components, main, and anything it depends on. +idf_build_set_property(MINIMAL_BUILD ON) +project(ethernet_sublayer) diff --git a/examples/ethernet/sublayer/README.md b/examples/ethernet/sublayer/README.md new file mode 100644 index 00000000000..c2b59635caf --- /dev/null +++ b/examples/ethernet/sublayer/README.md @@ -0,0 +1,55 @@ +| Supported Targets | ESP32 | ESP32-P4 | ESP32-S31 | +| ----------------- | ----- | -------- | --------- | + +# Ethernet Sublayer Example + +Demonstrates the experimental Ethernet netif sublayer (`esp_eth_sublayer`): one physical Ethernet driver shared by an untagged `esp_netif` (DHCP) and a tagged 802.1Q VLAN `esp_netif` (static IP). + +Uses the [ethernet_init](https://components.espressif.com/components/espressif/ethernet_init/) component for driver setup. + +## How to use example + +### Configure the project + +``` +idf.py menuconfig +``` + +See common configurations for Ethernet examples from [upper level](../README.md#common-configurations). + +This example requires enabling `CONFIG_IDF_EXPERIMENTAL_FEATURES` and `CONFIG_ETH_SUBLAYER_SUPPORT`. + +### 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-]``.) + +### Setup VLAN interface on Linux + +Create a tagged 802.1Q interface on the host so you can reach the ESP VLAN netif (defaults: VID `20`, IP `192.168.20.10`): + +```bash +# Replace eth0 with your host Ethernet interface (e.g. enp3s0) +sudo ip link add link eth0 name eth0.20 type vlan id 20 +sudo ip addr add 192.168.20.1/24 dev eth0.20 +sudo ip link set eth0.20 up + +ping 192.168.20.10 +``` + +To remove it later: + +```bash +sudo ip link delete eth0.20 +``` + +Match `id` / address to **Example Configuration** if you changed the defaults. The physical link between the host and the board must carry tagged frames (direct cable, or a switch port in trunk/hybrid mode). + +See [upper-level Ethernet README](../README.md) for hardware notes and common troubleshooting. diff --git a/examples/ethernet/sublayer/main/CMakeLists.txt b/examples/ethernet/sublayer/main/CMakeLists.txt new file mode 100644 index 00000000000..01357c103ab --- /dev/null +++ b/examples/ethernet/sublayer/main/CMakeLists.txt @@ -0,0 +1,3 @@ +idf_component_register(SRCS "ethernet_sublayer_example_main.c" + PRIV_REQUIRES esp_netif esp_eth + INCLUDE_DIRS ".") diff --git a/examples/ethernet/sublayer/main/Kconfig.projbuild b/examples/ethernet/sublayer/main/Kconfig.projbuild new file mode 100644 index 00000000000..fab04dbb0c3 --- /dev/null +++ b/examples/ethernet/sublayer/main/Kconfig.projbuild @@ -0,0 +1,22 @@ +menu "Example Configuration" + + config EXAMPLE_ETHERNET_VLAN_ID + int "VLAN identifier" + range 1 4094 + default 20 + help + 802.1Q VLAN ID for the tagged virtual interface created via the Ethernet sublayer. + + config EXAMPLE_VLAN_STATIC_IPV4_ADDR + string "VLAN IPV4 Address" + default "192.168.20.10" + + config EXAMPLE_VLAN_STATIC_ADDR_MASK + string "VLAN Subnet Mask" + default "255.255.255.0" + + config EXAMPLE_VLAN_STATIC_ADDR_DEF_GW + string "VLAN IPV4 Default Gateway" + default "192.168.20.1" + +endmenu diff --git a/examples/ethernet/sublayer/main/ethernet_sublayer_example_main.c b/examples/ethernet/sublayer/main/ethernet_sublayer_example_main.c new file mode 100644 index 00000000000..958072a7b70 --- /dev/null +++ b/examples/ethernet/sublayer/main/ethernet_sublayer_example_main.c @@ -0,0 +1,143 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Unlicense OR CC0-1.0 + */ +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_event.h" +#include "esp_netif.h" +#include "esp_eth.h" +#include "ethernet_init.h" +#include "esp_log.h" +#include "sdkconfig.h" + +#ifndef CONFIG_ETH_SUBLAYER_SUPPORT +#error "This example requires CONFIG_ETH_SUBLAYER_SUPPORT (enable IDF experimental features)" +#endif + +static const char *TAG = "eth_sublayer_example"; + +/** Event handler for Ethernet events */ +static 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}; + 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: + break; + } +} + +/** Event handler for IP_EVENT_ETH_GOT_IP */ +static 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; + + ESP_LOGI(TAG, "Ethernet Got IP Address (%s)", 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, "~~~~~~~~~~~"); +} + +static esp_err_t create_vlan_netif_config(uint16_t vlan_id, esp_netif_config_t *cfg) +{ + char *if_key; + if (asprintf(&if_key, "ETH_VLAN%d", vlan_id) < 0) { + return ESP_ERR_NO_MEM; + } + + esp_netif_inherent_config_t *base = malloc(sizeof(*base)); + if (base == NULL) { + free(if_key); + return ESP_ERR_NO_MEM; + } + *base = (esp_netif_inherent_config_t)ESP_NETIF_INHERENT_DEFAULT_ETH(); + base->if_key = if_key; + base->if_desc = "eth_vlan"; + base->route_prio = 30; + + cfg->base = base; + cfg->driver = NULL; + cfg->stack = ESP_NETIF_NETSTACK_DEFAULT_ETH; + return ESP_OK; +} + +static void free_vlan_netif_config(esp_netif_config_t *cfg) +{ + if (cfg && cfg->base) { + free((void *)cfg->base->if_key); + free((void *)cfg->base); + } +} + +void app_main(void) +{ + uint8_t eth_port_cnt = 0; + esp_eth_handle_t *eth_handles = NULL; + + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + ESP_ERROR_CHECK(ethernet_init_all(ð_handles, ð_port_cnt)); + if (eth_port_cnt > 1) { + ESP_LOGW(TAG, "Multiple Ethernet interfaces detected, using the first one"); + } + + 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)); + + // Create Ethernet sublayer bound to the physical driver + esp_eth_sublayer_config_t sub_config = ESP_ETH_SUBLAYER_CONFIG_DEFAULT(); + sub_config.eth_handle = eth_handles[0]; + esp_eth_sublayer_handle_t sublayer = NULL; + ESP_ERROR_CHECK(esp_eth_sublayer_new(&sub_config, &sublayer)); + + // Untagged interface (DHCP) + esp_eth_sublayer_vlan_handle_t untagged = NULL; + ESP_ERROR_CHECK(esp_eth_sublayer_vlan_add(sublayer, ESP_ETH_SUBLAYER_UNTAGGED_VID, &untagged)); + esp_netif_config_t eth_cfg = ESP_NETIF_DEFAULT_ETH(); + esp_netif_t *eth_netif = esp_netif_new(ð_cfg); + ESP_ERROR_CHECK(esp_netif_attach(eth_netif, untagged)); + + // Tagged VLAN interface (static IP) + esp_eth_sublayer_vlan_handle_t vlan = NULL; + ESP_ERROR_CHECK(esp_eth_sublayer_vlan_add(sublayer, CONFIG_EXAMPLE_ETHERNET_VLAN_ID, &vlan)); + esp_netif_config_t vlan_cfg; + ESP_ERROR_CHECK(create_vlan_netif_config(CONFIG_EXAMPLE_ETHERNET_VLAN_ID, &vlan_cfg)); + esp_netif_t *vlan_netif = esp_netif_new(&vlan_cfg); + free_vlan_netif_config(&vlan_cfg); + ESP_ERROR_CHECK(esp_netif_attach(vlan_netif, vlan)); + + esp_netif_dhcpc_stop(vlan_netif); + esp_netif_ip_info_t vlan_ip = {0}; + inet_aton(CONFIG_EXAMPLE_VLAN_STATIC_IPV4_ADDR, &vlan_ip.ip.addr); + inet_aton(CONFIG_EXAMPLE_VLAN_STATIC_ADDR_DEF_GW, &vlan_ip.gw.addr); + inet_aton(CONFIG_EXAMPLE_VLAN_STATIC_ADDR_MASK, &vlan_ip.netmask.addr); + ESP_ERROR_CHECK(esp_netif_set_ip_info(vlan_netif, &vlan_ip)); + + ESP_ERROR_CHECK(esp_eth_start(eth_handles[0])); +} diff --git a/examples/ethernet/sublayer/main/idf_component.yml b/examples/ethernet/sublayer/main/idf_component.yml new file mode 100644 index 00000000000..cc244f74d1f --- /dev/null +++ b/examples/ethernet/sublayer/main/idf_component.yml @@ -0,0 +1,3 @@ +dependencies: + espressif/ethernet_init: + version: "~1.4.1" diff --git a/examples/ethernet/sublayer/pytest_eth_sublayer.py b/examples/ethernet/sublayer/pytest_eth_sublayer.py new file mode 100644 index 00000000000..a58a3cbb45b --- /dev/null +++ b/examples/ethernet/sublayer/pytest_eth_sublayer.py @@ -0,0 +1,26 @@ +# SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD +# SPDX-License-Identifier: Unlicense OR CC0-1.0 +import platform +import subprocess + +import pytest +from pytest_embedded import Dut + + +@pytest.mark.parametrize( + 'config, target', + [ + pytest.param('defaults', 'esp32', marks=[pytest.mark.eth_ip101]), + pytest.param('defaults_esp32p4', 'esp32p4', marks=[pytest.mark.eth_ip101]), + pytest.param('defaults_esp32s31', 'esp32s31', marks=[pytest.mark.eth_yt8531]), + ], + indirect=['target'], +) +def test_esp_eth_sublayer(dut: Dut) -> None: + # wait for IP on the untagged interface + dut_ip = dut.expect(r'esp_netif_handlers: .+ ip: (\d+\.\d+\.\d+\.\d+),').group(1) + param = '-n' if platform.system().lower() == 'windows' else '-c' + command = ['ping', param, '1', dut_ip] + output = subprocess.run(command, capture_output=True) + if 'unreachable' in str(output.stdout): + raise RuntimeError('Host unreachable') diff --git a/examples/ethernet/sublayer/sdkconfig.ci.defaults b/examples/ethernet/sublayer/sdkconfig.ci.defaults new file mode 100644 index 00000000000..4514247a716 --- /dev/null +++ b/examples/ethernet/sublayer/sdkconfig.ci.defaults @@ -0,0 +1,4 @@ +CONFIG_IDF_TARGET="esp32" + +CONFIG_ETHERNET_INTERNAL_SUPPORT=y +CONFIG_ETHERNET_PHY_IP101=y diff --git a/examples/ethernet/sublayer/sdkconfig.ci.defaults_esp32p4 b/examples/ethernet/sublayer/sdkconfig.ci.defaults_esp32p4 new file mode 100644 index 00000000000..987db90b976 --- /dev/null +++ b/examples/ethernet/sublayer/sdkconfig.ci.defaults_esp32p4 @@ -0,0 +1,4 @@ +CONFIG_IDF_TARGET="esp32p4" + +CONFIG_ETHERNET_INTERNAL_SUPPORT=y +CONFIG_ETHERNET_PHY_IP101=y diff --git a/examples/ethernet/sublayer/sdkconfig.ci.defaults_esp32s31 b/examples/ethernet/sublayer/sdkconfig.ci.defaults_esp32s31 new file mode 100644 index 00000000000..0e057be5f18 --- /dev/null +++ b/examples/ethernet/sublayer/sdkconfig.ci.defaults_esp32s31 @@ -0,0 +1,4 @@ +CONFIG_IDF_TARGET="esp32s31" + +CONFIG_ETHERNET_INTERNAL_SUPPORT=y +CONFIG_ETHERNET_PHY_YT8531=y diff --git a/examples/ethernet/sublayer/sdkconfig.defaults b/examples/ethernet/sublayer/sdkconfig.defaults new file mode 100644 index 00000000000..009d650eae2 --- /dev/null +++ b/examples/ethernet/sublayer/sdkconfig.defaults @@ -0,0 +1,5 @@ +CONFIG_IDF_EXPERIMENTAL_FEATURES=y +CONFIG_ETH_SUBLAYER_SUPPORT=y +CONFIG_ETH_SUBLAYER_VLAN_SUPPORT=y +CONFIG_ETH_TRANSMIT_MUTEX=n +CONFIG_ETH_SUBLAYER_TRANSMIT_MUTEX=y