Skip to content

Commit a3cb0c9

Browse files
committed
extmod/network: Implement IPv6 API to set and get nic configuration.
Signed-off-by: Felix Dörre <felix@dogcraft.de>
1 parent 8fdcc25 commit a3cb0c9

File tree

4 files changed

+307
-1
lines changed

4 files changed

+307
-1
lines changed

extmod/modlwip.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,8 @@ STATIC void lwip_socket_free_incoming(lwip_socket_obj_t *socket) {
354354
}
355355

356356
mp_obj_t lwip_format_inet_addr(const ip_addr_t *ip, mp_uint_t port) {
357-
char *ipstr = ipaddr_ntoa(ip);
357+
char ipstr[IPADDR_STRLEN_MAX];
358+
ipaddr_ntoa_r(ip, ipstr, sizeof(ipstr));
358359
mp_obj_t tuple[2] = {
359360
tuple[0] = mp_obj_new_str(ipstr, strlen(ipstr)),
360361
tuple[1] = mp_obj_new_int(port),
@@ -1717,6 +1718,8 @@ STATIC void lwip_getaddrinfo_cb(const char *name, const ip_addr_t *ipaddr, void
17171718
}
17181719
}
17191720

1721+
extern int mp_mod_network_prefer_dns_use_ip_version;
1722+
17201723
// lwip.getaddrinfo
17211724
STATIC mp_obj_t lwip_getaddrinfo(size_t n_args, const mp_obj_t *args) {
17221725
mp_obj_t host_in = args[0], port_in = args[1];
@@ -1750,7 +1753,11 @@ STATIC mp_obj_t lwip_getaddrinfo(size_t n_args, const mp_obj_t *args) {
17501753
state.status = 0;
17511754

17521755
MICROPY_PY_LWIP_ENTER
1756+
#if LWIP_VERSION_MAJOR < 2
17531757
err_t ret = dns_gethostbyname(host, (ip_addr_t *)&state.ipaddr, lwip_getaddrinfo_cb, &state);
1758+
#else
1759+
err_t ret = dns_gethostbyname_addrtype(host, (ip_addr_t *)&state.ipaddr, lwip_getaddrinfo_cb, &state, mp_mod_network_prefer_dns_use_ip_version == 4 ? LWIP_DNS_ADDRTYPE_IPV4_IPV6 : LWIP_DNS_ADDRTYPE_IPV6_IPV4);
1760+
#endif
17541761
MICROPY_PY_LWIP_EXIT
17551762

17561763
switch (ret) {

extmod/modnetwork.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,19 @@ mp_obj_t mod_network_hostname(size_t n_args, const mp_obj_t *args) {
141141
}
142142
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_network_hostname_obj, 0, 1, mod_network_hostname);
143143

144+
#if LWIP_VERSION_MAJOR >= 2
145+
mp_obj_t network_ipconfig(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs);
146+
MP_DEFINE_CONST_FUN_OBJ_KW(mod_network_ipconfig_obj, 0, network_ipconfig);
147+
#endif
148+
149+
144150
STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
145151
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) },
146152
{ MP_ROM_QSTR(MP_QSTR_country), MP_ROM_PTR(&mod_network_country_obj) },
147153
{ MP_ROM_QSTR(MP_QSTR_hostname), MP_ROM_PTR(&mod_network_hostname_obj) },
154+
#if LWIP_VERSION_MAJOR >= 2
155+
{ MP_ROM_QSTR(MP_QSTR_ipconfig), MP_ROM_PTR(&mod_network_ipconfig_obj) },
156+
#endif
148157

149158
// Defined per port in mpconfigport.h
150159
#ifdef MICROPY_PORT_NETWORK_INTERFACES

extmod/network_cyw43.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,13 @@ STATIC mp_obj_t network_cyw43_ifconfig(size_t n_args, const mp_obj_t *args) {
321321
}
322322
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(network_cyw43_ifconfig_obj, 1, 2, network_cyw43_ifconfig);
323323

324+
mp_obj_t network_nic_config(struct netif *netif, size_t n_args, const mp_obj_t *args, mp_map_t *kwargs);
325+
STATIC mp_obj_t network_cyw43_ipconfig(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
326+
network_cyw43_obj_t *self = MP_OBJ_TO_PTR(args[0]);
327+
return network_nic_config(&self->cyw->netif[self->itf], n_args - 1, args + 1, kwargs);
328+
}
329+
MP_DEFINE_CONST_FUN_OBJ_KW(network_cyw43_ipconfig_obj, 1, network_cyw43_ipconfig);
330+
324331
STATIC mp_obj_t network_cyw43_status(size_t n_args, const mp_obj_t *args) {
325332
network_cyw43_obj_t *self = MP_OBJ_TO_PTR(args[0]);
326333
(void)self;
@@ -535,6 +542,8 @@ STATIC const mp_rom_map_elem_t network_cyw43_locals_dict_table[] = {
535542
{ MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&network_cyw43_status_obj) },
536543
{ MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&network_cyw43_config_obj) },
537544

545+
{ MP_ROM_QSTR(MP_QSTR_ipconfig), MP_ROM_PTR(&network_cyw43_ipconfig_obj) },
546+
538547
// Class constants.
539548
{ MP_ROM_QSTR(MP_QSTR_PM_NONE), MP_ROM_INT(PM_NONE) },
540549
{ MP_ROM_QSTR(MP_QSTR_PM_PERFORMANCE), MP_ROM_INT(PM_PERFORMANCE) },

extmod/network_lwip.c

Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
#include "py/runtime.h"
2828
#include "py/mphal.h"
29+
#include "py/parsenum.h"
2930

3031
#if MICROPY_PY_NETWORK && MICROPY_PY_LWIP
3132

@@ -40,6 +41,14 @@
4041
#include "lwip/timeouts.h"
4142
#include "lwip/dns.h"
4243
#include "lwip/dhcp.h"
44+
#include "lwip/nd6.h"
45+
#include "lwip/dhcp6.h"
46+
#include "lwip/prot/dhcp.h"
47+
#include "lwip/prot/dhcp6.h"
48+
#include <string.h>
49+
#include <stdlib.h>
50+
51+
int mp_mod_network_prefer_dns_use_ip_version = 4;
4352

4453
// Implementations of network methods that can be used by any interface.
4554

@@ -90,6 +99,278 @@ mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_o
9099
}
91100
}
92101

102+
mp_obj_t network_ipconfig(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
103+
if (kwargs->used == 0) {
104+
// Get config value
105+
if (n_args != 1) {
106+
mp_raise_TypeError(MP_ERROR_TEXT("must query one param"));
107+
}
108+
109+
switch (mp_obj_str_get_qstr(args[0])) {
110+
case MP_QSTR_dns: {
111+
char addr_str[IPADDR_STRLEN_MAX];
112+
ipaddr_ntoa_r(dns_getserver(0), addr_str, sizeof(addr_str));
113+
return mp_obj_new_str(addr_str, strlen(addr_str));
114+
}
115+
case MP_QSTR_prefer: {
116+
return MP_OBJ_NEW_SMALL_INT(mp_mod_network_prefer_dns_use_ip_version);
117+
}
118+
default: {
119+
mp_raise_ValueError(MP_ERROR_TEXT("unexpected key"));
120+
break;
121+
}
122+
}
123+
} else {
124+
// Set config value(s)
125+
if (n_args != 0) {
126+
mp_raise_TypeError(MP_ERROR_TEXT("can't specify pos and kw args"));
127+
}
128+
129+
for (size_t i = 0; i < kwargs->alloc; ++i) {
130+
if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) {
131+
mp_map_elem_t *e = &kwargs->table[i];
132+
switch (mp_obj_str_get_qstr(e->key)) {
133+
case MP_QSTR_dns: {
134+
ip_addr_t dns;
135+
size_t addr_len;
136+
const char *addr_str = mp_obj_str_get_data(e->value, &addr_len);
137+
if (!ipaddr_aton(addr_str, &dns)) {
138+
mp_raise_ValueError(MP_ERROR_TEXT("invalid arguments as dns server"));
139+
}
140+
dns_setserver(0, &dns);
141+
break;
142+
}
143+
case MP_QSTR_prefer: {
144+
int value = mp_obj_get_int(e->value);
145+
if (value != 4 && value != 6) {
146+
mp_raise_ValueError(MP_ERROR_TEXT("invalid prefer argument"));
147+
}
148+
mp_mod_network_prefer_dns_use_ip_version = value;
149+
break;
150+
}
151+
default: {
152+
mp_raise_ValueError(MP_ERROR_TEXT("unexpected key"));
153+
break;
154+
}
155+
}
156+
}
157+
}
158+
}
159+
return mp_const_none;
160+
}
161+
mp_obj_t network_nic_config(struct netif *netif, size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
162+
163+
if (kwargs->used == 0) {
164+
// Get config value
165+
if (n_args != 1) {
166+
mp_raise_TypeError(MP_ERROR_TEXT("must query one param"));
167+
}
168+
169+
switch (mp_obj_str_get_qstr(args[0])) {
170+
case MP_QSTR_dhcp4: {
171+
struct dhcp *dhcp = netif_dhcp_data(netif);
172+
return mp_obj_new_bool(dhcp != NULL && dhcp->state != DHCP_STATE_OFF);
173+
}
174+
#if LWIP_IPV6_DHCP6
175+
case MP_QSTR_dhcp6: {
176+
struct dhcp6 *dhcp = netif_dhcp6_data(netif);
177+
return mp_obj_new_bool(dhcp != NULL && dhcp->state != DHCP6_STATE_OFF);
178+
}
179+
#endif
180+
#if LWIP_IPV6_AUTOCONFIG
181+
case MP_QSTR_autoconf6: {
182+
return netif->ip6_autoconfig_enabled ? mp_const_true : mp_const_false;
183+
}
184+
#endif
185+
case MP_QSTR_addr4: {
186+
mp_obj_t tuple[2] = {
187+
netutils_format_ipv4_addr((uint8_t *)&netif->ip_addr, NETUTILS_BIG),
188+
netutils_format_ipv4_addr((uint8_t *)&netif->netmask, NETUTILS_BIG),
189+
};
190+
return mp_obj_new_tuple(2, tuple);
191+
}
192+
#if LWIP_IPV6
193+
case MP_QSTR_addr6: {
194+
mp_obj_t addrs[LWIP_IPV6_NUM_ADDRESSES];
195+
size_t n_addrs = 0;
196+
for (int i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
197+
if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i))) {
198+
char addr_str[IPADDR_STRLEN_MAX];
199+
ipaddr_ntoa_r(netif_ip_addr6(netif, i), addr_str, sizeof(addr_str));
200+
mp_obj_t tuple[4] = {
201+
mp_obj_new_str(addr_str, strlen(addr_str)),
202+
MP_OBJ_NEW_SMALL_INT(netif_ip6_addr_state(netif, i)),
203+
MP_OBJ_NEW_SMALL_INT(netif_ip6_addr_pref_life(netif, i)), // preferred
204+
MP_OBJ_NEW_SMALL_INT(netif_ip6_addr_valid_life(netif, i))
205+
};
206+
addrs[n_addrs++] = mp_obj_new_tuple(4, tuple);
207+
}
208+
}
209+
return mp_obj_new_list(n_addrs, addrs);
210+
}
211+
#endif
212+
case MP_QSTR_gw4: {
213+
return netutils_format_ipv4_addr((uint8_t *)&netif->gw, NETUTILS_BIG);
214+
}
215+
default: {
216+
mp_raise_ValueError(MP_ERROR_TEXT("unexpected key"));
217+
break;
218+
}
219+
}
220+
return mp_const_none;
221+
} else {
222+
// Set config value(s)
223+
if (n_args != 0) {
224+
mp_raise_TypeError(MP_ERROR_TEXT("can't specify pos and kw args"));
225+
}
226+
227+
for (size_t i = 0; i < kwargs->alloc; ++i) {
228+
if (MP_MAP_SLOT_IS_FILLED(kwargs, i)) {
229+
mp_map_elem_t *e = &kwargs->table[i];
230+
switch (mp_obj_str_get_qstr(e->key)) {
231+
case MP_QSTR_dhcp4: {
232+
if (mp_obj_is_true(e->value)) {
233+
if (dhcp_supplied_address(netif)) {
234+
dhcp_renew(netif);
235+
} else {
236+
dhcp_release_and_stop(netif);
237+
dhcp_start(netif);
238+
}
239+
uint32_t start = mp_hal_ticks_ms();
240+
while (!dhcp_supplied_address(netif)) {
241+
if (mp_hal_ticks_ms() - start > 10000) {
242+
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("timeout waiting for DHCP to get IP address"));
243+
}
244+
mp_hal_delay_ms(100);
245+
}
246+
} else {
247+
dhcp_release_and_stop(netif);
248+
}
249+
break;
250+
}
251+
#if LWIP_IPV6_DHCP6
252+
case MP_QSTR_dhcp6: {
253+
dhcp6_disable(netif);
254+
dhcp6_enable_stateless(netif);
255+
break;
256+
}
257+
#endif
258+
#if LWIP_IPV6_AUTOCONFIG
259+
case MP_QSTR_autoconf6: {
260+
netif_set_ip6_autoconfig_enabled(netif, mp_obj_is_true(e->value));
261+
if (mp_obj_is_true(e->value)) {
262+
nd6_restart_netif(netif);
263+
uint32_t start = mp_hal_ticks_ms();
264+
while (1) {
265+
int found = 0;
266+
for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
267+
if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
268+
!netif_ip6_addr_isstatic(netif, i)) {
269+
found = 1;
270+
break;
271+
}
272+
}
273+
if (found) {
274+
break;
275+
}
276+
if (mp_hal_ticks_ms() - start > 10000) {
277+
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("timeout waiting for DHCP to get IP address"));
278+
}
279+
mp_hal_delay_ms(100);
280+
}
281+
} else {
282+
// Clear out any non-static addresses, skip link-local address in slot 0
283+
for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
284+
if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
285+
!netif_ip6_addr_isstatic(netif, i)) {
286+
netif_ip6_addr_set_state(netif, i, IP6_ADDR_INVALID);
287+
}
288+
}
289+
}
290+
break;
291+
}
292+
#endif
293+
case MP_QSTR_addr4:
294+
case MP_QSTR_addr6: {
295+
ip_addr_t ip_addr;
296+
int prefix_bits = 32;
297+
if (e->value != mp_const_none) {
298+
size_t addr_len;
299+
const char *input_str = mp_obj_str_get_data(e->value, &addr_len);
300+
char plain_ip[IPADDR_STRLEN_MAX];
301+
char *split = strchr(input_str, '/');
302+
const char *addr_str = input_str;
303+
if (split) {
304+
int to_copy = sizeof(plain_ip) - 1;
305+
if (split - addr_str < to_copy) {
306+
to_copy = split - addr_str;
307+
}
308+
memcpy(plain_ip, addr_str, to_copy);
309+
prefix_bits = atoi(split + 1);
310+
}
311+
if (!ipaddr_aton(addr_str, &ip_addr)) {
312+
mp_raise_ValueError(MP_ERROR_TEXT("invalid arguments"));
313+
}
314+
if ((mp_obj_str_get_qstr(args[0]) == MP_QSTR_addr6) != IP_IS_V6(&ip_addr)
315+
|| (mp_obj_str_get_qstr(args[0]) == MP_QSTR_addr4) != IP_IS_V4(&ip_addr)) {
316+
mp_raise_ValueError(MP_ERROR_TEXT("invalid address type"));
317+
}
318+
}
319+
if (mp_obj_str_get_qstr(args[0]) == MP_QSTR_addr4) {
320+
if (e->value != mp_const_none) {
321+
netif->ip_addr = ip_addr;
322+
uint32_t mask = -(1u << (32 - prefix_bits));
323+
ip_addr_set_ip4_u32_val(netif->netmask, ((mask & 0xFF) << 24) | ((mask & 0xFF00) << 8) | ((mask >> 8) & 0xFF00) | ((mask >> 24) & 0xFF));
324+
} else {
325+
ip4_addr_set_any(ip_2_ip4(&netif->ip_addr));
326+
}
327+
#if LWIP_IPV6
328+
} else if (mp_obj_str_get_qstr(args[0]) == MP_QSTR_addr6) {
329+
// Clear out any existing static addresses. Address 0 comes from autoconf.
330+
for (i = 1; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
331+
if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
332+
netif_ip6_addr_isstatic(netif, i)) {
333+
netif_ip6_addr_set_state(netif, i, IP6_ADDR_INVALID);
334+
}
335+
}
336+
if (e->value != mp_const_none) {
337+
s8_t free_idx;
338+
netif_add_ip6_address(netif, ip_2_ip6(&ip_addr), &free_idx);
339+
netif_ip6_addr_set_valid_life(netif, free_idx, IP6_ADDR_LIFE_STATIC);
340+
netif_ip6_addr_set_pref_life(netif, free_idx, IP6_ADDR_LIFE_STATIC);
341+
netif_ip6_addr_set_state(netif, free_idx, IP6_ADDR_PREFERRED);
342+
}
343+
#endif
344+
}
345+
break;
346+
}
347+
case MP_QSTR_gw4: {
348+
ip_addr_t ip_addr;
349+
size_t addr_len;
350+
const char *addr_str = mp_obj_str_get_data(e->value, &addr_len);
351+
if (!ipaddr_aton(addr_str, &ip_addr)) {
352+
mp_raise_ValueError(MP_ERROR_TEXT("invalid arguments"));
353+
}
354+
if (IP_IS_V4(&ip_addr)) {
355+
netif->gw = ip_addr;
356+
} else {
357+
mp_raise_ValueError(MP_ERROR_TEXT("invalid address type"));
358+
}
359+
break;
360+
}
361+
default: {
362+
mp_raise_ValueError(MP_ERROR_TEXT("unexpected key"));
363+
break;
364+
}
365+
}
366+
}
367+
}
368+
}
369+
return mp_const_none;
370+
}
371+
372+
373+
93374
#endif // LWIP_VERSION_MAJOR >= 2
94375

95376
#endif // MICROPY_PY_NETWORK && MICROPY_PY_LWIP

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy