1 /*
2  * This file is part of the MicroPython project, http://micropython.org/
3  *
4  * Development of the code in this file was sponsored by Microbric Pty Ltd
5  * and Mnemote Pty Ltd
6  *
7  * The MIT License (MIT)
8  *
9  * Copyright (c) 2016, 2017 Nick Moore @mnemote
10  * Copyright (c) 2017 "Eric Poulsen" <eric@zyxod.com>
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a copy
13  * of this software and associated documentation files (the "Software"), to deal
14  * in the Software without restriction, including without limitation the rights
15  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16  * copies of the Software, and to permit persons to whom the Software is
17  * furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included in
20  * all copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28  * THE SOFTWARE.
29  */
30 
31 #include "modnetwork.h"
32 
33 #include <stdint.h>
34 #include <stdio.h>
35 #include <string.h>
36 
37 #include "shared/netutils/netutils.h"
38 #include "lwip/dns.h"
39 #include "netmgr_wifi.h"
40 #include "py/mperrno.h"
41 #include "py/mphal.h"
42 #include "py/nlr.h"
43 #include "py/objlist.h"
44 #include "py/runtime.h"
45 #include "ulog/ulog.h"
46 
47 #define LOG_TAG                      "mod_network"
48 
49 #define DNS_MAIN                     TCPIP_ADAPTER_DNS_MAIN
50 #define MODNETWORK_INCLUDE_CONSTANTS (1)
51 
52 #define QS(x)                        (uintptr_t) MP_OBJ_NEW_QSTR(x)
53 
54 typedef enum {
55     WIFI_MODE_NULL = 0x00,
56     WIFI_MODE_STA = 0x01,
57     WIFI_MODE_AP = 0x02,
58 } wifi_mode_t;
59 
60 enum {
61     STAT_IDLE = 1000,
62     STAT_CONNECTING = 1001,
63     STAT_GOT_IP = 1010,
64 };
65 
_haas_wifi_exceptions(wifi_result_t e)66 NORETURN void _haas_wifi_exceptions(wifi_result_t e)
67 {
68     switch (e) {
69     case RET_WIFI_COMMON_FAIL:
70         mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Common Fail"));
71     case RET_WIFI_INVALID_ARG:
72         mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Invalid Arguments"));
73     case RET_WIFI_INVALID_PASSWORD:
74         mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Invalid Password"));
75     case RET_WIFI_MEMORY_ERROR:
76         mp_raise_OSError(MP_ENOMEM);
77     case RET_WIFI_INIT_FAIL:
78         mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Init Fail"));
79     case RET_WIFI_NOT_INITED:
80         mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Not Initialized"));
81     case RET_WIFI_STATUS_ERROR:
82         mp_raise_msg(&mp_type_OSError,
83                      MP_ERROR_TEXT("Wifi Request In Error Status"));
84     case RET_WIFI_SCAN_REQ_FAIL:
85         mp_raise_msg(&mp_type_OSError,
86                      MP_ERROR_TEXT("Wifi Scan Fail To Start"));
87     case RET_WIFI_SCAN_NO_AP_FOUND:
88         mp_raise_msg(&mp_type_OSError,
89                      MP_ERROR_TEXT("Wifi Can Not Find Any SSID"));
90     case RET_WIFI_NO_SUITABLE_NETWORK:
91         mp_raise_msg(&mp_type_OSError,
92                      MP_ERROR_TEXT("Wifi No Suitable Network To Connect"));
93     case RET_WIFI_CONN_REQ_FAIL:
94         mp_raise_msg(&mp_type_OSError,
95                      MP_ERROR_TEXT("Wifi Connect Fail To Start"));
96     case RET_WIFI_CONN_FAIL:
97         mp_raise_msg(&mp_type_OSError,
98                      MP_ERROR_TEXT("Wifi Connect Procedure Result In Fail"));
99     case RET_WIFI_CONN_NO_SSID_CONFIG:
100         mp_raise_msg(&mp_type_OSError,
101                      MP_ERROR_TEXT("Wifi No Saved SSID Config To Connect"));
102     case RET_WIFI_DISC_FAIL:
103         mp_raise_msg(&mp_type_OSError,
104                      MP_ERROR_TEXT("Wifi Disconnect Procedure Result In Fail"));
105     case RET_WIFI_WPS_NOT_FOUND:
106         mp_raise_msg(&mp_type_OSError,
107                      MP_ERROR_TEXT("Wifi Can Not Find WPS AP"));
108     case RET_WIFI_WPS_REQ_FAIL:
109         mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Wifi Fail To Start WPS"));
110     default:
111         mp_raise_msg_varg(&mp_type_RuntimeError,
112                           MP_ERROR_TEXT("Wifi Unknown Error 0x%04x"), e);
113     }
114 }
115 
haas_exceptions(wifi_result_t e)116 static inline void haas_exceptions(wifi_result_t e)
117 {
118     if (e != RET_WIFI_OK) {
119         _haas_wifi_exceptions(e);
120     }
121 }
122 
123 #define HAAS_EXCEPTIONS(x)  \
124     do {                    \
125         haas_exceptions(x); \
126     } while (0);
127 
128 typedef struct _wlan_if_obj_t {
129     mp_obj_base_t base;
130     netmgr_hdl_t hdl;  // can get through netmgr_wifi_get_dev
131     netmgr_wifi_mode_t if_id;
132 } wlan_if_obj_t;
133 
134 const mp_obj_type_t wlan_if_type;
135 STATIC const wlan_if_obj_t wlan_sta_obj = { { &wlan_if_type },
136                                             NETMGR_WIFI_MODE_STA };
137 STATIC const wlan_if_obj_t wlan_ap_obj = { { &wlan_if_type },
138                                            NETMGR_WIFI_MODE_AP };
139 
140 // Set to "true" if haas_wifi_start() was called
141 static bool wifi_started = false;
142 
143 // Set to "true" if the STA interface is requested to be connected by the
144 // user, used for automatic reassociation.
145 static bool wifi_sta_connect_requested = false;
146 
147 // Set to "true" if the STA interface is connected to wifi and has IP address.
148 static bool wifi_sta_connected = false;
149 
150 // Store the current status. 0 means None here, safe to do so as first enum
151 // value is WIFI_REASON_UNSPECIFIED=1.
152 static uint8_t wifi_sta_disconn_reason = 0;
153 
wifi_set_mac(netmgr_hdl_t hdl,uint8_t * mac)154 static int wifi_set_mac(netmgr_hdl_t hdl, uint8_t *mac)
155 {
156     return ioctl(hdl, WIFI_DEV_CMD_SET_MAC, mac);
157 }
158 
wifi_get_mac(netmgr_hdl_t hdl,uint8_t * mac)159 static int wifi_get_mac(netmgr_hdl_t hdl, uint8_t *mac)
160 {
161     return ioctl(hdl, WIFI_DEV_CMD_GET_MAC, mac);
162 }
163 
wifi_get_rssi(netmgr_hdl_t hdl,int * rssi)164 static int wifi_get_rssi(netmgr_hdl_t hdl, int *rssi)
165 {
166     int state = -1;
167     wifi_ap_record_t out = { 0 };
168     int ret = ioctl(hdl, WIFI_DEV_CMD_STA_GET_LINK_STATUS, &out));
169     if (ret == 0) {
170         memcpy(rssi, &out.rssi, sizeof(out.rssi));
171         state = 0;
172     }
173 
174     return state;
175 }
176 
177 // This function is called by the system-event task and so runs in a different
178 // thread to the main MicroPython task.  It must not raise any Python
179 // exceptions.
event_handler(void * ctx,system_event_t * event)180 static wifi_result_t event_handler(void *ctx, system_event_t *event)
181 {
182     switch (event->event_id) {
183     case CONN_STATE_DISCONNECTING:
184         LOGD(LOG_TAG, "wifi CONN_STATE_DISCONNECTING");
185         break;
186     case CONN_STATE_DISCONNECTED:
187         LOGI(LOG_TAG, "wifi STA_DISCONNECTED");
188         break;
189     case CONN_STATE_CONNECTING:
190         LOGD(LOG_TAG, "wifi CONN_STATE_CONNECTING");
191         break;
192     case CONN_STATE_CONNECTED:
193         LOGI(LOG_TAG, "wifi CONN_STATE_CONNECTED");
194         break;
195     case CONN_STATE_OBTAINING_IP:
196         LOGI(LOG_TAG, "wifi CONN_STATE_OBTAINING_IP");
197         wifi_sta_connected = true;
198         wifi_sta_disconn_reason = 0;
199         break;
200     case CONN_STATE_NETWORK_CONNECTED:
201         LOGI(LOG_TAG, "wifi CONN_STATE_NETWORK_CONNECTED");
202         break;
203     case CONN_STATE_FAILED:
204         LOGI(LOG_TAG, "wifi CONN_STATE_FAILED");
205         break;
206     default:
207         LOGI(LOG_TAG, "event %d", event->event_id);
208         break;
209     }
210     return RET_WIFI_OK;
211 }
212 
require_if(mp_obj_t wlan_if,int if_no)213 STATIC void require_if(mp_obj_t wlan_if, int if_no)
214 {
215     wlan_if_obj_t *self = MP_OBJ_TO_PTR(wlan_if);
216     if (self->if_id != if_no) {
217         mp_raise_msg(&mp_type_OSError, if_no == NETMGR_WIFI_MODE_STA
218                                            ? MP_ERROR_TEXT("STA required")
219                                            : MP_ERROR_TEXT("AP required"));
220     }
221 }
222 
get_wlan(size_t n_args,const mp_obj_t * args)223 STATIC mp_obj_t get_wlan(size_t n_args, const mp_obj_t *args)
224 {
225     static int initialized = 0;
226     if (!initialized) {
227         LOGD(LOG_TAG, "modnetwork get WLAN start");
228         HAAS_EXCEPTIONS(event_service_init(NULL));
229         HAAS_EXCEPTIONS(netmgr_service_init(NULL));
230         LOGD(LOG_TAG, "modnetwork got WLAN");
231         initialized = 1;
232     }
233 
234     int idx = (n_args > 0) ? mp_obj_get_int(args[0]) : NETMGR_WIFI_MODE_STA;
235     if (idx == NETMGR_WIFI_MODE_STA) {
236         return MP_OBJ_FROM_PTR(&wlan_sta_obj);
237     } else if (idx == NETMGR_WIFI_MODE_AP) {
238         return MP_OBJ_FROM_PTR(&wlan_ap_obj);
239     } else {
240         mp_raise_ValueError(MP_ERROR_TEXT("invalid WLAN interface identifier"));
241     }
242 }
243 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_wlan_obj, 0, 1, get_wlan);
244 
wlan_initialize()245 STATIC mp_obj_t wlan_initialize()
246 {
247     static int initialized = 0;
248     if (!initialized) {
249         LOGD(LOG_TAG, "modnetwork Initializing start");
250         HAAS_EXCEPTIONS(event_service_init(NULL));
251         HAAS_EXCEPTIONS(netmgr_service_init(NULL));
252         LOGD(LOG_TAG, "modnetwork Initialized");
253         initialized = 1;
254     }
255     return mp_const_none;
256 }
257 STATIC MP_DEFINE_CONST_FUN_OBJ_0(wlan_initialize_obj, wlan_initialize);
258 
haas_wlan_active(size_t n_args,const mp_obj_t * args)259 STATIC mp_obj_t haas_wlan_active(size_t n_args, const mp_obj_t *args)
260 {
261     wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
262     wifi_mode_t mode;
263     if (!wifi_started) {
264         mode = WIFI_MODE_NULL;
265     } else {
266         HAAS_EXCEPTIONS(haas_wlan_wifi_get_mode(&mode));
267     }
268 
269     int bit =
270         (self->if_id == NETMGR_WIFI_MODE_STA) ? WIFI_MODE_STA : WIFI_MODE_AP;
271     if (n_args > 1) {
272         bool active = mp_obj_is_true(args[1]);
273         mode = active ? (mode | bit) : (mode & ~bit);
274         if (mode == WIFI_MODE_NULL) {
275             if (wifi_started) {
276                 HAAS_EXCEPTIONS(haas_wlan_wifi_stop());
277                 wifi_started = false;
278             }
279         } else {
280             HAAS_EXCEPTIONS(haas_wlan_wifi_set_mode(mode));
281             if (!wifi_started) {
282                 HAAS_EXCEPTIONS(haas_wlan_wifi_start());
283                 wifi_started = true;
284             }
285         }
286     }
287 
288     return (mode & bit) ? mp_const_true : mp_const_false;
289 }
290 
291 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(haas_wlan_active_obj, 1, 2,
292                                            haas_wlan_active);
293 
haas_wlan_connect(size_t n_args,const mp_obj_t * pos_args,mp_map_t * kw_args)294 STATIC mp_obj_t haas_wlan_connect(size_t n_args, const mp_obj_t *pos_args,
295                                   mp_map_t *kw_args)
296 {
297     enum {
298         ARG_ssid,
299         ARG_password,
300         ARG_bssid
301     };
302     static const mp_arg_t allowed_args[] = {
303         { MP_QSTR_, MP_ARG_OBJ, { .u_obj = mp_const_none } },
304         { MP_QSTR_, MP_ARG_OBJ, { .u_obj = mp_const_none } },
305         { MP_QSTR_bssid,
306           MP_ARG_KW_ONLY | MP_ARG_OBJ,
307           { .u_obj = mp_const_none } },
308     };
309 
310     wlan_if_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
311 
312     // parse args
313     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
314     mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args,
315                      MP_ARRAY_SIZE(allowed_args), allowed_args, args);
316 
317     netmgr_connect_params_t wifi_sta_config = { 0 };
318 
319     // configure any parameters that are given
320     if (n_args > 1) {
321         size_t len;
322         const char *p;
323         if (args[ARG_ssid].u_obj != mp_const_none) {
324             p = mp_obj_str_get_data(args[ARG_ssid].u_obj, &len);
325             memcpy(wifi_sta_config.wifi_params.ssid, p,
326                    MIN(len, sizeof(wifi_sta_config.wifi_params.ssid)));
327         }
328         if (args[ARG_password].u_obj != mp_const_none) {
329             p = mp_obj_str_get_data(args[ARG_password].u_obj, &len);
330             memcpy(wifi_sta_config.wifi_params.pwd, p,
331                    MIN(len, sizeof(wifi_sta_config.wifi_params.pwd)));
332         }
333         if (args[ARG_bssid].u_obj != mp_const_none) {
334             p = mp_obj_str_get_data(args[ARG_bssid].u_obj, &len);
335             if (len != sizeof(wifi_sta_config.wifi_params.bssid)) {
336                 mp_raise_ValueError(NULL);
337             }
338             wifi_sta_config.wifi_params.bssid_set = 1;
339             memcpy(wifi_sta_config.wifi_params.bssid, p,
340                    sizeof(wifi_sta_config.wifi_params.bssid));
341         }
342         // HAAS_EXCEPTIONS(haas_wlan_wifi_set_config(NETMGR_WIFI_MODE_STA,
343         // &wifi_sta_config));
344     }
345 
346     // connect to the WiFi AP
347     MP_THREAD_GIL_EXIT();
348     HAAS_EXCEPTIONS(netmgr_connect(self->hdl, &wifi_sta_config));
349     MP_THREAD_GIL_ENTER();
350     wifi_sta_connect_requested = true;
351 
352     return mp_const_none;
353 }
354 STATIC MP_DEFINE_CONST_FUN_OBJ_KW(haas_wlan_connect_obj, 1, haas_wlan_connect);
355 
haas_wlan_disconnect(mp_obj_t self_in)356 STATIC mp_obj_t haas_wlan_disconnect(mp_obj_t self_in)
357 {
358     wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in);
359     wifi_sta_connect_requested = false;
360     HAAS_EXCEPTIONS(netmgr_disconnect(self->hdl));
361     return mp_const_none;
362 }
363 STATIC MP_DEFINE_CONST_FUN_OBJ_1(haas_wlan_disconnect_obj,
364                                  haas_wlan_disconnect);
365 
haas_wlan_status(size_t n_args,const mp_obj_t * args)366 STATIC mp_obj_t haas_wlan_status(size_t n_args, const mp_obj_t *args)
367 {
368     wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
369     if (n_args == 1) {
370         if (self->if_id == NETMGR_WIFI_MODE_STA) {
371             // Case of no arg is only for the STA interface
372             if (wifi_sta_connected) {
373                 // Happy path, connected with IP
374                 return MP_OBJ_NEW_SMALL_INT(STAT_GOT_IP);
375             } else if (wifi_sta_connect_requested) {
376                 // No connection or error, but is requested = Still connecting
377                 return MP_OBJ_NEW_SMALL_INT(STAT_CONNECTING);
378             } else if (wifi_sta_disconn_reason == 0) {
379                 // No activity, No error = Idle
380                 return MP_OBJ_NEW_SMALL_INT(STAT_IDLE);
381             } else {
382                 // Simply pass the error through from haas_wlan-identifier
383                 return MP_OBJ_NEW_SMALL_INT(wifi_sta_disconn_reason);
384             }
385         }
386         return mp_const_none;
387     }
388 
389 #if 0
390     // one argument: return status based on query parameter
391     switch ((uintptr_t)args[1]) {
392         case QS(MP_QSTR_stations): {
393             // return list of connected stations, only if in soft-AP mode
394             require_if(args[0], NETMGR_WIFI_MODE_AP);
395             netmgr_wifi_config_t station_list = {0};
396             HAAS_EXCEPTIONS(netmgr_wifi_get_config(self->hdl, &station_list));
397             netmgr_wifi_ap_info_t *stations = &station_list.config;
398             mp_obj_t list = mp_obj_new_list(0, NULL);
399             for (int i = 0; i < station_list.ap_num; ++i) {
400                 mp_obj_tuple_t *t = mp_obj_new_tuple(1, NULL);
401                 t->items[0] = mp_obj_new_bytes(stations[i].mac, sizeof(stations[i].mac));
402                 mp_obj_list_append(list, t);
403             }
404             return list;
405         }
406         case QS(MP_QSTR_rssi): {
407             // return signal of AP, only in STA mode
408             require_if(args[0], NETMGR_WIFI_MODE_STA);
409 
410             netmgr_ifconfig_info_t info;
411             HAAS_EXCEPTIONS(netmgr_get_ifconfig(self->hdl, &info));
412             return MP_OBJ_NEW_SMALL_INT(info.rssi);
413         }
414         default:
415             mp_raise_ValueError(MP_ERROR_TEXT("unknown status param"));
416     }
417 #endif
418 
419     return mp_const_none;
420 }
421 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(haas_wlan_status_obj, 1, 2,
422                                            haas_wlan_status);
423 
haas_wlan_scan(mp_obj_t self_in)424 STATIC mp_obj_t haas_wlan_scan(mp_obj_t self_in)
425 {
426     wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in);
427 
428     // check that STA mode is active
429     wifi_mode_t mode;
430     HAAS_EXCEPTIONS(haas_wlan_wifi_get_mode(&mode));
431     if ((mode & WIFI_MODE_STA) == 0) {
432         mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("STA must be active"));
433     }
434 
435     mp_obj_t list = mp_obj_new_list(0, NULL);
436     netmgr_wifi_ap_list_t wifi_ap_records[16] = { 0 };
437     // XXX how do we scan hidden APs (and if we can scan them, are they really
438     // hidden?)
439     MP_THREAD_GIL_EXIT();
440     int ap_num = netmgr_wifi_scan_result(&wifi_ap_records, 16,
441                                          NETMGR_WIFI_SCAN_TYPE_FULL);
442     MP_THREAD_GIL_ENTER();
443     if ((ap_num != -1) && (ap_num < 16)) {
444         for (uint16_t i = 0; i < ap_num; i++) {
445             mp_obj_tuple_t *t = mp_obj_new_tuple(5, NULL);
446             int8_t *x = memchr(wifi_ap_records[i].ssid, 0,
447                                sizeof(wifi_ap_records[i].ssid));
448             int ssid_len = x ? x - wifi_ap_records[i].ssid
449                              : sizeof(wifi_ap_records[i].ssid);
450             t->items[0] = mp_obj_new_bytes(wifi_ap_records[i].ssid, ssid_len);
451             t->items[1] = mp_obj_new_bytes(wifi_ap_records[i].bssid,
452                                            sizeof(wifi_ap_records[i].bssid));
453             t->items[2] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].ap_power);
454             t->items[3] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].channel);
455             t->items[4] = MP_OBJ_NEW_SMALL_INT(wifi_ap_records[i].sec_type);
456             mp_obj_list_append(list, MP_OBJ_FROM_PTR(t));
457         }
458         free(wifi_ap_records);
459     }
460     return list;
461 }
462 STATIC MP_DEFINE_CONST_FUN_OBJ_1(haas_wlan_scan_obj, haas_wlan_scan);
463 
haas_wlan_isconnected(mp_obj_t self_in)464 STATIC mp_obj_t haas_wlan_isconnected(mp_obj_t self_in)
465 {
466     wlan_if_obj_t *self = MP_OBJ_TO_PTR(self_in);
467     if (self->if_id == NETMGR_WIFI_MODE_STA) {
468         return mp_obj_new_bool(wifi_sta_connected);
469     } else {
470         wifi_sta_list_t sta;
471         haas_wlan_wifi_ap_get_sta_list(&sta);
472         return mp_obj_new_bool(sta.num != 0);
473     }
474 }
475 STATIC MP_DEFINE_CONST_FUN_OBJ_1(haas_wlan_isconnected_obj,
476                                  haas_wlan_isconnected);
477 
haas_wlan_ifconfig(size_t n_args,const mp_obj_t * args)478 STATIC mp_obj_t haas_wlan_ifconfig(size_t n_args, const mp_obj_t *args)
479 {
480     wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
481     netmgr_ifconfig_info_t info = { 0 };
482     if (n_args == 1) {
483         // get
484         HAAS_EXCEPTIONS(netmgr_get_ifconfig(self->hdl, &info));
485         mp_obj_t tuple[4] = {
486             netutils_format_ipv4_addr((uint8_t *)&info.ip_addr, NETUTILS_BIG),
487             netutils_format_ipv4_addr((uint8_t *)&info.mask, NETUTILS_BIG),
488             netutils_format_ipv4_addr((uint8_t *)&info.gw, NETUTILS_BIG),
489             netutils_format_ipv4_addr((uint8_t *)&info.dns_server,
490                                       NETUTILS_BIG),
491         };
492         return mp_obj_new_tuple(4, tuple);
493     } else {
494         // set
495         if (mp_obj_is_type(args[1], &mp_type_tuple) ||
496             mp_obj_is_type(args[1], &mp_type_list)) {
497             mp_obj_t *items;
498             mp_obj_get_array_fixed_n(args[1], 4, &items);
499             netutils_parse_ipv4_addr(items[0], (void *)&info.ip_addr,
500                                      NETUTILS_BIG);
501             if (mp_obj_is_integer(items[1])) {
502                 // allow numeric mask, i.e.:
503                 // 24 -> 255.255.255.0
504                 // 16 -> 255.255.0.0
505                 // etc...
506                 uint32_t *m = (uint32_t *)&info.mask;
507                 *m = htonl(0xffffffff << (32 - mp_obj_get_int(items[1])));
508             } else {
509                 netutils_parse_ipv4_addr(items[1], (void *)&info.mask,
510                                          NETUTILS_BIG);
511             }
512             netutils_parse_ipv4_addr(items[2], (void *)&info.gw, NETUTILS_BIG);
513             netutils_parse_ipv4_addr(items[3], (void *)&info.dns_server,
514                                      NETUTILS_BIG);
515         } else {
516             // check for the correct string
517             const char *mode = mp_obj_str_get_str(args[1]);
518             if (self->if_id != NETMGR_WIFI_MODE_STA || strcmp("dhcp", mode)) {
519                 mp_raise_ValueError(MP_ERROR_TEXT("invalid arguments"));
520             }
521         }
522         HAAS_EXCEPTIONS(netmgr_set_ifconfig(self->hdl, &info));
523         return mp_const_none;
524     }
525 }
526 MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(haas_wlan_ifconfig_obj, 1, 2,
527                                     haas_wlan_ifconfig);
528 
haas_wlan_config(size_t n_args,const mp_obj_t * args,mp_map_t * kwargs)529 STATIC mp_obj_t haas_wlan_config(size_t n_args, const mp_obj_t *args,
530                                  mp_map_t *kwargs)
531 {
532     if (n_args != 1 && kwargs->used != 0) {
533         mp_raise_TypeError(MP_ERROR_TEXT("either pos or kw args are allowed"));
534     }
535 
536     wlan_if_obj_t *self = MP_OBJ_TO_PTR(args[0]);
537     bool is_wifi = self->if_id == NETMGR_WIFI_MODE_AP ||
538                    self->if_id == NETMGR_WIFI_MODE_STA;
539 
540     netmgr_config_t cfg = { 0 };
541     if (is_wifi) {
542         HAAS_EXCEPTIONS(netmgr_get_config(self->if_id, &cfg));
543     }
544 
545     mp_obj_t val = mp_const_none;
546 
547     // if (kwargs->used != 0) {
548     //     if (!is_wifi) {
549     //         goto unknown;
550     //     }
551 
552     //     for (size_t i = 0; i < kwargs->alloc; i++) {
553     //         if (mp_map_slot_is_filled(kwargs, i)) {
554     //             int req_if = -1;
555 
556     //             switch ((uintptr_t)kwargs->table[i].key) {
557     //                 case QS(MP_QSTR_mac): {
558     //                     mp_buffer_info_t bufinfo;
559     //                     mp_get_buffer_raise(kwargs->table[i].value, &bufinfo,
560     //                     MP_BUFFER_READ); if (bufinfo.len != 6) {
561     //                         mp_raise_ValueError(MP_ERROR_TEXT("invalid buffer
562     //                         length"));
563     //                     }
564     //                     HAAS_EXCEPTIONS(wifi_set_mac(self->hdl,
565     //                     bufinfo.buf)); break;
566     //                 }
567     //                 case QS(MP_QSTR_essid): {
568     //                     req_if = NETMGR_WIFI_MODE_AP;
569     //                     size_t len;
570     //                     const char *s =
571     //                     mp_obj_str_get_data(kwargs->table[i].value, &len);
572     //                     len = MIN(len, sizeof(cfg.ap.ssid));
573     //                     memcpy(cfg.ap.ssid, s, len);
574     //                     cfg.ap.ssid_len = len;
575     //                     break;
576     //                 }
577     //                 case QS(MP_QSTR_hidden): {
578     //                     req_if = NETMGR_WIFI_MODE_AP;
579     //                     cfg.ap.ssid_hidden =
580     //                     mp_obj_is_true(kwargs->table[i].value); break;
581     //                 }
582     //                 case QS(MP_QSTR_authmode): {
583     //                     req_if = NETMGR_WIFI_MODE_AP;
584     //                     cfg.ap.authmode =
585     //                     mp_obj_get_int(kwargs->table[i].value); break;
586     //                 }
587     //                 case QS(MP_QSTR_password): {
588     //                     req_if = NETMGR_WIFI_MODE_AP;
589     //                     size_t len;
590     //                     const char *s =
591     //                     mp_obj_str_get_data(kwargs->table[i].value, &len);
592     //                     len = MIN(len, sizeof(cfg.ap.password) - 1);
593     //                     memcpy(cfg.ap.password, s, len);
594     //                     cfg.ap.password[len] = 0;
595     //                     break;
596     //                 }
597     //                 case QS(MP_QSTR_channel): {
598     //                     req_if = NETMGR_WIFI_MODE_AP;
599     //                     cfg.ap.channel =
600     //                     mp_obj_get_int(kwargs->table[i].value); break;
601     //                 }
602     //                 case QS(MP_QSTR_dhcp_hostname): {
603     //                     const char *s =
604     //                     mp_obj_str_get_str(kwargs->table[i].value);
605     //                     HAAS_EXCEPTIONS(tcpip_adapter_set_hostname(self->if_id,
606     //                     s)); break;
607     //                 }
608     //                 case QS(MP_QSTR_max_clients): {
609     //                     req_if = NETMGR_WIFI_MODE_AP;
610     //                     cfg.ap.max_connection =
611     //                     mp_obj_get_int(kwargs->table[i].value); break;
612     //                 }
613     //                 default:
614     //                     goto unknown;
615     //             }
616 
617     //             // We post-check interface requirements to save on code size
618     //             if (req_if >= 0) {
619     //                 require_if(args[0], req_if);
620     //             }
621     //         }
622     //     }
623 
624     //     HAAS_EXCEPTIONS(haas_wlan_wifi_set_config(self->if_id, &cfg));
625     //     return mp_const_none;
626     // }
627 
628     // // Get config
629     // if (n_args != 2) {
630     //     mp_raise_TypeError(MP_ERROR_TEXT("can query only one param"));
631     // }
632 
633     // int req_if = -1;
634 
635     // switch ((uintptr_t)args[1]) {
636     //     case QS(MP_QSTR_mac): {
637     //         uint8_t mac[6];
638     //         switch (self->if_id) {
639     //             case NETMGR_WIFI_MODE_AP: // fallthrough intentional
640     //             case NETMGR_WIFI_MODE_STA:
641     //                 HAAS_EXCEPTIONS(wifi_get_mac(self->hdl, mac));
642     //                 return mp_obj_new_bytes(mac, sizeof(mac));
643 
644     //             default:
645     //                 goto unknown;
646     //         }
647     //     }
648     //         break;
649     //     case QS(MP_QSTR_essid):
650     //         switch (self->if_id) {
651     //             case NETMGR_WIFI_MODE_STA:
652     //                 val = mp_obj_new_str((char *)cfg.sta.ssid, strlen((char
653     //                 *)cfg.sta.ssid)); break;
654     //             case NETMGR_WIFI_MODE_AP:
655     //                 val = mp_obj_new_str((char *)cfg.ap.ssid,
656     //                 cfg.ap.ssid_len); break;
657     //             default:
658     //                 req_if = NETMGR_WIFI_MODE_AP;
659     //         }
660     //         break;
661     //     case QS(MP_QSTR_hidden):
662     //         req_if = NETMGR_WIFI_MODE_AP;
663     //         val = mp_obj_new_bool(cfg.ap.ssid_hidden);
664     //         break;
665     //     case QS(MP_QSTR_authmode):
666     //         req_if = NETMGR_WIFI_MODE_AP;
667     //         val = MP_OBJ_NEW_SMALL_INT(cfg.ap.authmode);
668     //         break;
669     //     case QS(MP_QSTR_channel):
670     //         req_if = NETMGR_WIFI_MODE_AP;
671     //         val = MP_OBJ_NEW_SMALL_INT(cfg.ap.channel);
672     //         break;
673     //     case QS(MP_QSTR_dhcp_hostname): {
674     //         const char *s;
675     //         HAAS_EXCEPTIONS(tcpip_adapter_get_hostname(self->if_id, &s));
676     //         val = mp_obj_new_str(s, strlen(s));
677     //         break;
678     //     }
679     //     case QS(MP_QSTR_max_clients): {
680     //         val = MP_OBJ_NEW_SMALL_INT(cfg.ap.max_connection);
681     //         break;
682     //     }
683     //     default:
684     //         goto unknown;
685     // }
686 
687     // // We post-check interface requirements to save on code size
688     // if (req_if >= 0) {
689     //     require_if(args[0], req_if);
690     // }
691 
692     return val;
693 
694 unknown:
695     mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
696 }
697 MP_DEFINE_CONST_FUN_OBJ_KW(haas_wlan_config_obj, 1, haas_wlan_config);
698 
699 STATIC const mp_rom_map_elem_t wlan_if_locals_dict_table[] = {
700     { MP_ROM_QSTR(MP_QSTR_active), MP_ROM_PTR(&haas_wlan_active_obj) },
701     { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&haas_wlan_connect_obj) },
702     { MP_ROM_QSTR(MP_QSTR_disconnect), MP_ROM_PTR(&haas_wlan_disconnect_obj) },
703     { MP_ROM_QSTR(MP_QSTR_status), MP_ROM_PTR(&haas_wlan_status_obj) },
704     { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&haas_wlan_scan_obj) },
705     { MP_ROM_QSTR(MP_QSTR_isconnected),
706       MP_ROM_PTR(&haas_wlan_isconnected_obj) },
707     { MP_ROM_QSTR(MP_QSTR_config), MP_ROM_PTR(&haas_wlan_config_obj) },
708     { MP_ROM_QSTR(MP_QSTR_ifconfig), MP_ROM_PTR(&haas_wlan_ifconfig_obj) },
709 };
710 
711 STATIC MP_DEFINE_CONST_DICT(wlan_if_locals_dict, wlan_if_locals_dict_table);
712 
713 const mp_obj_type_t wlan_if_type = {
714     { &mp_type_type },
715     .name = MP_QSTR_WLAN,
716     .locals_dict = (mp_obj_t)&wlan_if_locals_dict,
717 };
718 
719 STATIC const mp_rom_map_elem_t mp_module_network_globals_table[] = {
720     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_network) },
721     { MP_ROM_QSTR(MP_QSTR___init__), MP_ROM_PTR(&wlan_initialize_obj) },
722     { MP_ROM_QSTR(MP_QSTR_WLAN), MP_ROM_PTR(&get_wlan_obj) },
723 
724 #if MODNETWORK_INCLUDE_CONSTANTS
725     { MP_ROM_QSTR(MP_QSTR_STA_IF), MP_ROM_INT(NETMGR_WIFI_MODE_STA) },
726     { MP_ROM_QSTR(MP_QSTR_AP_IF), MP_ROM_INT(NETMGR_WIFI_MODE_AP) },
727 
728 #if 0
729     { MP_ROM_QSTR(MP_QSTR_MODE_11B), MP_ROM_INT(WIFI_PROTOCOL_11B) },
730     { MP_ROM_QSTR(MP_QSTR_MODE_11G), MP_ROM_INT(WIFI_PROTOCOL_11G) },
731     { MP_ROM_QSTR(MP_QSTR_MODE_11N), MP_ROM_INT(WIFI_PROTOCOL_11N) },
732 
733     { MP_ROM_QSTR(MP_QSTR_AUTH_OPEN), MP_ROM_INT(WIFI_AUTH_OPEN) },
734     { MP_ROM_QSTR(MP_QSTR_AUTH_WEP), MP_ROM_INT(WIFI_AUTH_WEP) },
735     { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_PSK), MP_ROM_INT(WIFI_AUTH_WPA_PSK) },
736     { MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_PSK), MP_ROM_INT(WIFI_AUTH_WPA2_PSK) },
737     { MP_ROM_QSTR(MP_QSTR_AUTH_WPA_WPA2_PSK), MP_ROM_INT(WIFI_AUTH_WPA_WPA2_PSK) },
738     { MP_ROM_QSTR(MP_QSTR_AUTH_WPA2_ENTERPRISE), MP_ROM_INT(WIFI_AUTH_WPA2_ENTERPRISE) },
739     { MP_ROM_QSTR(MP_QSTR_AUTH_MAX), MP_ROM_INT(WIFI_AUTH_MAX) },
740 
741     { MP_ROM_QSTR(MP_QSTR_STAT_IDLE), MP_ROM_INT(STAT_IDLE)},
742     { MP_ROM_QSTR(MP_QSTR_STAT_CONNECTING), MP_ROM_INT(STAT_CONNECTING)},
743     { MP_ROM_QSTR(MP_QSTR_STAT_GOT_IP), MP_ROM_INT(STAT_GOT_IP)},
744     { MP_ROM_QSTR(MP_QSTR_STAT_NO_AP_FOUND), MP_ROM_INT(WIFI_REASON_NO_AP_FOUND)},
745     { MP_ROM_QSTR(MP_QSTR_STAT_WRONG_PASSWORD), MP_ROM_INT(WIFI_REASON_AUTH_FAIL)},
746     { MP_ROM_QSTR(MP_QSTR_STAT_BEACON_TIMEOUT), MP_ROM_INT(WIFI_REASON_BEACON_TIMEOUT)},
747     { MP_ROM_QSTR(MP_QSTR_STAT_ASSOC_FAIL), MP_ROM_INT(WIFI_REASON_ASSOC_FAIL)},
748     { MP_ROM_QSTR(MP_QSTR_STAT_HANDSHAKE_TIMEOUT), MP_ROM_INT(WIFI_REASON_HANDSHAKE_TIMEOUT)},
749 #endif
750 #endif
751 };
752 
753 STATIC MP_DEFINE_CONST_DICT(mp_module_network_globals,
754                             mp_module_network_globals_table);
755 
756 const mp_obj_module_t mp_module_network = {
757     .base = { &mp_type_module },
758     .globals = (mp_obj_dict_t *)&mp_module_network_globals,
759 };
760