Skip to content

Commit a74b01e

Browse files
authored
Merge pull request #812 from david-cermak/feat/eppp_transports
feat(eppp): Add support for TUN interface
2 parents b8cdd37 + c5a4a51 commit a74b01e

24 files changed

+1534
-701
lines changed

.github/workflows/eppp__build.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@ jobs:
1313
name: Build
1414
strategy:
1515
matrix:
16-
idf_ver: ["latest", "release-v5.3"]
16+
idf_ver: ["latest", "release-v5.5", "release-v5.4", "release-v5.3"]
1717
test: [ { app: host, path: "examples/host" }, { app: slave, path: "examples/slave" }, { app: test_app, path: "test/test_app" }]
1818
runs-on: ubuntu-22.04
1919
container: espressif/idf:${{ matrix.idf_ver }}
2020
steps:
2121
- name: Checkout esp-protocols
2222
uses: actions/checkout@v3
2323
- name: Build ${{ matrix.test.app }} with IDF-${{ matrix.idf_ver }}
24+
env:
25+
EXPECTED_WARNING: "DeprecationWarning: 'MultiCommand' is deprecated and will be removed\nCryptographyDeprecationWarning: Parsed a serial number which wasn't positive"
2426
shell: bash
2527
run: |
2628
. ${IDF_PATH}/export.sh

components/eppp_link/.cz.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ commitizen:
33
bump_message: 'bump(eppp): $current_version -> $new_version'
44
pre_bump_hooks: python ../../ci/changelog.py eppp_link
55
tag_format: eppp-v$version
6-
version: 0.2.0
6+
version: 0.3.0
77
version_files:
88
- idf_component.yml

components/eppp_link/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## [0.3.0](https://github.com/espressif/esp-protocols/commits/eppp-v0.3.0)
4+
5+
### Features
6+
7+
- Add support for TUN interface ([2ff150c3](https://github.com/espressif/esp-protocols/commit/2ff150c3))
8+
- Add support for transport via Ethernet link ([a21ce883](https://github.com/espressif/esp-protocols/commit/a21ce883))
9+
310
## [0.2.0](https://github.com/espressif/esp-protocols/commits/eppp-v0.2.0)
411

512
### Features

components/eppp_link/CMakeLists.txt

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,26 @@ if(CONFIG_EPPP_LINK_DEVICE_ETH)
88
set(transport_src eppp_eth.c)
99
endif()
1010

11+
if(CONFIG_EPPP_LINK_DEVICE_SPI)
12+
set(transport_src eppp_spi.c)
13+
endif()
14+
15+
if(CONFIG_EPPP_LINK_DEVICE_UART)
16+
set(transport_src eppp_uart.c)
17+
endif()
18+
1119
if(CONFIG_EPPP_LINK_DEVICE_SDIO)
12-
set(transport_src eppp_sdio_slave.c eppp_sdio_host.c)
20+
set(transport_src eppp_sdio.c eppp_sdio_slave.c eppp_sdio_host.c)
21+
endif()
22+
23+
if(NOT CONFIG_EPPP_LINK_USES_PPP)
24+
set(netif_src eppp_netif_tun.c)
1325
endif()
1426

15-
idf_component_register(SRCS eppp_link.c ${transport_src}
27+
idf_component_register(SRCS eppp_link.c ${transport_src} ${netif_src}
1628
INCLUDE_DIRS "include"
1729
PRIV_REQUIRES esp_netif esp_timer esp_eth ${driver_deps})
1830

1931
if(CONFIG_EPPP_LINK_DEVICE_ETH)
20-
idf_component_get_property(ethernet_init espressif__ethernet_init COMPONENT_LIB)
21-
target_link_libraries(${COMPONENT_LIB} PRIVATE ${ethernet_init})
32+
idf_component_optional_requires(PRIVATE ethernet_init espressif__ethernet_init)
2233
endif()

components/eppp_link/Kconfig

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
menu "eppp_link"
22

3-
config EPPP_LINK_USES_LWIP
4-
bool
5-
default "y"
3+
config EPPP_LINK_USES_PPP
4+
bool "Use PPP network interface"
5+
default "n"
66
select LWIP_PPP_SUPPORT
77
select LWIP_PPP_SERVER_SUPPORT
8+
help
9+
Enable this option to use PPP network interface.
10+
This is useful when pairing with another PPP device,
11+
e.g. pppd service on Linux.
12+
By default EPPP_LINK uses plain TUN interface,
13+
relying on transports to split on packet boundaries.
814

915
choice EPPP_LINK_DEVICE
1016
prompt "Choose PPP device"

components/eppp_link/README.md

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,45 @@
11
# ESP PPP Link component (eppp_link)
22

3-
The component provides a general purpose connectivity engine between two microcontrollers, one acting as PPP server (slave), the other one as PPP client (host).
4-
This component could be used for extending network using physical serial connection. Applications could vary from providing PRC engine for multiprocessor solutions to serial connection to POSIX machine. This uses a standard PPP protocol to negotiate IP addresses and networking, so standard PPP toolset could be used, e.g. a `pppd` service on linux. Typical application is a WiFi connectivity provider for chips that do not have WiFi
3+
The component provides a general purpose connectivity engine between two microcontrollers, one acting as PPP server, the other one as PPP client.
4+
This component could be used for extending network using physical serial connection. Applications could vary from providing PRC engine for multiprocessor solutions to serial connection to POSIX machine. This uses a standard PPP protocol (if enabled) to negotiate IP addresses and networking, so standard PPP toolset could be used, e.g. a `pppd` service on linux. Typical application is a WiFi connectivity provider for chips that do not have WiFi.
5+
Uses simplified TUN network interface by default to enable faster data transfer on non-UART transports.
56

67
## Typical application
78

89
Using this component we can construct a WiFi connectivity gateway on PPP channel. The below diagram depicts an application where
910
PPP server is running on a WiFi capable chip with NAPT module translating packets between WiFi and PPPoS interface.
10-
We usually call this node a SLAVE microcontroller. The "HOST" microcontroller runs PPP client and connects only to the serial line,
11-
brings in the WiFi connectivity from the "SLAVE" microcontroller.
11+
We usually call this node a communication coprocessor, or a "SLAVE" microcontroller.
12+
The main microcontroller (sometimes also called the "HOST") runs PPP client and connects only to the serial line,
13+
brings in the WiFi connectivity from the communication coprocessor.
1214

1315
```
14-
SLAVE micro HOST micro
16+
Communication coprocessor Main microcontroller
1517
\|/ +----------------+ +----------------+
1618
| | | (serial) line | |
1719
+---+ WiFi NAT PPPoS |=== UART / SPI / SDIO / ETH ===| PPPoS client |
1820
| (server)| | |
1921
+----------------+ +----------------+
2022
```
2123

24+
## Configuration
25+
26+
### Choose the transport layer
27+
28+
Use `idf.py menuconfig` to select the transport layer:
29+
30+
* `CONFIG_EPPP_LINK_UART` -- Use UART transport layer
31+
* `CONFIG_EPPP_LINK_SPI` -- Use SPI transport layer
32+
* `CONFIG_EPPP_LINK_SDIO` -- Use SDIO transport layer
33+
* `CONFIG_EPPP_LINK_ETHERNET` -- Use Ethernet transport
34+
- Note: Ethernet creates it's own task, so calling `eppp_perform()` would not work
35+
- Note: Add dependency to ethernet_init component to use other Ethernet drivers
36+
- Note: You can override functions `eppp_transport_ethernet_deinit()` and `eppp_transport_ethernet_init()` to use your own Ethernet driver
37+
38+
### Choose the network interface
39+
40+
Use PPP netif for UART; Keep the default (TUN) for others
41+
42+
2243
## API
2344

2445
### Client

components/eppp_link/eppp_eth.c

Lines changed: 117 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,18 @@
1111
#include "esp_check.h"
1212
#include "esp_event.h"
1313
#include "esp_mac.h"
14+
#include "esp_idf_version.h"
1415
#include "eppp_link.h"
1516
#include "eppp_transport.h"
1617
#include "esp_eth_driver.h"
17-
#include "ethernet_init.h"
1818
#include "esp_eth_spec.h"
19+
#include "eppp_transport_eth.h"
20+
// Use Ethernet Init component if available
21+
// (otherwise use just simple init/deinit with generic MAC/PHY)
22+
#if __has_include("ethernet_init.h")
23+
#define USE_ETHERNET_INIT_COMPONENT
24+
#include "ethernet_init.h"
25+
#endif
1926

2027
typedef struct header {
2128
uint8_t dst[ETH_ADDR_LEN];
@@ -26,10 +33,57 @@ typedef struct header {
2633
static const char *TAG = "eppp_ethernet";
2734
static bool s_is_connected = false;
2835
static esp_eth_handle_t *s_eth_handles = NULL;
29-
static uint8_t s_out_buffer[ETH_MAX_PACKET_SIZE];
3036
static uint8_t s_their_mac[ETH_ADDR_LEN];
3137
static uint8_t s_our_mac[ETH_ADDR_LEN];
3238

39+
#ifndef USE_ETHERNET_INIT_COMPONENT
40+
static esp_eth_handle_t s_handles[1] = { NULL };
41+
static esp_eth_mac_t *s_mac = NULL;
42+
static esp_eth_phy_t *s_phy = NULL;
43+
44+
static void simple_deinit(esp_eth_handle_t *handle_array[])
45+
{
46+
if (s_handles[0] != NULL) {
47+
esp_eth_driver_uninstall(s_handles[0]);
48+
s_handles[0] = NULL;
49+
}
50+
if (s_mac != NULL) {
51+
s_mac->del(s_mac);
52+
s_mac = NULL;
53+
}
54+
if (s_phy != NULL) {
55+
s_phy->del(s_phy);
56+
s_phy = NULL;
57+
}
58+
}
59+
60+
static esp_err_t simple_init(struct eppp_config_ethernet_s *config, esp_eth_handle_t *handle_array[])
61+
{
62+
esp_err_t ret = ESP_OK;
63+
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
64+
eth_esp32_emac_config_t esp32_emac_config = ETH_ESP32_EMAC_DEFAULT_CONFIG();
65+
esp32_emac_config.smi_gpio.mdc_num = config->mdc_io;
66+
esp32_emac_config.smi_gpio.mdio_num = config->mdio_io;
67+
s_mac = esp_eth_mac_new_esp32(&esp32_emac_config, &mac_config);
68+
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
69+
phy_config.phy_addr = config->phy_addr;
70+
phy_config.reset_gpio_num = config->rst_io;
71+
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)
72+
s_phy = esp_eth_phy_new_generic(&phy_config);
73+
#else
74+
s_phy = esp_eth_phy_new_ip101(&phy_config);
75+
#endif
76+
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(s_mac, s_phy);
77+
ESP_GOTO_ON_ERROR(esp_eth_driver_install(&eth_config, &s_handles[0]), err, TAG, "Ethernet driver install failed");
78+
*handle_array = s_handles;
79+
return ESP_OK;
80+
err:
81+
simple_deinit(handle_array);
82+
return ret;
83+
}
84+
85+
#endif // USE_ETHERNET_INIT_COMPONENT
86+
3387
static void event_handler(void *arg, esp_event_base_t event_base,
3488
int32_t event_id, void *event_data)
3589
{
@@ -65,55 +119,92 @@ static esp_err_t receive(esp_eth_handle_t h, uint8_t *buffer, uint32_t len, void
65119
return ESP_FAIL;
66120
}
67121

68-
__attribute__((weak)) esp_err_t eppp_transport_ethernet_init(esp_eth_handle_t *handle_array[])
122+
__attribute__((weak)) esp_err_t eppp_transport_ethernet_init(struct eppp_config_ethernet_s *config, esp_eth_handle_t *handle_array[])
69123
{
124+
#ifdef USE_ETHERNET_INIT_COMPONENT
70125
uint8_t eth_port_cnt = 0;
71126
ESP_RETURN_ON_ERROR(ethernet_init_all(handle_array, &eth_port_cnt), TAG, "Failed to init common eth drivers");
72127
ESP_RETURN_ON_FALSE(eth_port_cnt == 1, ESP_ERR_INVALID_ARG, TAG, "multiple Ethernet devices detected, please init only one");
73128
return ESP_OK;
129+
#else
130+
return simple_init(config, handle_array);
131+
#endif
74132
}
75133

76-
__attribute__((weak)) void eppp_transport_ethernet_deinit(esp_eth_handle_t *handle_array)
134+
__attribute__((weak)) void eppp_transport_ethernet_deinit(esp_eth_handle_t *handle_array[])
77135
{
136+
#ifdef USE_ETHERNET_INIT_COMPONENT
78137
ethernet_deinit_all(s_eth_handles);
138+
#else
139+
simple_deinit(handle_array);
140+
#endif
79141
}
80142

143+
esp_err_t eppp_transport_tx(void *h, void *buffer, size_t len)
144+
{
145+
static uint8_t out_buffer[ETH_HEADER_LEN];
146+
if (!s_is_connected) {
147+
return ESP_FAIL;
148+
}
149+
// setup Ethernet header
150+
header_t *head = (header_t *)out_buffer;
151+
memcpy(head->dst, s_their_mac, ETH_ADDR_LEN);
152+
memcpy(head->src, s_our_mac, ETH_ADDR_LEN);
153+
head->len = len;
154+
// support only payloads with len <= ETH_MAX_PAYLOAD_LEN
155+
if (len > ETH_MAX_PAYLOAD_LEN) {
156+
return ESP_FAIL;
157+
}
158+
return esp_eth_transmit_vargs(s_eth_handles[0], 2, out_buffer, ETH_HEADER_LEN, buffer, len);
159+
}
81160

82-
esp_err_t eppp_transport_init(eppp_config_t *config, esp_netif_t *esp_netif)
161+
static esp_err_t start_driver(esp_netif_t *esp_netif)
83162
{
84-
ESP_RETURN_ON_ERROR(eppp_transport_ethernet_init(&s_eth_handles), TAG, "Failed to initialize Ethernet driver");
85163
ESP_RETURN_ON_ERROR(esp_eth_update_input_path(s_eth_handles[0], receive, esp_netif), TAG, "Failed to set Ethernet Rx callback");
86-
sscanf(CONFIG_EPPP_LINK_ETHERNET_OUR_ADDRESS, "%2" PRIu8 ":%2" PRIu8 ":%2" PRIi8 ":%2" PRIu8 ":%2" PRIu8 ":%2" PRIu8,
164+
sscanf(CONFIG_EPPP_LINK_ETHERNET_OUR_ADDRESS, "%2" PRIx8 ":%2" PRIx8 ":%2" PRIx8 ":%2" PRIx8 ":%2" PRIx8 ":%2" PRIx8,
87165
&s_our_mac[0], &s_our_mac[1], &s_our_mac[2], &s_our_mac[3], &s_our_mac[4], &s_our_mac[5]);
88166

89-
sscanf(CONFIG_EPPP_LINK_ETHERNET_THEIR_ADDRESS, "%2" PRIu8 ":%2" PRIu8 ":%2" PRIi8 ":%2" PRIu8 ":%2" PRIu8 ":%2" PRIu8,
167+
sscanf(CONFIG_EPPP_LINK_ETHERNET_THEIR_ADDRESS, "%2" PRIx8 ":%2" PRIx8 ":%2" PRIx8 ":%2" PRIx8 ":%2" PRIx8 ":%2" PRIx8,
90168
&s_their_mac[0], &s_their_mac[1], &s_their_mac[2], &s_their_mac[3], &s_their_mac[4], &s_their_mac[5]);
91169
esp_eth_ioctl(s_eth_handles[0], ETH_CMD_S_MAC_ADDR, s_our_mac);
92170
ESP_RETURN_ON_ERROR(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, event_handler, NULL), TAG, "Failed to register Ethernet handlers");
93171
ESP_RETURN_ON_ERROR(esp_eth_start(s_eth_handles[0]), TAG, "Failed to start Ethernet driver");
94172
return ESP_OK;
95173
}
96174

97-
void eppp_transport_deinit(void)
175+
static esp_err_t post_attach(esp_netif_t *esp_netif, void *args)
98176
{
99-
esp_eth_stop(s_eth_handles[0]);
100-
eppp_transport_ethernet_deinit(s_eth_handles);
177+
eppp_transport_handle_t h = (eppp_transport_handle_t)args;
178+
ESP_RETURN_ON_FALSE(h, ESP_ERR_INVALID_ARG, TAG, "Transport handle cannot be null");
179+
h->base.netif = esp_netif;
180+
181+
esp_netif_driver_ifconfig_t driver_ifconfig = {
182+
.handle = h,
183+
.transmit = eppp_transport_tx,
184+
};
185+
186+
ESP_RETURN_ON_ERROR(esp_netif_set_driver_config(esp_netif, &driver_ifconfig), TAG, "Failed to set driver config");
187+
ESP_LOGI(TAG, "EPPP Ethernet transport attached to EPPP netif %s", esp_netif_get_desc(esp_netif));
188+
ESP_RETURN_ON_ERROR(start_driver(esp_netif), TAG, "Failed to start EPPP ethernet driver");
189+
ESP_LOGI(TAG, "EPPP Ethernet driver started");
190+
return ESP_OK;
101191
}
102192

103-
esp_err_t eppp_transport_tx(void *h, void *buffer, size_t len)
193+
eppp_transport_handle_t eppp_eth_init(struct eppp_config_ethernet_s *config)
104194
{
105-
if (!s_is_connected) {
106-
return ESP_FAIL;
107-
}
108-
// setup Ethernet header
109-
header_t *head = (header_t *)s_out_buffer;
110-
memcpy(head->dst, s_their_mac, ETH_ADDR_LEN);
111-
memcpy(head->src, s_our_mac, ETH_ADDR_LEN);
112-
head->len = len;
113-
// support only payloads with len <= ETH_MAX_PAYLOAD_LEN
114-
if (len > ETH_MAX_PAYLOAD_LEN) {
115-
return ESP_FAIL;
116-
}
117-
memcpy(s_out_buffer + ETH_HEADER_LEN, buffer, len);
118-
return esp_eth_transmit(s_eth_handles[0], s_out_buffer, len + ETH_HEADER_LEN);
195+
__attribute__((unused)) esp_err_t ret = ESP_OK;
196+
ESP_RETURN_ON_FALSE(config, NULL, TAG, "Config cannot be null");
197+
eppp_transport_handle_t h = calloc(1, sizeof(struct eppp_handle));
198+
ESP_RETURN_ON_FALSE(h, NULL, TAG, "Failed to allocate eppp_handle");
199+
ESP_GOTO_ON_ERROR(eppp_transport_ethernet_init(config, &s_eth_handles), err, TAG, "Failed to init Ethernet transport");
200+
h->base.post_attach = post_attach;
201+
return h;
202+
err:
203+
return NULL;
204+
}
205+
206+
void eppp_eth_deinit(eppp_transport_handle_t h)
207+
{
208+
esp_eth_stop(s_eth_handles[0]);
209+
eppp_transport_ethernet_deinit(&s_eth_handles);
119210
}

0 commit comments

Comments
 (0)