|
26 | 26 |
|
27 | 27 | #include "py/runtime.h"
|
28 | 28 | #include "py/mphal.h"
|
| 29 | +#include "py/parsenum.h" |
29 | 30 |
|
30 | 31 | #if MICROPY_PY_NETWORK && MICROPY_PY_LWIP
|
31 | 32 |
|
|
40 | 41 | #include "lwip/timeouts.h"
|
41 | 42 | #include "lwip/dns.h"
|
42 | 43 | #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; |
43 | 52 |
|
44 | 53 | // Implementations of network methods that can be used by any interface.
|
45 | 54 |
|
@@ -90,6 +99,278 @@ mp_obj_t mod_network_nic_ifconfig(struct netif *netif, size_t n_args, const mp_o
|
90 | 99 | }
|
91 | 100 | }
|
92 | 101 |
|
| 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 | + |
93 | 374 | #endif // LWIP_VERSION_MAJOR >= 2
|
94 | 375 |
|
95 | 376 | #endif // MICROPY_PY_NETWORK && MICROPY_PY_LWIP
|
0 commit comments