Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b913020

Browse files
committed
extmod/network: Implement IPv6 API to set and get nic configuration.
Signed-off-by: Felix Dörre <[email protected]>
1 parent 8fdcc25 commit b913020

File tree

4 files changed

+303
-1
lines changed

4 files changed

+303
-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: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,15 @@ 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+
mp_obj_t network_ipconfig(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs);
145+
MP_DEFINE_CONST_FUN_OBJ_KW(mod_network_ipconfig_obj, 0, network_ipconfig);
146+
147+
144148
STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
145149
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) },
146150
{ MP_ROM_QSTR(MP_QSTR_country), MP_ROM_PTR(&mod_network_country_obj) },
147151
{ MP_ROM_QSTR(MP_QSTR_hostname), MP_ROM_PTR(&mod_network_hostname_obj) },
152+
{ MP_ROM_QSTR(MP_QSTR_ipconfig), MP_ROM_PTR(&mod_network_ipconfig_obj) },
148153

149154
// Defined per port in mpconfigport.h
150155
#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)