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