summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Dörre <felix@dogcraft.de>2022-08-25 17:25:08 +0000
committerDamien George <damien@micropython.org>2024-02-16 11:46:40 +1100
commit628abf8f25a7705a2810fffe2ca6ae652c532896 (patch)
treef7e07475d1cd733e411e77b0f2563fac78219a1b
parent866fc3447c7a685c6c04d6a03ee94083b8d0dd72 (diff)
extmod/modlwip: Support IPv6.
With these changes IPv6 works on the rp2 port (and possibly others that use the lwIP socket implementation). Things that have been tested and work: - Neighbour solicitation for v6 link local address. - Ping of v6 link-local address. - Receiving a SLAAC address via router advertisement. - Ping a v6 address allocated via SLAAC. - Perform an outgoing connection to a routed v6-address (via default gateway). - Create a listening IPv6 wildcard socked bound to ::, and trying to access it via link-local, SLAAC, and IPv4 (to ensure the dual-stack binding works). Things that could be improved: - socket.socket().getaddrinfo only returns the v4 address. It could also return v6 addresses (getaddrinfo is actively programmed to only return a single address, and this is the v4-address by default, with fallback to the v6 address if both are enabled). Signed-off-by: Felix Dörre <felix@dogcraft.de>
-rw-r--r--extmod/modlwip.c70
-rw-r--r--extmod/network_cyw43.c9
-rw-r--r--shared/netutils/dhcpserver.c14
3 files changed, 60 insertions, 33 deletions
diff --git a/extmod/modlwip.c b/extmod/modlwip.c
index 6f8703d5a..8ccc38891 100644
--- a/extmod/modlwip.c
+++ b/extmod/modlwip.c
@@ -353,6 +353,26 @@ STATIC void lwip_socket_free_incoming(lwip_socket_obj_t *socket) {
}
}
+mp_obj_t lwip_format_inet_addr(const ip_addr_t *ip, mp_uint_t port) {
+ char *ipstr = ipaddr_ntoa(ip);
+ mp_obj_t tuple[2] = {
+ tuple[0] = mp_obj_new_str(ipstr, strlen(ipstr)),
+ tuple[1] = mp_obj_new_int(port),
+ };
+ return mp_obj_new_tuple(2, tuple);
+}
+
+mp_uint_t lwip_parse_inet_addr(mp_obj_t addr_in, ip_addr_t *out_ip) {
+ mp_obj_t *addr_items;
+ mp_obj_get_array_fixed_n(addr_in, 2, &addr_items);
+ size_t addr_len;
+ const char *addr_str = mp_obj_str_get_data(addr_items[0], &addr_len);
+ if (!ipaddr_aton(addr_str, out_ip)) {
+ mp_raise_ValueError(MP_ERROR_TEXT("invalid arguments"));
+ }
+ return mp_obj_get_int(addr_items[1]);
+}
+
/*******************************************************************************/
// Callback functions for the lwIP raw API.
@@ -538,7 +558,7 @@ STATIC err_t _lwip_tcp_recv(void *arg, struct tcp_pcb *tcpb, struct pbuf *p, err
// these to do the work.
// Helper function for send/sendto to handle raw/UDP packets.
-STATIC mp_uint_t lwip_raw_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_uint_t len, byte *ip, mp_uint_t port, int *_errno) {
+STATIC mp_uint_t lwip_raw_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_uint_t len, ip_addr_t *ip, mp_uint_t port, int *_errno) {
if (len > 0xffff) {
// Any packet that big is probably going to fail the pbuf_alloc anyway, but may as well try
len = 0xffff;
@@ -567,15 +587,13 @@ STATIC mp_uint_t lwip_raw_udp_send(lwip_socket_obj_t *socket, const byte *buf, m
err = udp_send(socket->pcb.udp, p);
}
} else {
- ip_addr_t dest;
- IP4_ADDR(&dest, ip[0], ip[1], ip[2], ip[3]);
#if MICROPY_PY_LWIP_SOCK_RAW
if (socket->type == MOD_NETWORK_SOCK_RAW) {
- err = raw_sendto(socket->pcb.raw, p, &dest);
+ err = raw_sendto(socket->pcb.raw, p, ip);
} else
#endif
{
- err = udp_sendto(socket->pcb.udp, p, &dest, port);
+ err = udp_sendto(socket->pcb.udp, p, ip, port);
}
}
@@ -885,11 +903,8 @@ STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, size_t n_args, s
STATIC mp_obj_t lwip_socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(self_in);
- uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE];
- mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG);
-
ip_addr_t bind_addr;
- IP4_ADDR(&bind_addr, ip[0], ip[1], ip[2], ip[3]);
+ mp_uint_t port = lwip_parse_inet_addr(addr_in, &bind_addr);
err_t err = ERR_ARG;
switch (socket->type) {
@@ -926,6 +941,12 @@ STATIC mp_obj_t lwip_socket_listen(size_t n_args, const mp_obj_t *args) {
if (socket->type != MOD_NETWORK_SOCK_STREAM) {
mp_raise_OSError(MP_EOPNOTSUPP);
}
+ #if LWIP_IPV6
+ if (ip_addr_cmp(&socket->pcb.tcp->local_ip, IP6_ADDR_ANY)) {
+ IP_SET_TYPE_VAL(socket->pcb.tcp->local_ip, IPADDR_TYPE_ANY);
+ IP_SET_TYPE_VAL(socket->pcb.tcp->remote_ip, IPADDR_TYPE_ANY);
+ }
+ #endif
struct tcp_pcb *new_pcb;
#if LWIP_VERSION_MACRO < 0x02000100
@@ -1043,12 +1064,10 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) {
MICROPY_PY_LWIP_EXIT
// make the return value
- uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE];
- memcpy(ip, &(socket2->pcb.tcp->remote_ip), sizeof(ip));
mp_uint_t port = (mp_uint_t)socket2->pcb.tcp->remote_port;
mp_obj_tuple_t *client = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL));
client->items[0] = MP_OBJ_FROM_PTR(socket2);
- client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG);
+ client->items[1] = lwip_format_inet_addr(&socket2->pcb.tcp->remote_ip, port);
return MP_OBJ_FROM_PTR(client);
}
@@ -1062,11 +1081,8 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
}
// get address
- uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE];
- mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG);
-
ip_addr_t dest;
- IP4_ADDR(&dest, ip[0], ip[1], ip[2], ip[3]);
+ mp_uint_t port = lwip_parse_inet_addr(addr_in, &dest);
err_t err = ERR_ARG;
switch (socket->type) {
@@ -1219,8 +1235,8 @@ STATIC mp_obj_t lwip_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ);
- uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE];
- mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG);
+ ip_addr_t ip;
+ mp_uint_t port = lwip_parse_inet_addr(addr_in, &ip);
mp_uint_t ret = 0;
switch (socket->type) {
@@ -1232,7 +1248,7 @@ STATIC mp_obj_t lwip_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t
#if MICROPY_PY_LWIP_SOCK_RAW
case MOD_NETWORK_SOCK_RAW:
#endif
- ret = lwip_raw_udp_send(socket, bufinfo.buf, bufinfo.len, ip, port, &_errno);
+ ret = lwip_raw_udp_send(socket, bufinfo.buf, bufinfo.len, &ip, port, &_errno);
break;
}
if (ret == -1) {
@@ -1357,6 +1373,12 @@ STATIC mp_obj_t lwip_socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_setblocking_obj, lwip_socket_setblocking);
+#if LWIP_VERSION_MAJOR < 2
+#define MP_IGMP_IP_ADDR_TYPE ip_addr_t
+#else
+#define MP_IGMP_IP_ADDR_TYPE ip4_addr_t
+#endif
+
STATIC mp_obj_t lwip_socket_setsockopt(size_t n_args, const mp_obj_t *args) {
(void)n_args; // always 4
lwip_socket_obj_t *socket = MP_OBJ_TO_PTR(args[0]);
@@ -1397,9 +1419,9 @@ STATIC mp_obj_t lwip_socket_setsockopt(size_t n_args, const mp_obj_t *args) {
// POSIX setsockopt has order: group addr, if addr, lwIP has it vice-versa
err_t err;
if (opt == IP_ADD_MEMBERSHIP) {
- err = igmp_joingroup((ip_addr_t *)bufinfo.buf + 1, bufinfo.buf);
+ err = igmp_joingroup((MP_IGMP_IP_ADDR_TYPE *)bufinfo.buf + 1, bufinfo.buf);
} else {
- err = igmp_leavegroup((ip_addr_t *)bufinfo.buf + 1, bufinfo.buf);
+ err = igmp_leavegroup((MP_IGMP_IP_ADDR_TYPE *)bufinfo.buf + 1, bufinfo.buf);
}
if (err != ERR_OK) {
mp_raise_OSError(error_lookup_table[-err]);
@@ -1412,6 +1434,9 @@ STATIC mp_obj_t lwip_socket_setsockopt(size_t n_args, const mp_obj_t *args) {
}
return mp_const_none;
}
+
+#undef MP_IGMP_IP_ADDR_TYPE
+
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_socket_setsockopt_obj, 4, 4, lwip_socket_setsockopt);
STATIC mp_obj_t lwip_socket_makefile(size_t n_args, const mp_obj_t *args) {
@@ -1742,12 +1767,13 @@ STATIC mp_obj_t lwip_getaddrinfo(size_t n_args, const mp_obj_t *args) {
mp_raise_OSError(state.status);
}
+ ip_addr_t ipcopy = state.ipaddr;
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL));
tuple->items[0] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_AF_INET);
tuple->items[1] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_SOCK_STREAM);
tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0);
tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_);
- tuple->items[4] = netutils_format_inet_addr((uint8_t *)&state.ipaddr, port, NETUTILS_BIG);
+ tuple->items[4] = lwip_format_inet_addr(&ipcopy, port);
return mp_obj_new_list(1, (mp_obj_t *)&tuple);
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(lwip_getaddrinfo_obj, 2, 6, lwip_getaddrinfo);
diff --git a/extmod/network_cyw43.c b/extmod/network_cyw43.c
index f8490d6b9..2f188dbad 100644
--- a/extmod/network_cyw43.c
+++ b/extmod/network_cyw43.c
@@ -78,13 +78,14 @@ STATIC void network_cyw43_print(const mp_print_t *print, mp_obj_t self_in, mp_pr
} else {
status_str = "fail";
}
+ ip4_addr_t *addr = ip_2_ip4(&netif->ip_addr);
mp_printf(print, "<CYW43 %s %s %u.%u.%u.%u>",
self->itf == CYW43_ITF_STA ? "STA" : "AP",
status_str,
- netif->ip_addr.addr & 0xff,
- netif->ip_addr.addr >> 8 & 0xff,
- netif->ip_addr.addr >> 16 & 0xff,
- netif->ip_addr.addr >> 24
+ addr->addr & 0xff,
+ addr->addr >> 8 & 0xff,
+ addr->addr >> 16 & 0xff,
+ addr->addr >> 24
);
}
diff --git a/shared/netutils/dhcpserver.c b/shared/netutils/dhcpserver.c
index dca95507d..9a4d461a9 100644
--- a/shared/netutils/dhcpserver.c
+++ b/shared/netutils/dhcpserver.c
@@ -113,7 +113,7 @@ static void dhcp_socket_free(struct udp_pcb **udp) {
static int dhcp_socket_bind(struct udp_pcb **udp, uint32_t ip, uint16_t port) {
ip_addr_t addr;
- IP4_ADDR(&addr, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff);
+ IP_ADDR4(&addr, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff);
// TODO convert lwIP errors to errno
return udp_bind(*udp, &addr, port);
}
@@ -131,7 +131,7 @@ static int dhcp_socket_sendto(struct udp_pcb **udp, struct netif *netif, const v
memcpy(p->payload, buf, len);
ip_addr_t dest;
- IP4_ADDR(&dest, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff);
+ IP_ADDR4(&dest, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff);
err_t err;
if (netif != NULL) {
err = udp_sendto_if(*udp, p, &dest, port, netif);
@@ -205,7 +205,7 @@ static void dhcp_server_process(void *arg, struct udp_pcb *upcb, struct pbuf *p,
}
dhcp_msg.op = DHCPOFFER;
- memcpy(&dhcp_msg.yiaddr, &d->ip.addr, 4);
+ memcpy(&dhcp_msg.yiaddr, &ip_2_ip4(&d->ip)->addr, 4);
uint8_t *opt = (uint8_t *)&dhcp_msg.options;
opt += 4; // assume magic cookie: 99, 130, 83, 99
@@ -248,7 +248,7 @@ static void dhcp_server_process(void *arg, struct udp_pcb *upcb, struct pbuf *p,
// Should be NACK
goto ignore_request;
}
- if (memcmp(o + 2, &d->ip.addr, 3) != 0) {
+ if (memcmp(o + 2, &ip_2_ip4(&d->ip)->addr, 3) != 0) {
// Should be NACK
goto ignore_request;
}
@@ -280,9 +280,9 @@ static void dhcp_server_process(void *arg, struct udp_pcb *upcb, struct pbuf *p,
goto ignore_request;
}
- opt_write_n(&opt, DHCP_OPT_SERVER_ID, 4, &d->ip.addr);
- opt_write_n(&opt, DHCP_OPT_SUBNET_MASK, 4, &d->nm.addr);
- opt_write_n(&opt, DHCP_OPT_ROUTER, 4, &d->ip.addr); // aka gateway; can have multiple addresses
+ opt_write_n(&opt, DHCP_OPT_SERVER_ID, 4, &ip_2_ip4(&d->ip)->addr);
+ opt_write_n(&opt, DHCP_OPT_SUBNET_MASK, 4, &ip_2_ip4(&d->nm)->addr);
+ opt_write_n(&opt, DHCP_OPT_ROUTER, 4, &ip_2_ip4(&d->ip)->addr); // aka gateway; can have multiple addresses
opt_write_u32(&opt, DHCP_OPT_DNS, DEFAULT_DNS); // can have multiple addresses
opt_write_u32(&opt, DHCP_OPT_IP_LEASE_TIME, DEFAULT_LEASE_TIME_S);
*opt++ = DHCP_OPT_END;