mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
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:
parent
1ad891361f
commit
3288f83401
@ -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()
|
||||
|
||||
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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 \
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
71
examples/network/bridge/docs/network_1.drawio
Normal file
71
examples/network/bridge/docs/network_1.drawio
Normal 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 <b>Eth ports</b><br>(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<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;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<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_1.png
Normal file
BIN
examples/network/bridge/docs/network_1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
73
examples/network/bridge/docs/network_2.drawio
Normal file
73
examples/network/bridge/docs/network_2.drawio
Normal 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 <b>WiFi AP &amp; Eth port</b><br>(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<br>(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<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="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>
|
BIN
examples/network/bridge/docs/network_2.png
Normal file
BIN
examples/network/bridge/docs/network_2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
45
examples/network/bridge/main/Kconfig.projbuild
Normal file
45
examples/network/bridge/main/Kconfig.projbuild
Normal 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
|
@ -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));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user