WIP ipv6 works(-ish)

* metro esp32s2 only, because that's what I had handy
 * nothing is started at boot; I hung it on `start_dhcp()` which is dubious
 * I get a stateless address (which doesn't seem to work) and a dhcpv6 address (which does)

```
>>> wifi.radio.ipv6_addresses
('FE80::7EDF:A1FF:FE00:518C', 'FD5F:3F5C:FE50:0:7EDF:A1FF:FE00:518C')
```

 * depending whether a v4 or v6 dns server is configured, DNS resolution breaks

wrong ipv4_dns is first 4 bytes of the v6 dns server address:
```
>>> wifi.radio.ipv4_dns
253.95.63.92
```

 * I can connect to a v4 or v6 SSH server on the local network and read its banner

>>> s.close(); s = socket.socket(socket.AF_INET6, socket.SOCK_STREAM); s.connect(("fd5f:3f5c:fe50:0:6d9:f5ff:fe1f:ce10", 22))
*** len[0]=28
*** len=28 family=10 port=5632
>>> s.recv_into(buf)
40
>>> bytes(buf)
b'SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u3\r\n\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
This commit is contained in:
Jeff Epler 2024-07-16 12:27:19 -05:00
parent 3b30f0cc36
commit 9088488d1c
7 changed files with 83 additions and 51 deletions

View file

@ -0,0 +1,4 @@
CONFIG_LWIP_IPV6_AUTOCONFIG=y
CONFIG_LWIP_IPV6_RDNSS_MAX_DNS_SERVERS=2
CONFIG_LWIP_IPV6_DHCP6=y

View file

@ -11,6 +11,7 @@
#include "py/mperrno.h"
#include "py/runtime.h"
#include "shared-bindings/socketpool/SocketPool.h"
#include "common-hal/socketpool/__init__.h"
#if CIRCUITPY_SSL
#include "shared-bindings/ssl/SSLSocket.h"
#include "shared-module/ssl/SSLSocket.h"
@ -25,6 +26,20 @@
#include "components/lwip/lwip/src/include/lwip/netdb.h"
#include "components/vfs/include/esp_vfs_eventfd.h"
static void resolve_host_or_throw(socketpool_socket_obj_t *self, const char *hostname, struct sockaddr_storage *addr, int port) {
struct addrinfo *result_i;
const struct addrinfo hints = {
.ai_family = self->family,
.ai_socktype = self->type,
};
int error = socketpool_getaddrinfo_common(hostname, port, &hints, &result_i);
if (error != 0 || result_i == NULL) {
common_hal_socketpool_socketpool_raise_gaierror_noname();
}
memcpy(addr, result_i->ai_addr, sizeof(struct sockaddr_storage));
lwip_freeaddrinfo(result_i);
}
StackType_t socket_select_stack[2 * configMINIMAL_STACK_SIZE];
/* Socket state table:
@ -339,7 +354,7 @@ size_t common_hal_socketpool_socket_bind(socketpool_socket_obj_t *self,
ip = inet_addr(host);
}
bind_addr.sin_addr.s_addr = ip;
bind_addr.sin_family = AF_INET;
bind_addr.sin_family = self->family;
bind_addr.sin_port = htons(port);
int result = lwip_bind(self->num, (struct sockaddr *)&bind_addr, sizeof(bind_addr));
@ -382,26 +397,8 @@ void common_hal_socketpool_socket_close(socketpool_socket_obj_t *self) {
void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self,
const char *host, size_t hostlen, uint32_t port) {
const struct addrinfo hints = {
.ai_family = self->family,
.ai_socktype = self->type,
};
struct addrinfo *result_i;
int error = lwip_getaddrinfo(host, NULL, &hints, &result_i);
if (error != 0 || result_i == NULL) {
common_hal_socketpool_socketpool_raise_gaierror_noname();
}
// Set parameters
struct sockaddr_in dest_addr;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-align"
dest_addr.sin_addr.s_addr = ((struct sockaddr_in *)result_i->ai_addr)->sin_addr.s_addr;
#pragma GCC diagnostic pop
lwip_freeaddrinfo(result_i);
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(port);
struct sockaddr_storage addr;
resolve_host_or_throw(self, host, &addr, port);
// Replace above with function call -----
@ -409,7 +406,7 @@ void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self,
// All our sockets are non-blocking, so we check the timeout ourselves.
int result = -1;
result = lwip_connect(self->num, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in));
result = lwip_connect(self->num, (struct sockaddr *)&addr, addr.s2_len);
if (result == 0) {
// Connected immediately.
@ -611,29 +608,10 @@ mp_uint_t common_hal_socketpool_socket_send(socketpool_socket_obj_t *self, const
mp_uint_t common_hal_socketpool_socket_sendto(socketpool_socket_obj_t *self,
const char *host, size_t hostlen, uint32_t port, const uint8_t *buf, uint32_t len) {
// Set parameters
const struct addrinfo hints = {
.ai_family = self->family,
.ai_socktype = self->type,
};
struct addrinfo *result_i;
int error = lwip_getaddrinfo(host, NULL, &hints, &result_i);
if (error != 0 || result_i == NULL) {
common_hal_socketpool_socketpool_raise_gaierror_noname();
}
struct sockaddr_storage addr;
resolve_host_or_throw(self, host, &addr, port);
// Set parameters
struct sockaddr_in dest_addr;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-align"
dest_addr.sin_addr.s_addr = ((struct sockaddr_in *)result_i->ai_addr)->sin_addr.s_addr;
#pragma GCC diagnostic pop
lwip_freeaddrinfo(result_i);
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(port);
int bytes_sent = lwip_sendto(self->num, buf, len, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
int bytes_sent = lwip_sendto(self->num, buf, len, 0, (struct sockaddr *)&addr, addr.s2_len);
if (bytes_sent < 0) {
mp_raise_BrokenPipeError();
return 0;

View file

@ -9,6 +9,7 @@
#include "py/runtime.h"
#include "shared-bindings/wifi/__init__.h"
#include "common-hal/socketpool/__init__.h"
#include "components/lwip/lwip/src/include/lwip/netdb.h"
@ -22,7 +23,7 @@ void common_hal_socketpool_socketpool_construct(socketpool_socketpool_obj_t *sel
// common_hal_socketpool_socket is in socketpool/Socket.c to centralize open socket tracking.
static int getaddrinfo_common(const char *host, int service, const struct addrinfo *hints, struct addrinfo **res) {
int socketpool_getaddrinfo_common(const char *host, int service, const struct addrinfo *hints, struct addrinfo **res) {
// As of 2022, the version of lwip in esp-idf does not handle the
// trailing-dot syntax of domain names, so emulate it.
// Remove this once https://github.com/espressif/esp-idf/issues/10013 has
@ -67,7 +68,7 @@ mp_obj_t common_hal_socketpool_socketpool_gethostbyname(socketpool_socketpool_ob
.ai_socktype = SOCK_STREAM,
};
struct addrinfo *res = NULL;
int err = getaddrinfo_common(host, 0, &hints, &res);
int err = socketpool_getaddrinfo_common(host, 0, &hints, &res);
if (err != 0 || res == NULL) {
return mp_const_none;
}
@ -121,7 +122,7 @@ mp_obj_t common_hal_socketpool_getaddrinfo_raise(socketpool_socketpool_obj_t *se
};
struct addrinfo *res = NULL;
int err = getaddrinfo_common(host, port, &hints, &res);
int err = socketpool_getaddrinfo_common(host, port, &hints, &res);
if (err != 0 || res == NULL) {
common_hal_socketpool_socketpool_raise_gaierror_noname();
}

View file

@ -6,8 +6,6 @@
#pragma once
#ifndef MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_SOCKETPOOL___INIT___H
#define MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_SOCKETPOOL___INIT___H
struct addrinfo;
#endif // MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_SOCKETPOOL___INIT___H
int socketpool_getaddrinfo_common(const char *host, int service, const struct addrinfo *hints, struct addrinfo **res);

View file

@ -13,6 +13,7 @@
#include "common-hal/wifi/__init__.h"
#include "shared/runtime/interrupt_char.h"
#include "py/gc.h"
#include "py/obj.h"
#include "py/runtime.h"
#include "shared-bindings/ipaddress/IPv4Address.h"
#include "shared-bindings/wifi/ScannedNetworks.h"
@ -20,8 +21,14 @@
#include "shared-bindings/time/__init__.h"
#include "shared-module/ipaddress/__init__.h"
#include "components/esp_netif/include/esp_netif_net_stack.h"
#include "components/esp_wifi/include/esp_wifi.h"
#include "components/lwip/include/apps/ping/ping_sock.h"
#include "lwip/sockets.h"
#if LWIP_IPV6_DHCP6
#include "lwip/dhcp6.h"
#endif
#if CIRCUITPY_MDNS
#include "common-hal/mdns/Server.h"
@ -445,6 +452,24 @@ mp_obj_t common_hal_wifi_radio_get_ipv4_subnet_ap(wifi_radio_obj_t *self) {
return common_hal_ipaddress_new_ipv4address(self->ap_ip_info.netmask.addr);
}
mp_obj_t common_hal_wifi_radio_get_ipv6_addresses(wifi_radio_obj_t *self) {
if (!esp_netif_is_netif_up(self->netif)) {
return mp_const_none;
}
esp_ip6_addr_t addresses[LWIP_IPV6_NUM_ADDRESSES];
int n_addresses = esp_netif_get_all_ip6(self->netif, &addresses[0]);
if (!n_addresses) {
return mp_const_none;
}
mp_obj_tuple_t *result = MP_OBJ_TO_PTR(mp_obj_new_tuple(n_addresses, NULL));
for (int i = 0; i < n_addresses; i++) {
char buf[IP6ADDR_STRLEN_MAX];
inet_ntop(AF_INET6, &addresses[i], buf, sizeof(buf));
result->items[i] = mp_obj_new_str(buf, strlen(buf));
}
return MP_OBJ_FROM_PTR(result);
}
uint32_t wifi_radio_get_ipv4_address(wifi_radio_obj_t *self) {
if (!esp_netif_is_netif_up(self->netif)) {
return 0;
@ -491,10 +516,17 @@ void common_hal_wifi_radio_set_ipv4_dns(wifi_radio_obj_t *self, mp_obj_t ipv4_dn
void common_hal_wifi_radio_start_dhcp_client(wifi_radio_obj_t *self) {
esp_netif_dhcpc_start(self->netif);
#if LWIP_IPV6_DHCP6
esp_netif_create_ip6_linklocal(self->netif);
dhcp6_enable_stateless(esp_netif_get_netif_impl(self->netif));
#endif
}
void common_hal_wifi_radio_stop_dhcp_client(wifi_radio_obj_t *self) {
esp_netif_dhcpc_stop(self->netif);
#if LWIP_IPV6_DHCP6
dhcp6_disable(esp_netif_get_netif_impl(self->netif));
#endif
}
void common_hal_wifi_radio_start_dhcp_server(wifi_radio_obj_t *self) {

View file

@ -596,6 +596,22 @@ static mp_obj_t wifi_radio_set_ipv4_address_ap(size_t n_args, const mp_obj_t *po
}
static MP_DEFINE_CONST_FUN_OBJ_KW(wifi_radio_set_ipv4_address_ap_obj, 1, wifi_radio_set_ipv4_address_ap);
//| ipv6_addresses: Sequence[str]
//| """IPv6 address(es) of the station when connected to an access point. None otherwise. (read-only)"""
static mp_obj_t _wifi_radio_get_ipv6_addresses(mp_obj_t self) {
return common_hal_wifi_radio_get_ipv6_addresses(self);
}
MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_ipv6_addresses_obj, _wifi_radio_get_ipv6_addresses);
MP_PROPERTY_GETTER(wifi_radio_ipv6_addresses_obj,
(mp_obj_t)&wifi_radio_get_ipv6_addresses_obj);
#if 0
MP_WEAK mp_obj_t common_hal_wifi_radio_get_ipv6_addresses(wifi_radio_obj_t *self) {
return mp_const_none;
}
#endif
//| ipv4_address: Optional[ipaddress.IPv4Address]
//| """IP v4 Address of the station when connected to an access point. None otherwise. (read-only)"""
static mp_obj_t _wifi_radio_get_ipv4_address(mp_obj_t self) {
@ -768,6 +784,7 @@ static const mp_rom_map_elem_t wifi_radio_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_ipv4_subnet_ap), MP_ROM_PTR(&wifi_radio_ipv4_subnet_ap_obj) },
{ MP_ROM_QSTR(MP_QSTR_ipv4_address), MP_ROM_PTR(&wifi_radio_ipv4_address_obj) },
{ MP_ROM_QSTR(MP_QSTR_ipv4_address_ap), MP_ROM_PTR(&wifi_radio_ipv4_address_ap_obj) },
{ MP_ROM_QSTR(MP_QSTR_ipv6_addresses), MP_ROM_PTR(&wifi_radio_ipv6_addresses_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_ipv4_address), MP_ROM_PTR(&wifi_radio_set_ipv4_address_obj) },
{ MP_ROM_QSTR(MP_QSTR_set_ipv4_address_ap), MP_ROM_PTR(&wifi_radio_set_ipv4_address_ap_obj) },

View file

@ -105,6 +105,8 @@ uint32_t wifi_radio_get_ipv4_address(wifi_radio_obj_t *self);
extern mp_obj_t common_hal_wifi_radio_get_ipv4_address(wifi_radio_obj_t *self);
extern mp_obj_t common_hal_wifi_radio_get_ipv4_address_ap(wifi_radio_obj_t *self);
mp_obj_t common_hal_wifi_radio_get_ipv6_addresses(wifi_radio_obj_t *self);
extern void common_hal_wifi_radio_set_ipv4_address(wifi_radio_obj_t *self, mp_obj_t ipv4, mp_obj_t netmask, mp_obj_t gateway, mp_obj_t ipv4_dns_addr);
extern void common_hal_wifi_radio_set_ipv4_address_ap(wifi_radio_obj_t *self, mp_obj_t ipv4, mp_obj_t netmask, mp_obj_t gateway);