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>
This commit is contained in:
parent
866fc3447c
commit
628abf8f25
@ -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);
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user