feat(network/examples): extended LwIP bridge example

Extended LwIP bridge example to support WiFi AP interface and DHCP Server

https://github.com/espressif/esp-idf/issues/5697
This commit is contained in:
Ondrej Kosta 2023-05-24 15:56:24 +02:00
parent 1ad891361f
commit 3288f83401
13 changed files with 545 additions and 136 deletions

View File

@ -51,7 +51,17 @@ idf_component_register(SRCS "${srcs}"
LDFRAGMENTS linker.lf)
if(CONFIG_ESP_NETIF_L2_TAP OR CONFIG_ESP_NETIF_BRIDGE_EN)
idf_component_optional_requires(PRIVATE esp_eth vfs)
set(optional_requires "")
if(CONFIG_ESP_NETIF_L2_TAP)
list(APPEND optional_requires "vfs")
endif()
if(CONFIG_ESP_NETIF_BRIDGE_EN)
list(APPEND optional_requires "esp_wifi")
endif()
list(APPEND optional_requires "esp_eth")
idf_component_optional_requires(PRIVATE "${optional_requires}")
endif()

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -28,14 +28,23 @@ typedef struct esp_netif_br_glue_t* esp_netif_br_glue_handle_t;
esp_netif_br_glue_handle_t esp_netif_br_glue_new(void);
/**
* @brief Add a port to the bridge netif glue
* @brief Add Ethernet port to the bridge netif glue
*
* @param netif_br_glue bridge netif glue
* @param esp_netif_port port netif
* @param esp_netif_port Ethernet 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 Add WiFi port to the bridge netif glue
*
* @param netif_br_glue bridge netif glue
* @param esp_netif_port WiFi port netif
* @return - ESP_OK on success
*/
esp_err_t esp_netif_br_glue_add_wifi_port(esp_netif_br_glue_handle_t netif_br_glue, esp_netif_t *esp_netif_port);
/**
* @brief Delete netif glue of bridge
*

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -104,9 +104,6 @@ extern "C" {
}
#endif /* CONFIG_PPP_SUPPORT */
#define ESP_NETIF_INHERENT_DEFAULT_BR() \
{ \
.flags = (esp_netif_flags_t)(ESP_NETIF_DHCP_CLIENT | ESP_NETIF_DEFAULT_ARP_FLAGS | ESP_NETIF_FLAG_EVENT_IP_MODIFIED | ESP_NETIF_FLAG_IS_BRIDGE), \
@ -114,8 +111,21 @@ extern "C" {
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", \
.if_key = "BR0", \
.if_desc = "br0", \
.route_prio = 70, \
.bridge_info = NULL \
}
#define ESP_NETIF_INHERENT_DEFAULT_BR_DHCPS() \
{ \
.flags = (esp_netif_flags_t)(ESP_NETIF_DHCP_SERVER | ESP_NETIF_FLAG_IS_BRIDGE), \
ESP_COMPILER_DESIGNATED_INIT_AGGREGATE_TYPE_EMPTY(mac) \
.ip_info = &_g_esp_netif_soft_ap_ip, \
.get_ip_event = 0, \
.lost_ip_event = 0, \
.if_key = "BR1", \
.if_desc = "br1", \
.route_prio = 70, \
.bridge_info = NULL \
}

View File

@ -1,11 +1,13 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <string.h>
#include "esp_netif_br_glue.h"
#include "esp_eth_driver.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_check.h"
@ -16,16 +18,23 @@ const static char *TAG = "esp_netif_br_glue";
typedef struct esp_netif_br_glue_t esp_netif_br_glue_t;
typedef enum {
START_CTX_HANDLER,
STOP_CTX_HANDLER,
CONNECT_CTX_HANDLER,
DISCONNECT_CTX_HANDLER,
CTX_HANDLERS_END_LIST
} ctx_handl_type_t;
struct esp_netif_br_glue_t {
esp_netif_driver_base_t base;
bool br_started;
esp_netif_t **ports_esp_netifs;
esp_netif_t *wifi_esp_netif;
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 *eth_ctx_handlers;
esp_event_handler_instance_t get_ip_ctx_handler;
esp_event_handler_instance_t *wifi_ctx_handlers;
};
static esp_err_t esp_eth_post_attach_br(esp_netif_t *esp_netif, void *args)
@ -43,87 +52,128 @@ static esp_err_t esp_eth_post_attach_br(esp_netif_t *esp_netif, void *args)
return ESP_OK;
}
static void eth_action_start(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
static void start_br_if_stopped(esp_netif_br_glue_t *netif_glue)
{
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]);
}
if (netif_glue->br_started == false) {
esp_netif_action_start(netif_glue->base.netif, 0, 0, NULL); // basically creates lwip_netif br instance
netif_glue->br_started = true;
ESP_LOGD(TAG, "bridge netif %p is started", netif_glue->base.netif);
}
}
static void eth_action_stop(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
static void stop_br_if_started(esp_netif_br_glue_t *netif_glue)
{
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);
}
}
if (netif_glue->br_started == true) {
esp_netif_action_stop(netif_glue->base.netif, 0, 0, NULL); // 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)
static bool are_ports_disconnected(esp_netif_br_glue_t *netif_glue)
{
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);
int disc_cnt;
// check Ethernet ports at first
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 (disc_cnt >= netif_glue->port_cnt) {
// check WiFi port if is also registered
if (netif_glue->wifi_esp_netif != NULL) {
if (esp_netif_is_netif_up(netif_glue->wifi_esp_netif) == false) {
return true;
}
} else {
return true;
}
}
return false;
}
static void eth_action_disconnected(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
static void port_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_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);
if (base == WIFI_EVENT) {
ESP_LOGD(TAG, "wifi_action_start: %p, %p, %d, %p", netif_glue, base, event_id, event_data);
start_br_if_stopped(netif_glue);
esp_netif_bridge_add_port(netif_glue->base.netif, netif_glue->wifi_esp_netif);
} else if (base == ETH_EVENT) {
esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;
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])) {
start_br_if_stopped(netif_glue);
esp_netif_bridge_add_port(netif_glue->base.netif, netif_glue->ports_esp_netifs[i]);
}
}
}
}
static void port_action_stop(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
esp_netif_br_glue_t *netif_glue = handler_args;
// 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 (base == WIFI_EVENT) {
ESP_LOGD(TAG, "wifi_action_stop: %p, %p, %d, %p", netif_glue, base, event_id, event_data);
stop_br_if_started(netif_glue);
} else if (base == ETH_EVENT) {
esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;
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 (eth_handle == esp_netif_get_io_driver(netif_glue->ports_esp_netifs[i])) {
stop_br_if_started(netif_glue);
}
}
}
}
static void port_action_connected(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
esp_netif_br_glue_t *netif_glue = handler_args;
// if bridge interface is already up, do nothing
if (esp_netif_is_netif_up(netif_glue->base.netif) == true) {
ESP_LOGD(TAG, "action_connected, no action bridge is up");
return;
}
if (base == WIFI_EVENT) {
ESP_LOGD(TAG, "wifi_action_connected: %p, %p, %d, %p", netif_glue, base, event_id, event_data);
esp_netif_action_connected(netif_glue->base.netif, 0, 0, NULL);
} else if (base == ETH_EVENT) {
esp_eth_handle_t eth_handle = *(esp_eth_handle_t *)event_data;
ESP_LOGD(TAG, "eth_action_connected: %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])) {
esp_netif_action_connected(netif_glue->base.netif, 0, 0, NULL);
ESP_LOGD(TAG, "bridge netif %p is connected", netif_glue->base.netif);
break;
}
}
}
if (esp_netif_is_netif_up(netif_glue->base.netif) == true &&
(esp_netif_get_flags(netif_glue->base.netif) & ESP_NETIF_DHCP_SERVER) == ESP_NETIF_DHCP_SERVER) {
esp_netif_dhcps_start(netif_glue->base.netif);
}
}
static void port_action_disconnected(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
esp_netif_br_glue_t *netif_glue = handler_args;
ESP_LOGD(TAG, "action_disconnected: %p, %p, %d, %p", netif_glue, base, event_id, event_data);
// if all ports are disconnected, set bridge as disconnected too
if (are_ports_disconnected(netif_glue)) {
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;
@ -138,25 +188,22 @@ static esp_err_t esp_netif_br_glue_clear_instance_handlers(esp_netif_br_glue_han
{
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_ctx_handlers[START_CTX_HANDLER]) {
esp_event_handler_instance_unregister(ETH_EVENT, ETHERNET_EVENT_START, esp_netif_br_glue->eth_ctx_handlers[START_CTX_HANDLER]);
}
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_ctx_handlers[STOP_CTX_HANDLER]) {
esp_event_handler_instance_unregister(ETH_EVENT, ETHERNET_EVENT_STOP, esp_netif_br_glue->eth_ctx_handlers[STOP_CTX_HANDLER]);
}
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_ctx_handlers[CONNECT_CTX_HANDLER]) {
esp_event_handler_instance_unregister(ETH_EVENT, ETHERNET_EVENT_CONNECTED, esp_netif_br_glue->eth_ctx_handlers[CONNECT_CTX_HANDLER]);
}
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->eth_ctx_handlers[DISCONNECT_CTX_HANDLER]) {
esp_event_handler_instance_unregister(ETH_EVENT, ETHERNET_EVENT_DISCONNECTED, esp_netif_br_glue->eth_ctx_handlers[DISCONNECT_CTX_HANDLER]);
}
free(esp_netif_br_glue->eth_ctx_handlers);
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);
@ -168,24 +215,28 @@ static esp_err_t esp_netif_br_glue_clear_instance_handlers(esp_netif_br_glue_han
static esp_err_t esp_netif_br_glue_set_instance_handlers(esp_netif_br_glue_handle_t esp_netif_br_glue)
{
esp_err_t ret = ESP_OK;
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);
esp_netif_br_glue->eth_ctx_handlers = calloc(CTX_HANDLERS_END_LIST, sizeof(esp_event_handler_instance_t));
ESP_GOTO_ON_FALSE(esp_netif_br_glue->eth_ctx_handlers, ESP_ERR_NO_MEM, fail, TAG, "no memory for Ethernet event context handlers");
ret = esp_event_handler_instance_register(ETH_EVENT, ETHERNET_EVENT_START, port_action_start, esp_netif_br_glue, &esp_netif_br_glue->eth_ctx_handlers[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);
ret = esp_event_handler_instance_register(ETH_EVENT, ETHERNET_EVENT_STOP, port_action_stop, esp_netif_br_glue, &esp_netif_br_glue->eth_ctx_handlers[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);
ret = esp_event_handler_instance_register(ETH_EVENT, ETHERNET_EVENT_CONNECTED, port_action_connected, esp_netif_br_glue, &esp_netif_br_glue->eth_ctx_handlers[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);
ret = esp_event_handler_instance_register(ETH_EVENT, ETHERNET_EVENT_DISCONNECTED, port_action_disconnected, esp_netif_br_glue, &esp_netif_br_glue->eth_ctx_handlers[DISCONNECT_CTX_HANDLER]);
if (ret != ESP_OK) {
goto fail;
}
@ -202,6 +253,103 @@ fail:
return ret;
}
static esp_err_t esp_netif_br_glue_clear_instance_handlers_wifi(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_RETURN_ON_FALSE(esp_netif_br_glue->wifi_ctx_handlers, ESP_ERR_INVALID_STATE, TAG, "WiFi event handlers are empty");
if (esp_netif_br_glue->wifi_ctx_handlers[START_CTX_HANDLER]) {
esp_event_handler_instance_unregister(WIFI_EVENT, WIFI_EVENT_AP_START, esp_netif_br_glue->wifi_ctx_handlers[START_CTX_HANDLER]);
}
if (esp_netif_br_glue->wifi_ctx_handlers[STOP_CTX_HANDLER]) {
esp_event_handler_instance_unregister(WIFI_EVENT, WIFI_EVENT_AP_STOP, esp_netif_br_glue->wifi_ctx_handlers[STOP_CTX_HANDLER]);
}
if (esp_netif_br_glue->wifi_ctx_handlers[CONNECT_CTX_HANDLER]) {
esp_event_handler_instance_unregister(WIFI_EVENT, WIFI_EVENT_AP_STACONNECTED, esp_netif_br_glue->wifi_ctx_handlers[CONNECT_CTX_HANDLER]);
}
if (esp_netif_br_glue->wifi_ctx_handlers[DISCONNECT_CTX_HANDLER]) {
esp_event_handler_instance_unregister(WIFI_EVENT, WIFI_EVENT_AP_STADISCONNECTED, esp_netif_br_glue->wifi_ctx_handlers[DISCONNECT_CTX_HANDLER]);
}
free(esp_netif_br_glue->wifi_ctx_handlers);
return ESP_OK;
}
static esp_err_t esp_netif_br_glue_set_instance_handlers_wifi(esp_netif_br_glue_handle_t esp_netif_br_glue)
{
esp_err_t ret= ESP_OK;
ESP_RETURN_ON_FALSE(esp_netif_br_glue, ESP_ERR_INVALID_ARG, TAG, "esp_netif_br_glue handle can't be null");
ESP_RETURN_ON_FALSE(esp_netif_br_glue->wifi_esp_netif, ESP_ERR_INVALID_ARG, TAG, "WiFi port esp_netif isn't registered");
esp_netif_br_glue->wifi_ctx_handlers = calloc(CTX_HANDLERS_END_LIST, sizeof(esp_event_handler_instance_t));
ESP_GOTO_ON_FALSE(esp_netif_br_glue->wifi_ctx_handlers, ESP_ERR_NO_MEM, fail, TAG, "no memory for WiFi event context handlers");
ret = esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_AP_START, port_action_start, esp_netif_br_glue, &esp_netif_br_glue->wifi_ctx_handlers[START_CTX_HANDLER]);
if (ret != ESP_OK) {
goto fail;
}
ret = esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_AP_STOP, port_action_stop, esp_netif_br_glue, &esp_netif_br_glue->wifi_ctx_handlers[STOP_CTX_HANDLER]);
if (ret != ESP_OK) {
goto fail;
}
ret = esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_AP_STACONNECTED, port_action_connected, esp_netif_br_glue, &esp_netif_br_glue->wifi_ctx_handlers[CONNECT_CTX_HANDLER]);
if (ret != ESP_OK) {
goto fail;
}
ret = esp_event_handler_instance_register(WIFI_EVENT, WIFI_EVENT_AP_STADISCONNECTED, port_action_disconnected, esp_netif_br_glue, &esp_netif_br_glue->wifi_ctx_handlers[DISCONNECT_CTX_HANDLER]);
if (ret != ESP_OK) {
goto fail;
}
return ESP_OK;
fail:
esp_netif_br_glue_clear_instance_handlers_wifi(esp_netif_br_glue);
return ret;
}
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_add_wifi_port(esp_netif_br_glue_handle_t netif_br_glue, esp_netif_t *esp_netif_port)
{
esp_err_t ret = ESP_OK;
ESP_GOTO_ON_FALSE(netif_br_glue->wifi_esp_netif == NULL, ESP_ERR_INVALID_STATE, fail_ret, TAG, "WiFi interface already registered");
const char *if_desc = esp_netif_get_desc(esp_netif_port);
ESP_GOTO_ON_FALSE(strcmp(if_desc, "ap") == 0, ESP_ERR_INVALID_ARG, fail_ret, TAG, "interface is not WiFi AP");
netif_br_glue->wifi_esp_netif = esp_netif_port;
ESP_GOTO_ON_ERROR(esp_netif_br_glue_set_instance_handlers_wifi(netif_br_glue), fail, TAG, "failed to create WiFi event handlers");
return ESP_OK;
fail:
netif_br_glue->wifi_esp_netif = NULL;
netif_br_glue->wifi_ctx_handlers = NULL;
fail_ret:
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));
@ -220,27 +368,13 @@ esp_netif_br_glue_handle_t esp_netif_br_glue_new(void)
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)
{
stop_br_if_started(netif_br_glue);
esp_netif_br_glue_clear_instance_handlers(netif_br_glue);
if (netif_br_glue->wifi_esp_netif != NULL) {
esp_netif_br_glue_clear_instance_handlers_wifi(netif_br_glue);
}
free(netif_br_glue->ports_esp_netifs);
free(netif_br_glue);
netif_br_glue = NULL;

View File

@ -45,7 +45,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->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET;
#if ESP_LWIP
#if LWIP_IGMP

View File

@ -604,7 +604,7 @@ static void send_offer(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len)
ip_addr_t ip_temp = IPADDR4_INIT(0x0);
ip4_addr_set(ip_2_ip4(&ip_temp), &dhcps->broadcast_dhcps);
#if DHCPS_DEBUG
SendOffer_err_t = udp_sendto(pcb_dhcps, p, &ip_temp, DHCPS_CLIENT_PORT);
SendOffer_err_t = udp_sendto(dhcps->dhcps_pcb, p, &ip_temp, DHCPS_CLIENT_PORT);
DHCPS_LOG("dhcps: send_offer>>udp_sendto result %x\n", SendOffer_err_t);
#else
udp_sendto(dhcps->dhcps_pcb, p, &ip_temp, DHCPS_CLIENT_PORT);
@ -682,7 +682,7 @@ static void send_nak(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len)
ip_addr_t ip_temp = IPADDR4_INIT(0x0);
ip4_addr_set(ip_2_ip4(&ip_temp), &dhcps->broadcast_dhcps);
#if DHCPS_DEBUG
SendNak_err_t = udp_sendto(pcb_dhcps, p, &ip_temp, DHCPS_CLIENT_PORT);
SendNak_err_t = udp_sendto(dhcps->dhcps_pcb, p, &ip_temp, DHCPS_CLIENT_PORT);
DHCPS_LOG("dhcps: send_nak>>udp_sendto result %x\n", SendNak_err_t);
#else
udp_sendto(dhcps->dhcps_pcb, p, &ip_temp, DHCPS_CLIENT_PORT);
@ -1005,7 +1005,7 @@ POOL_CHECK:
#if DHCPS_DEBUG
DHCPS_LOG("dhcps: xid changed\n");
DHCPS_LOG("dhcps: client_address.addr = %x\n", client_address.addr);
DHCPS_LOG("dhcps: client_address.addr = %x\n", dhcps->client_address.addr);
#endif
return ret;
}

View File

@ -14,34 +14,34 @@ Performance of this type of "software" bridge is limited by the performance of E
## How to use example
The bellow sections demonstrate just two basic bridge configurations. However, note that additional combinations are possible.
### Example 1 - Ethernet Interfaces, DHCP Client
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.
```mermaid
graph TD;
classDef classPing fill:#0000,stroke-width:0px;
esp32["ESP32 w/ 2 bridged<br/>Ethernet ports<br/>(DHCP Client)"];
pc1["PC#1<br/>(DHCP Server)"];
pc2["PC#2<br/>(DHCP Client)"];
ping1["ping"]:::classPing
ping2["ping"]:::classPing
ping3["ping"]:::classPing
esp32 -.- ping1;
ping1 -.- pc1;
esp32 == Eth === pc2;
esp32 == Eth === pc1;
esp32 -.- ping2;
ping2 -.- pc2;
pc1 <-.- ping3;
pc2 <-.- ping3;
```
![network_1](./docs/network_1.png)
The work flow of the example is then as follows:
1. Install the Ethernet ports drivers in ESP32.
1. Install the Ethernet ports 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).
### Example 2 - Ethernet & WiFi AP, DHCP Server
You need one ESP32 with at least one Ethernet port and WiFi, and two PCs (or other Ethernet/WiFi capable devices). Connect the network as shown in figure below, configure PC#1 and PC#2 as DHCP clients. Enable DHCP server option in example menuconfig.
![network_2](./docs/network_2.png)
The work flow of the example is then as follows:
1. Install the Ethernet ports & WiFi AP in ESP32.
2. Configure bridge.
3. Wait for a DHCP leases in PC#1 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 and 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. Note that it is recommended to use multiple SPI Ethernet modules of the same type rather than combination of internal EMAC and SPI module since you don't need to take care of load balancing (internal EMAC has much higher bandwidth than SPI Ethernet modules).
@ -159,8 +159,9 @@ Now you can ping your ESP32 in PC#1 terminal by entering `ping 192.168.20.105` a
## 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.
* Only Ethernet and WiFi AP interfaces can be bridged using LwIP bridge since ESP WiFi station will only receive packets destined to it due to operating in 3 address system.
* If you need to stop just one network interface which is bridged to perform some action (like speed/duplex setting in Ethernet case), **all remaining interfaces** associated with the bridge need to be stopped as well to the bridge work properly after the interfaces are started again.
* No traffic balancing is implemented between faster and slower interface.
## Troubleshooting

View File

@ -0,0 +1,71 @@
<mxfile host="65bd71144e">
<diagram id="qvqIMWZhLYQI7_66ceEl" name="Page-1">
<mxGraphModel dx="866" dy="367" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" background="none" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="2" value="ESP32 w/ 2 bridged &lt;b&gt;Eth ports&lt;/b&gt;&lt;br&gt;(DHCP Client)" style="rounded=0;whiteSpace=wrap;html=1;strokeWidth=3;" 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;strokeWidth=2;" parent="1" source="3" target="2" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="15" value="Ethernet" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="5" vertex="1" connectable="0">
<mxGeometry x="-0.2899" y="-1" relative="1" as="geometry">
<mxPoint x="7" y="-11" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="3" value="PC#1&lt;br&gt;(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;strokeWidth=2;" parent="1" source="4" target="2" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="14" value="Ethernet" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="6" vertex="1" connectable="0">
<mxGeometry x="0.1867" y="-4" relative="1" as="geometry">
<mxPoint x="9" y="-6" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="4" value="PC#2&lt;br&gt;(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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@ -0,0 +1,73 @@
<mxfile host="65bd71144e">
<diagram id="qvqIMWZhLYQI7_66ceEl" name="Page-1">
<mxGraphModel dx="866" dy="367" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" background="none" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="2" value="ESP32 w/ bridged &lt;b&gt;WiFi AP &amp;amp; Eth port&lt;/b&gt;&lt;br&gt;(DHCP Server)" style="rounded=0;whiteSpace=wrap;html=1;strokeWidth=3;" parent="1" vertex="1">
<mxGeometry x="280" y="390" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="5" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;strokeWidth=2;" parent="1" source="3" target="2" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="220" y="420"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="15" value="Ethernet" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="5" vertex="1" connectable="0">
<mxGeometry x="-0.2899" y="-1" relative="1" as="geometry">
<mxPoint x="31" y="-11" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="3" value="PC#1&lt;br&gt;(DHCP Client)" 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="4" value="PC#2&lt;br&gt;(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="250" y="440" as="sourcePoint"/>
<mxPoint x="180" y="350" as="targetPoint"/>
<Array as="points">
<mxPoint x="190" y="420"/>
</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="500" y="350" as="sourcePoint"/>
<mxPoint x="430" y="440" as="targetPoint"/>
<Array as="points">
<mxPoint x="490" y="410"/>
</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="140" y="405" 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="480" y="400" 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>
<mxCell id="17" value="" style="shape=mxgraph.arrows2.wedgeArrowDashed2;html=1;bendable=0;startWidth=20;stepSize=15;entryX=1;entryY=0.5;entryDx=0;entryDy=0;strokeWidth=2;" parent="1" target="2" edge="1">
<mxGeometry width="100" height="100" relative="1" as="geometry">
<mxPoint x="460" y="370" as="sourcePoint"/>
<mxPoint x="420" y="420" as="targetPoint"/>
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -0,0 +1,45 @@
menu "Example Bridge Configuration"
config EXAMPLE_BR_DHCPS
bool "Enable DHCP Server"
default n
help
Enable DHCP Server on the device.
endmenu
menu "Example AP Wifi Configuration"
config EXAMPLE_BR_WIFI
depends on SOC_WIFI_SUPPORTED
default n
bool "Bridge WiFi interface"
help
Add WiFi interface to be bridged.
config EXAMPLE_BR_WIFI_SSID
depends on EXAMPLE_BR_WIFI
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config EXAMPLE_BR_WIFI_PASSWORD
depends on EXAMPLE_BR_WIFI
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
config EXAMPLE_BR_WIFI_CHANNEL
depends on EXAMPLE_BR_WIFI
int "WiFi Channel"
range 1 13
default 1
help
WiFi channel (network channel) for the example to use.
config EXAMPLE_BR_MAX_STA_CONN
depends on EXAMPLE_BR_WIFI
int "Maximal STA connections"
default 4
help
Max number of the STA connects to AP.
endmenu

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
@ -15,6 +15,10 @@
#include "esp_log.h"
#include "esp_mac.h"
#include "ethernet_init.h"
#if CONFIG_EXAMPLE_BR_WIFI
#include "esp_wifi.h"
#include "nvs_flash.h"
#endif // CONFIG_EXAMPLE_BR_WIFI
#include "sdkconfig.h"
#include "esp_console.h"
#include "bridge_console_cmd.h"
@ -65,6 +69,36 @@ static void got_ip_event_handler(void *arg, esp_event_base_t event_base,
ESP_LOGI(TAG, "~~~~~~~~~~~");
}
#if CONFIG_EXAMPLE_BR_WIFI
static void example_wifi_init(void)
{
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ESP_ERROR_CHECK(nvs_flash_init());
}
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
wifi_config_t wifi_config = {
.ap = {
.ssid = CONFIG_EXAMPLE_BR_WIFI_SSID,
.ssid_len = strlen(CONFIG_EXAMPLE_BR_WIFI_SSID),
.password = CONFIG_EXAMPLE_BR_WIFI_PASSWORD,
.max_connection = CONFIG_EXAMPLE_BR_MAX_STA_CONN,
.authmode = WIFI_AUTH_WPA_WPA2_PSK,
.channel = CONFIG_EXAMPLE_BR_WIFI_CHANNEL
},
};
if (strlen(CONFIG_EXAMPLE_BR_WIFI_PASSWORD) == 0) {
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
}
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
}
#endif //CONFIG_EXAMPLE_BR_WIFI
void app_main(void)
{
// Initialize Ethernet driver
@ -110,9 +144,24 @@ void app_main(void)
// Attach Ethernet driver to TCP/IP stack
ESP_ERROR_CHECK(esp_netif_attach(eth_netifs[i], esp_eth_new_netif_glue(eth_handles[i])));
}
uint8_t br_ports = eth_port_cnt;
#if CONFIG_EXAMPLE_BR_WIFI
example_wifi_init();
esp_netif_inherent_config_t esp_netif_config_wifi = ESP_NETIF_INHERENT_DEFAULT_WIFI_AP();
esp_netif_config_wifi.flags = ESP_NETIF_FLAG_AUTOUP; // esp-netif flags need to be zero when port's to be bridged except for AP's ESP_NETIF_FLAG_AUTOUP
esp_netif_config_wifi.ip_info = NULL; // no IP address for physical interface
esp_netif_t *wifi_netif = esp_netif_create_wifi(WIFI_IF_AP, &esp_netif_config_wifi);
ESP_ERROR_CHECK(esp_wifi_set_default_wifi_ap_handlers());
br_ports++;
#endif
// Create instance of esp-netif for bridge interface
#if CONFIG_EXAMPLE_BR_DHCPS
esp_netif_inherent_config_t esp_netif_br_config = ESP_NETIF_INHERENT_DEFAULT_BR_DHCPS();
#else
esp_netif_inherent_config_t esp_netif_br_config = ESP_NETIF_INHERENT_DEFAULT_BR();
#endif // CONFIG_EXAMPLE_BR_DHCPS
esp_netif_config_t netif_br_cfg = {
.base = &esp_netif_br_config,
.stack = ESP_NETIF_NETSTACK_DEFAULT_BR,
@ -121,7 +170,7 @@ void app_main(void)
bridgeif_config_t bridgeif_config = {
.max_fdb_dyn_entries = 10, // maximum number of address entries in dynamic forwarding database
.max_fdb_sta_entries = 2, // maximum number of address entries in static forwarding database
.max_ports = eth_port_cnt // maximum number of ports the bridge can consist of
.max_ports = br_ports // maximum number of ports the bridge can consist of
};
esp_netif_br_config.bridge_info = &bridgeif_config;
// Set MAC address of bridge interface the same as the Ethernet interface
@ -134,6 +183,10 @@ void app_main(void)
for (int i = 0; i < eth_port_cnt; i++) {
ESP_ERROR_CHECK(esp_netif_br_glue_add_port(netif_br_glue, eth_netifs[i]));
}
#if CONFIG_EXAMPLE_BR_WIFI
ESP_ERROR_CHECK(esp_netif_br_glue_add_wifi_port(netif_br_glue, wifi_netif));
#endif // CONFIG_EXAMPLE_BR_WIFI
// Attach esp netif bridge glue instance with added ports to bridge netif
ESP_ERROR_CHECK(esp_netif_attach(br_netif, netif_br_glue));
@ -148,6 +201,9 @@ void app_main(void)
// Start Ethernet driver state machine
ESP_ERROR_CHECK(esp_eth_start(eth_handles[i]));
}
#if CONFIG_EXAMPLE_BR_WIFI
ESP_ERROR_CHECK(esp_wifi_start());
#endif
// --- Initialize Console ---
esp_console_repl_t *repl = NULL;
@ -157,7 +213,7 @@ void app_main(void)
// install console REPL environment
esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_console_new_repl_uart(&uart_config, &repl_config, &repl));
example_register_br_config_commands(br_netif, eth_port_cnt);
example_register_br_config_commands(br_netif, br_ports);
// start console REPL
ESP_ERROR_CHECK(esp_console_start_repl(repl));
}