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 
10 /* broadcast mac address */
11 uint8_t br_mac[ETH_ALEN];
12 /* all zero mac address */
13 uint8_t zero_mac[ETH_ALEN];
14 
15 /* which channel lock at */
16 uint8_t zconfig_channel_locked = INVALID_CHANNEL; /* locked channel */
17 /*
18  * avoid zconfig_callback_over() was called twice,
19  * once from tods, once from fromds
20  */
21 uint8_t zconfig_finished;
22 
23 /* global data structure, which hold all broadcast data */
24 struct zconfig_data *zconfig_data;
25 
26 /*
27  * 8bit -> x bit
28  *
29  * serialize chinese char from 8bit to x bit
30  */
encode_chinese(uint8_t * in,uint8_t in_len,uint8_t * out,uint8_t * out_len,uint8_t bits)31 void encode_chinese(uint8_t *in, uint8_t in_len, uint8_t *out, uint8_t *out_len,
32                     uint8_t bits)
33 {
34     if (bits == 0 || bits > 7) {
35         return;
36     }
37 
38     do {
39         uint8_t i, j;
40         uint8_t bit[ZC_MAX_SSID_LEN * 8] = { 0 };
41         uint8_t output_len = ((in_len * 8) + bits - 1) / bits;
42 
43         /* char to bit stream */
44         for (i = 0; i < in_len; i++) {
45             for (j = 0; j < 8; j++) {
46                 bit[i * 8 + j] = (in[i] >> j) & 0x01;
47             }
48         }
49 
50         out[output_len] = '\0'; /* NULL-terminated */
51         for (i = 0; i < output_len; i++) {
52             for (j = 0, out[i] = 0; j < bits; j++) {
53                 out[i] |= bit[i * bits + j] << j;
54             }
55         }
56 
57         if (out_len) {
58             *out_len = output_len;
59         }
60     } while (0);
61 }
62 
63 /* x bit -> 8bit */
decode_chinese(uint8_t * in,uint8_t in_len,uint8_t * out,uint8_t * out_len,uint8_t bits)64 void decode_chinese(uint8_t *in, uint8_t in_len, uint8_t *out, uint8_t *out_len,
65                     uint8_t bits)
66 {
67     if (bits == 0 || bits > 7 || in_len == 0) {
68         return;
69     }
70 
71     do {
72         uint8_t i, j;
73         uint8_t output_len = (in_len * bits) / 8;
74         uint8_t *bit = (uint8_t *)awss_zalloc(in_len * bits);
75 
76         if (bit == NULL) {
77             awss_crit("decode malloc failed!\r\n");
78             return;
79         }
80 
81         /* char to bit stream */
82         for (i = 0; i < in_len; i++) {
83             for (j = 0; j < bits; j++) {
84                 bit[i * bits + j] = (in[i] >> j) & 0x01;
85             }
86         }
87 
88         out[output_len] = '\0'; /* NULL-terminated */
89         for (i = 0; i < output_len; i++) {
90             for (j = 0, out[i] = 0; j < 8; j++) {
91                 out[i] |= bit[i * 8 + j] << j;
92             }
93         }
94 
95         HAL_Free(bit);
96         if (out_len) {
97             *out_len = output_len;
98         }
99     } while (0);
100 }
101 
102 /*
103  * 1/locked, 0/not locked
104  */
is_channel_locked(void)105 uint8_t is_channel_locked(void)
106 {
107     return zconfig_channel_locked != INVALID_CHANNEL;
108 }
109 
110 /*
111  * Note: this notification will be kept called, in case of
112  *     user clear the channel locked state to re-scanning
113  *    channel because of waiting timeout.
114  */
zconfig_callback_channel_locked(uint8_t channel)115 uint8_t zconfig_callback_channel_locked(uint8_t channel)
116 {
117     if (channel != zconfig_channel_locked) {
118         awss_info("channel lock @ %d\r\n", channel);
119         zconfig_channel_locked = channel;
120     }
121 
122     /*
123      * if recv timeout, vendor may re-scanning channel,
124      * so keep calling channel locked notification here.
125      */
126     zconfig_channel_locked_callback(channel, 0, zc_bssid);
127 
128     return 0;
129 }
130 
zconfig_callback_over(uint8_t * ssid,uint8_t * passwd,uint8_t * bssid,uint8_t * token)131 uint8_t zconfig_callback_over(uint8_t *ssid, uint8_t *passwd, uint8_t *bssid,
132                               uint8_t *token)
133 {
134     uint8_t auth = ZC_AUTH_TYPE_INVALID, encry = ZC_ENC_TYPE_INVALID,
135             channel = 0;
136 
137     awss_info("zconfig done. ssid:%s, mac:%02x%02x%02x%02x%02x%02x\r\n", ssid,
138               bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
139 
140     if (zconfig_finished) {
141         return 0;
142     }
143 
144 #ifdef AWSS_SUPPORT_APLIST
145     awss_get_auth_info(ssid, bssid, &auth, &encry, &channel);
146 #endif
147 
148     zconfig_got_ssid_passwd_callback(ssid, passwd, bssid, token, auth, encry,
149                                      channel);
150 
151     zconfig_finished = 1;
152 
153     return 0;
154 }
155 
zconfig_set_state(uint8_t state,uint8_t tods,uint8_t channel)156 void zconfig_set_state(uint8_t state, uint8_t tods, uint8_t channel)
157 {
158     /* state change callback */
159     switch (state) {
160     case STATE_CHN_SCANNING:
161         break;
162     case STATE_CHN_LOCKED_BY_P2P:
163         /* locked state used by action/wps frame */
164         zconfig_callback_channel_locked(channel);
165         break;
166     case STATE_CHN_LOCKED_BY_BR:
167     case STATE_CHN_LOCKED_BY_MCAST:
168         /* locked state used by br frame */
169         zconfig_callback_channel_locked(zc_channel ? zc_channel : channel);
170         break;
171     case STATE_RCV_DONE:
172         /* prevent main_thread_func to free zconfig_data until curent task is
173          * finished. */
174         HAL_MutexLock(zc_mutex);
175         /*
176          * in case of p2p/router, direct into RCV_DONE state,
177          * skiped the chn lock state, so better to call channel lock here
178          */
179         if (!is_channel_locked()) {
180             zconfig_callback_channel_locked(channel);
181         }
182         zconfig_callback_over(zc_ssid, zc_passwd, zc_bssid, zc_token);
183         break;
184     default:
185         break;
186     }
187 
188     /*
189      * state machine loop:
190      * scanning -> p2p lock -> rcv_done
191      * scanning -> (p2p) rcv_done
192      * scanning -> br lock -> (br) rcv_done
193      * scanning -> br lock -> (p2p) recv_done
194      * scanning -> p2p lock -> br lock -> (br) recv_done
195      *
196      * watch out zc_state rolling back.
197      * zconfig_set_state(CHN_LOCKED) will be called more than once,
198      */
199     if (zc_state < state) {
200         zc_state = state;
201     }
202     if (state == STATE_RCV_DONE) {
203         HAL_MutexUnlock(zc_mutex);
204     }
205 }
206 
207 /*
208     pkt_data & pkt_length:
209         radio_hdr + 80211 hdr + payload, without fcs(4B)
210     return:
211         PKG_INVALID -- invalid pkt,
212         PKG_START_FRAME -- start frame,
213         PKG_DATA_FRAME -- data frame,
214         PKG_ALINK_ROUTER -- alink router,
215         PKG_GROUP_FRAME -- group frame,
216         PKG_BC_FRAME -- broadcast frame
217 */
is_invalid_pkg(void * pkt_data,uint32_t pkt_length)218 int is_invalid_pkg(void *pkt_data, uint32_t pkt_length)
219 {
220 #define MIN_PKG (33)
221 #define MAX_PKG (1480 + 56 + 200)
222     if (pkt_length < MIN_PKG || pkt_length > MAX_PKG) {
223         return 1;
224     }
225     return 0;
226 }
227 
228 /*
229  * zconfig_recv_callback()
230  *
231  * ieee80211 package parser
232  *
233  * @Return:
234  *     zconfig state
235  */
zconfig_recv_callback(void * pkt_data,uint32_t pkt_length,uint8_t channel,int link_type,int with_fcs,signed char rssi)236 int zconfig_recv_callback(void *pkt_data, uint32_t pkt_length, uint8_t channel,
237                           int link_type, int with_fcs, signed char rssi)
238 {
239     int pkt_type = PKG_INVALID;
240     struct parser_res res;
241     memset(&res, 0, sizeof(res));
242 
243     /* remove FCS filed */
244     if (with_fcs) {
245         pkt_length -= 4;
246     }
247 
248     /* useless, will be removed */
249     if (is_invalid_pkg(pkt_data, pkt_length)) {
250         printf("ethan: invalid packet\r\n");
251         return PKG_INVALID;
252     }
253 
254     res.channel = channel;
255 
256     pkt_type =
257         ieee80211_data_extract(pkt_data, pkt_length, link_type, &res, rssi);
258 
259     return pkt_type;
260 }
261 
262 /* init mem */
zconfig_init()263 void zconfig_init()
264 {
265     awss_info("%s\r\n", __func__);
266 
267     zconfig_channel_locked = INVALID_CHANNEL;
268     zconfig_finished = 0;
269 
270     memset(br_mac, 0xff, ETH_ALEN);
271     memset(zero_mac, 0x00, ETH_ALEN);
272 
273     zconfig_data =
274         (struct zconfig_data *)awss_zalloc(sizeof(struct zconfig_data));
275     if (zconfig_data == NULL) {
276         goto ZCONFIG_INIT_FAIL;
277     }
278     zc_mutex = HAL_MutexCreate();
279     if (zc_mutex == NULL) {
280         goto ZCONFIG_INIT_FAIL;
281     }
282 
283 #ifdef AWSS_SUPPORT_APLIST
284     if (awss_init_ieee80211_aplist()) {
285         goto ZCONFIG_INIT_FAIL;
286     }
287 #endif
288 
289 #ifdef AWSS_SUPPORT_HT40
290     ht40_init();
291 #endif
292     return;
293 
294 ZCONFIG_INIT_FAIL:
295     awss_crit("malloc failed!\r\n");
296     zconfig_destroy();
297 
298 #ifdef AWSS_SUPPORT_APLIST
299     awss_deinit_ieee80211_aplist();
300 #endif
301     return;
302 }
303 
zconfig_destroy(void)304 void zconfig_destroy(void)
305 {
306     if (zconfig_data) {
307         if (zc_mutex) {
308             HAL_MutexDestroy(zc_mutex);
309         }
310         HAL_Free((void *)zconfig_data);
311         zconfig_data = NULL;
312     }
313 }
314 
zconfig_force_destroy(void)315 void zconfig_force_destroy(void)
316 {
317     zconfig_destroy();
318 
319 #ifdef AWSS_SUPPORT_APLIST
320     awss_deinit_ieee80211_aplist();
321 #endif
322 }
323 
zconfig_is_valid_channel(int channel)324 int zconfig_is_valid_channel(int channel)
325 {
326     return (ZC_MIN_CHANNEL <= channel && channel <= ZC_MAX_CHANNEL);
327 }
328 
329 #if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
330 }
331 #endif
332