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