Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions components/esp_netif/lwip/esp_netif_lwip_ppp.c
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,11 @@ netif_related_data_t * esp_netif_new_ppp(esp_netif_t *esp_netif, const esp_netif
#if PPP_NOTIFY_PHASE
ppp_set_notify_phase_callback(ppp_obj->ppp, on_ppp_notify_phase);
#endif
#if PPP_IPV4_SUPPORT
#if LWIP_DNS
ppp_set_usepeerdns(ppp_obj->ppp, 1);
#endif /* LWIP_DNS */
#endif /* PPP_IPV4_SUPPORT */

return (netif_related_data_t *)ppp_obj;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -384,16 +384,29 @@ menu "Example Connection Configuration"
select LWIP_IPV6
select LWIP_PPP_ENABLE_IPV6 if EXAMPLE_CONNECT_PPP
help
By default, examples will wait until IPv4 and IPv6 local link addresses are obtained.
Disable this option if the network does not support IPv6.
Choose the preferred IPv6 address type if the connection code should wait until other than
the local link address gets assigned.
Consider enabling IPv6 stateless address autoconfiguration (SLAAC) in the LWIP component.
By default, examples will wait until any IP preferred (usually global) address is obtained,
allowing flexible deployment to IPv4-only, IPv6-only, or dual-stack networks.

Enables SLAAC (State-Less Address Auto-Configuration) to get IPv6
address prefixes from Router Advertisement (RA) messages, and both
RA RDNSS (Recursive DNS Server) and DHCPv6 Stateless mode to get IPv6 DNS
server details from whichever is available on the network.

if EXAMPLE_CONNECT_IPV6
config EXAMPLE_CONNECT_PREF_ANY
bool "Obtain any preferred address"
default y
help
By default, examples will wait until any IP preferred address is obtained, either an IPv4 or
IPv6 global scope addresses.
This enables flexible deployment into any network type.
Disable this option to wait for both address types, although this will break single-stack networks.
Choose the preferred IPv6 address type if the connection code should wait until other than
an IPv6 global address.

choice EXAMPLE_CONNECT_PREFERRED_IPV6
prompt "Preferred IPv6 Type"
default EXAMPLE_CONNECT_IPV6_PREF_LOCAL_LINK
default EXAMPLE_CONNECT_IPV6_PREF_GLOBAL
help
Select which kind of IPv6 address the connect logic waits for.

Expand Down Expand Up @@ -421,5 +434,4 @@ menu "Example Connection Configuration"

endif


endmenu
44 changes: 44 additions & 0 deletions examples/common_components/protocol_examples_common/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "freertos/event_groups.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"

static const char *TAG = "example_common";

Expand Down Expand Up @@ -136,3 +137,46 @@ esp_err_t example_disconnect(void)
#endif
return ESP_OK;
}

esp_err_t example_getaddrinfo(const char *nodename, const char *servname, struct addrinfo **res)
{
#if CONFIG_EXAMPLE_CONNECT_IPV6
// Iterate over active interfaces, and find if we have any global scope IPv6
bool has_global_scope_ipv6 = false;
esp_netif_t *netif = NULL;
while ((netif = esp_netif_next_unsafe(netif)) != NULL) {
esp_ip6_addr_t ip6[MAX_IP6_ADDRS_PER_NETIF];
int ip6_addrs = esp_netif_get_all_ip6(netif, ip6);
for (int j = 0; j < ip6_addrs; ++j) {
// Both global and unique local addresses have global scope.
// ULA assumes either private DNS or NAT66 (same assumpation as IPv4 private address ranges).
esp_ip6_addr_type_t ipv6_type = esp_netif_ip6_get_addr_type(&(ip6[j]));
if (ipv6_type == ESP_IP6_ADDR_IS_GLOBAL || ipv6_type == ESP_IP6_ADDR_IS_UNIQUE_LOCAL) {
has_global_scope_ipv6 = true;
break;
}
}
if (has_global_scope_ipv6) break;
}

if (has_global_scope_ipv6) {
const struct addrinfo hints6 = {
.ai_family = AF_INET6,
.ai_socktype = SOCK_STREAM,
};
ESP_LOGI(TAG, "IPv6 DNS lookup");
int err6 = getaddrinfo(nodename, servname, &hints6, res);
if(err6 == 0) return err6;
ESP_LOGI(TAG, "- IPv6 DNS lookup failed, trying IPv4 lookup");
}
#endif

const struct addrinfo hints4 = {
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
};
ESP_LOGI(TAG, "IPv4 DNS lookup");
int err4 = getaddrinfo(nodename, servname, &hints4, res);

return err4;
}
21 changes: 21 additions & 0 deletions examples/common_components/protocol_examples_common/eth_connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@
static const char *TAG = "ethernet_connect";
static SemaphoreHandle_t s_semph_get_ip_addrs = NULL;
#if CONFIG_EXAMPLE_CONNECT_IPV6
#if CONFIG_EXAMPLE_CONNECT_PREF_ANY
#else
static SemaphoreHandle_t s_semph_get_ip6_addrs = NULL;
#endif
#endif

static esp_netif_t *eth_start(void);
static void eth_stop(void);
Expand Down Expand Up @@ -55,7 +58,11 @@ static void eth_on_got_ipv6(void *arg, esp_event_base_t event_base,
ESP_LOGI(TAG, "Got IPv6 event: Interface \"%s\" address: " IPV6STR ", type: %s", esp_netif_get_desc(event->esp_netif),
IPV62STR(event->ip6_info.ip), example_ipv6_addr_types_to_str[ipv6_type]);
if (ipv6_type == EXAMPLE_CONNECT_PREFERRED_IPV6_TYPE) {
#if CONFIG_EXAMPLE_CONNECT_PREF_ANY
xSemaphoreGive(s_semph_get_ip_addrs);
#else
xSemaphoreGive(s_semph_get_ip6_addrs);
#endif
}
}

Expand Down Expand Up @@ -206,14 +213,23 @@ void example_ethernet_shutdown(void)
vSemaphoreDelete(s_semph_get_ip_addrs);
s_semph_get_ip_addrs = NULL;
#if CONFIG_EXAMPLE_CONNECT_IPV6
#if CONFIG_EXAMPLE_CONNECT_PREF_ANY
#else
vSemaphoreDelete(s_semph_get_ip6_addrs);
s_semph_get_ip6_addrs = NULL;
#endif
#endif
eth_stop();
}

esp_err_t example_ethernet_connect(void)
{
#if CONFIG_EXAMPLE_CONNECT_PREF_ANY
s_semph_get_ip_addrs = xSemaphoreCreateBinary();
if (s_semph_get_ip_addrs == NULL) {
return ESP_ERR_NO_MEM;
}
#else
#if CONFIG_EXAMPLE_CONNECT_IPV4
s_semph_get_ip_addrs = xSemaphoreCreateBinary();
if (s_semph_get_ip_addrs == NULL) {
Expand All @@ -226,14 +242,19 @@ esp_err_t example_ethernet_connect(void)
vSemaphoreDelete(s_semph_get_ip_addrs);
return ESP_ERR_NO_MEM;
}
#endif
#endif
eth_start();
ESP_LOGI(TAG, "Waiting for IP(s).");
#if CONFIG_EXAMPLE_CONNECT_PREF_ANY
xSemaphoreTake(s_semph_get_ip_addrs, portMAX_DELAY);
#else
#if CONFIG_EXAMPLE_CONNECT_IPV4
xSemaphoreTake(s_semph_get_ip_addrs, portMAX_DELAY);
#endif
#if CONFIG_EXAMPLE_CONNECT_IPV6
xSemaphoreTake(s_semph_get_ip6_addrs, portMAX_DELAY);
#endif
#endif
return ESP_OK;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "esp_eth.h"
#endif
#endif // !CONFIG_IDF_TARGET_LINUX
#include "lwip/netdb.h"

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -77,6 +78,14 @@ esp_err_t example_disconnect(void);
*/
esp_err_t example_configure_stdin_stdout(void);

/**
* @brief Resolve best destination address based on available source addresses
*
* If a global IPv6 address is available, this tries to get an IPv6 address,
* otherwise it falls back to IPv4.
*/
esp_err_t example_getaddrinfo(const char *nodename, const char *servname, struct addrinfo **res);

/**
* @brief Returns esp-netif pointer created by example_connect() described by
* the supplied desc field
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ esp_err_t example_ppp_connect(void)
#endif // CONNECT_PPP_DEVICE

ESP_LOGI(TAG, "Waiting for IP address");
// Note: CONFIG_EXAMPLE_CONNECT_PREF_ANY is ignored; PPP always waits for ANY (does not wait for all)
EventBits_t bits = xEventGroupWaitBits(s_event_group, CONNECT_BITS, pdFALSE, pdFALSE, portMAX_DELAY);
if (bits & CONNECTION_FAILED) {
ESP_LOGE(TAG, "Connection failed!");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ static const char *TAG = "example_connect";
static esp_netif_t *s_example_sta_netif = NULL;
static SemaphoreHandle_t s_semph_get_ip_addrs = NULL;
#if CONFIG_EXAMPLE_CONNECT_IPV6
#if CONFIG_EXAMPLE_CONNECT_PREF_ANY
#else
static SemaphoreHandle_t s_semph_get_ip6_addrs = NULL;
#endif
#endif

#if CONFIG_EXAMPLE_WIFI_SCAN_METHOD_FAST
#define EXAMPLE_WIFI_SCAN_METHOD WIFI_FAST_SCAN
Expand Down Expand Up @@ -71,9 +74,12 @@ static void example_handler_on_wifi_disconnect(void *arg, esp_event_base_t event
xSemaphoreGive(s_semph_get_ip_addrs);
}
#if CONFIG_EXAMPLE_CONNECT_IPV6
#if CONFIG_EXAMPLE_CONNECT_PREF_ANY
#else
if (s_semph_get_ip6_addrs) {
xSemaphoreGive(s_semph_get_ip6_addrs);
}
#endif
#endif
return;
}
Expand Down Expand Up @@ -102,6 +108,7 @@ static void example_handler_on_sta_got_ip(void *arg, esp_event_base_t event_base
return;
}
ESP_LOGI(TAG, "Got IPv4 event: Interface \"%s\" address: " IPSTR, esp_netif_get_desc(event->esp_netif), IP2STR(&event->ip_info.ip));

if (s_semph_get_ip_addrs) {
xSemaphoreGive(s_semph_get_ip_addrs);
} else {
Expand All @@ -122,10 +129,15 @@ static void example_handler_on_sta_got_ipv6(void *arg, esp_event_base_t event_ba
IPV62STR(event->ip6_info.ip), example_ipv6_addr_types_to_str[ipv6_type]);

if (ipv6_type == EXAMPLE_CONNECT_PREFERRED_IPV6_TYPE) {
#if CONFIG_EXAMPLE_CONNECT_PREF_ANY
if (s_semph_get_ip_addrs) {
xSemaphoreGive(s_semph_get_ip_addrs);
#else
if (s_semph_get_ip6_addrs) {
xSemaphoreGive(s_semph_get_ip6_addrs);
#endif
} else {
ESP_LOGI(TAG, "- IPv6 address: " IPV6STR ", type: %s", IPV62STR(event->ip6_info.ip), example_ipv6_addr_types_to_str[ipv6_type]);
ESP_LOGI(TAG, "- IPv6 address: " IPV6STR ", type: %s", IPV62STR(event->ip6_info.ip), example_ipv6_addr_types_to_str[ipv6_type]);
}
}
}
Expand Down Expand Up @@ -172,11 +184,14 @@ esp_err_t example_wifi_sta_do_connect(wifi_config_t wifi_config, bool wait)
return ESP_ERR_NO_MEM;
}
#if CONFIG_EXAMPLE_CONNECT_IPV6
#if CONFIG_EXAMPLE_CONNECT_PREF_ANY
#else
s_semph_get_ip6_addrs = xSemaphoreCreateBinary();
if (s_semph_get_ip6_addrs == NULL) {
vSemaphoreDelete(s_semph_get_ip_addrs);
return ESP_ERR_NO_MEM;
}
#endif
#endif
}
s_retry_num = 0;
Expand All @@ -196,11 +211,15 @@ esp_err_t example_wifi_sta_do_connect(wifi_config_t wifi_config, bool wait)
}
if (wait) {
ESP_LOGI(TAG, "Waiting for IP(s)");
#if CONFIG_EXAMPLE_CONNECT_PREF_ANY
xSemaphoreTake(s_semph_get_ip_addrs, portMAX_DELAY);
#else
#if CONFIG_EXAMPLE_CONNECT_IPV4
xSemaphoreTake(s_semph_get_ip_addrs, portMAX_DELAY);
#endif
#if CONFIG_EXAMPLE_CONNECT_IPV6
xSemaphoreTake(s_semph_get_ip6_addrs, portMAX_DELAY);
#endif
#endif
if (s_retry_num > CONFIG_EXAMPLE_WIFI_CONN_MAX_RETRY) {
return ESP_FAIL;
Expand All @@ -221,9 +240,12 @@ esp_err_t example_wifi_sta_do_disconnect(void)
vSemaphoreDelete(s_semph_get_ip_addrs);
}
#if CONFIG_EXAMPLE_CONNECT_IPV6
#if CONFIG_EXAMPLE_CONNECT_PREF_ANY
#else
if (s_semph_get_ip6_addrs) {
vSemaphoreDelete(s_semph_get_ip6_addrs);
}
#endif
#endif
return esp_wifi_disconnect();
}
Expand Down
24 changes: 22 additions & 2 deletions examples/protocols/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,26 @@ When connecting using Wi-Fi, enter SSID and password of your Wi-Fi access point

When connecting using Ethernet, set up PHY type and configuration in the provided fields. If using Ethernet for the first time, it is recommended to start with the [Ethernet example readme](../ethernet/basic/README.md), which contains instructions for connecting and configuring the PHY. Once Ethernet example obtains IP address successfully, proceed to the protocols example and set the same configuration options.

### Disabling IPv6
### IP protocol handling

By default, `example_connect()` function waits until Wi-Fi or Ethernet connection is established, and IPv4 address and IPv6 link-local address are obtained. In network environments where IPv6 link-local address cannot be obtained, disable "Obtain IPv6 link-local address" option found in "Example Connection Configuration" menu.
By default the examples support any network configuration: IPv4 only, IPv6 only, and dual stack.

The `example_connect()` function waits until Wi-Fi or Ethernet connection is established, and either an IPv4 address or an IPv6 global scope address is obtained. By waiting for the first (of either), this allows it to work in any network.

The behaviour is based on the available network:

| Network | Addresses | DNS | IPv4 destination | IPv6 destination | Dual-stack destination
| -- | -- | -- | -- | -- | --
| IPv4 only | IPv4, IPv6 link-local | IPv4 | Yes | Not possible | Uses IPv4
| IPv6 only | IPv6 global, IPv6 link-local | IPv6 | NAT64 if available | Yes | Uses IPv6
| Dual-stack | IPv6 global (*1), IPv4, IPv6 link-local | IPv6, then IPv4 | Yes | Yes | Uses IPv6

(*1) There may be a delay waiting for an IPv6 global address, in which case IPv4 may be used for the first test request (with IPv4 DNS)

#### Disabling protocol versions

Where the target network is unknown, such as this sample, using an adaptable configuration that supports all networks (whatever is available) is best.

However in some cases you may want to restrict network configuration.

For example the Matter standard requires IPv6, so you can reduce application size and simplify development and testing complexity by completely disabling IPv4 (`LWIP_IPV4`), as it is never needed for a Matter device.
Loading