Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ethernet to WiFi bridge: where to start? #508

Open
FrigoEU opened this issue Oct 23, 2024 · 9 comments
Open

Ethernet to WiFi bridge: where to start? #508

FrigoEU opened this issue Oct 23, 2024 · 9 comments

Comments

@FrigoEU
Copy link

FrigoEU commented Oct 23, 2024

Hi,

This isn't an issue but rather a request for a nudge in the right direction. I've made a fairly large application in Rust running on the ESP32. So far it's been fairly smooth sailing. But the next feature I'd like to build is to me quite difficult to get started on.

The situation: my ESP32 will be plugged into Ethernet. When connection is successful (and it's configured as such) it should start a WiFi access point (with pre-configured ssid/password) and allow another device to connect to the WiFi and connect to the internet via the ESP32's Ethernet connection. I feel in theory this should be possible but I've found only very limited information/examples online (especially in the Rust language).

I'd greatly appreciate it if somebody could point me in the right direction to get started on this.

Simon

@ivmarkov
Copy link
Collaborator

ivmarkov commented Oct 23, 2024

A quick googling reveals this C ESP IDF example which should be your starting point, and seems to do exactly what you want: https://github.com/espressif/esp-idf/tree/release/v5.2/examples/network/bridge

Informally speaking, how it operates is as follows:

  • It can bridge N ethernet devices and optionally, one Wifi device (in AP mode only; STA bridging not supported, but you don't want this anyway)
  • It uses something called lwIP bridge (modeled with a regular ESP IDF Netif (EspNetif in Rust-speak) and "assigns" to this bridge all N ethernet netifs + the optional Wifi AP netif.
  • All ethernet phys (plus the "phy" of the bridge) should have the same MAC address. Weirdly, this is not done for the Wifi AP phy in the example (?)

Apparently, this is something new in ESP IDF 5. ESP IDF 4.4 did not support layer-2 bridging, only layer3 IP packet forwarding (which is still supported in the esp-idf-* crates btw)

How to do it in Rust?

  • Create N (N > 0) EspEth instances (these are a combination of phy (EthDriver) + netif (EspNetif). For their netifs, use a custom NetworkConfiguration, so that you can assign a different netif key and different distance to each ethernet netif. In each ethernet EspEth instance, you need to set the same Ethernet Mac address, as per the example. There is a public API for that, I think, otherwise unsafely call into esp_idf_svc::sys::esp_eth_ioctl as per the example
  • Create the single Ap Wifi with EspWifi (a combination of phy WifiDriver + netif EspNetif), and set it in AP mode, as usual

Now the non-trivial part:
Once the above laborious excercise is done, you need to create - as per the C example - an extra netif, and configure it as a bridge. The configuration currently cannot be 100% done with safe Rust calls, because the ESP IDF bridge APIs are not yet exposed in a safe manner in esp-idf-svc (as in the esp_netif_br_* structs and glue functions). Until this is available in Rust, you can just do it with unsafe calls into esp_idf_svc::sys::*.

Once you have this, I would appreciate if you publish it as I can use it as a template to expose the bridge APIs in a safe way in esp-idf-svc.

The bridge configuration stuff in the example starts from here. All above (ethernet and wifi conf) can be done with safe Rust.

Hope that helps.

@FrigoEU
Copy link
Author

FrigoEU commented Oct 25, 2024

Hi @ivmarkov ,

This helps so much! I plan to get started on this next week and I'll report my findings. Thank you so much for this, I don't think I would have been able to figure this out in a reasonable time myself. Many thanks!

Simon

@ivmarkov
Copy link
Collaborator

Np.
Actually, since you have one and only one Eth instance, your work would be simpler. Where I said:

Create N (N > 0) EspEth instances (these are a combination of phy (EthDriver) + netif (EspNetif). For their netifs, use a custom NetworkConfiguration, so that you can assign a different netif key and different distance to each ethernet netif. In each ethernet EspEth instance, you need to set the same Ethernet Mac address, as per the example. There is a public API for that, I think, otherwise unsafely call into esp_idf_svc::sys::esp_eth_ioctl as per the example

... the custom network configuration is only necessary if you have multiple eth interfaces, as then each needs to have its own unique key and distance. Since you'll have only one, none of this is necessary.

Only the step where you assign the same MAC address to both your eth and the netif bridge is necessary.

@FrigoEU
Copy link
Author

FrigoEU commented Oct 30, 2024

Hey @ivmarkov,

I've been getting some work done on and this and have been slowly porting the C code from the example to Rust. However, I got stuck on the last part that uses the esp_netif_br_glue_* types and structs and functions. I can't seem to find these anywhere on the rust side. Not in esp-idf-svc, nor in esp-idf-sys. Is this just missing for now or am I looking in the wrong place?

@FrigoEU
Copy link
Author

FrigoEU commented Nov 8, 2024

Hey @ivmarkov,

Just checking if you've already looked at this. I don't have much experience making Rust bindings for C so I'm (for now at least) hoping you can point me in the right direction :P.

Simon

@ivmarkov
Copy link
Collaborator

ivmarkov commented Nov 8, 2024

@FrigoEU Thanksd for reminding me!
I just pushed to esp-idf-sys master a small change that should expose the netif bridge raw bindings you are looking for.

Just make sure to add the following in your Cargo.toml:

[patch.crates-io]
esp-idf-svc = { git = "https://github.com/esp-rs/esp-idf-svc" }
esp-idf-hal = { git = "https://github.com/esp-rs/esp-idf-hal" }
esp-idf-sys = { git = "https://github.com/esp-rs/esp-idf-sys" }
cmake = { git = "https://github.com/ivmarkov/cmake-rs" }

@ivmarkov
Copy link
Collaborator

ivmarkov commented Nov 8, 2024

And in your sdkconfig.defaults:

CONFIG_ESP_NETIF_TCPIP_LWIP=y
CONFIG_ESP_NETIF_BRIDGE_EN=y

CONFIG_LWIP_NUM_NETIF_CLIENT_DATA=1

... as per the C example.

@FrigoEU
Copy link
Author

FrigoEU commented Nov 8, 2024

Thank you very much! I'll continue with this next week.

@ivmarkov
Copy link
Collaborator

ivmarkov commented Nov 8, 2024

You should look for the raw bindings in esp_idf_svc::sys which re-exports esp_idf_sys.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Todo
Development

No branches or pull requests

2 participants