Skip to content

Commit

Permalink
Merge branch 'feature/lwip_bridge_wifi' into 'master'
Browse files Browse the repository at this point in the history
lwip bridge wifi

Closes IDFGH-3778

See merge request espressif/esp-idf!24112
  • Loading branch information
kostaond committed Jul 11, 2023
2 parents a065f0f + 3288f83 commit 35d4dd7
Show file tree
Hide file tree
Showing 13 changed files with 528 additions and 119 deletions.
12 changes: 11 additions & 1 deletion components/esp_netif/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()


Expand Down
15 changes: 12 additions & 3 deletions components/esp_netif/include/esp_netif_br_glue.h
Original file line number Diff line number Diff line change
@@ -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
*/
Expand Down Expand Up @@ -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
*
Expand Down
22 changes: 16 additions & 6 deletions components/esp_netif/include/esp_netif_defaults.h
Original file line number Diff line number Diff line change
@@ -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
*/
Expand Down Expand Up @@ -104,18 +104,28 @@ 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), \
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", \
.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 \
}
Expand Down
296 changes: 215 additions & 81 deletions components/esp_netif/lwip/esp_netif_br_glue.c

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion components/esp_netif/lwip/netif/wlanif.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions components/lwip/apps/dhcpserver/dhcpserver.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -1005,7 +1005,7 @@ static s16_t parse_msg(dhcps_t *dhcps, struct dhcps_msg *m, u16_t len)

#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;
}
Expand Down
43 changes: 22 additions & 21 deletions examples/network/bridge/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down Expand Up @@ -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

Expand Down
71 changes: 71 additions & 0 deletions examples/network/bridge/docs/network_1.drawio
Original file line number Diff line number Diff line change
@@ -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 added examples/network/bridge/docs/network_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
73 changes: 73 additions & 0 deletions examples/network/bridge/docs/network_2.drawio
Original file line number Diff line number Diff line change
@@ -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 added examples/network/bridge/docs/network_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 35d4dd7

Please sign in to comment.