mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
esp_netif: added support for LwIP bridge
examples: created bridge example
This commit is contained in:
parent
7f884dc966
commit
53082a22f7
@ -37,12 +37,17 @@ list(APPEND srcs
|
||||
"vfs_l2tap/esp_vfs_l2tap.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_ESP_NETIF_BRIDGE_EN)
|
||||
list(APPEND srcs
|
||||
"lwip/esp_netif_br_glue.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS "${include_dirs}"
|
||||
PRIV_INCLUDE_DIRS "${priv_include_dirs}"
|
||||
REQUIRES lwip)
|
||||
|
||||
|
||||
if(CONFIG_ESP_NETIF_L2_TAP)
|
||||
idf_component_optional_requires(PRIVATE esp_eth)
|
||||
if(CONFIG_ESP_NETIF_L2_TAP OR CONFIG_ESP_NETIF_BRIDGE_EN)
|
||||
idf_component_optional_requires(PRIVATE esp_eth)
|
||||
endif()
|
||||
|
@ -56,4 +56,12 @@ menu "ESP NETIF Adapter"
|
||||
Maximum number of frames queued in opened File descriptor. Once the queue is full, the newly arriving
|
||||
frames are dropped until the queue has enough room to accept incoming traffic (Tail Drop queue
|
||||
management).
|
||||
|
||||
config ESP_NETIF_BRIDGE_EN
|
||||
depends on ESP_NETIF_TCPIP_LWIP
|
||||
bool "Enable LwIP IEEE 802.1D bridge"
|
||||
default n
|
||||
help
|
||||
Enable LwIP IEEE 802.1D bridge support in ESP-NETIF. Note that "Number of clients store data in netif"
|
||||
(LWIP_NUM_NETIF_CLIENT_DATA) option needs to be properly configured to be LwIP bridge avaiable!
|
||||
endmenu
|
||||
|
@ -276,6 +276,37 @@ void esp_netif_action_remove_ip6_address(void *esp_netif, esp_event_base_t base,
|
||||
*/
|
||||
esp_err_t esp_netif_set_default_netif(esp_netif_t *esp_netif);
|
||||
|
||||
|
||||
#if CONFIG_ESP_NETIF_BRIDGE_EN
|
||||
/**
|
||||
* @brief Add a port to the bridge
|
||||
*
|
||||
* @param esp_netif_br Handle to bridge esp-netif instance
|
||||
* @param esp_netif_port Handle to port esp-netif instance
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_netif_bridge_add_port(esp_netif_t *esp_netif_br, esp_netif_t *esp_netif_port);
|
||||
|
||||
/**
|
||||
* @brief Add a static entry to bridge forwarding database
|
||||
*
|
||||
* @param esp_netif_br Handle to bridge esp-netif instance
|
||||
* @param addr MAC address entry to be added
|
||||
* @param ports_mask Port(s) mask where to be the address forwarded
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_netif_bridge_fdb_add(esp_netif_t *esp_netif_br, uint8_t *addr, uint64_t ports_mask);
|
||||
|
||||
/**
|
||||
* @brief Remove a static entry from bridge forwarding database
|
||||
*
|
||||
* @param esp_netif_br Handle to bridge esp-netif instance
|
||||
* @param addr MAC address entry to be removed
|
||||
* @return ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_netif_bridge_fdb_remove(esp_netif_t *esp_netif_br, uint8_t *addr);
|
||||
#endif // CONFIG_ESP_NETIF_BRIDGE_EN
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
49
components/esp_netif/include/esp_netif_br_glue.h
Normal file
49
components/esp_netif/include/esp_netif_br_glue.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "esp_netif.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Handle of bridge netif glue - an intermediate layer between ESP-NETIF and bridge ports ESP-NETIFs
|
||||
* to access ports io drivers properties
|
||||
*
|
||||
*/
|
||||
typedef struct esp_netif_br_glue_t* esp_netif_br_glue_handle_t;
|
||||
|
||||
/**
|
||||
* @brief Create a netif glue for bridge
|
||||
* @note bridge netif glue is used to attach ports netifs to the bridge (e.g. to get io driver statuses)
|
||||
*
|
||||
* @return - glue object on success
|
||||
* - NULL on fail
|
||||
*/
|
||||
esp_netif_br_glue_handle_t esp_netif_br_glue_new(void);
|
||||
|
||||
/**
|
||||
* @brief Add a port to the bridge netif glue
|
||||
*
|
||||
* @param netif_br_glue bridge netif glue
|
||||
* @param esp_netif_port port netif
|
||||
* @return - ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_netif_br_glue_add_port(esp_netif_br_glue_handle_t netif_br_glue, esp_netif_t *esp_netif_port);
|
||||
|
||||
/**
|
||||
* @brief Delete netif glue of bridge
|
||||
*
|
||||
* @param netif_br_glue bridge netif glue
|
||||
* @return - ESP_OK: delete netif glue successfully
|
||||
*/
|
||||
esp_err_t esp_netif_br_glue_del(esp_netif_br_glue_handle_t netif_br_glue);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -26,7 +26,8 @@ extern "C" {
|
||||
.lost_ip_event = IP_EVENT_STA_LOST_IP, \
|
||||
.if_key = "WIFI_STA_DEF", \
|
||||
.if_desc = "sta", \
|
||||
.route_prio = 100 \
|
||||
.route_prio = 100, \
|
||||
.bridge_info = NULL \
|
||||
} \
|
||||
|
||||
#ifdef CONFIG_ESP_WIFI_SOFTAP_SUPPORT
|
||||
@ -39,7 +40,8 @@ extern "C" {
|
||||
.lost_ip_event = 0, \
|
||||
.if_key = "WIFI_AP_DEF", \
|
||||
.if_desc = "ap", \
|
||||
.route_prio = 10 \
|
||||
.route_prio = 10, \
|
||||
.bridge_info = NULL \
|
||||
};
|
||||
#endif
|
||||
|
||||
@ -52,7 +54,8 @@ extern "C" {
|
||||
.lost_ip_event = IP_EVENT_ETH_LOST_IP, \
|
||||
.if_key = "ETH_DEF", \
|
||||
.if_desc = "eth", \
|
||||
.route_prio = 50 \
|
||||
.route_prio = 50, \
|
||||
.bridge_info = NULL \
|
||||
};
|
||||
|
||||
#define ESP_NETIF_INHERENT_DEFAULT_PPP() \
|
||||
@ -64,7 +67,8 @@ extern "C" {
|
||||
.lost_ip_event = IP_EVENT_PPP_LOST_IP, \
|
||||
.if_key = "PPP_DEF", \
|
||||
.if_desc = "ppp", \
|
||||
.route_prio = 20 \
|
||||
.route_prio = 20, \
|
||||
.bridge_info = NULL \
|
||||
};
|
||||
|
||||
#define ESP_NETIF_INHERENT_DEFAULT_OPENTHREAD() \
|
||||
@ -76,7 +80,8 @@ extern "C" {
|
||||
.lost_ip_event = 0, \
|
||||
.if_key = "OT_DEF", \
|
||||
.if_desc = "openthread", \
|
||||
.route_prio = 15 \
|
||||
.route_prio = 15, \
|
||||
.bridge_info = NULL \
|
||||
};
|
||||
|
||||
#define ESP_NETIF_INHERENT_DEFAULT_SLIP() \
|
||||
@ -88,9 +93,22 @@ extern "C" {
|
||||
.lost_ip_event = 0, \
|
||||
.if_key = "SLP_DEF", \
|
||||
.if_desc = "slip", \
|
||||
.route_prio = 16 \
|
||||
.route_prio = 16, \
|
||||
.bridge_info = NULL \
|
||||
};
|
||||
|
||||
#define ESP_NETIF_INHERENT_DEFAULT_BR() \
|
||||
{ \
|
||||
.flags = (esp_netif_flags_t)(ESP_NETIF_DHCP_CLIENT | ESP_NETIF_FLAG_GARP | ESP_NETIF_FLAG_EVENT_IP_MODIFIED | ESP_NETIF_FLAG_IS_BRIDGE), \
|
||||
ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_EMPTY(mac) \
|
||||
ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_EMPTY(ip_info) \
|
||||
.get_ip_event = IP_EVENT_ETH_GOT_IP, \
|
||||
.lost_ip_event = IP_EVENT_ETH_LOST_IP, \
|
||||
.if_key = "BR", \
|
||||
.if_desc = "br", \
|
||||
.route_prio = 70, \
|
||||
.bridge_info = NULL \
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Default configuration reference of ethernet interface
|
||||
@ -174,6 +192,7 @@ extern "C" {
|
||||
|
||||
|
||||
#define ESP_NETIF_NETSTACK_DEFAULT_ETH _g_esp_netif_netstack_default_eth
|
||||
#define ESP_NETIF_NETSTACK_DEFAULT_BR _g_esp_netif_netstack_default_br
|
||||
#define ESP_NETIF_NETSTACK_DEFAULT_WIFI_STA _g_esp_netif_netstack_default_wifi_sta
|
||||
#ifdef CONFIG_ESP_WIFI_SOFTAP_SUPPORT
|
||||
#define ESP_NETIF_NETSTACK_DEFAULT_WIFI_AP _g_esp_netif_netstack_default_wifi_ap
|
||||
@ -189,6 +208,7 @@ extern "C" {
|
||||
// - Here referenced only as opaque pointers
|
||||
//
|
||||
extern const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_eth;
|
||||
extern const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_br;
|
||||
extern const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_wifi_sta;
|
||||
#ifdef CONFIG_ESP_WIFI_SOFTAP_SUPPORT
|
||||
extern const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_wifi_ap;
|
||||
|
@ -28,12 +28,18 @@ extern "C" {
|
||||
#define ESP_ERR_ESP_NETIF_DHCP_ALREADY_STOPPED ESP_ERR_ESP_NETIF_BASE + 0x05
|
||||
#define ESP_ERR_ESP_NETIF_NO_MEM ESP_ERR_ESP_NETIF_BASE + 0x06
|
||||
#define ESP_ERR_ESP_NETIF_DHCP_NOT_STOPPED ESP_ERR_ESP_NETIF_BASE + 0x07
|
||||
#define ESP_ERR_ESP_NETIF_DRIVER_ATTACH_FAILED ESP_ERR_ESP_NETIF_BASE + 0x08
|
||||
#define ESP_ERR_ESP_NETIF_DRIVER_ATTACH_FAILED ESP_ERR_ESP_NETIF_BASE + 0x08
|
||||
#define ESP_ERR_ESP_NETIF_INIT_FAILED ESP_ERR_ESP_NETIF_BASE + 0x09
|
||||
#define ESP_ERR_ESP_NETIF_DNS_NOT_CONFIGURED ESP_ERR_ESP_NETIF_BASE + 0x0A
|
||||
#define ESP_ERR_ESP_NETIF_MLD6_FAILED ESP_ERR_ESP_NETIF_BASE + 0x0B
|
||||
#define ESP_ERR_ESP_NETIF_IP6_ADDR_FAILED ESP_ERR_ESP_NETIF_BASE + 0x0C
|
||||
|
||||
/**
|
||||
* @brief Definition of ESP-NETIF bridge controll
|
||||
*/
|
||||
#define ESP_NETIF_BR_FLOOD -1
|
||||
#define ESP_NETIF_BR_DROP 0
|
||||
#define ESP_NETIF_BR_FDW_CPU (1ULL << 63)
|
||||
|
||||
/** @brief Type of esp_netif_object server */
|
||||
struct esp_netif_obj;
|
||||
@ -146,8 +152,6 @@ typedef struct {
|
||||
} ip_event_ap_staipassigned_t;
|
||||
|
||||
|
||||
|
||||
|
||||
typedef enum esp_netif_flags {
|
||||
ESP_NETIF_DHCP_CLIENT = 1 << 0,
|
||||
ESP_NETIF_DHCP_SERVER = 1 << 1,
|
||||
@ -156,6 +160,7 @@ typedef enum esp_netif_flags {
|
||||
ESP_NETIF_FLAG_EVENT_IP_MODIFIED = 1 << 4,
|
||||
ESP_NETIF_FLAG_IS_PPP = 1 << 5,
|
||||
ESP_NETIF_FLAG_IS_SLIP = 1 << 6,
|
||||
ESP_NETIF_FLAG_IS_BRIDGE = 1 << 7,
|
||||
} esp_netif_flags_t;
|
||||
|
||||
typedef enum esp_netif_ip_event_type {
|
||||
@ -164,6 +169,13 @@ typedef enum esp_netif_ip_event_type {
|
||||
} esp_netif_ip_event_type_t;
|
||||
|
||||
|
||||
/** LwIP bridge configuration */
|
||||
typedef struct bridgeif_config {
|
||||
uint16_t max_fdb_dyn_entries; /*!< maximum number of entries in dynamic forwarding database */
|
||||
uint16_t max_fdb_sta_entries; /*!< maximum number of entries in static forwarding database */
|
||||
uint8_t max_ports; /*!< maximum number of ports the bridge can consist of */
|
||||
} bridgeif_config_t;
|
||||
|
||||
//
|
||||
// ESP-NETIF interface configuration:
|
||||
// 1) general (behavioral) config (esp_netif_config_t)
|
||||
@ -187,6 +199,7 @@ typedef struct esp_netif_inherent_config {
|
||||
routing if (if other netifs are up).
|
||||
A higher value of route_prio indicates
|
||||
a higher priority */
|
||||
bridgeif_config_t *bridge_info; /*!< LwIP bridge configuration */
|
||||
} esp_netif_inherent_config_t;
|
||||
|
||||
typedef struct esp_netif_config esp_netif_config_t;
|
||||
|
250
components/esp_netif/lwip/esp_netif_br_glue.c
Normal file
250
components/esp_netif/lwip/esp_netif_br_glue.c
Normal file
@ -0,0 +1,250 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include "esp_netif_br_glue.h"
|
||||
#include "esp_eth_driver.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
|
||||
#if CONFIG_ESP_NETIF_BRIDGE_EN
|
||||
|
||||
const static char *TAG = "esp_netif_br_glue";
|
||||
|
||||
typedef struct esp_netif_br_glue_t esp_netif_br_glue_t;
|
||||
|
||||
struct esp_netif_br_glue_t {
|
||||
esp_netif_driver_base_t base;
|
||||
bool br_started;
|
||||
esp_netif_t **ports_esp_netifs;
|
||||
uint8_t port_cnt;
|
||||
esp_event_handler_instance_t eth_start_ctx_handler;
|
||||
esp_event_handler_instance_t eth_stop_ctx_handler;
|
||||
esp_event_handler_instance_t eth_connect_ctx_handler;
|
||||
esp_event_handler_instance_t eth_disconnect_ctx_handler;
|
||||
esp_event_handler_instance_t get_ip_ctx_handler;
|
||||
};
|
||||
|
||||
static esp_err_t esp_eth_post_attach_br(esp_netif_t *esp_netif, void *args)
|
||||
{
|
||||
uint8_t eth_mac[6];
|
||||
esp_netif_br_glue_t *netif_glue = (esp_netif_br_glue_t *)args;
|
||||
netif_glue->base.netif = esp_netif;
|
||||
|
||||
esp_netif_get_mac(esp_netif, eth_mac);
|
||||
ESP_LOGI(TAG, "%02x:%02x:%02x:%02x:%02x:%02x", eth_mac[0], eth_mac[1],
|
||||
eth_mac[2], eth_mac[3], eth_mac[4], eth_mac[5]);
|
||||
|
||||
ESP_LOGI(TAG, "bridge netif glue attached");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void eth_action_start(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;
|
||||
esp_netif_br_glue_t *netif_glue = handler_args;
|
||||
ESP_LOGD(TAG, "eth_action_start: %p, %p, %d, %p, %p", netif_glue, base, event_id, event_data, *(esp_eth_handle_t *)event_data);
|
||||
|
||||
for (int i = 0; i < netif_glue->port_cnt; i++) {
|
||||
if (eth_handle == esp_netif_get_io_driver(netif_glue->ports_esp_netifs[i])) {
|
||||
if (netif_glue->br_started == false) {
|
||||
esp_netif_action_start(netif_glue->base.netif, base, event_id, event_data); // basically creates lwip_netif br instance
|
||||
netif_glue->br_started = true;
|
||||
ESP_LOGD(TAG, "bridge netif %p is started", netif_glue->base.netif);
|
||||
}
|
||||
esp_netif_bridge_add_port(netif_glue->base.netif, netif_glue->ports_esp_netifs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void eth_action_stop(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;
|
||||
esp_netif_br_glue_t *netif_glue = handler_args;
|
||||
ESP_LOGD(TAG, "eth_action_stop: %p, %p, %d, %p, %p", netif_glue, base, event_id, event_data, *(esp_eth_handle_t *)event_data);
|
||||
|
||||
for (int i = 0; i < netif_glue->port_cnt; i++) {
|
||||
// if one of the bridge's ports is stopped, we need to stop the bridge too, since port's lwip_netif is removed and so it would become
|
||||
// an invalid reference in the bridge's internal structure (there is no way how to remove single port from bridge in current LwIP)
|
||||
if (eth_handle == esp_netif_get_io_driver(netif_glue->ports_esp_netifs[i])) {
|
||||
if (netif_glue->br_started == true) {
|
||||
esp_netif_action_stop(netif_glue->base.netif, base, event_id, event_data); // basically removes lwip_netif br
|
||||
netif_glue->br_started = false;
|
||||
ESP_LOGD(TAG, "bridge netif %p is stopped", netif_glue->base.netif);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void eth_action_connected(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;
|
||||
esp_netif_br_glue_t *netif_glue = handler_args;
|
||||
ESP_LOGD(TAG, "eth_action_connected: %p, %p, %d, %p, %p", netif_glue, base, event_id, event_data, *(esp_eth_handle_t *)event_data);
|
||||
|
||||
// if bridge interface is already up, do nothing
|
||||
if (esp_netif_is_netif_up(netif_glue->base.netif) == true) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < netif_glue->port_cnt; i++) {
|
||||
if (eth_handle == esp_netif_get_io_driver(netif_glue->ports_esp_netifs[i])) {
|
||||
esp_netif_action_connected(netif_glue->base.netif, base, event_id, event_data);
|
||||
ESP_LOGD(TAG, "bridge netif %p is connected", netif_glue->base.netif);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void eth_action_disconnected(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;
|
||||
esp_netif_br_glue_t *netif_glue = handler_args;
|
||||
ESP_LOGD(TAG, "eth_action_disconnected: %p, %p, %d, %p, %p", netif_glue, base, event_id, event_data, *(esp_eth_handle_t *)event_data);
|
||||
|
||||
for (int i = 0; i < netif_glue->port_cnt; i++) {
|
||||
// if this is a Ethernet interface associated with bridge, check if other ports are disconnected
|
||||
if (eth_handle == esp_netif_get_io_driver(netif_glue->ports_esp_netifs[i])) {
|
||||
int disc_cnt;
|
||||
for (disc_cnt = 0; disc_cnt < netif_glue->port_cnt; disc_cnt++) {
|
||||
if (esp_netif_is_netif_up(netif_glue->ports_esp_netifs[disc_cnt]) == true) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if all ports are disconnected, set bridge as disconnected too
|
||||
if (disc_cnt >= netif_glue->port_cnt) {
|
||||
esp_netif_action_disconnected(netif_glue->base.netif, base, event_id, event_data);
|
||||
ESP_LOGD(TAG, "bridge netif %p is disconnected", netif_glue->base.netif);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void br_action_got_ip(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
|
||||
{
|
||||
ip_event_got_ip_t *ip_event = (ip_event_got_ip_t *)event_data;
|
||||
esp_netif_br_glue_t *netif_glue = handler_args;
|
||||
ESP_LOGD(TAG, "br_action_got_ip: %p, %p, %d, %p, %p", netif_glue, base, event_id, event_data, *(esp_eth_handle_t *)event_data);
|
||||
if (netif_glue->base.netif == ip_event->esp_netif) {
|
||||
esp_netif_action_got_ip(ip_event->esp_netif, base, event_id, event_data);
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t esp_netif_br_glue_clear_instance_handlers(esp_netif_br_glue_handle_t esp_netif_br_glue)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(esp_netif_br_glue, ESP_ERR_INVALID_ARG, TAG, "esp_netif_br_glue handle can't be null");
|
||||
|
||||
if (esp_netif_br_glue->eth_start_ctx_handler) {
|
||||
esp_event_handler_instance_unregister(ETH_EVENT, ETHERNET_EVENT_START, esp_netif_br_glue->eth_start_ctx_handler);
|
||||
esp_netif_br_glue->eth_start_ctx_handler = NULL;
|
||||
}
|
||||
|
||||
if (esp_netif_br_glue->eth_stop_ctx_handler) {
|
||||
esp_event_handler_instance_unregister(ETH_EVENT, ETHERNET_EVENT_STOP, esp_netif_br_glue->eth_stop_ctx_handler);
|
||||
esp_netif_br_glue->eth_stop_ctx_handler = NULL;
|
||||
}
|
||||
|
||||
if (esp_netif_br_glue->eth_connect_ctx_handler) {
|
||||
esp_event_handler_instance_unregister(ETH_EVENT, ETHERNET_EVENT_CONNECTED, esp_netif_br_glue->eth_connect_ctx_handler);
|
||||
esp_netif_br_glue->eth_connect_ctx_handler = NULL;
|
||||
}
|
||||
|
||||
if (esp_netif_br_glue->eth_disconnect_ctx_handler) {
|
||||
esp_event_handler_instance_unregister(ETH_EVENT, ETHERNET_EVENT_DISCONNECTED, esp_netif_br_glue->eth_disconnect_ctx_handler);
|
||||
esp_netif_br_glue->eth_disconnect_ctx_handler = NULL;
|
||||
}
|
||||
|
||||
if (esp_netif_br_glue->get_ip_ctx_handler) {
|
||||
esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP, esp_netif_br_glue->get_ip_ctx_handler);
|
||||
esp_netif_br_glue->get_ip_ctx_handler = NULL;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t esp_netif_br_glue_set_instance_handlers(esp_netif_br_glue_handle_t esp_netif_br_glue)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(esp_netif_br_glue, ESP_ERR_INVALID_ARG, TAG, "esp_netif_br_glue handle can't be null");
|
||||
|
||||
esp_err_t ret = esp_event_handler_instance_register(ETH_EVENT, ETHERNET_EVENT_START, eth_action_start, esp_netif_br_glue, &esp_netif_br_glue->eth_start_ctx_handler);
|
||||
if (ret != ESP_OK) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = esp_event_handler_instance_register(ETH_EVENT, ETHERNET_EVENT_STOP, eth_action_stop, esp_netif_br_glue, &esp_netif_br_glue->eth_stop_ctx_handler);
|
||||
if (ret != ESP_OK) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = esp_event_handler_instance_register(ETH_EVENT, ETHERNET_EVENT_CONNECTED, eth_action_connected, esp_netif_br_glue, &esp_netif_br_glue->eth_connect_ctx_handler);
|
||||
if (ret != ESP_OK) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = esp_event_handler_instance_register(ETH_EVENT, ETHERNET_EVENT_DISCONNECTED, eth_action_disconnected, esp_netif_br_glue, &esp_netif_br_glue->eth_disconnect_ctx_handler);
|
||||
if (ret != ESP_OK) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = esp_event_handler_instance_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, br_action_got_ip, esp_netif_br_glue, &esp_netif_br_glue->get_ip_ctx_handler);
|
||||
if (ret != ESP_OK) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
fail:
|
||||
esp_netif_br_glue_clear_instance_handlers(esp_netif_br_glue);
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_netif_br_glue_handle_t esp_netif_br_glue_new(void)
|
||||
{
|
||||
esp_netif_br_glue_t *netif_glue = calloc(1, sizeof(esp_netif_br_glue_t));
|
||||
if (!netif_glue) {
|
||||
ESP_LOGE(TAG, "create netif glue failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
netif_glue->base.post_attach = esp_eth_post_attach_br;
|
||||
|
||||
if (esp_netif_br_glue_set_instance_handlers(netif_glue) != ESP_OK) {
|
||||
esp_netif_br_glue_del(netif_glue);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return netif_glue;
|
||||
}
|
||||
|
||||
esp_err_t esp_netif_br_glue_add_port(esp_netif_br_glue_handle_t netif_br_glue, esp_netif_t *esp_netif_port)
|
||||
{
|
||||
if (netif_br_glue->ports_esp_netifs == NULL) {
|
||||
netif_br_glue->ports_esp_netifs = malloc(sizeof(esp_netif_t *));
|
||||
} else {
|
||||
netif_br_glue->ports_esp_netifs = realloc(netif_br_glue->ports_esp_netifs, (netif_br_glue->port_cnt + 1) * sizeof(esp_netif_t *));
|
||||
}
|
||||
if (!netif_br_glue->ports_esp_netifs) {
|
||||
ESP_LOGE(TAG, "no memory to add br port");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
netif_br_glue->ports_esp_netifs[netif_br_glue->port_cnt] = esp_netif_port;
|
||||
netif_br_glue->port_cnt++;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_netif_br_glue_del(esp_netif_br_glue_handle_t netif_br_glue)
|
||||
{
|
||||
esp_netif_br_glue_clear_instance_handlers(netif_br_glue);
|
||||
free(netif_br_glue->ports_esp_netifs);
|
||||
free(netif_br_glue);
|
||||
netif_br_glue = NULL;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#endif // CONFIG_ESP_NETIF_BRIDGE_EN
|
@ -26,13 +26,16 @@
|
||||
#include "lwip/priv/tcpip_priv.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/etharp.h"
|
||||
#if CONFIG_ESP_NETIF_BRIDGE_EN
|
||||
#include "netif/bridgeif.h"
|
||||
#endif // CONFIG_ESP_NETIF_BRIDGE_EN
|
||||
#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
|
||||
#include "lwip/dns.h"
|
||||
#endif
|
||||
#endif // LWIP_DNS
|
||||
|
||||
#if CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT
|
||||
#include "lwip_default_hooks.h"
|
||||
#endif
|
||||
#endif // CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT
|
||||
|
||||
#include "esp_netif_lwip_ppp.h"
|
||||
#include "esp_netif_lwip_slip.h"
|
||||
@ -340,6 +343,39 @@ esp_err_t esp_netif_set_default_netif(esp_netif_t *esp_netif)
|
||||
return esp_netif_update_default_netif(esp_netif, ESP_NETIF_SET_DEFAULT);
|
||||
}
|
||||
|
||||
#if CONFIG_ESP_NETIF_BRIDGE_EN
|
||||
esp_err_t esp_netif_bridge_add_port(esp_netif_t *esp_netif_br, esp_netif_t *esp_netif_port)
|
||||
{
|
||||
if (ERR_OK != bridgeif_add_port(esp_netif_br->lwip_netif, esp_netif_port->lwip_netif)) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_netif_bridge_fdb_add(esp_netif_t *esp_netif_br, uint8_t *addr, uint64_t ports_mask)
|
||||
{
|
||||
bridgeif_portmask_t ports;
|
||||
if (ports_mask == ESP_NETIF_BR_FDW_CPU) {
|
||||
ports = 1 << BRIDGEIF_MAX_PORTS;
|
||||
} else {
|
||||
ports = (bridgeif_portmask_t)ports_mask;
|
||||
}
|
||||
|
||||
if (ERR_OK != bridgeif_fdb_add(esp_netif_br->lwip_netif, (const struct eth_addr *)addr, ports)) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t esp_netif_bridge_fdb_remove(esp_netif_t *esp_netif_br, uint8_t *addr)
|
||||
{
|
||||
if (ERR_OK != bridgeif_fdb_remove(esp_netif_br->lwip_netif, (const struct eth_addr *)addr)) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif // CONFIG_ESP_NETIF_BRIDGE_EN
|
||||
|
||||
void esp_netif_set_ip4_addr(esp_ip4_addr_t *addr, uint8_t a, uint8_t b, uint8_t c, uint8_t d)
|
||||
{
|
||||
ip4_addr_t *address = (ip4_addr_t*)addr;
|
||||
@ -383,7 +419,23 @@ esp_netif_t* esp_netif_get_handle_from_netif_impl(void *dev)
|
||||
{
|
||||
// ppp_pcb ptr would never get to app code, so this function only works with vanilla lwip impl
|
||||
struct netif *lwip_netif = dev;
|
||||
#if CONFIG_ESP_NETIF_BRIDGE_EN
|
||||
// bridge lwip netif uses "state" member for something different => need to traverse all esp_netifs
|
||||
if (lwip_netif->name[0] == 'b' && lwip_netif->name[1] == 'r') {
|
||||
esp_netif_t* esp_netif = esp_netif_next(NULL);
|
||||
do
|
||||
{
|
||||
if(esp_netif->lwip_netif == lwip_netif) {
|
||||
return esp_netif;
|
||||
}
|
||||
} while ((esp_netif = esp_netif_next(esp_netif)) != NULL);
|
||||
} else {
|
||||
return lwip_netif->state;
|
||||
}
|
||||
return NULL;
|
||||
#else
|
||||
return lwip_netif->state;
|
||||
#endif // CONFIG_ESP_NETIF_BRIDGE_EN
|
||||
}
|
||||
|
||||
void* esp_netif_get_netif_impl(esp_netif_t *esp_netif)
|
||||
@ -485,6 +537,19 @@ static esp_err_t esp_netif_init_configuration(esp_netif_t *esp_netif, const esp_
|
||||
esp_netif->route_prio = cfg->base->route_prio;
|
||||
}
|
||||
|
||||
#if CONFIG_ESP_NETIF_BRIDGE_EN
|
||||
// Setup bridge configuration if the interface is to be bridge
|
||||
if (cfg->base->flags & ESP_NETIF_FLAG_IS_BRIDGE) {
|
||||
if (cfg->base->bridge_info != NULL) {
|
||||
esp_netif->max_fdb_dyn_entries = cfg->base->bridge_info->max_fdb_dyn_entries;
|
||||
esp_netif->max_fdb_sta_entries = cfg->base->bridge_info->max_fdb_sta_entries;
|
||||
esp_netif->max_ports = cfg->base->bridge_info->max_ports;
|
||||
} else {
|
||||
return ESP_ERR_ESP_NETIF_INVALID_PARAMS;
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_ESP_NETIF_BRIDGE_EN
|
||||
|
||||
// Install network stack functions -- connects netif and L3 stack
|
||||
const esp_netif_netstack_config_t *esp_netif_stack_config = cfg->stack;
|
||||
if (cfg->base->flags & ESP_NETIF_FLAG_IS_PPP) {
|
||||
@ -668,12 +733,31 @@ static esp_err_t esp_netif_lwip_add(esp_netif_t *esp_netif)
|
||||
#endif
|
||||
}
|
||||
|
||||
if (NULL == netif_add(esp_netif->lwip_netif, (struct ip4_addr*)&esp_netif->ip_info->ip,
|
||||
(struct ip4_addr*)&esp_netif->ip_info->netmask, (struct ip4_addr*)&esp_netif->ip_info->gw,
|
||||
esp_netif, esp_netif->lwip_init_fn, tcpip_input)) {
|
||||
esp_netif_lwip_remove(esp_netif);
|
||||
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
|
||||
#if CONFIG_ESP_NETIF_BRIDGE_EN
|
||||
if (esp_netif->flags & ESP_NETIF_FLAG_IS_BRIDGE) {
|
||||
bridgeif_initdata_t bridge_initdata = {
|
||||
.max_fdb_dynamic_entries = esp_netif->max_fdb_dyn_entries,
|
||||
.max_fdb_static_entries = esp_netif->max_fdb_sta_entries,
|
||||
.max_ports = esp_netif->max_ports
|
||||
};
|
||||
memcpy(&bridge_initdata.ethaddr, esp_netif->mac, ETH_HWADDR_LEN);
|
||||
if (NULL == netif_add(esp_netif->lwip_netif, (struct ip4_addr*)&esp_netif->ip_info->ip,
|
||||
(struct ip4_addr*)&esp_netif->ip_info->netmask, (struct ip4_addr*)&esp_netif->ip_info->gw,
|
||||
&bridge_initdata, esp_netif->lwip_init_fn, tcpip_input)) {
|
||||
esp_netif_lwip_remove(esp_netif);
|
||||
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
|
||||
}
|
||||
} else {
|
||||
#endif // CONFIG_ESP_NETIF_BRIDGE_EN
|
||||
if (NULL == netif_add(esp_netif->lwip_netif, (struct ip4_addr*)&esp_netif->ip_info->ip,
|
||||
(struct ip4_addr*)&esp_netif->ip_info->netmask, (struct ip4_addr*)&esp_netif->ip_info->gw,
|
||||
esp_netif, esp_netif->lwip_init_fn, tcpip_input)) {
|
||||
esp_netif_lwip_remove(esp_netif);
|
||||
return ESP_ERR_ESP_NETIF_IF_NOT_READY;
|
||||
}
|
||||
#if CONFIG_ESP_NETIF_BRIDGE_EN
|
||||
}
|
||||
#endif // CONFIG_ESP_NETIF_BRIDGE_EN
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -803,9 +887,8 @@ static esp_err_t esp_netif_config_sanity_check(const esp_netif_t * esp_netif)
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (esp_netif->driver_transmit == NULL ||
|
||||
esp_netif->driver_handle == NULL ||
|
||||
esp_netif->lwip_input_fn == NULL ||
|
||||
if ((!(esp_netif->flags & ESP_NETIF_FLAG_IS_BRIDGE) && (esp_netif->driver_transmit == NULL ||
|
||||
esp_netif->driver_handle == NULL || esp_netif->lwip_input_fn == NULL)) ||
|
||||
esp_netif->lwip_init_fn == NULL) {
|
||||
ESP_LOGE(TAG, "Cannot start esp_netif: Missing mandatory configuration:\n"
|
||||
"esp_netif->driver_transmit: %p, esp_netif->driver_handle:%p, "
|
||||
@ -847,6 +930,7 @@ static esp_err_t esp_netif_start_api(esp_netif_api_msg_t *msg)
|
||||
if (esp_netif->flags&ESP_NETIF_FLAG_AUTOUP) {
|
||||
ESP_LOGD(TAG, "%s Setting the lwip netif%p UP", __func__, p_netif);
|
||||
netif_set_up(p_netif);
|
||||
netif_set_link_up(p_netif);
|
||||
}
|
||||
if (esp_netif->flags & ESP_NETIF_DHCP_SERVER) {
|
||||
#if ESP_DHCPS
|
||||
@ -1394,6 +1478,7 @@ static esp_err_t esp_netif_up_api(esp_netif_api_msg_t *msg)
|
||||
/* use last obtained ip, or static ip */
|
||||
netif_set_addr(lwip_netif, (ip4_addr_t*)&esp_netif->ip_info->ip, (ip4_addr_t*)&esp_netif->ip_info->netmask, (ip4_addr_t*)&esp_netif->ip_info->gw);
|
||||
netif_set_up(lwip_netif);
|
||||
netif_set_link_up(lwip_netif);
|
||||
|
||||
esp_netif_update_default_netif(esp_netif, ESP_NETIF_STARTED);
|
||||
|
||||
@ -1431,6 +1516,7 @@ static esp_err_t esp_netif_down_api(esp_netif_api_msg_t *msg)
|
||||
#endif
|
||||
netif_set_addr(lwip_netif, IP4_ADDR_ANY4, IP4_ADDR_ANY4, IP4_ADDR_ANY4);
|
||||
netif_set_down(lwip_netif);
|
||||
netif_set_link_down(lwip_netif);
|
||||
|
||||
if (esp_netif->flags & ESP_NETIF_DHCP_CLIENT) {
|
||||
esp_netif_start_ip_lost_timer(esp_netif);
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "netif/wlanif.h"
|
||||
#include "netif/ethernetif.h"
|
||||
#include "netif/bridgeif.h"
|
||||
#if CONFIG_OPENTHREAD_ENABLED
|
||||
#include "netif/openthreadif.h"
|
||||
#endif
|
||||
@ -27,6 +28,12 @@ static const struct esp_netif_netstack_config s_eth_netif_config = {
|
||||
.input_fn = ethernetif_input
|
||||
}
|
||||
};
|
||||
static const struct esp_netif_netstack_config s_br_netif_config = {
|
||||
.lwip = {
|
||||
.init_fn = bridgeif_init,
|
||||
.input_fn = NULL
|
||||
}
|
||||
};
|
||||
static const struct esp_netif_netstack_config s_wifi_netif_config_ap = {
|
||||
.lwip = {
|
||||
.init_fn = wlanif_init_ap,
|
||||
@ -52,6 +59,7 @@ static const struct esp_netif_netstack_config s_netif_config_ppp = {
|
||||
};
|
||||
|
||||
const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_eth = &s_eth_netif_config;
|
||||
const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_br = &s_br_netif_config;
|
||||
const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_wifi_sta = &s_wifi_netif_config_sta;
|
||||
const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_wifi_ap = &s_wifi_netif_config_ap;
|
||||
const esp_netif_netstack_config_t *_g_esp_netif_netstack_default_ppp = &s_netif_config_ppp;
|
||||
|
@ -126,6 +126,13 @@ struct esp_netif_obj {
|
||||
char * if_key;
|
||||
char * if_desc;
|
||||
int route_prio;
|
||||
|
||||
#if CONFIG_ESP_NETIF_BRIDGE_EN
|
||||
// bridge configuration
|
||||
uint16_t max_fdb_dyn_entries;
|
||||
uint16_t max_fdb_sta_entries;
|
||||
uint8_t max_ports;
|
||||
#endif // CONFIG_ESP_NETIF_BRIDGE_EN
|
||||
};
|
||||
|
||||
#endif /* CONFIG_ESP_NETIF_TCPIP_LWIP */
|
||||
|
@ -56,6 +56,9 @@ set(srcs
|
||||
"lwip/src/core/ipv6/mld6.c"
|
||||
"lwip/src/core/ipv6/nd6.c"
|
||||
"lwip/src/netif/ethernet.c"
|
||||
"lwip/src/netif/bridgeif.c"
|
||||
"lwip/src/netif/bridgeif_fdb.c"
|
||||
"lwip/src/netif/slipif.c"
|
||||
"lwip/src/netif/slipif.c"
|
||||
"lwip/src/netif/ppp/auth.c"
|
||||
"lwip/src/netif/ppp/ccp.c"
|
||||
|
@ -250,6 +250,13 @@ menu "LWIP"
|
||||
options and values. If your code meets LWIP_ASSERT due to option value is too long.
|
||||
Please increase the LWIP_DHCP_OPTIONS_LEN value.
|
||||
|
||||
config LWIP_NUM_NETIF_CLIENT_DATA
|
||||
int "Number of clients store data in netif"
|
||||
default 0
|
||||
range 0 256
|
||||
help
|
||||
Number of clients that may store data in client_data member array of struct netif.
|
||||
|
||||
menu "DHCP server"
|
||||
|
||||
config LWIP_DHCPS
|
||||
@ -870,6 +877,13 @@ menu "LWIP"
|
||||
|
||||
endmenu # SNTP
|
||||
|
||||
config LWIP_BRIDGEIF_MAX_PORTS
|
||||
int "Maximum number of bridge ports"
|
||||
default 7
|
||||
range 1 63
|
||||
help
|
||||
Set maximum number of ports a bridge can consists of.
|
||||
|
||||
config LWIP_ESP_LWIP_ASSERT
|
||||
bool "Enable LWIP ASSERT checks"
|
||||
default y
|
||||
@ -1075,4 +1089,19 @@ menu "LWIP"
|
||||
depends on LWIP_DEBUG
|
||||
default n
|
||||
|
||||
config LWIP_BRIDGEIF_DEBUG
|
||||
bool "Enable bridge generic debug messages"
|
||||
depends on LWIP_DEBUG
|
||||
default n
|
||||
|
||||
config LWIP_BRIDGEIF_FDB_DEBUG
|
||||
bool "Enable bridge FDB debug messages"
|
||||
depends on LWIP_DEBUG
|
||||
default n
|
||||
|
||||
config LWIP_BRIDGEIF_FW_DEBUG
|
||||
bool "Enable bridge forwarding debug messages"
|
||||
depends on LWIP_DEBUG
|
||||
default n
|
||||
|
||||
endmenu
|
||||
|
@ -661,6 +661,22 @@ static inline uint32_t timeout_from_offered(uint32_t lease, uint32_t min)
|
||||
*/
|
||||
#define LWIP_NETIF_TX_SINGLE_PBUF 1
|
||||
|
||||
/**
|
||||
* LWIP_NUM_NETIF_CLIENT_DATA: Number of clients that may store
|
||||
* data in client_data member array of struct netif (max. 256).
|
||||
*/
|
||||
#ifdef CONFIG_LWIP_NUM_NETIF_CLIENT_DATA
|
||||
#define LWIP_NUM_NETIF_CLIENT_DATA CONFIG_LWIP_NUM_NETIF_CLIENT_DATA
|
||||
#endif
|
||||
|
||||
/**
|
||||
* BRIDGEIF_MAX_PORTS: this is used to create a typedef used for forwarding
|
||||
* bit-fields: the number of bits required is this + 1 (for the internal/cpu port)
|
||||
*/
|
||||
#ifdef CONFIG_LWIP_BRIDGEIF_MAX_PORTS
|
||||
#define BRIDGEIF_MAX_PORTS CONFIG_LWIP_BRIDGEIF_MAX_PORTS
|
||||
#endif
|
||||
|
||||
/*
|
||||
------------------------------------
|
||||
---------- LOOPIF options ----------
|
||||
@ -1328,6 +1344,27 @@ static inline uint32_t timeout_from_offered(uint32_t lease, uint32_t min)
|
||||
*/
|
||||
#define TCP_OOSEQ_DEBUG LWIP_DBG_OFF
|
||||
|
||||
/**
|
||||
* BRIDGEIF_DEBUG: Enable generic debugging for bridge.
|
||||
*/
|
||||
#ifdef CONFIG_LWIP_BRIDGEIF_DEBUG
|
||||
#define BRIDGEIF_DEBUG LWIP_DBG_ON
|
||||
#endif
|
||||
|
||||
/**
|
||||
* BRIDGEIF_FDB_DEBUG: Enable debugging for bridge FDB.
|
||||
*/
|
||||
#ifdef CONFIG_LWIP_BRIDGEIF_FDB_DEBUG
|
||||
#define BRIDGEIF_FDB_DEBUG LWIP_DBG_ON
|
||||
#endif
|
||||
|
||||
/**
|
||||
* BRIDGEIF_FW_DEBUG: Enable debugging for bridge forwarding.
|
||||
*/
|
||||
#ifdef CONFIG_LWIP_BRIDGEIF_FW_DEBUG
|
||||
#define BRIDGEIF_FW_DEBUG LWIP_DBG_ON
|
||||
#endif
|
||||
|
||||
/*
|
||||
--------------------------------------
|
||||
------------ SNTP options ------------
|
||||
|
@ -74,7 +74,7 @@ static void ethernet_low_level_init(struct netif *netif)
|
||||
|
||||
/* device capabilities */
|
||||
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
|
||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
|
||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET;
|
||||
|
||||
#if ESP_LWIP
|
||||
#if LWIP_IGMP
|
||||
|
@ -61,7 +61,7 @@ low_level_init(struct netif *netif)
|
||||
|
||||
/* device capabilities */
|
||||
/* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */
|
||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;
|
||||
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;
|
||||
|
||||
#if ESP_LWIP
|
||||
#if LWIP_IGMP
|
||||
|
6
examples/network/bridge/CMakeLists.txt
Normal file
6
examples/network/bridge/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# 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.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(bridge)
|
145
examples/network/bridge/README.md
Normal file
145
examples/network/bridge/README.md
Normal file
@ -0,0 +1,145 @@
|
||||
# Bridge Example
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
## Overview
|
||||
|
||||
This example demonstrates basic usage of `LwIP IEEE 802.1D bridge`. Bridge connects two separate networks to appear as if they were a single network at layer 2.
|
||||
|
||||
Specifically, from IOT use cases point of view, one of the advantages of bridge usage is to enable ring topology of Ethernet connected devices which would otherwise needed to be connected in tree topology. Tree topology usually requires extensive wiring since each device is connected to the central point (switch/router) by separate cable. In opposite, ring topology can save wiring since the devices can be "daisy-chained" (each device in path can pass the traffic further to the final destination). Note that the ring may not be "closed" and so simplifies network topology even further.
|
||||
|
||||
Performance of this type of "software" bridge is limited by the performance of ESP32 and data bus used to interconnect ESP32 with physical network interfaces (e.g. SPI shared among multiple Ethernet modules). If your application requires higher performance network, please consider using switch ICs which are specifically designed for such applications like [KSZ8863](https://github.com/espressif/esp-eth-drivers/blob/master/ksz8863/).
|
||||
|
||||
## How to use example
|
||||
|
||||
You need one ESP32 with at least two Ethernet ports and two PCs (or other Ethernet capable devices). Connect the network as shown in figure below, configure PC#1 as DHCP server and PC#2 as DHCP client.
|
||||
|
||||
![example network](docs/network.png)
|
||||
|
||||
The work flow of the example is then as follows:
|
||||
|
||||
1. Install the Ethernet ports drivers in ESP32.
|
||||
2. Configure bridge.
|
||||
3. Wait for a DHCP leases in ESP32 and PC#2.
|
||||
4. If get IP addresses successfully, then you will be able to ping the ESP32 device and PC#2 from PC#1 (and vice versa).
|
||||
|
||||
## Hardware Required
|
||||
|
||||
To run this example, it's recommended that you have either 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), or 3rd party ESP32 board as long as it's integrated with a supported Ethernet PHY chips, connected with supported SPI Ethernet modules (for example `DM9051`, `W5500` or `KSZ8851SNL`). Or ESP32(S/C series) board without internal Ethernet interface but connected to multiple SPI Ethernet modules.
|
||||
|
||||
### Pin Assignment
|
||||
|
||||
See common pin assignments for [Ethernet examples](../../ethernet/README.md#common-pin-assignments).
|
||||
|
||||
When using two Ethernet SPI modules at a time, they are to be connected to single SPI interface. Both modules then share data (MOSI/MISO) and CLK signals. However, the CS, interrupt and reset pins need to be connected to separate GPIO for each Ethernet SPI module.
|
||||
|
||||
## Configure the project
|
||||
|
||||
```
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
To be the bridge feature available, enable `LwIP IEEE 802.1D bridge` option in ESP-NETIF Adapter component config menu and properly configure `Number of clients store data in netif` in LWIP component config menu.
|
||||
|
||||
For Ethernet configuration, see common configurations in [Ethernet examples](../../ethernet/README.md#common-configurations).
|
||||
|
||||
## 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
|
||||
|
||||
**ESP32 output:**
|
||||
|
||||
```bash
|
||||
I (436) esp_eth.netif.netif_glue: 08:3a:f2:31:20:f7
|
||||
I (436) esp_eth.netif.netif_glue: ethernet attached to netif
|
||||
I (436) w5500.mac: version=4
|
||||
I (446) esp_eth.netif.netif_glue: 08:3a:f2:31:20:f7
|
||||
I (446) esp_eth.netif.netif_glue: ethernet attached to netif
|
||||
I (446) esp_netif_br_glue: 08:3a:f2:31:20:f7
|
||||
I (456) esp_netif_br_glue: bridge netif glue attached
|
||||
I (3456) eth_example: Ethernet Started
|
||||
I (3456) eth_example: Ethernet Link Up
|
||||
I (3456) eth_example: Ethernet HW Addr 08:3a:f2:31:20:f7
|
||||
I (3466) eth_example: Ethernet Started
|
||||
I (5466) eth_example: Ethernet Link Up
|
||||
I (5466) eth_example: Ethernet HW Addr 08:3a:f2:31:20:f7
|
||||
I (8896) esp_netif_handlers: br0 ip: 192.168.20.105, mask: 255.255.255.0, gw: 192.168.20.1
|
||||
I (8896) eth_example: Ethernet Got IP Address
|
||||
I (8896) eth_example: ~~~~~~~~~~~
|
||||
I (8896) eth_example: ETHIP:192.168.20.105
|
||||
I (8906) eth_example: ETHMASK:255.255.255.0
|
||||
I (8906) eth_example: ETHGW:192.168.20.1
|
||||
I (8916) eth_example: ~~~~~~~~~~~
|
||||
```
|
||||
|
||||
**PC output (on Linux OS):**
|
||||
|
||||
```bash
|
||||
$ ip a
|
||||
|
||||
...
|
||||
|
||||
2: enp4s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
|
||||
link/ether 70:85:c2:d3:ea:18 brd ff:ff:ff:ff:ff:ff
|
||||
inet 192.168.20.116/24 brd 192.168.20.255 scope global dynamic noprefixroute enp4s0
|
||||
valid_lft 346sec preferred_lft 346sec
|
||||
inet6 fe80::4efa:2bae:e58c:231e/64 scope link noprefixroute
|
||||
valid_lft forever preferred_lft forever
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
**PC output (on Windows OS):**
|
||||
|
||||
```bash
|
||||
ipconfig -all
|
||||
|
||||
...
|
||||
|
||||
Ethernet adapter Ethernet:
|
||||
|
||||
Connection-specific DNS Suffix . : example.org
|
||||
Description . . . . . . . . . . . : Realtek PCIe GbE Family Controller
|
||||
Physical Address. . . . . . . . . : 70-85-C2-D3-EA-18
|
||||
DHCP Enabled. . . . . . . . . . . : Yes
|
||||
Autoconfiguration Enabled . . . . : Yes
|
||||
Link-local IPv6 Address . . . . . : fe80::21e3:aa78:f165:bbc8%15(Preferred)
|
||||
IPv4 Address. . . . . . . . . . . : 192.168.20.116(Preferred)
|
||||
Subnet Mask . . . . . . . . . . . : 255.255.255.0
|
||||
Lease Obtained. . . . . . . . . . : Tuesday, May 10, 2022 10:36:52 AM
|
||||
Lease Expires . . . . . . . . . . : Tuesday, May 10, 2022 10:46:51 AM
|
||||
Default Gateway . . . . . . . . . :
|
||||
DHCP Server . . . . . . . . . . . : 192.168.20.1
|
||||
DHCPv6 IAID . . . . . . . . . . . : 259032514
|
||||
DHCPv6 Client DUID. . . . . . . . : 00-01-00-01-25-3F-B4-00-70-85-C2-D3-EA-18
|
||||
DNS Servers . . . . . . . . . . . : fec0:0:0:ffff::1%1
|
||||
fec0:0:0:ffff::2%1
|
||||
fec0:0:0:ffff::3%1
|
||||
NetBIOS over Tcpip. . . . . . . . : Enabled
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
Now you can ping your ESP32 in PC#1 terminal by entering `ping 192.168.20.105` and you can ping your PC#2 in PC#1 terminal by entering `ping 192.168.20.116` (note that actual IP addresses depend on what you get by DHCP server).
|
||||
|
||||
## Known Limitations
|
||||
|
||||
* Currently only Ethernet interfaces can be bridged using LwIP bridge.
|
||||
* If you need to stop just one Ethernet interface which is bridged to perform some action like speed/duplex setting, **all remaining interfaces** associated with the bridge need to be stopped as well to the bridge work properly after the interfaces are started again.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
See common troubleshooting for [Ethernet examples](../../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.)
|
61
examples/network/bridge/docs/network.drawio
Normal file
61
examples/network/bridge/docs/network.drawio
Normal file
@ -0,0 +1,61 @@
|
||||
<mxfile host="65bd71144e">
|
||||
<diagram id="qvqIMWZhLYQI7_66ceEl" name="Page-1">
|
||||
<mxGraphModel dx="1074" dy="527" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" background="#B8B8B8" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0"/>
|
||||
<mxCell id="1" parent="0"/>
|
||||
<mxCell id="2" value="ESP32 w/ 2 bridged Eth ports<br>(DHCP Client)" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="280" y="160" width="120" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="5" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.25;entryY=1;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="3" target="2" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="3" value="PC#1<br>(DHCP Server)" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="160" y="280" width="120" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="6" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="4" target="2" edge="1">
|
||||
<mxGeometry relative="1" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="4" value="PC#2<br>(DHCP Client)" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||
<mxGeometry x="400" y="280" width="120" height="60" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="7" value="" style="endArrow=open;startArrow=open;html=1;startFill=0;endFill=0;dashed=1;dashPattern=1 1;" parent="1" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="290" y="309.71" as="sourcePoint"/>
|
||||
<mxPoint x="390" y="309.71" as="targetPoint"/>
|
||||
<Array as="points">
|
||||
<mxPoint x="340" y="309.71"/>
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="8" value="" style="endArrow=open;startArrow=open;html=1;startFill=0;endFill=0;dashed=1;dashPattern=1 1;" parent="1" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="180" y="270" as="sourcePoint"/>
|
||||
<mxPoint x="270" y="190" as="targetPoint"/>
|
||||
<Array as="points">
|
||||
<mxPoint x="210" y="210"/>
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9" value="" style="endArrow=open;startArrow=open;html=1;startFill=0;endFill=0;dashed=1;dashPattern=1 1;" parent="1" edge="1">
|
||||
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||
<mxPoint x="410" y="190" as="sourcePoint"/>
|
||||
<mxPoint x="500" y="270" as="targetPoint"/>
|
||||
<Array as="points">
|
||||
<mxPoint x="470" y="210"/>
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="11" value="ping" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="160" y="190" width="60" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="12" value="ping" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="460" y="190" width="60" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
<mxCell id="13" value="ping" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="310" y="280" width="60" height="30" as="geometry"/>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
BIN
examples/network/bridge/docs/network.png
Normal file
BIN
examples/network/bridge/docs/network.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
2
examples/network/bridge/main/CMakeLists.txt
Normal file
2
examples/network/bridge/main/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "bridge_example_main.c"
|
||||
INCLUDE_DIRS ".")
|
241
examples/network/bridge/main/Kconfig.projbuild
Normal file
241
examples/network/bridge/main/Kconfig.projbuild
Normal file
@ -0,0 +1,241 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps"
|
||||
|
||||
config EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
depends on IDF_TARGET_ESP32
|
||||
select ETH_USE_ESP32_EMAC
|
||||
bool "Internal EMAC"
|
||||
help
|
||||
Use internal Ethernet MAC controller.
|
||||
|
||||
if EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
choice EXAMPLE_ETH_PHY_MODEL
|
||||
prompt "Ethernet PHY Device"
|
||||
default EXAMPLE_ETH_PHY_IP101
|
||||
help
|
||||
Select the Ethernet PHY device to use in the example.
|
||||
|
||||
config EXAMPLE_ETH_PHY_IP101
|
||||
bool "IP101"
|
||||
help
|
||||
IP101 is a single port 10/100 MII/RMII/TP/Fiber Fast Ethernet Transceiver.
|
||||
Goto http://www.icplus.com.tw/pp-IP101G.html for more information about it.
|
||||
|
||||
config EXAMPLE_ETH_PHY_RTL8201
|
||||
bool "RTL8201/SR8201"
|
||||
help
|
||||
RTL8201F/SR8201F is a single port 10/100Mb Ethernet Transceiver with auto MDIX.
|
||||
Goto http://www.corechip-sz.com/productsview.asp?id=22 for more information about it.
|
||||
|
||||
config EXAMPLE_ETH_PHY_LAN87XX
|
||||
bool "LAN87xx"
|
||||
help
|
||||
Below chips are supported:
|
||||
LAN8710A is a small footprint MII/RMII 10/100 Ethernet Transceiver with HP Auto-MDIX and
|
||||
flexPWR® Technology.
|
||||
LAN8720A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX Support.
|
||||
LAN8740A/LAN8741A is a small footprint MII/RMII 10/100 Energy Efficient Ethernet Transceiver
|
||||
with HP Auto-MDIX and flexPWR® Technology.
|
||||
LAN8742A is a small footprint RMII 10/100 Ethernet Transceiver with HP Auto-MDIX and
|
||||
flexPWR® Technology.
|
||||
Goto https://www.microchip.com for more information about them.
|
||||
|
||||
config EXAMPLE_ETH_PHY_DP83848
|
||||
bool "DP83848"
|
||||
help
|
||||
DP83848 is a single port 10/100Mb/s Ethernet Physical Layer Transceiver.
|
||||
Goto http://www.ti.com/product/DP83848J for more information about it.
|
||||
|
||||
config EXAMPLE_ETH_PHY_KSZ80XX
|
||||
bool "KSZ80xx"
|
||||
help
|
||||
With the KSZ80xx series, Microchip offers single-chip 10BASE-T/100BASE-TX
|
||||
Ethernet Physical Layer Tranceivers (PHY).
|
||||
The following chips are supported: KSZ8001, KSZ8021, KSZ8031, KSZ8041,
|
||||
KSZ8051, KSZ8061, KSZ8081, KSZ8091
|
||||
Goto https://www.microchip.com for more information about them.
|
||||
endchoice # EXAMPLE_ETH_PHY_MODEL
|
||||
|
||||
config EXAMPLE_ETH_MDC_GPIO
|
||||
int "SMI MDC GPIO number"
|
||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||
default 23
|
||||
help
|
||||
Set the GPIO number used by SMI MDC.
|
||||
|
||||
config EXAMPLE_ETH_MDIO_GPIO
|
||||
int "SMI MDIO GPIO number"
|
||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||
default 18
|
||||
help
|
||||
Set the GPIO number used by SMI MDIO.
|
||||
|
||||
config EXAMPLE_ETH_PHY_RST_GPIO
|
||||
int "PHY Reset GPIO number"
|
||||
range -1 ENV_GPIO_OUT_RANGE_MAX
|
||||
default 5
|
||||
help
|
||||
Set the GPIO number used to reset PHY chip.
|
||||
Set to -1 to disable PHY chip hardware reset.
|
||||
|
||||
config EXAMPLE_ETH_PHY_ADDR
|
||||
int "PHY Address"
|
||||
range 0 31
|
||||
default 1
|
||||
help
|
||||
Set PHY address according your board schematic.
|
||||
endif # EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
|
||||
config EXAMPLE_USE_SPI_ETHERNET
|
||||
bool "SPI Ethernet"
|
||||
default y
|
||||
select ETH_USE_SPI_ETHERNET
|
||||
help
|
||||
Use external SPI-Ethernet module(s).
|
||||
|
||||
if EXAMPLE_USE_SPI_ETHERNET
|
||||
config EXAMPLE_SPI_ETHERNETS_NUM
|
||||
int "Number of SPI Ethernet modules to use at a time"
|
||||
range 1 2
|
||||
default 1
|
||||
help
|
||||
Set the number of SPI Ethernet modules you want to use at a time. Multiple SPI modules can be connected
|
||||
to one SPI interface and can be separately accessed based on state of associated Chip Select (CS).
|
||||
|
||||
choice EXAMPLE_ETHERNET_TYPE_SPI
|
||||
prompt "Ethernet SPI"
|
||||
default EXAMPLE_USE_W5500
|
||||
help
|
||||
Select which kind of Ethernet will be used in the example.
|
||||
|
||||
config EXAMPLE_USE_DM9051
|
||||
bool "DM9051 Module"
|
||||
select ETH_SPI_ETHERNET_DM9051
|
||||
help
|
||||
Select external SPI-Ethernet module (DM9051).
|
||||
|
||||
config EXAMPLE_USE_KSZ8851SNL
|
||||
bool "KSZ8851SNL Module"
|
||||
select ETH_SPI_ETHERNET_KSZ8851SNL
|
||||
help
|
||||
Select external SPI-Ethernet module (KSZ8851SNL).
|
||||
|
||||
config EXAMPLE_USE_W5500
|
||||
bool "W5500 Module"
|
||||
select ETH_SPI_ETHERNET_W5500
|
||||
help
|
||||
Select external SPI-Ethernet module (W5500).
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_ETH_SPI_HOST
|
||||
int "SPI Host Number"
|
||||
range 0 2
|
||||
default 1
|
||||
help
|
||||
Set the SPI host used to communicate with the SPI Ethernet Controller.
|
||||
|
||||
config EXAMPLE_ETH_SPI_SCLK_GPIO
|
||||
int "SPI SCLK GPIO number"
|
||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||
default 14 if IDF_TARGET_ESP32
|
||||
default 12 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
default 6 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2
|
||||
help
|
||||
Set the GPIO number used by SPI SCLK.
|
||||
|
||||
config EXAMPLE_ETH_SPI_MOSI_GPIO
|
||||
int "SPI MOSI GPIO number"
|
||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||
default 13 if IDF_TARGET_ESP32
|
||||
default 11 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
default 7 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2
|
||||
help
|
||||
Set the GPIO number used by SPI MOSI.
|
||||
|
||||
config EXAMPLE_ETH_SPI_MISO_GPIO
|
||||
int "SPI MISO GPIO number"
|
||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX
|
||||
default 12 if IDF_TARGET_ESP32
|
||||
default 13 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
default 2 if IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2
|
||||
help
|
||||
Set the GPIO number used by SPI MISO.
|
||||
|
||||
config EXAMPLE_ETH_SPI_CLOCK_MHZ
|
||||
int "SPI clock speed (MHz)"
|
||||
range 5 80
|
||||
default 12 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32C2
|
||||
default 36 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
help
|
||||
Set the clock speed (MHz) of SPI interface.
|
||||
|
||||
config EXAMPLE_ETH_SPI_CS0_GPIO
|
||||
int "SPI CS0 GPIO number for SPI Ethernet module #1"
|
||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||
default 15 if IDF_TARGET_ESP32
|
||||
default 10 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C2
|
||||
help
|
||||
Set the GPIO number used by SPI CS0, i.e. Chip Select associated with the first SPI Eth module).
|
||||
|
||||
config EXAMPLE_ETH_SPI_CS1_GPIO
|
||||
depends on EXAMPLE_SPI_ETHERNETS_NUM > 1
|
||||
int "SPI CS1 GPIO number for SPI Ethernet module #2"
|
||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||
default 32 if IDF_TARGET_ESP32
|
||||
default 7 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
|
||||
default 8 if IDF_TARGET_ESP32C3
|
||||
default 3 if IDF_TARGET_ESP32C2
|
||||
help
|
||||
Set the GPIO number used by SPI CS1, i.e. Chip Select associated with the second SPI Eth module.
|
||||
|
||||
config EXAMPLE_ETH_SPI_INT0_GPIO
|
||||
int "Interrupt GPIO number SPI Ethernet module #1"
|
||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX
|
||||
default 4 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C3
|
||||
default 4 if IDF_TARGET_ESP32C2
|
||||
help
|
||||
Set the GPIO number used by the first SPI Ethernet module interrupt line.
|
||||
|
||||
config EXAMPLE_ETH_SPI_INT1_GPIO
|
||||
depends on EXAMPLE_SPI_ETHERNETS_NUM > 1
|
||||
int "Interrupt GPIO number SPI Ethernet module #2"
|
||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX
|
||||
default 33 if IDF_TARGET_ESP32
|
||||
default 5 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32C3 || IDF_TARGET_ESP32S3 || IDF_TARGET_ESP32C2
|
||||
help
|
||||
Set the GPIO number used by the second SPI Ethernet module interrupt line.
|
||||
|
||||
config EXAMPLE_ETH_SPI_PHY_RST0_GPIO
|
||||
int "PHY Reset GPIO number of SPI Ethernet Module #1"
|
||||
range -1 ENV_GPIO_OUT_RANGE_MAX
|
||||
default -1
|
||||
help
|
||||
Set the GPIO number used to reset PHY chip on the first SPI Ethernet module.
|
||||
Set to -1 to disable PHY chip hardware reset.
|
||||
|
||||
config EXAMPLE_ETH_SPI_PHY_RST1_GPIO
|
||||
depends on EXAMPLE_SPI_ETHERNETS_NUM > 1
|
||||
int "PHY Reset GPIO number of SPI Ethernet Module #2"
|
||||
range -1 ENV_GPIO_OUT_RANGE_MAX
|
||||
default -1
|
||||
help
|
||||
Set the GPIO number used to reset PHY chip on the second SPI Ethernet module.
|
||||
Set to -1 to disable PHY chip hardware reset.
|
||||
|
||||
config EXAMPLE_ETH_SPI_PHY_ADDR0
|
||||
int "PHY Address of SPI Ethernet Module #1"
|
||||
range 0 31
|
||||
default 1
|
||||
help
|
||||
Set the first SPI Ethernet module PHY address according your board schematic.
|
||||
|
||||
config EXAMPLE_ETH_SPI_PHY_ADDR1
|
||||
depends on EXAMPLE_SPI_ETHERNETS_NUM > 1
|
||||
int "PHY Address of SPI Ethernet Module #2"
|
||||
range 0 31
|
||||
default 1
|
||||
help
|
||||
Set the second SPI Ethernet module PHY address according your board schematic.
|
||||
endif # EXAMPLE_USE_SPI_ETHERNET
|
||||
endmenu
|
334
examples/network/bridge/main/bridge_example_main.c
Normal file
334
examples/network/bridge/main/bridge_example_main.c
Normal file
@ -0,0 +1,334 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_netif_br_glue.h"
|
||||
#include "esp_eth.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "sdkconfig.h"
|
||||
#if CONFIG_ETH_USE_SPI_ETHERNET
|
||||
#include "driver/spi_master.h"
|
||||
#endif // CONFIG_ETH_USE_SPI_ETHERNET
|
||||
|
||||
static const char *TAG = "eth_bridge_example";
|
||||
|
||||
#if CONFIG_EXAMPLE_SPI_ETHERNETS_NUM
|
||||
#define SPI_ETHERNETS_NUM CONFIG_EXAMPLE_SPI_ETHERNETS_NUM
|
||||
#else
|
||||
#define SPI_ETHERNETS_NUM 0
|
||||
#endif
|
||||
|
||||
#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
#define INTERNAL_ETHERNETS_NUM 1
|
||||
#else
|
||||
#define INTERNAL_ETHERNETS_NUM 0
|
||||
#endif
|
||||
|
||||
#if CONFIG_EXAMPLE_USE_SPI_ETHERNET
|
||||
#define INIT_SPI_ETH_MODULE_CONFIG(eth_module_config, num) \
|
||||
do { \
|
||||
eth_module_config[num].spi_cs_gpio = CONFIG_EXAMPLE_ETH_SPI_CS ##num## _GPIO; \
|
||||
eth_module_config[num].int_gpio = CONFIG_EXAMPLE_ETH_SPI_INT ##num## _GPIO; \
|
||||
eth_module_config[num].phy_reset_gpio = CONFIG_EXAMPLE_ETH_SPI_PHY_RST ##num## _GPIO; \
|
||||
eth_module_config[num].phy_addr = CONFIG_EXAMPLE_ETH_SPI_PHY_ADDR ##num; \
|
||||
} while(0)
|
||||
|
||||
typedef struct {
|
||||
uint8_t spi_cs_gpio;
|
||||
uint8_t int_gpio;
|
||||
int8_t phy_reset_gpio;
|
||||
uint8_t phy_addr;
|
||||
}spi_eth_module_config_t;
|
||||
#endif
|
||||
|
||||
/** 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};
|
||||
/* 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 (%p) Link Up", eth_handle);
|
||||
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 (%p) Link Down", eth_handle);
|
||||
break;
|
||||
case ETHERNET_EVENT_START:
|
||||
ESP_LOGI(TAG, "Ethernet (%p) Started", eth_handle);
|
||||
break;
|
||||
case ETHERNET_EVENT_STOP:
|
||||
ESP_LOGI(TAG, "Ethernet (%p) Stopped", eth_handle);
|
||||
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");
|
||||
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, "~~~~~~~~~~~");
|
||||
}
|
||||
|
||||
#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
/** Internal EMAC initialization */
|
||||
esp_eth_handle_t eth_init_internal(void)
|
||||
{
|
||||
esp_eth_handle_t eth_handle;
|
||||
|
||||
// Init MAC and PHY configs to default
|
||||
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
|
||||
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
|
||||
|
||||
phy_config.phy_addr = CONFIG_EXAMPLE_ETH_PHY_ADDR;
|
||||
phy_config.reset_gpio_num = CONFIG_EXAMPLE_ETH_PHY_RST_GPIO;
|
||||
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
|
||||
esp32_emac_config.smi_mdc_gpio_num = CONFIG_EXAMPLE_ETH_MDC_GPIO;
|
||||
esp32_emac_config.smi_mdio_gpio_num = CONFIG_EXAMPLE_ETH_MDIO_GPIO;
|
||||
esp_eth_mac_t *mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
|
||||
#if CONFIG_EXAMPLE_ETH_PHY_IP101
|
||||
esp_eth_phy_t *phy = esp_eth_phy_new_ip101(&phy_config);
|
||||
#elif CONFIG_EXAMPLE_ETH_PHY_RTL8201
|
||||
esp_eth_phy_t *phy = esp_eth_phy_new_rtl8201(&phy_config);
|
||||
#elif CONFIG_EXAMPLE_ETH_PHY_LAN87XX
|
||||
esp_eth_phy_t *phy = esp_eth_phy_new_lan87xx(&phy_config);
|
||||
#elif CONFIG_EXAMPLE_ETH_PHY_DP83848
|
||||
esp_eth_phy_t *phy = esp_eth_phy_new_dp83848(&phy_config);
|
||||
#elif CONFIG_EXAMPLE_ETH_PHY_KSZ80XX
|
||||
esp_eth_phy_t *phy = esp_eth_phy_new_ksz80xx(&phy_config);
|
||||
#endif
|
||||
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
|
||||
ESP_ERROR_CHECK(esp_eth_driver_install(&config, ð_handle));
|
||||
|
||||
return eth_handle;
|
||||
}
|
||||
#endif // CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
|
||||
#if CONFIG_EXAMPLE_USE_SPI_ETHERNET
|
||||
/** Ethernet SPI modules initialization */
|
||||
esp_eth_handle_t eth_init_spi(spi_eth_module_config_t *spi_eth_module_config, uint8_t *mac_addr)
|
||||
{
|
||||
esp_eth_handle_t eth_handle;
|
||||
|
||||
// Init MAC and PHY configs to default
|
||||
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
|
||||
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
|
||||
|
||||
// Configure SPI interface and Ethernet driver for specific SPI module
|
||||
esp_eth_mac_t *mac;
|
||||
esp_eth_phy_t *phy;
|
||||
|
||||
spi_device_handle_t spi_handle;
|
||||
#if CONFIG_EXAMPLE_USE_KSZ8851SNL
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.mode = 0,
|
||||
.clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
|
||||
.queue_size = 20
|
||||
};
|
||||
|
||||
// Set SPI module Chip Select GPIO
|
||||
devcfg.spics_io_num = spi_eth_module_config->spi_cs_gpio;
|
||||
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
|
||||
// KSZ8851SNL ethernet driver is based on spi driver
|
||||
eth_ksz8851snl_config_t ksz8851snl_config = ETH_KSZ8851SNL_DEFAULT_CONFIG(spi_handle);
|
||||
|
||||
// Set remaining GPIO numbers and configuration used by the SPI module
|
||||
ksz8851snl_config.int_gpio_num = spi_eth_module_config->int_gpio;
|
||||
phy_config.phy_addr = spi_eth_module_config->phy_addr;
|
||||
phy_config.reset_gpio_num = spi_eth_module_config->phy_reset_gpio;
|
||||
|
||||
mac = esp_eth_mac_new_ksz8851snl(&ksz8851snl_config, &mac_config);
|
||||
phy = esp_eth_phy_new_ksz8851snl(&phy_config);
|
||||
#elif CONFIG_EXAMPLE_USE_DM9051
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.command_bits = 1,
|
||||
.address_bits = 7,
|
||||
.mode = 0,
|
||||
.clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
|
||||
.queue_size = 20
|
||||
};
|
||||
|
||||
// Set SPI module Chip Select GPIO
|
||||
devcfg.spics_io_num = spi_eth_module_config->spi_cs_gpio;
|
||||
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
|
||||
// dm9051 ethernet driver is based on spi driver
|
||||
eth_dm9051_config_t dm9051_config = ETH_DM9051_DEFAULT_CONFIG(spi_handle);
|
||||
|
||||
// Set remaining GPIO numbers and configuration used by the SPI module
|
||||
dm9051_config.int_gpio_num = spi_eth_module_config->int_gpio;
|
||||
phy_config.phy_addr = spi_eth_module_config->phy_addr;
|
||||
phy_config.reset_gpio_num = spi_eth_module_config->phy_reset_gpio;
|
||||
|
||||
mac = esp_eth_mac_new_dm9051(&dm9051_config, &mac_config);
|
||||
phy = esp_eth_phy_new_dm9051(&phy_config);
|
||||
#elif CONFIG_EXAMPLE_USE_W5500
|
||||
spi_device_interface_config_t devcfg = {
|
||||
.command_bits = 16, // Actually it's the address phase in W5500 SPI frame
|
||||
.address_bits = 8, // Actually it's the control phase in W5500 SPI frame
|
||||
.mode = 0,
|
||||
.clock_speed_hz = CONFIG_EXAMPLE_ETH_SPI_CLOCK_MHZ * 1000 * 1000,
|
||||
.queue_size = 20
|
||||
};
|
||||
|
||||
// Set SPI module Chip Select GPIO
|
||||
devcfg.spics_io_num = spi_eth_module_config->spi_cs_gpio;
|
||||
|
||||
ESP_ERROR_CHECK(spi_bus_add_device(CONFIG_EXAMPLE_ETH_SPI_HOST, &devcfg, &spi_handle));
|
||||
// w5500 ethernet driver is based on spi driver
|
||||
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_handle);
|
||||
|
||||
// Set remaining GPIO numbers and configuration used by the SPI module
|
||||
w5500_config.int_gpio_num = spi_eth_module_config->int_gpio;
|
||||
phy_config.phy_addr = spi_eth_module_config->phy_addr;
|
||||
phy_config.reset_gpio_num = spi_eth_module_config->phy_reset_gpio;
|
||||
|
||||
mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
|
||||
phy = esp_eth_phy_new_w5500(&phy_config);
|
||||
|
||||
#endif //CONFIG_EXAMPLE_USE_W5500
|
||||
esp_eth_config_t eth_config_spi = ETH_DEFAULT_CONFIG(mac, phy);
|
||||
ESP_ERROR_CHECK(esp_eth_driver_install(ð_config_spi, ð_handle));
|
||||
|
||||
// The SPI Ethernet module might not have a burned factory MAC address, we cat to set it manually.
|
||||
ESP_ERROR_CHECK(esp_eth_ioctl(eth_handle, ETH_CMD_S_MAC_ADDR, mac_addr));
|
||||
|
||||
return eth_handle;
|
||||
}
|
||||
#endif // CONFIG_EXAMPLE_USE_SPI_ETHERNET
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
// number of Ethernet ports to be used in the bridge
|
||||
uint8_t port_cnt = 0;
|
||||
// the same MAC address will be used for all Ethernet ports since the bridge acts as one device
|
||||
uint8_t common_mac_addr[ETH_ADDR_LEN];
|
||||
|
||||
esp_eth_handle_t eth_handles[SPI_ETHERNETS_NUM + INTERNAL_ETHERNETS_NUM] = { NULL };
|
||||
esp_netif_t *eth_netifs[SPI_ETHERNETS_NUM + INTERNAL_ETHERNETS_NUM] = { NULL };
|
||||
|
||||
// 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());
|
||||
|
||||
#if CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
eth_handles[port_cnt++] = eth_init_internal();
|
||||
// use burned ESP32 MAC address as commom address for all Ethernet interfaces
|
||||
ESP_ERROR_CHECK(esp_eth_ioctl(eth_handles[0], ETH_CMD_G_MAC_ADDR, common_mac_addr));
|
||||
#elif CONFIG_EXAMPLE_USE_SPI_ETHERNET
|
||||
// if ESP32 internal Ethernet is not used, use manually configured MAC address
|
||||
// 02:00:00 is a Locally Administered OUI range so should not be used except when testing on a LAN under your control.
|
||||
memcpy(common_mac_addr, (uint8_t[]) {0x02, 0x00, 0x00, 0x12, 0x34, 0x56}, ETH_ADDR_LEN);
|
||||
#endif //CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET
|
||||
|
||||
#if CONFIG_EXAMPLE_USE_SPI_ETHERNET
|
||||
// Install GPIO ISR handler to be able to service SPI Eth modlues interrupts
|
||||
gpio_install_isr_service(0);
|
||||
|
||||
// Init SPI bus
|
||||
spi_bus_config_t buscfg = {
|
||||
.miso_io_num = CONFIG_EXAMPLE_ETH_SPI_MISO_GPIO,
|
||||
.mosi_io_num = CONFIG_EXAMPLE_ETH_SPI_MOSI_GPIO,
|
||||
.sclk_io_num = CONFIG_EXAMPLE_ETH_SPI_SCLK_GPIO,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
};
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(CONFIG_EXAMPLE_ETH_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
|
||||
// Init specific SPI Ethernet module configuration from Kconfig (CS GPIO, Interrupt GPIO, etc.)
|
||||
spi_eth_module_config_t spi_eth_module_config[CONFIG_EXAMPLE_SPI_ETHERNETS_NUM];
|
||||
INIT_SPI_ETH_MODULE_CONFIG(spi_eth_module_config, 0);
|
||||
#if CONFIG_EXAMPLE_SPI_ETHERNETS_NUM > 1
|
||||
INIT_SPI_ETH_MODULE_CONFIG(spi_eth_module_config, 1);
|
||||
#endif
|
||||
for (int i = 0; i < CONFIG_EXAMPLE_SPI_ETHERNETS_NUM; i++) {
|
||||
eth_handles[port_cnt++] = eth_init_spi(&spi_eth_module_config[i], common_mac_addr);
|
||||
}
|
||||
#endif // CONFIG_ETH_USE_SPI_ETHERNET
|
||||
// Create instances of esp-netif for Ethernet ports
|
||||
esp_netif_inherent_config_t esp_netif_config = ESP_NETIF_INHERENT_DEFAULT_ETH();
|
||||
esp_netif_config_t netif_cfg = {
|
||||
.base = &esp_netif_config,
|
||||
.stack = ESP_NETIF_NETSTACK_DEFAULT_ETH
|
||||
};
|
||||
char if_key_str[10];
|
||||
char if_desc_str[10];
|
||||
char num_str[3];
|
||||
for (int i = 0; i < port_cnt; i++) {
|
||||
itoa(i, num_str, 10);
|
||||
strcat(strcpy(if_key_str, "ETH_"), num_str);
|
||||
strcat(strcpy(if_desc_str, "eth"), num_str);
|
||||
esp_netif_config.if_key = if_key_str;
|
||||
esp_netif_config.if_desc = if_desc_str;
|
||||
esp_netif_config.route_prio = 50 - i;
|
||||
esp_netif_config.flags = 0; // ESP-NETIF flags need to be zero when port's to be bridged
|
||||
|
||||
eth_netifs[i] = esp_netif_new(&netif_cfg);
|
||||
|
||||
// attach Ethernet driver to TCP/IP stack
|
||||
ESP_ERROR_CHECK(esp_netif_attach(eth_netifs[i], esp_eth_new_netif_glue(eth_handles[i])));
|
||||
}
|
||||
|
||||
// Create instance of esp-netif for bridge interface
|
||||
esp_netif_inherent_config_t esp_netif_br_config = ESP_NETIF_INHERENT_DEFAULT_BR();
|
||||
esp_netif_config_t netif_br_cfg = {
|
||||
.base = &esp_netif_br_config,
|
||||
.stack = ESP_NETIF_NETSTACK_DEFAULT_BR,
|
||||
};
|
||||
bridgeif_config_t bridgeif_config = {
|
||||
.max_fdb_dyn_entries = 10,
|
||||
.max_fdb_sta_entries = 2,
|
||||
.max_ports = port_cnt
|
||||
};
|
||||
esp_netif_br_config.bridge_info = &bridgeif_config;
|
||||
// Set MAC address of bridge interface the same as the Ethernet interface
|
||||
memcpy(esp_netif_br_config.mac, common_mac_addr, ETH_ADDR_LEN);
|
||||
esp_netif_t *br_netif = esp_netif_new(&netif_br_cfg);
|
||||
|
||||
// Create new esp netif bridge glue instance
|
||||
esp_netif_br_glue_handle_t netif_br_glue = esp_netif_br_glue_new();
|
||||
// Add Ethernet port interfaces to that esp netif bridge glue instance
|
||||
for (int i = 0; i < port_cnt; i++) {
|
||||
ESP_ERROR_CHECK(esp_netif_br_glue_add_port(netif_br_glue, eth_netifs[i]));
|
||||
}
|
||||
// Attach esp netif bridge glue instance with added ports to bridge netif
|
||||
ESP_ERROR_CHECK(esp_netif_attach(br_netif, netif_br_glue));
|
||||
|
||||
// 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));
|
||||
|
||||
for (int i = 0; i < port_cnt; i++) {
|
||||
// Since the MAC forwarding is performed in lwIP bridge, we need to pass all addresses through the Ethernet MACs
|
||||
bool promiscuous = true;
|
||||
esp_eth_ioctl(eth_handles[i], ETH_CMD_S_PROMISCUOUS, &promiscuous);
|
||||
// Start Ethernet driver state machine
|
||||
ESP_ERROR_CHECK(esp_eth_start(eth_handles[i]));
|
||||
}
|
||||
}
|
4
examples/network/bridge/sdkconfig.defaults
Normal file
4
examples/network/bridge/sdkconfig.defaults
Normal file
@ -0,0 +1,4 @@
|
||||
CONFIG_ESP_NETIF_TCPIP_LWIP=y
|
||||
CONFIG_ESP_NETIF_BRIDGE_EN=y
|
||||
|
||||
CONFIG_LWIP_NUM_NETIF_CLIENT_DATA=1
|
Loading…
Reference in New Issue
Block a user