Skip to content

Commit 9088488

Browse files
committed
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'
1 parent 3b30f0c commit 9088488

File tree

7 files changed

+83
-51
lines changed

7 files changed

+83
-51
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
CONFIG_LWIP_IPV6_AUTOCONFIG=y
3+
CONFIG_LWIP_IPV6_RDNSS_MAX_DNS_SERVERS=2
4+
CONFIG_LWIP_IPV6_DHCP6=y

ports/espressif/common-hal/socketpool/Socket.c

Lines changed: 22 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "py/mperrno.h"
1212
#include "py/runtime.h"
1313
#include "shared-bindings/socketpool/SocketPool.h"
14+
#include "common-hal/socketpool/__init__.h"
1415
#if CIRCUITPY_SSL
1516
#include "shared-bindings/ssl/SSLSocket.h"
1617
#include "shared-module/ssl/SSLSocket.h"
@@ -25,6 +26,20 @@
2526
#include "components/lwip/lwip/src/include/lwip/netdb.h"
2627
#include "components/vfs/include/esp_vfs_eventfd.h"
2728

29+
static void resolve_host_or_throw(socketpool_socket_obj_t *self, const char *hostname, struct sockaddr_storage *addr, int port) {
30+
struct addrinfo *result_i;
31+
const struct addrinfo hints = {
32+
.ai_family = self->family,
33+
.ai_socktype = self->type,
34+
};
35+
int error = socketpool_getaddrinfo_common(hostname, port, &hints, &result_i);
36+
if (error != 0 || result_i == NULL) {
37+
common_hal_socketpool_socketpool_raise_gaierror_noname();
38+
}
39+
memcpy(addr, result_i->ai_addr, sizeof(struct sockaddr_storage));
40+
lwip_freeaddrinfo(result_i);
41+
}
42+
2843
StackType_t socket_select_stack[2 * configMINIMAL_STACK_SIZE];
2944

3045
/* Socket state table:
@@ -339,7 +354,7 @@ size_t common_hal_socketpool_socket_bind(socketpool_socket_obj_t *self,
339354
ip = inet_addr(host);
340355
}
341356
bind_addr.sin_addr.s_addr = ip;
342-
bind_addr.sin_family = AF_INET;
357+
bind_addr.sin_family = self->family;
343358
bind_addr.sin_port = htons(port);
344359

345360
int result = lwip_bind(self->num, (struct sockaddr *)&bind_addr, sizeof(bind_addr));
@@ -382,34 +397,16 @@ void common_hal_socketpool_socket_close(socketpool_socket_obj_t *self) {
382397

383398
void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self,
384399
const char *host, size_t hostlen, uint32_t port) {
385-
const struct addrinfo hints = {
386-
.ai_family = self->family,
387-
.ai_socktype = self->type,
388-
};
389-
struct addrinfo *result_i;
390-
int error = lwip_getaddrinfo(host, NULL, &hints, &result_i);
391-
if (error != 0 || result_i == NULL) {
392-
common_hal_socketpool_socketpool_raise_gaierror_noname();
393-
}
394-
395-
// Set parameters
396-
struct sockaddr_in dest_addr;
397-
#pragma GCC diagnostic push
398-
#pragma GCC diagnostic ignored "-Wcast-align"
399-
dest_addr.sin_addr.s_addr = ((struct sockaddr_in *)result_i->ai_addr)->sin_addr.s_addr;
400-
#pragma GCC diagnostic pop
401-
lwip_freeaddrinfo(result_i);
402-
403-
dest_addr.sin_family = AF_INET;
404-
dest_addr.sin_port = htons(port);
400+
struct sockaddr_storage addr;
401+
resolve_host_or_throw(self, host, &addr, port);
405402

406403
// Replace above with function call -----
407404

408405
// Emulate SO_CONTIMEO, which is not implemented by lwip.
409406
// All our sockets are non-blocking, so we check the timeout ourselves.
410407

411408
int result = -1;
412-
result = lwip_connect(self->num, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in));
409+
result = lwip_connect(self->num, (struct sockaddr *)&addr, addr.s2_len);
413410

414411
if (result == 0) {
415412
// Connected immediately.
@@ -611,29 +608,10 @@ mp_uint_t common_hal_socketpool_socket_send(socketpool_socket_obj_t *self, const
611608
mp_uint_t common_hal_socketpool_socket_sendto(socketpool_socket_obj_t *self,
612609
const char *host, size_t hostlen, uint32_t port, const uint8_t *buf, uint32_t len) {
613610

614-
// Set parameters
615-
const struct addrinfo hints = {
616-
.ai_family = self->family,
617-
.ai_socktype = self->type,
618-
};
619-
struct addrinfo *result_i;
620-
int error = lwip_getaddrinfo(host, NULL, &hints, &result_i);
621-
if (error != 0 || result_i == NULL) {
622-
common_hal_socketpool_socketpool_raise_gaierror_noname();
623-
}
624-
625-
// Set parameters
626-
struct sockaddr_in dest_addr;
627-
#pragma GCC diagnostic push
628-
#pragma GCC diagnostic ignored "-Wcast-align"
629-
dest_addr.sin_addr.s_addr = ((struct sockaddr_in *)result_i->ai_addr)->sin_addr.s_addr;
630-
#pragma GCC diagnostic pop
631-
lwip_freeaddrinfo(result_i);
632-
633-
dest_addr.sin_family = AF_INET;
634-
dest_addr.sin_port = htons(port);
611+
struct sockaddr_storage addr;
612+
resolve_host_or_throw(self, host, &addr, port);
635613

636-
int bytes_sent = lwip_sendto(self->num, buf, len, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
614+
int bytes_sent = lwip_sendto(self->num, buf, len, 0, (struct sockaddr *)&addr, addr.s2_len);
637615
if (bytes_sent < 0) {
638616
mp_raise_BrokenPipeError();
639617
return 0;

ports/espressif/common-hal/socketpool/SocketPool.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "py/runtime.h"
1111
#include "shared-bindings/wifi/__init__.h"
12+
#include "common-hal/socketpool/__init__.h"
1213

1314
#include "components/lwip/lwip/src/include/lwip/netdb.h"
1415

@@ -22,7 +23,7 @@ void common_hal_socketpool_socketpool_construct(socketpool_socketpool_obj_t *sel
2223

2324
// common_hal_socketpool_socket is in socketpool/Socket.c to centralize open socket tracking.
2425

25-
static int getaddrinfo_common(const char *host, int service, const struct addrinfo *hints, struct addrinfo **res) {
26+
int socketpool_getaddrinfo_common(const char *host, int service, const struct addrinfo *hints, struct addrinfo **res) {
2627
// As of 2022, the version of lwip in esp-idf does not handle the
2728
// trailing-dot syntax of domain names, so emulate it.
2829
// 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
6768
.ai_socktype = SOCK_STREAM,
6869
};
6970
struct addrinfo *res = NULL;
70-
int err = getaddrinfo_common(host, 0, &hints, &res);
71+
int err = socketpool_getaddrinfo_common(host, 0, &hints, &res);
7172
if (err != 0 || res == NULL) {
7273
return mp_const_none;
7374
}
@@ -121,7 +122,7 @@ mp_obj_t common_hal_socketpool_getaddrinfo_raise(socketpool_socketpool_obj_t *se
121122
};
122123

123124
struct addrinfo *res = NULL;
124-
int err = getaddrinfo_common(host, port, &hints, &res);
125+
int err = socketpool_getaddrinfo_common(host, port, &hints, &res);
125126
if (err != 0 || res == NULL) {
126127
common_hal_socketpool_socketpool_raise_gaierror_noname();
127128
}

ports/espressif/common-hal/socketpool/__init__.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66

77
#pragma once
88

9-
#ifndef MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_SOCKETPOOL___INIT___H
10-
#define MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_SOCKETPOOL___INIT___H
9+
struct addrinfo;
1110

12-
13-
#endif // MICROPY_INCLUDED_ESPRESSIF_COMMON_HAL_SOCKETPOOL___INIT___H
11+
int socketpool_getaddrinfo_common(const char *host, int service, const struct addrinfo *hints, struct addrinfo **res);

ports/espressif/common-hal/wifi/Radio.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,22 @@
1313
#include "common-hal/wifi/__init__.h"
1414
#include "shared/runtime/interrupt_char.h"
1515
#include "py/gc.h"
16+
#include "py/obj.h"
1617
#include "py/runtime.h"
1718
#include "shared-bindings/ipaddress/IPv4Address.h"
1819
#include "shared-bindings/wifi/ScannedNetworks.h"
1920
#include "shared-bindings/wifi/AuthMode.h"
2021
#include "shared-bindings/time/__init__.h"
2122
#include "shared-module/ipaddress/__init__.h"
2223

24+
#include "components/esp_netif/include/esp_netif_net_stack.h"
2325
#include "components/esp_wifi/include/esp_wifi.h"
2426
#include "components/lwip/include/apps/ping/ping_sock.h"
27+
#include "lwip/sockets.h"
28+
29+
#if LWIP_IPV6_DHCP6
30+
#include "lwip/dhcp6.h"
31+
#endif
2532

2633
#if CIRCUITPY_MDNS
2734
#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) {
445452
return common_hal_ipaddress_new_ipv4address(self->ap_ip_info.netmask.addr);
446453
}
447454

455+
mp_obj_t common_hal_wifi_radio_get_ipv6_addresses(wifi_radio_obj_t *self) {
456+
if (!esp_netif_is_netif_up(self->netif)) {
457+
return mp_const_none;
458+
}
459+
esp_ip6_addr_t addresses[LWIP_IPV6_NUM_ADDRESSES];
460+
int n_addresses = esp_netif_get_all_ip6(self->netif, &addresses[0]);
461+
if (!n_addresses) {
462+
return mp_const_none;
463+
}
464+
mp_obj_tuple_t *result = MP_OBJ_TO_PTR(mp_obj_new_tuple(n_addresses, NULL));
465+
for (int i = 0; i < n_addresses; i++) {
466+
char buf[IP6ADDR_STRLEN_MAX];
467+
inet_ntop(AF_INET6, &addresses[i], buf, sizeof(buf));
468+
result->items[i] = mp_obj_new_str(buf, strlen(buf));
469+
}
470+
return MP_OBJ_FROM_PTR(result);
471+
}
472+
448473
uint32_t wifi_radio_get_ipv4_address(wifi_radio_obj_t *self) {
449474
if (!esp_netif_is_netif_up(self->netif)) {
450475
return 0;
@@ -491,10 +516,17 @@ void common_hal_wifi_radio_set_ipv4_dns(wifi_radio_obj_t *self, mp_obj_t ipv4_dn
491516

492517
void common_hal_wifi_radio_start_dhcp_client(wifi_radio_obj_t *self) {
493518
esp_netif_dhcpc_start(self->netif);
519+
#if LWIP_IPV6_DHCP6
520+
esp_netif_create_ip6_linklocal(self->netif);
521+
dhcp6_enable_stateless(esp_netif_get_netif_impl(self->netif));
522+
#endif
494523
}
495524

496525
void common_hal_wifi_radio_stop_dhcp_client(wifi_radio_obj_t *self) {
497526
esp_netif_dhcpc_stop(self->netif);
527+
#if LWIP_IPV6_DHCP6
528+
dhcp6_disable(esp_netif_get_netif_impl(self->netif));
529+
#endif
498530
}
499531

500532
void common_hal_wifi_radio_start_dhcp_server(wifi_radio_obj_t *self) {

shared-bindings/wifi/Radio.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,22 @@ static mp_obj_t wifi_radio_set_ipv4_address_ap(size_t n_args, const mp_obj_t *po
596596
}
597597
static MP_DEFINE_CONST_FUN_OBJ_KW(wifi_radio_set_ipv4_address_ap_obj, 1, wifi_radio_set_ipv4_address_ap);
598598

599+
//| ipv6_addresses: Sequence[str]
600+
//| """IPv6 address(es) of the station when connected to an access point. None otherwise. (read-only)"""
601+
static mp_obj_t _wifi_radio_get_ipv6_addresses(mp_obj_t self) {
602+
return common_hal_wifi_radio_get_ipv6_addresses(self);
603+
}
604+
MP_DEFINE_CONST_FUN_OBJ_1(wifi_radio_get_ipv6_addresses_obj, _wifi_radio_get_ipv6_addresses);
605+
606+
MP_PROPERTY_GETTER(wifi_radio_ipv6_addresses_obj,
607+
(mp_obj_t)&wifi_radio_get_ipv6_addresses_obj);
608+
609+
#if 0
610+
MP_WEAK mp_obj_t common_hal_wifi_radio_get_ipv6_addresses(wifi_radio_obj_t *self) {
611+
return mp_const_none;
612+
}
613+
#endif
614+
599615
//| ipv4_address: Optional[ipaddress.IPv4Address]
600616
//| """IP v4 Address of the station when connected to an access point. None otherwise. (read-only)"""
601617
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[] = {
768784
{ MP_ROM_QSTR(MP_QSTR_ipv4_subnet_ap), MP_ROM_PTR(&wifi_radio_ipv4_subnet_ap_obj) },
769785
{ MP_ROM_QSTR(MP_QSTR_ipv4_address), MP_ROM_PTR(&wifi_radio_ipv4_address_obj) },
770786
{ MP_ROM_QSTR(MP_QSTR_ipv4_address_ap), MP_ROM_PTR(&wifi_radio_ipv4_address_ap_obj) },
787+
{ MP_ROM_QSTR(MP_QSTR_ipv6_addresses), MP_ROM_PTR(&wifi_radio_ipv6_addresses_obj) },
771788

772789
{ MP_ROM_QSTR(MP_QSTR_set_ipv4_address), MP_ROM_PTR(&wifi_radio_set_ipv4_address_obj) },
773790
{ MP_ROM_QSTR(MP_QSTR_set_ipv4_address_ap), MP_ROM_PTR(&wifi_radio_set_ipv4_address_ap_obj) },

shared-bindings/wifi/Radio.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ uint32_t wifi_radio_get_ipv4_address(wifi_radio_obj_t *self);
105105
extern mp_obj_t common_hal_wifi_radio_get_ipv4_address(wifi_radio_obj_t *self);
106106
extern mp_obj_t common_hal_wifi_radio_get_ipv4_address_ap(wifi_radio_obj_t *self);
107107

108+
mp_obj_t common_hal_wifi_radio_get_ipv6_addresses(wifi_radio_obj_t *self);
109+
108110
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);
109111
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);
110112

0 commit comments

Comments
 (0)