1 /*
2  * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3  */
4 #include "wifi_provision_internal.h"
5 
6 #ifdef AWSS_SUPPORT_DEV_AP
7 
8 #if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
9 extern "C" {
10 #endif
11 
12 #define TIMEOUT_CNT     10
13 #define GET_GBK_TIMEOUT 6000
14 static void *g_awss_dev_ap_mutex = NULL;
15 static char awss_dev_ap_switchap_done = 0;
16 static char awss_dev_ap_switchap_resp_suc = 0;
17 static char awss_dev_ap_ongoing = 0;
18 static void start_connect_ap();
19 
20 typedef struct {
21     char ssid[PLATFORM_MAX_SSID_LEN + 1];
22     char passwd[PLATFORM_MAX_PASSWD_LEN + 1];
23     uint8_t bssid[ETH_ALEN];
24     uint8_t token[RANDOM_MAX_LEN + 1];
25     uint16_t msgid;
26     uint8_t cnt;
27     uint8_t token_found;
28 } ap_info_t;
29 ap_info_t *g_dev_ap_info_ptr = NULL;
30 
31 struct ssid_config {
32     uint8_t bssid[ETH_ALEN];
33     char ssid[33];
34     uint8_t got_ssid;
35 };
36 
37 static struct ssid_config config;
38 
awss_80211_frame_handler(char * buf,int length,enum AWSS_LINK_TYPE link_type,int with_fcs,signed char rssi)39 static int awss_80211_frame_handler(char *buf, int length,
40                                     enum AWSS_LINK_TYPE link_type, int with_fcs,
41                                     signed char rssi)
42 {
43     uint8_t ssid[PLATFORM_MAX_SSID_LEN] = { 0 }, bssid[ETH_ALEN] = { 0 };
44     struct ieee80211_hdr *hdr;
45     int fc;
46     int ret = -1;
47 
48     if (link_type != AWSS_LINK_TYPE_NONE) {
49         return -1;
50     }
51     /* remove FCS filed */
52     if (with_fcs) {
53         length -= 4;
54     }
55 
56     hdr = (struct ieee80211_hdr *)buf;
57 
58     fc = hdr->frame_control;
59     if (!ieee80211_is_beacon(fc) && !ieee80211_is_probe_resp(fc)) {
60         return -1;
61     }
62 
63     ret = ieee80211_get_bssid_2((uint8_t *)hdr, bssid);
64     if (ret < 0) {
65         return -1;
66     }
67 
68     awss_trace("bssid = %02x %02x %02x %02x %02x %02x", bssid[0], bssid[1],
69                bssid[2], bssid[3], bssid[4], bssid[5]);
70     if (memcmp(config.bssid, bssid, ETH_ALEN) != 0) {
71         return -1;
72     }
73 
74     ret = ieee80211_get_ssid((uint8_t *)hdr, length, ssid);
75     if (ret < 0) {
76         return -1;
77     }
78 
79     memcpy(config.ssid, ssid, sizeof(config.ssid) - 1);
80     config.got_ssid = 1;
81     awss_info("get ssid in RAW FRAME :%s\n", ssid);
82     return 0;
83 }
84 
is_str_asii(char * str)85 static char is_str_asii(char *str)
86 {
87     int i;
88     for (i = 0; str[i] != '\0'; ++i) {
89         if ((uint8_t)str[i] > 0x7F) {
90             return 0;
91         }
92     }
93     return 1;
94 }
95 
bssid_is_valid(uint8_t * bssid)96 static char bssid_is_valid(uint8_t *bssid)
97 {
98     int i;
99     for (i = 0; i < ETH_ALEN; ++i) {
100         if (bssid[i] != 0) {
101             return 1;
102         }
103     }
104     return 0;
105 }
106 
get_next_channel(void)107 static uint8_t get_next_channel(void)
108 {
109     static int aws_chn_index = 0;
110 
111     aws_chn_index++;
112     if (aws_chn_index > 13) {
113         aws_chn_index = 1; /* rollback to start */
114     }
115 
116     return aws_chn_index;
117 }
118 
try_get_real_ssid(uint32_t timeout,uint8_t * bissd_in,char * ssid_out)119 static int try_get_real_ssid(uint32_t timeout, uint8_t *bissd_in,
120                              char *ssid_out)
121 {
122     uint64_t pre_time = HAL_UptimeMs();
123     uint64_t start_time = pre_time;
124     uint64_t cur_time = 0;
125     int ret = -1;
126     memset(&config, 0, sizeof(struct ssid_config));
127 
128     memcpy(config.bssid, bissd_in, ETH_ALEN);
129     HAL_Awss_Open_Monitor(awss_80211_frame_handler);
130 
131     do {
132         HAL_SleepMs(50);
133         if (config.got_ssid) {
134             strncpy(ssid_out, config.ssid, strlen(config.ssid));
135             ssid_out[strlen(config.ssid)] = 0;
136             ret = 0;
137             break;
138         }
139         cur_time = HAL_UptimeMs();
140         if (cur_time - pre_time > 250) {
141             int channel = get_next_channel();
142             HAL_Awss_Switch_Channel(channel, 0, NULL);
143             pre_time = cur_time;
144         }
145     } while (cur_time - start_time < timeout);
146     return ret;
147 }
awss_dev_ap_setup()148 static int awss_dev_ap_setup()
149 {
150     char ssid[PLATFORM_MAX_SSID_LEN + 1] = { 0 };
151     char passwd[PLATFORM_MAX_PASSWD_LEN + 1] = { 0 };
152     int ret = -1;
153     int count = 0;
154     do { /* reduce stack used */
155         char pk[OS_PRODUCT_KEY_LEN + 1] = { 0 };
156         char mac_str[OS_MAC_LEN + 1] = { 0 };
157 
158         HAL_GetProductKey(pk);
159         os_wifi_get_mac_str(mac_str);
160         memmove(mac_str + 11, mac_str + 12, 2);
161         memmove(mac_str + 13, mac_str + 15, 2);
162         mac_str[15] = '\0';
163         HAL_Snprintf(ssid, PLATFORM_MAX_SSID_LEN, "adh_%s_%s", pk, &mac_str[9]);
164     } while (0);
165 
166     awss_trace("ssid:%s\n", ssid);
167     for (count = 0; count < 3; count++) {
168         ret = HAL_Awss_Open_Ap(ssid, passwd, 100, 0);
169         if (0 == ret) {
170             break;
171         }
172         HAL_SleepMs(2000);
173     }
174     return ret;
175 }
176 
try_to_do_connect_ap()177 static void try_to_do_connect_ap()
178 {
179     int ret;
180     ap_info_t *info = g_dev_ap_info_ptr;
181     if (NULL == info) {
182         return;
183     }
184     if (awss_dev_ap_ongoing == 0) {
185         awss_cmp_coap_cancel_packet(info->msgid);
186         return;
187     }
188     if ((strlen(info->ssid) == 0) && (strlen(info->passwd) == 0)) {
189         return;
190     }
191 
192     if (awss_dev_ap_switchap_resp_suc || ++info->cnt == TIMEOUT_CNT) {
193         start_connect_ap();
194         /* reset ssid/passwd data to 0 */
195         memset(info, 0, sizeof(ap_info_t));
196     }
197 }
198 
199 extern int awss_success_notify(void);
awss_dev_ap_start(void)200 int awss_dev_ap_start(void)
201 {
202     int ret = -1;
203     ap_info_t dev_ap_info = { 0 };
204 
205     if (g_awss_dev_ap_mutex || awss_dev_ap_ongoing) {
206         awss_trace("dev ap already running");
207         return -1;
208     }
209 
210     if (g_awss_dev_ap_mutex == NULL) {
211         g_awss_dev_ap_mutex = HAL_MutexCreate();
212     }
213     if (g_awss_dev_ap_mutex == NULL) {
214         awss_trace("awss dev ap start fail");
215         goto AWSS_DEV_AP_FAIL;
216     }
217 
218     HAL_MutexLock(g_awss_dev_ap_mutex);
219 
220     awss_dev_ap_ongoing = 1;
221     awss_dev_ap_switchap_done = 0;
222     awss_dev_ap_switchap_resp_suc = 0;
223     g_dev_ap_info_ptr = &dev_ap_info;
224 
225     HAL_MutexUnlock(g_awss_dev_ap_mutex);
226     ret = awss_dev_ap_setup();
227     if (0 != ret) {
228         awss_trace("awss dev ap setup fail");
229         goto AWSS_DEV_AP_FAIL;
230     }
231 
232     HAL_SleepMs(1000); /* wait for dev ap to work well */
233     HAL_MutexLock(g_awss_dev_ap_mutex);
234     if (awss_dev_ap_ongoing) {
235         awss_cmp_local_init(AWSS_LC_INIT_DEV_AP);
236     }
237     while (awss_dev_ap_ongoing) {
238         HAL_MutexUnlock(g_awss_dev_ap_mutex);
239         HAL_SleepMs(200);
240         HAL_MutexLock(g_awss_dev_ap_mutex);
241         if (awss_dev_ap_switchap_done) {
242             break;
243         }
244         try_to_do_connect_ap();
245     }
246     g_dev_ap_info_ptr = NULL;
247     HAL_MutexUnlock(g_awss_dev_ap_mutex);
248 
249     ret = awss_dev_ap_switchap_done == 0 ? -1 : 0;
250 
251     if (awss_dev_ap_ongoing == 0) { /* interrupt by user */
252         HAL_SleepMs(1000);
253         return -1;
254     }
255 
256     awss_dev_ap_ongoing = 0;
257     awss_success_notify();
258 
259 AWSS_DEV_AP_FAIL:
260     if (g_awss_dev_ap_mutex) {
261         HAL_MutexUnlock(g_awss_dev_ap_mutex);
262         HAL_MutexDestroy(g_awss_dev_ap_mutex);
263     }
264     g_awss_dev_ap_mutex = NULL;
265     g_dev_ap_info_ptr = NULL;
266     return ret;
267 }
268 
awss_dev_ap_stop(void)269 int awss_dev_ap_stop(void)
270 {
271     if (awss_dev_ap_ongoing == 0) {
272         return 0;
273     }
274 
275     awss_dev_ap_ongoing = 0;
276 
277     awss_trace("%s", __func__);
278 
279     if (g_awss_dev_ap_mutex) {
280         HAL_MutexLock(g_awss_dev_ap_mutex);
281     }
282 
283     HAL_Awss_Close_Ap();
284 
285     awss_cmp_local_deinit(1);
286 
287     if (g_awss_dev_ap_mutex) {
288         HAL_MutexUnlock(g_awss_dev_ap_mutex);
289         HAL_MutexDestroy(g_awss_dev_ap_mutex);
290         g_awss_dev_ap_mutex = NULL;
291     }
292 
293     awss_dev_ap_switchap_done = 0;
294     awss_dev_ap_switchap_resp_suc = 0;
295     g_dev_ap_info_ptr = NULL;
296 
297     awss_trace("%s exit", __func__);
298 
299     return 0;
300 }
301 
awss_dev_ap_switchap_resp(void * context,int result,void * userdata,void * remote,void * message)302 static int awss_dev_ap_switchap_resp(void *context, int result, void *userdata,
303                                      void *remote, void *message)
304 {
305     if (result == 2) { /* success */
306         awss_dev_ap_switchap_resp_suc = 1;
307     }
308     return 0;
309 }
310 
start_connect_ap()311 static void start_connect_ap()
312 {
313     int ret = 0;
314     ap_info_t *info = g_dev_ap_info_ptr;
315     if (NULL == info) {
316         return;
317     }
318     awss_cmp_coap_cancel_packet(info->msgid);
319     AWSS_UPDATE_STATIS(AWSS_STATIS_CONN_ROUTER_IDX,
320                        AWSS_STATIS_TYPE_TIME_START);
321     if (awss_dev_ap_ongoing == 0) { /* interrupt by user */
322         ret = -1;
323         return;
324     }
325     HAL_Awss_Close_Ap();
326 
327     if (is_str_asii(info->ssid) == 0 &&
328         bssid_is_valid(
329             info->bssid)) { /*try to get real ssid from mngmt frame */
330         HAL_SleepMs(200);   /*wait ap close */
331         try_get_real_ssid(GET_GBK_TIMEOUT, info->bssid, info->ssid);
332     }
333     ret = awss_connect(info->ssid, info->passwd, info->bssid, ETH_ALEN,
334                        info->token_found == 1 ? info->token : NULL,
335                        info->token_found == 1 ? RANDOM_MAX_LEN : 0);
336     if (ret == 0) {
337         AWSS_UPDATE_STATIS(AWSS_STATIS_CONN_ROUTER_IDX,
338                            AWSS_STATIS_TYPE_TIME_SUC);
339         awss_dev_ap_switchap_done = 1;
340         AWSS_UPDATE_STATIS(AWSS_STATIS_DAP_IDX, AWSS_STATIS_TYPE_TIME_SUC);
341     } else {
342         int ret = awss_dev_ap_setup();
343         if (0 != ret) {
344             awss_trace("retry, but awss dev ap setup fail");
345         }
346     }
347     awss_trace("connect '%s' %s\r\n", info->ssid,
348                ret == 0 ? "success" : "fail");
349 }
350 
wifimgr_process_dev_ap_switchap_request(void * ctx,void * resource,void * remote,void * request)351 int wifimgr_process_dev_ap_switchap_request(void *ctx, void *resource,
352                                             void *remote, void *request)
353 {
354 #define AWSS_DEV_AP_SWITCHA_RSP_LEN (512)
355     int str_len = 0, success = 1, len = 0;
356     char req_msg_id[MSG_REQ_ID_LEN] = { 0 };
357     char random[RANDOM_MAX_LEN + 1] = { 0 };
358     char *msg = NULL, *dev_info = NULL;
359     char *str = NULL, *buf = NULL;
360     char ssid_found = 0;
361     int ret = -1;
362     char *ssid;
363     char *passwd;
364     uint8_t *bssid;
365     uint8_t *token_found;
366     uint8_t *token;
367     static char dev_ap_switchap_parsed = 0;
368     char topic[TOPIC_LEN_MAX] = { 0 };
369     uint16_t msgid = -1;
370     int result = 0;
371 
372     ap_info_t *info = g_dev_ap_info_ptr;
373     if (NULL == info) {
374         return -1;
375     }
376 
377     if (awss_dev_ap_switchap_done != 0) {
378         return -1;
379     }
380 
381     ssid = info->ssid;
382     passwd = info->passwd;
383     bssid = info->bssid;
384     token_found = &(info->token_found);
385     token = info->token;
386 
387     if (dev_ap_switchap_parsed != 0) {
388         goto DEV_AP_SWITCHAP_END;
389     }
390     dev_ap_switchap_parsed = 1;
391 
392     AWSS_UPDATE_STATIS(AWSS_STATIS_DAP_IDX, AWSS_STATIS_TYPE_TIME_START);
393 
394     msg = awss_zalloc(AWSS_DEV_AP_SWITCHA_RSP_LEN);
395     if (msg == NULL) {
396         goto DEV_AP_SWITCHAP_END;
397     }
398     dev_info = awss_zalloc(AWSS_DEV_AP_SWITCHA_RSP_LEN);
399     if (dev_info == NULL) {
400         goto DEV_AP_SWITCHAP_END;
401     }
402 
403     buf = awss_cmp_get_coap_payload(request, &len);
404     str = json_get_value_by_name(buf, len, "id", &str_len, 0);
405     memcpy(req_msg_id, str,
406            str_len > MSG_REQ_ID_LEN - 1 ? MSG_REQ_ID_LEN - 1 : str_len);
407     awss_trace("dev ap, len:%u, %s\r\n", len, buf);
408     buf = json_get_value_by_name(buf, len, "params", &len, 0);
409     if (buf == NULL) {
410         goto DEV_AP_SWITCHAP_END;
411     }
412 
413     do {
414         str_len = 0;
415         str = json_get_value_by_name(buf, len, "ssid", &str_len, 0);
416         awss_trace("ssid, len:%u, %s\r\n", str_len, str != NULL ? str : "NULL");
417         if (str && (str_len < PLATFORM_MAX_SSID_LEN)) {
418             memcpy(ssid, str, str_len);
419             ssid_found = 1;
420         }
421 
422         if (!ssid_found) {
423             str_len = 0;
424             str = json_get_value_by_name(buf, len, "xssid", &str_len, 0);
425             if (str && (str_len < PLATFORM_MAX_SSID_LEN * 2 - 1)) {
426                 uint8_t decoded[OS_MAX_SSID_LEN] = { 0 };
427                 int len = str_len / 2;
428                 memcpy(ssid, str, str_len);
429                 utils_str_to_hex(ssid, str_len, decoded, OS_MAX_SSID_LEN);
430                 memcpy(ssid, (const char *)decoded, len);
431                 ssid[len] = '\0';
432             } else {
433                 HAL_Snprintf(msg, AWSS_DEV_AP_SWITCHA_RSP_LEN, AWSS_ACK_FMT,
434                              req_msg_id, -1, "\"ssid error\"");
435                 success = 0;
436                 break;
437             }
438         }
439 
440         str_len = 0;
441         str = json_get_value_by_name(buf, len, "random", &str_len, 0);
442         if (str && str_len == RANDOM_MAX_LEN * 2) {
443             utils_str_to_hex(str, str_len, (unsigned char *)random,
444                              RANDOM_MAX_LEN);
445         } else {
446             HAL_Snprintf(msg, AWSS_DEV_AP_SWITCHA_RSP_LEN, AWSS_ACK_FMT,
447                          req_msg_id, -4, "\"random len error\"");
448             success = 0;
449             break;
450         }
451 
452         str_len = 0;
453         str = json_get_value_by_name(buf, len, "token", &str_len, 0);
454         if (str &&
455             str_len == RANDOM_MAX_LEN * 2) { /* token len equal to random len */
456             utils_str_to_hex(str, str_len, (unsigned char *)token,
457                              RANDOM_MAX_LEN);
458             *token_found = 1;
459         }
460 
461         str_len = 0;
462         str = json_get_value_by_name(buf, len, "bssid", &str_len, 0);
463         if (str) {
464             os_wifi_str2mac(str, (char *)bssid);
465         }
466 
467         str_len = 0;
468         str = json_get_value_by_name(buf, len, "passwd", &str_len, 0);
469 
470         if (str_len < (PLATFORM_MAX_PASSWD_LEN * 2) - 1) {
471             char encoded[PLATFORM_MAX_PASSWD_LEN * 2 + 1] = { 0 };
472             memcpy(encoded, str, str_len);
473             aes_decrypt_string(encoded, passwd, str_len, 0,
474                                awss_get_encrypt_type(), 1,
475                                random); /* 64bytes=2x32bytes */
476         } else {
477             HAL_Snprintf(msg, AWSS_DEV_AP_SWITCHA_RSP_LEN, AWSS_ACK_FMT,
478                          req_msg_id, -3, "\"passwd len error\"");
479             success = 0;
480             AWSS_UPDATE_STATIS(AWSS_STATIS_DAP_IDX,
481                                AWSS_STATIS_TYPE_PASSWD_ERR);
482         }
483 
484         if (success && is_utf8(passwd, strlen(passwd)) == 0) {
485             HAL_Snprintf(msg, AWSS_DEV_AP_SWITCHA_RSP_LEN, AWSS_ACK_FMT,
486                          req_msg_id, -3, "\"passwd content error\"");
487             success = 0;
488             AWSS_UPDATE_STATIS(AWSS_STATIS_DAP_IDX,
489                                AWSS_STATIS_TYPE_PASSWD_ERR);
490         }
491     } while (0);
492 
493     awss_trace("Sending message to app: %s", msg);
494     awss_trace("switch to ap: '%s'", ssid);
495     if (success == 1) {
496         if (*token_found == 0) {
497             produce_random(aes_random, sizeof(aes_random));
498         }
499         dev_info[0] = '{';
500         awss_build_dev_info(*token_found == 1 ? AWSS_NOTIFY_TYPE_MAX
501                                               : AWSS_NOTIFY_DEV_BIND_TOKEN,
502                             dev_info + 1, AWSS_DEV_AP_SWITCHA_RSP_LEN - 1);
503         dev_info[strlen(dev_info)] = '}';
504         dev_info[AWSS_DEV_AP_SWITCHA_RSP_LEN - 1] = '\0';
505         HAL_Snprintf(msg, AWSS_DEV_AP_SWITCHA_RSP_LEN, AWSS_ACK_FMT, req_msg_id,
506                      200, dev_info);
507     }
508     awss_build_topic((const char *)TOPIC_AWSS_DEV_AP_SWITCHAP, topic,
509                      TOPIC_LEN_MAX);
510     result =
511         awss_cmp_coap_send_resp(msg, strlen(msg), remote, topic, request,
512                                 awss_dev_ap_switchap_resp, &(info->msgid), 1);
513     (void)result; /* remove complier warnings */
514     awss_trace("sending %s.", result == 0 ? "success" : "fail");
515 
516 DEV_AP_SWITCHAP_END:
517     dev_ap_switchap_parsed = 0;
518     if (dev_info) {
519         HAL_Free(dev_info);
520     }
521     if (msg) {
522         HAL_Free(msg);
523     }
524     return ret;
525 }
526 #if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
527 }
528 #endif
529 #endif
530