1 /*
2 * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3 */
4 #include "wifi_provision_internal.h"
5
6 #if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
7 extern "C" {
8 #endif
9 /* aws state machine */
10 enum {
11 /* used by aws_state */
12 AWS_SCANNING,
13 AWS_CHN_LOCKED,
14 AWS_SUCCESS,
15 AWS_TIMEOUT,
16
17 /* used by aws_stop */
18 AWS_STOPPING,
19 AWS_STOPPED
20 };
21
22 struct aws_info {
23 uint8_t state;
24
25 uint8_t cur_chn; /* current working channel */
26 uint8_t chn_index;
27
28 uint8_t locked_chn;
29
30 #define AWS_MAX_CHN_NUMS (2 * 13 + 5) /* +5 for safety gap */
31 uint8_t chn_list[AWS_MAX_CHN_NUMS];
32 uint8_t stop;
33
34 uint32_t chn_timestamp; /* channel start time */
35 uint32_t start_timestamp; /* aws start time */
36 } *aws_info;
37
38 #define aws_state (aws_info->state)
39 #define aws_locked_chn (aws_info->locked_chn)
40 #define aws_cur_chn (aws_info->cur_chn)
41 #define aws_chn_index (aws_info->chn_index)
42 #define aws_chn_list (aws_info->chn_list)
43 #define aws_chn_timestamp (aws_info->chn_timestamp)
44 #define aws_start_timestamp (aws_info->start_timestamp)
45 #define aws_stop (aws_info->stop)
46
47 #define aws_channel_lock_timeout_ms (8 * 1000)
48
49 static const uint8_t aws_fixed_scanning_channels[] = { 1, 6, 11, 1, 2, 3,
50 4, 5, 6, 7, 8, 9,
51 10, 11, 12, 13 };
52
53 #define RESCAN_MONITOR_TIMEOUT_MS (5 * 60 * 1000)
54
55 /*
56 * sniffer result/storage
57 * use global variable/buffer to keep it usable after zconfig_destroy
58 */
59 uint8_t aws_result_ssid[ZC_MAX_SSID_LEN + 1];
60 uint8_t aws_result_passwd[ZC_MAX_PASSWD_LEN + 1];
61 uint8_t aws_result_bssid[ETH_ALEN]; /* mac addr */
62 uint8_t aws_result_token[ZC_MAX_TOKEN_LEN]; /* bind token */
63 uint8_t aws_result_channel = 0;
64 uint8_t aws_result_encry;
65 uint8_t aws_result_auth;
66
67 int aws_80211_frame_handler(char *, int, enum AWSS_LINK_TYPE, int, signed char);
68
zconfig_get_lock_chn(void)69 uint8_t zconfig_get_lock_chn(void)
70 {
71 return aws_locked_chn;
72 }
73
zconfig_force_rescan(void)74 void zconfig_force_rescan(void)
75 {
76 if (aws_info) {
77 aws_state = AWS_SCANNING;
78 }
79 }
80
zconfig_channel_locked_callback(uint8_t primary_channel,uint8_t secondary_channel,uint8_t * bssid)81 void zconfig_channel_locked_callback(uint8_t primary_channel,
82 uint8_t secondary_channel, uint8_t *bssid)
83 {
84 aws_locked_chn = primary_channel;
85
86 if (aws_state == AWS_SCANNING) {
87 aws_state = AWS_CHN_LOCKED;
88 }
89
90 awss_event_post(IOTX_AWSS_LOCK_CHAN);
91 }
92
zconfig_got_ssid_passwd_callback(uint8_t * ssid,uint8_t * passwd,uint8_t * bssid,uint8_t * token,uint8_t auth,uint8_t encry,uint8_t channel)93 void zconfig_got_ssid_passwd_callback(uint8_t *ssid, uint8_t *passwd,
94 uint8_t *bssid, uint8_t *token,
95 uint8_t auth, uint8_t encry,
96 uint8_t channel)
97 {
98 if (bssid) {
99 awss_debug("ssid:%s, bssid:%02x%02x%02x%02x%02x%02x, %d\r\n", ssid,
100 bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5],
101 channel);
102 } else {
103 awss_debug("ssid:%s, bssid:--, %d\r\n", ssid, channel);
104 }
105
106 memset(aws_result_ssid, 0, sizeof(aws_result_ssid));
107 memset(aws_result_passwd, 0, sizeof(aws_result_passwd));
108 strncpy((char *)aws_result_ssid, (const char *)ssid, ZC_MAX_SSID_LEN - 1);
109 strncpy((char *)aws_result_passwd, (const char *)passwd,
110 ZC_MAX_PASSWD_LEN - 1);
111
112 if (bssid) {
113 memcpy(aws_result_bssid, bssid, ETH_ALEN);
114 }
115 if (token) {
116 memcpy(aws_result_token, token, ZC_MAX_TOKEN_LEN);
117 }
118 aws_result_auth = auth;
119 aws_result_encry = encry;
120 aws_result_channel = channel;
121
122 aws_state = AWS_SUCCESS;
123
124 awss_event_post(IOTX_AWSS_GOT_SSID_PASSWD);
125 }
126
aws_next_channel(void)127 uint8_t aws_next_channel(void)
128 {
129 /* aws_chn_index start from -1 */
130 while (1) {
131 aws_chn_index++;
132 if (aws_chn_index >= AWS_MAX_CHN_NUMS) {
133 aws_chn_index = 0; /* rollback to start */
134 }
135
136 if (aws_chn_list[aws_chn_index]) { /* valid channel */
137 break;
138 }
139 }
140
141 aws_cur_chn = aws_chn_list[aws_chn_index];
142
143 return aws_cur_chn;
144 }
145
146 static void aws_switch_dst_chan(int channel);
147 static int aws_amend_dst_chan = 0;
aws_switch_channel(void)148 void aws_switch_channel(void)
149 {
150 HAL_MutexLock(zc_mutex);
151 if (aws_amend_dst_chan != 0) {
152 HAL_MutexUnlock(zc_mutex);
153 aws_switch_dst_chan(aws_amend_dst_chan);
154 aws_amend_dst_chan = 0;
155 return;
156 }
157
158 if (aws_state == AWS_CHN_LOCKED) {
159 HAL_MutexUnlock(zc_mutex);
160 return;
161 }
162
163 do {
164 int channel = aws_next_channel();
165 aws_chn_timestamp = os_get_time_ms();
166 HAL_Awss_Switch_Channel(channel, 0, NULL);
167 awss_trace("chan %d\r\n", channel);
168 } while (0);
169 HAL_MutexUnlock(zc_mutex);
170 }
171
aws_set_dst_chan(int channel)172 void aws_set_dst_chan(int channel)
173 {
174 HAL_MutexLock(zc_mutex);
175 aws_amend_dst_chan = channel;
176 HAL_MutexUnlock(zc_mutex);
177 }
178
aws_switch_dst_chan(int channel)179 static void aws_switch_dst_chan(int channel)
180 {
181 int i = aws_chn_index;
182 for (; i < AWS_MAX_CHN_NUMS; i++) {
183 if (aws_chn_list[i] == 0) {
184 continue;
185 }
186 if (aws_chn_list[i] == channel) {
187 break;
188 }
189 }
190
191 if (i >= AWS_MAX_CHN_NUMS) {
192 for (i = 0; i < aws_chn_index; i++) {
193 if (aws_chn_list[i] == 0) {
194 continue;
195 }
196 if (aws_chn_list[i] == channel) {
197 break;
198 }
199 }
200 }
201
202 if (i == aws_chn_index) { /* no need to switch channel. */
203 return;
204 }
205
206 aws_chn_index = i;
207 aws_locked_chn = channel;
208 aws_cur_chn = channel;
209 aws_chn_timestamp = os_get_time_ms();
210 if (aws_state == AWS_SCANNING) {
211 aws_state = AWS_CHN_LOCKED;
212 }
213 HAL_Awss_Switch_Channel(channel, 0, NULL);
214
215 awss_trace("adjust chan %d\r\n", channel);
216 }
217
218 enum {
219 CHNSCAN_ONGOING, /* no timeout, continue */
220 CHNSCAN_NEXT_CHN, /* should swith to next channel */
221 CHNSCAN_TIMEOUT /* aws timeout */
222 };
223
aws_is_chnscan_timeout(void)224 int aws_is_chnscan_timeout(void)
225 {
226 if (aws_stop == AWS_STOPPING) {
227 awss_debug("aws will stop...\r\n");
228 return CHNSCAN_TIMEOUT;
229 }
230
231 if (time_elapsed_ms_since(aws_chn_timestamp) >
232 awss_get_channel_scan_interval_ms()) {
233 if ((0 != awss_get_press_timeout_ms()) &&
234 (time_elapsed_ms_since(aws_start_timestamp) >
235 awss_get_press_timeout_ms())) {
236 return CHNSCAN_TIMEOUT;
237 } else {
238 return CHNSCAN_NEXT_CHN;
239 }
240 }
241
242 return CHNSCAN_ONGOING;
243 }
244
zconfig_add_active_channel(int channel)245 int zconfig_add_active_channel(int channel)
246 {
247 int fixed_channel_nums = sizeof(aws_fixed_scanning_channels);
248
249 if (!zconfig_is_valid_channel(channel)) {
250 return -1;
251 }
252
253 aws_chn_list[fixed_channel_nums + channel] = channel;
254 return 0;
255 }
256
257 /* sleep for RESCAN_MONITOR_TIMEOUT_MS if no one interrupts */
zconfig_sleep_before_rescan()258 void zconfig_sleep_before_rescan()
259 {
260 int iter = 0;
261 int count = RESCAN_MONITOR_TIMEOUT_MS / 200;
262 for (iter = 0; iter < count; iter++) {
263 if (awss_get_config_press() ||
264 aws_stop == AWS_STOPPING) { /* user interrupt sleep */
265 break;
266 }
267 HAL_SleepMs(200);
268 }
269 }
270
271 /*
272 * channel scanning/re-scanning control
273 * Note: 修改该函数时,需考虑到各平台差异
274 * 庆科平台:
275 * --aws_switch_channel() 为空
276 * --zconfig_destroy()会被调用两次,一次被aws_main_thread_fun(),一次被庆科驱动
277 * linux/rtos平台差异
278 * --vendor_recv_80211_frame()有实现,rtos平台该函数通常为空,通过注册callback方式收包
279 */
aws_main_thread_func(void)280 void aws_main_thread_func(void)
281 {
282 int interval = 0;
283 aws_start_timestamp = os_get_time_ms();
284 /* channel switch init */
285 aws_switch_channel();
286 rescanning:
287 /* start scaning channel */
288 memset(zc_bssid, 0, ETH_ALEN);
289 while (aws_amend_dst_chan != 0 || aws_state == AWS_SCANNING) {
290 awss_update_config_press();
291 switch (aws_is_chnscan_timeout()) {
292 case CHNSCAN_ONGOING:
293 break;
294 case CHNSCAN_NEXT_CHN:
295 aws_switch_channel();
296 break;
297 case CHNSCAN_TIMEOUT:
298 goto timeout_scanning;
299 default:
300 break;
301 }
302
303 if (aws_stop == AWS_STOPPING) { /* interrupt by user */
304 goto timeout_scanning;
305 }
306
307 if (aws_state !=
308 AWS_SCANNING) { /* channel is locked, don't need to tx probe req */
309 break;
310 }
311
312 interval = (awss_get_channel_scan_interval_ms() + 2) / 3;
313 if (interval < 1) {
314 interval = 1;
315 }
316
317 /* 80211 frame handled by callback */
318 HAL_SleepMs(interval);
319 #ifndef AWSS_DISABLE_ENROLLEE
320 awss_broadcast_enrollee_info();
321 #endif
322 HAL_SleepMs(interval);
323 #ifdef AWSS_SUPPORT_DISCOVER
324 aws_discover_send_beacon();
325 #endif
326 HAL_SleepMs(interval);
327 #ifdef AWSS_SUPPORT_AHA
328 aws_send_aha_probe_req();
329 #endif
330 }
331
332 /* channel lock */
333 awss_debug("[channel scanning] %d ms\r\n",
334 time_elapsed_ms_since(aws_start_timestamp));
335 /*
336 * make sure switch to locked channel,
337 * in case of inconsistent with aws_cur_chn
338 */
339 #ifdef AWSS_SUPPORT_APLIST
340 if (aws_state != AWS_SUCCESS)
341 aws_try_adjust_chan();
342 #endif
343 awss_debug("final channel %d\r\n", aws_locked_chn);
344
345 while (aws_state != AWS_SUCCESS) {
346 awss_update_config_press();
347 /* 80211 frame handled by callback */
348 HAL_SleepMs(300);
349
350 if (aws_stop == AWS_STOPPING) {
351 goto timeout_recving;
352 }
353 #ifdef AWSS_SUPPORT_APLIST
354 aws_try_adjust_chan();
355 #endif
356 if (aws_is_chnscan_timeout() == CHNSCAN_TIMEOUT) {
357 goto timeout_recving;
358 }
359
360 if (aws_state == AWS_SCANNING) {
361 awss_debug("channel rescanning...\n");
362 if (zconfig_data != NULL) {
363 void *temp_mutex = zc_mutex;
364 memset(zconfig_data, 0, sizeof(struct zconfig_data));
365 zc_mutex = temp_mutex;
366 }
367 goto rescanning;
368 }
369 }
370
371 awss_debug("[channel recving] %d ms\r\n",
372 time_elapsed_ms_since(aws_start_timestamp));
373 goto success;
374
375 timeout_scanning:
376 awss_debug("aws timeout scanning!\r\n");
377 timeout_recving:
378 awss_debug("aws timeout recving!\r\n");
379 do {
380 if (aws_stop == AWS_STOPPING) {
381 break;
382 }
383 HAL_Awss_Close_Monitor();
384 zconfig_sleep_before_rescan();
385 } while (0);
386
387 if (aws_stop == AWS_STOPPING) { /* interrupt by user */
388 aws_stop = AWS_STOPPED;
389 goto success;
390 }
391
392 aws_state = AWS_SCANNING;
393
394 aws_start_timestamp = os_get_time_ms();
395 HAL_Awss_Open_Monitor(aws_80211_frame_handler);
396 goto rescanning;
397
398 success:
399 /* don't destroy zconfig_data until monitor_cb is finished. */
400 awss_trace("ready to call zconfig_destroy to release mem \r\n");
401 printf("ready to call zconfig_destroy to release mem \r\n");
402 /*
403 * zconfig_destroy() after os_awss_monitor_close() beacause
404 * zconfig_destroy will release mem/buffer that
405 * zconfig_recv_callback will use
406 *
407 * Note: hiflying will reboot after calling this func, so
408 * aws_get_ssid_passwd() was called in os_awss_monitor_close()
409 */
410 if (aws_stop == AWS_STOPPED) {
411 awss_trace("zconfig mem released \r\n");
412 zconfig_force_destroy();
413 }
414 #if defined(AWSS_SUPPORT_AHA)
415 else if (strcmp((const char *)aws_result_ssid,
416 (const char *)zc_default_ssid) == 0) {
417 zconfig_destroy();
418 }
419 #endif
420 else {
421 zconfig_force_destroy();
422 }
423 }
424
aws_80211_frame_handler(char * buf,int length,enum AWSS_LINK_TYPE link_type,int with_fcs,signed char rssi)425 int aws_80211_frame_handler(char *buf, int length,
426 enum AWSS_LINK_TYPE link_type, int with_fcs,
427 signed char rssi)
428 {
429 static uint32_t lock_start;
430
431 int ret = zconfig_recv_callback(buf, length, aws_cur_chn, link_type,
432 with_fcs, rssi);
433
434 if (aws_state == AWS_CHN_LOCKED) {
435 switch (ret) {
436 case PKG_START_FRAME:
437 case PKG_DATA_FRAME:
438 case PKG_GROUP_FRAME:
439 case PKG_MCAST_FRAME:
440 lock_start = os_get_time_ms();
441 break;
442 default:
443 /* set to rescanning */
444 if (time_elapsed_ms_since(lock_start) >
445 aws_channel_lock_timeout_ms) {
446 aws_state = AWS_SCANNING;
447 }
448 break;
449 }
450 }
451
452 return ret;
453 }
454
aws_start(char * pk,char * dn,char * ds,char * ps)455 void aws_start(char *pk, char *dn, char *ds, char *ps)
456 {
457 aws_info = awss_zalloc(sizeof(struct aws_info));
458 if (!aws_info) {
459 return;
460 }
461
462 aws_state = AWS_SCANNING;
463
464 /* start from -1 */
465 aws_chn_index = 0xff;
466 memcpy(aws_chn_list, aws_fixed_scanning_channels,
467 sizeof(aws_fixed_scanning_channels));
468
469 memset(aws_result_ssid, 0, sizeof(aws_result_ssid));
470 memset(aws_result_passwd, 0, sizeof(aws_result_passwd));
471 memset(aws_result_bssid, 0, sizeof(aws_result_bssid));
472 aws_result_auth = ZC_AUTH_TYPE_INVALID;
473 aws_result_encry = ZC_ENC_TYPE_INVALID;
474 aws_result_channel = 0;
475
476 zconfig_init();
477
478 HAL_Awss_Open_Monitor(aws_80211_frame_handler);
479 #ifndef AWSS_DISABLE_ENROLLEE
480 awss_init_enrollee_info();
481 #endif
482 aws_main_thread_func();
483 }
484
485 static void *aws_mutex = NULL;
486
aws_destroy(void)487 void aws_destroy(void)
488 {
489 if (aws_mutex == NULL) {
490 aws_mutex = HAL_MutexCreate();
491 }
492 if (aws_mutex) {
493 HAL_MutexLock(aws_mutex);
494 }
495
496 if (aws_info == NULL) {
497 HAL_MutexUnlock(aws_mutex);
498 return;
499 }
500
501 if (aws_stop == AWS_STOPPED) {
502 HAL_MutexUnlock(aws_mutex);
503 return;
504 }
505
506 HAL_Awss_Close_Monitor();
507 awss_trace("aws_destroy \r\n");
508 aws_stop = AWS_STOPPING;
509
510 while (aws_stop != AWS_STOPPED) {
511 if (aws_state == AWS_SUCCESS) {
512 break;
513 }
514 HAL_SleepMs(100);
515 }
516 if (NULL != aws_info) {
517 HAL_Free(aws_info);
518 }
519 aws_info = NULL;
520
521 #ifndef AWSS_DISABLE_ENROLLEE
522 awss_destroy_enrollee_info();
523 #endif
524 if (aws_mutex) {
525 HAL_MutexUnlock(aws_mutex);
526 }
527 }
528
aws_release_mutex()529 void aws_release_mutex()
530 {
531 if (aws_mutex) {
532 HAL_MutexDestroy(aws_mutex);
533 aws_mutex = NULL;
534 }
535 }
536
aws_get_ssid_passwd(char * ssid,char * passwd,uint8_t * bssid,uint8_t * token,char * auth,char * encry,uint8_t * channel)537 int aws_get_ssid_passwd(char *ssid, char *passwd, uint8_t *bssid,
538 uint8_t *token, char *auth, char *encry,
539 uint8_t *channel)
540 {
541 if (aws_state != AWS_SUCCESS) {
542 return 0;
543 }
544 if (ssid) {
545 strncpy((char *)ssid, (const char *)aws_result_ssid,
546 ZC_MAX_SSID_LEN - 1);
547 }
548 if (passwd) {
549 strncpy((char *)passwd, (const char *)aws_result_passwd,
550 ZC_MAX_PASSWD_LEN - 1);
551 }
552 if (bssid) {
553 memcpy(bssid, aws_result_bssid, ETH_ALEN);
554 }
555 if (token) {
556 memcpy(token, aws_result_token, ZC_MAX_TOKEN_LEN);
557 }
558 if (auth) {
559 *auth = aws_result_auth;
560 }
561 if (encry) {
562 *encry = aws_result_encry;
563 }
564 if (channel) {
565 *channel = aws_result_channel;
566 }
567 return 1;
568 }
569
570 #if defined(AWSS_SUPPORT_SMARTCONFIG_MCAST) || defined(AWSS_SUPPORT_SMARTCONFIG)
571 const uint8_t zconfig_fixed_offset[ZC_ENC_TYPE_MAX + 1][2] = {
572 { /* open, none, ip(20) + udp(8) + 8(LLC) */
573 36, 36 },
574 {
575 /* wep, + iv(4) + data + ICV(4) */
576 44, 44 /* feixun, wep64(10byte), wep128(26byte) */
577 },
578 {
579 /* tkip, + iv/keyID(4) + Ext IV(4) + data + MIC(8) + ICV(4) */
580 56, 56 /* tkip(10byte, 20byte), wpa2+tkip(20byte) */
581 },
582 { /* aes, + ccmp header(8) + data + MIC(8) + ICV(4) */
583 52, 52 },
584 {
585 /* tkip-aes */
586 56, 52 /* fromDs==tkip,toDs==aes */
587 }
588 };
589 #endif
590
591 #if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
592 }
593 #endif
594