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