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

WIP: feat(6lowpan_ble): Simplified esp_netif driver #600

Open
wants to merge 16 commits into
base: master
Choose a base branch
from

Conversation

david-cermak
Copy link
Collaborator

  • Cleanup esp_netif sources
  • Make examples compatible with component manager projects
  • Add lwip 6lowpan netif to IDF
  • Make it work with simple linux router (e.g. as described here)

tomasgareau and others added 15 commits June 21, 2024 16:59
This dumps a BLE address to a static char buf. Note that this means it
can only be used once per log line (as calling it twice means you'll
overwrite that buffer).
This is the "driver" or "glue" code for ESP-NETIF.

See https://docs.espressif.com/projects/esp-idf/en/v5.2.1/esp32/api-reference/network/esp_netif_driver.html
for a more detailed overview of I/O drivers in ESP-IDF.

A quick overview though -- this module is responsible for the BLE side
of LoWPAN6 BLE. Given a BLE address to connect to (up to the user to
decide what address that is), it will:
* establish an L2CAP connection with:
  * the correct Protocol Service Multiplexer (PSM) for the Internet
    Protocol Support Profile (IPSP)
  * the correct MTU for LoWPAN6 (1280, as required by IPv6)
* on receipt of data, pass the received data to `esp_netif_receive`
* register and provide methods for transmitting data FROM esp_netif via
  the L2CAP channel
* forward events to the user (e.g., GAP connect/disconnect, so they can
  restart the discovery process on disconnect)

The driver/glue code does _not_ perform any of the protocol side of
LoWPAN6 BLE (i.e., we don't feed any data to LwIP): that will be the job
of a custom NETIF layer.
esp-lwip doesn't include the lowpan6 files in their build by default
(fair enough, given that it's not officially supported). This is a quick
workaround to pull those files in without changing ESP-IDF.
This defines the netstack required to support LoWPAN6 BLE with LwIP.

See https://docs.espressif.com/projects/esp-idf/en/v5.2.1/esp32/api-reference/network/esp_netif_driver.html
for a more detailed overview of how this fits into ESP-NETIF.

A quick summary here though. This module provides the "netstack": this
is the configuration used by ESP-NETIF to initialize the netif given to
it and to handle incoming data.

In our case, this means initializing the netif as an rfc7668 netif and
providing received data to `rfc7668_input`, as required by LwIP's
LoWPAN6 BLE module.

Also important is for us to set the local and peer addresses (used by
LwIP when compressing IPv6 headers for transmission over BLE) and to set
our link-local IPv6 address based on our BLE MAC address, as required by
the LoWPAN6 BLE standard.
Registering custom LwIP netstack functions was not supported in ESP-IDF
prior to v5.0:

From [this comment thread](espressif/esp-idf#13600 (comment))

> yes, registering custom lwip IO functions wasn't possible in IDF < v5.0.
> (still possible, if you redefine the opaque structs, like this)
> https://github.com/david-cermak/eth-ap-nat/blob/2279344e18a0b98b5368999aac9441c59871e6fa/eth-ap-idf4.3/main/ethernet_example_main.c#L90-L96

There are two things we need to do to shim this custom I/O driver into
ESP-NETIF for ESP-IDF v4 and co.

The first is to add implicitly required #include before
"esp_netif_types.h". This is fixed in v4.4+ by the following commit:
  espressif/esp-idf@822129e

but not backported to v4.3 (fair enough, seeing as it's EOL).

The second is to define a netstack config struct compatible with `struct
esp_netif_netstack_config_t`, which was not publically exported prior to
v5.0. We do so following the example linked above in the
david-cermak/eth-ap-nat repo:
* define `struct esp_netif_lwip_vanilla_config`
* cast our netstack to `esp_netif_netstack_config_t*`

`esp_netif_netstack_config_t` is just a union of
`struct esp_netif_lwip_vanilla_config` and some other struct we don't
care about, so while a bit sketchy this does actually work out (i.e., we
can correctly cast between them).
This commit introduces some helper functions for transforming BLE
addresses into link-local addresses.

This can be used by users to get the link-local address of their peer
after establishing a connection.
We were adding the missing lwIP sources to `lowpan6_ble`. While this
worked, it does break the link between `lwip` the target and the lwip
lowpan6_ble sources.

I bumped into this when enabling lwIP debug: some of their debug
statements were failing ESP-IDF's -Werror=format checks.

I tried to address this with:

```
idf_component_get_property(lwip lwip COMPONENT_LIB)
target_compile_options(${lwip} PRIVATE -Wno-error=format)
```

but of course, the `lwip` target did not contain the sources that were
causing an error -- `lowpan6_ble` did!

Appending the sources to the `lwip` target is the more correct approach
here.
This is a first stab at the additional "stuff" we'd need to support a
LoWPAN6 BLE client (the device that gets connected to rather than the
one that connects).
This example is a quick-and-dirty demo of how to communicate over
LoWPAN6 BLE between 2 ESP devices. This demonstrates how to hook the
lowpan6_ble component into the GAP discovery and connection process to
ensure that generic networking APIs such as lwIP can successfully
pass messages over our BLE connection.
The `ble_l2cap_send` implementation has a comment that says:

> Transmits a packet over an L2CAP channel.  This function only consumes
> the supplied mbuf on success.

This means that on _failure_, we're responsible for freeing the supplied
mbuf, otherwise we'll leak memory.
This disconnects our L2CAP and GAP connections, if applicable.
@david-cermak david-cermak self-assigned this Jun 21, 2024
@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ david-cermak
❌ tomasgareau
You have signed the CLA already but the status is still pending? Let us recheck it.

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

Successfully merging this pull request may close these issues.

4 participants