1 #include "wifi_provision_internal.h"
2
3 #if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
4 extern "C" {
5 #endif
6 #ifndef DISABLE_SMARTCONFIG_MCAST
7
8 #define SUCCESS_RETURN (0)
9 #define FAILURE_RETURN (-1)
10 static int processed_packet = 0;
11 static uint8_t mcast_bssid_mac[ETH_ALEN] = { 0 };
12 static uint8_t mcast_src_mac[ETH_ALEN] = { 0 };
13 static int mcast_locked_channel = -1;
14 static struct mcast_smartconfig_data_type mcast_smartconfig_data = { 0 };
15 static uint8_t receive_record[MCAST_MAX_LEN] = { 0 };
16
reset_mcast_data()17 void reset_mcast_data()
18 {
19 processed_packet = 0;
20 memset(mcast_bssid_mac, 0, ETH_ALEN);
21 memset(mcast_src_mac, 0, ETH_ALEN);
22 mcast_locked_channel = -1;
23 memset(&(mcast_smartconfig_data), 0,
24 sizeof(struct mcast_smartconfig_data_type));
25 memset(receive_record, 0, MCAST_MAX_LEN);
26 }
27
mcast_receive_done()28 int mcast_receive_done()
29 {
30 int iter = 0;
31 while (iter < mcast_smartconfig_data.tlen) {
32 if (0 == receive_record[iter++]) {
33 return FAILURE_RETURN;
34 }
35 }
36 return SUCCESS_RETURN;
37 }
38
decode_passwd()39 int decode_passwd()
40 {
41 int passwd_len = 0;
42 /* CAN'T use snawss_debug here, because of SPACE char */
43 passwd_len = mcast_smartconfig_data.passwd_len;
44 memset(zc_passwd, 0, ZC_MAX_PASSWD_LEN);
45 aes_decrypt_string((char *)(mcast_smartconfig_data.passwd),
46 (char *)zc_passwd, passwd_len, 1,
47 awss_get_encrypt_type(), 0, NULL);
48 if (is_utf8((const char *)zc_passwd, passwd_len) == 0) {
49 awss_trace("passwd err\r\n");
50 awss_event_post(IOTX_AWSS_PASSWD_ERR);
51 AWSS_UPDATE_STATIS(AWSS_STATIS_SM_IDX, AWSS_STATIS_TYPE_PASSWD_ERR);
52 return FAILURE_RETURN;
53 }
54 return SUCCESS_RETURN;
55 }
56
verify_checksum()57 int verify_checksum()
58 {
59 int ret = 0;
60 uint16_t cal_crc = zconfig_checksum_v5(&(mcast_smartconfig_data.data[0]),
61 mcast_smartconfig_data.tlen - 1);
62 uint8_t crc = mcast_smartconfig_data.checksum;
63 cal_crc = (cal_crc & 0xFF);
64 ret = cal_crc - crc;
65 awss_debug("mcast: verify checksum diff is %d, cal_crc, crc is %d,%d\n",
66 ret, cal_crc, crc);
67 return ret;
68 }
69
set_zc_ssid(int valid_bssid)70 void set_zc_ssid(int valid_bssid)
71 {
72 #ifdef AWSS_SUPPORT_APLIST
73 do { /* amend SSID automatically */
74 struct ap_info *ap = NULL;
75 if (SUCCESS_RETURN != valid_bssid) {
76 break;
77 }
78 ap = zconfig_get_apinfo(zc_bssid);
79 if (ap == NULL || ap->ssid[0] == '\0') {
80 break;
81 }
82 strncpy((char *)zc_ssid, (const char *)ap->ssid, ZC_MAX_SSID_LEN - 1);
83 return;
84 } while (0);
85 #endif
86 /* if we can't find ssid form aplist, we should take the default one */
87 strncpy((char *)zc_ssid, (char const *)mcast_smartconfig_data.ssid,
88 mcast_smartconfig_data.ssid_len);
89 return;
90 }
91
set_zc_bssid()92 int set_zc_bssid()
93 {
94 /* compare the last 3 bytes of bssid from apist with the one from app */
95 if (!memcmp(mcast_smartconfig_data.bssid, (uint8_t *)mcast_bssid_mac + 3,
96 3)) {
97 memcpy(zc_bssid, mcast_bssid_mac, ETH_ALEN);
98 awss_debug("mcast_bssid_mac from aplist");
99 return SUCCESS_RETURN;
100 } else {
101 #ifdef AWSS_SUPPORT_APLIST
102 struct ap_info *ap_info =
103 zconfig_get_apinfo_by_3_byte_mac(mcast_smartconfig_data.bssid);
104 if (NULL != ap_info) {
105 memcpy(zc_bssid, ap_info->mac, 6);
106 awss_debug("bssid1: bssid is %x,%x,%x,%x,%x,%x", zc_bssid[0],
107 zc_bssid[1], zc_bssid[2], zc_bssid[3], zc_bssid[4],
108 zc_bssid[5]);
109 return SUCCESS_RETURN;
110 }
111 #endif
112 }
113 return -1;
114 }
115
gen16ByteToken()116 void gen16ByteToken()
117 {
118 int bssid_len = mcast_smartconfig_data.bssid_type_len & 0x1f;
119 awss_complete_token((char *)zc_passwd, mcast_smartconfig_data.bssid,
120 bssid_len, mcast_smartconfig_data.token,
121 mcast_smartconfig_data.token_len, zc_token);
122 }
123
parse_result()124 int parse_result()
125 {
126 int offset = 0;
127 int ret, valid_bssid;
128 uint8_t BIT0_passwd = 0;
129 uint8_t BIT1_ssid = 0;
130 uint8_t BIT2_token = 0;
131 uint8_t BIT6_7_version = 0;
132
133 awss_debug("mcast: tlen is %d\n", mcast_smartconfig_data.tlen);
134 mcast_smartconfig_data.flag = mcast_smartconfig_data.data[1];
135 offset = 2;
136 awss_debug("mcast: flag is %d\n", mcast_smartconfig_data.flag);
137
138 BIT0_passwd = 0x1 & mcast_smartconfig_data.flag;
139 BIT1_ssid = 0x1 & (mcast_smartconfig_data.flag >> 1);
140 BIT2_token = 0x1 & (mcast_smartconfig_data.flag >> 2);
141 BIT6_7_version = 0x3 & (mcast_smartconfig_data.flag >> 6);
142
143 if (0x3 != BIT6_7_version) {
144 awss_err("error version");
145 return -1;
146 }
147
148 if (1 == BIT0_passwd) {
149 mcast_smartconfig_data.passwd_len = mcast_smartconfig_data.data[2];
150 awss_debug("mcast: passwd_len is %d\n",
151 mcast_smartconfig_data.passwd_len);
152 mcast_smartconfig_data.passwd = &(mcast_smartconfig_data.data[3]);
153 offset = 3 + mcast_smartconfig_data.passwd_len;
154 }
155
156 if (1 == BIT2_token) {
157 mcast_smartconfig_data.token_len = mcast_smartconfig_data.data[offset];
158 awss_debug("mcast: token_len is %d\n",
159 mcast_smartconfig_data.token_len);
160 offset++;
161 mcast_smartconfig_data.token = &(mcast_smartconfig_data.data[offset]);
162 awss_debug("mcast: token is %.*s\n", mcast_smartconfig_data.token_len,
163 mcast_smartconfig_data.token);
164 offset += mcast_smartconfig_data.token_len;
165 }
166
167 if (1 == BIT1_ssid) {
168 mcast_smartconfig_data.ssid_len = mcast_smartconfig_data.data[offset];
169 awss_debug("mcast: ssid_len is %d\n", mcast_smartconfig_data.ssid_len);
170 offset++;
171 mcast_smartconfig_data.ssid = &(mcast_smartconfig_data.data[offset]);
172 awss_debug("mcast: ssid is %.*s\n", mcast_smartconfig_data.ssid_len,
173 mcast_smartconfig_data.ssid);
174 offset += mcast_smartconfig_data.ssid_len;
175 }
176
177 mcast_smartconfig_data.bssid_type_len = mcast_smartconfig_data.data[offset];
178 awss_debug("mcast: bssid_type_len is %d\n",
179 mcast_smartconfig_data.bssid_type_len);
180 offset++;
181 mcast_smartconfig_data.bssid = &(mcast_smartconfig_data.data[offset]);
182 /* get bssid len from last 5 bits from bssid_type_len */
183 offset += mcast_smartconfig_data.bssid_type_len & 0x1f;
184 mcast_smartconfig_data.checksum = mcast_smartconfig_data.data[offset];
185 awss_debug("mcast: checksum is %d\n", mcast_smartconfig_data.checksum);
186 awss_debug("mcast: total processed %d packagets\n", processed_packet);
187
188 /* set zc_bssid*/
189 valid_bssid = set_zc_bssid();
190 /* set zc_ssid */
191 set_zc_ssid(valid_bssid);
192 ret = verify_checksum();
193 if (SUCCESS_RETURN != ret) {
194 awss_err("mcast: checksum mismatch\n");
195 return -1;
196 }
197 ret = decode_passwd();
198 gen16ByteToken();
199 reset_mcast_data();
200 if (SUCCESS_RETURN != ret) {
201 awss_err("mcast: passwd error\n");
202 return -1;
203 }
204 /* TODO: check channel info*/
205 zconfig_set_state(STATE_RCV_DONE, 0, mcast_locked_channel);
206 return SUCCESS_RETURN;
207 }
208
awss_ieee80211_mcast_smartconfig_process(uint8_t * ieee80211,int len,int link_type,struct parser_res * res,signed char rssi)209 int awss_ieee80211_mcast_smartconfig_process(uint8_t *ieee80211, int len,
210 int link_type,
211 struct parser_res *res,
212 signed char rssi)
213 {
214 int hdrlen, fc, seq_ctrl;
215 struct ieee80211_hdr *hdr;
216 uint8_t *data, *bssid_mac, *dst_mac;
217 uint8_t encry = ZC_ENC_TYPE_INVALID;
218 uint8_t tods;
219
220 /*
221 * when device try to connect current router (include aha)
222 * skip the new packet.
223 */
224 if (ieee80211 == NULL || zconfig_finished) {
225 return ALINK_INVALID;
226 }
227
228 /*
229 * we don't process smartconfig until user press configure button
230 */
231 if (awss_get_config_press() == 0) {
232 return ALINK_INVALID;
233 }
234
235 hdr = (struct ieee80211_hdr *)ieee80211;
236 fc = hdr->frame_control;
237 seq_ctrl = hdr->seq_ctrl;
238
239 /*
240 * for smartconfig with bcast of data
241 */
242 if (!ieee80211_is_data_exact(fc)) {
243 return ALINK_INVALID;
244 }
245
246 /* tods = 1, fromds = 0 || tods = 0, fromds = 1 */
247 if (ieee80211_has_tods(fc) == ieee80211_has_fromds(fc)) {
248 return ALINK_INVALID;
249 }
250
251 /* drop frag, more, order*/
252 if (ieee80211_has_frags(fc)) {
253 return ALINK_INVALID;
254 }
255
256 dst_mac = (uint8_t *)ieee80211_get_DA(hdr);
257 /* only multicast is passed */
258 if (0x1 != dst_mac[0] || 0x0 != dst_mac[1] || 0x5e != dst_mac[2]) {
259 #ifdef VERBOSE_MCAST_DEBUG
260 awss_debug("error type, %x, %x, %x\n", dst_mac[0], dst_mac[1],
261 dst_mac[2]);
262 #endif
263 return ALINK_INVALID; /* only handle br frame */
264 }
265
266 bssid_mac = (uint8_t *)ieee80211_get_BSSID(hdr);
267
268 /*
269 * payload len = frame.len - (radio_header + wlan_hdr)
270 */
271 hdrlen = ieee80211_hdrlen_2(fc);
272 if (hdrlen > len) {
273 return ALINK_INVALID;
274 }
275
276 #ifdef _PLATFORM_QCOM_
277 /* Note: http://stackoverflow.com/questions/17688710/802-11-qos-data-frames
278 */
279 hdrlen = (hdrlen + 3) & 0xFC; /* align header to 32bit boundary */
280 #endif
281
282 res->u.br.data_len = len - hdrlen; /* eating the hdr */
283 res->u.br.sn = IEEE80211_SEQ_TO_SN(os_le16toh(seq_ctrl));
284
285 data = ieee80211 + hdrlen; /* eating the hdr */
286 tods = ieee80211_has_tods(fc);
287
288 do {
289 #ifdef AWSS_SUPPORT_APLIST
290 struct ap_info *ap_info;
291 ap_info = zconfig_get_apinfo(bssid_mac);
292 if (ap_info && ZC_ENC_TYPE_INVALID != ap_info->encry[tods]) {
293 encry = ap_info->encry[tods];
294 } else {
295 #endif
296 if (!ieee80211_has_protected(fc)) {
297 encry = ZC_ENC_TYPE_NONE;
298 } else {
299 /* Note: avoid empty null data */
300 if (len < 8) { /* IV + ICV + DATA >= 8 */
301 return ALINK_INVALID;
302 }
303 if (!(ieee80211[3] & 0x3F)) {
304 encry = ZC_ENC_TYPE_WEP;
305 } else if (data[3] & (1 << 5)) { /* Extended IV */
306 if (data[1] ==
307 ((data[0] | 0x20) &
308 0x7F)) { /* tkip, WEPSeed = (TSC1 | 0x20 ) & 0x7F */
309 encry = ZC_ENC_TYPE_TKIP;
310 }
311 if (data[2] == 0 && (!(data[3] & 0x0F))) {
312 encry = ZC_ENC_TYPE_AES;
313 }
314
315 /*
316 * Note: above code use if(tkip) and if(ase)
317 * instead of if(tkip) else if(aes)
318 * beacause two condition may bother match.
319 */
320 }
321 }
322 #ifdef AWSS_SUPPORT_APLIST
323 }
324 #endif
325 } while (0);
326
327 if (encry == ZC_ENC_TYPE_INVALID) {
328 awss_warn("invalid encry type!\r\n");
329 }
330 res->u.br.encry_type = encry;
331
332 /* convert IEEE 802.11 header + possible LLC headers into Ethernet header
333 * IEEE 802.11 address fields:
334 * ToDS FromDS Addr1 Addr2 Addr3 Addr4
335 * 0 0 DA SA BSSID n/a
336 * 0 1 DA BSSID SA n/a
337 * 1 0 BSSID SA DA n/a
338 * 1 1 RA TA DA SA
339 */
340 res->src = ieee80211_get_SA(hdr);
341 res->dst = ieee80211_get_DA(hdr);
342 res->bssid = ieee80211_get_BSSID(hdr);
343 res->tods = ieee80211_has_tods(fc);
344
345 return ALINK_BROADCAST;
346 }
347
348 static int get_all = 0;
349 int find_channel_from_aplist = 0;
350
lock_mcast_channel(struct parser_res * res,int encry_type)351 int lock_mcast_channel(struct parser_res *res, int encry_type)
352 {
353 #ifdef AWSS_SUPPORT_APLIST
354 /* fix channel with apinfo if exist, otherwise return anyway. */
355 do {
356 struct ap_info *ap_info = zconfig_get_apinfo(res->bssid);
357 extern void aws_set_dst_chan(int channel);
358 int tods = res->tods;
359
360 if (ap_info && ap_info->encry[tods] == encry_type && ap_info->channel) {
361 if (res->channel != ap_info->channel) {
362 awss_info("fix channel from %d to %d\r\n", res->channel,
363 ap_info->channel);
364 zc_channel = ap_info->channel; /* fix by ap_info channel */
365 aws_set_dst_chan(zc_channel);
366 }
367 } else {
368 /* warning: channel may eq 0! */
369 };
370
371 find_channel_from_aplist = 1;
372 zconfig_set_state(STATE_CHN_LOCKED_BY_MCAST, 0, res->channel);
373 mcast_locked_channel = res->channel;
374 } while (0);
375 #endif
376 return SUCCESS_RETURN;
377 }
378
awss_recv_callback_mcast_smartconfig(struct parser_res * res)379 int awss_recv_callback_mcast_smartconfig(struct parser_res *res)
380 {
381 uint8_t index = *(res->dst + 3) & (0x7f);
382 uint8_t payload1 = *(res->dst + 4);
383 uint8_t payload2 = *(res->dst + 5);
384 uint8_t frame_offset;
385 uint16_t len;
386 uint8_t encry_type;
387
388 /* since put 2 bytes one time, so it has to mulitplied by 2 */
389 index = index << 1;
390 if (1 == get_all) {
391 return FAILURE_RETURN;
392 }
393
394 if (index > MCAST_MAX_LEN) {
395 #ifdef VERBOSE_MCAST_DEBUG
396 awss_debug("error index\n");
397 #endif
398 return FAILURE_RETURN;
399 }
400 len = res->u.br.data_len;
401 encry_type = res->u.br.encry_type;
402
403 frame_offset = zconfig_fixed_offset[encry_type][0];
404
405 len -= frame_offset;
406 if (len != 1) {
407 #ifdef VERBOSE_MCAST_DEBUG
408 awss_debug("error len, len is %d\n", len);
409 #endif
410 return FAILURE_RETURN;
411 }
412 /* Filter out interference */
413 /*
414 * 1) src not equal, bssid equal, interference
415 * 2) src not equal, bssid not equal, interference
416 * 3) src equal, bssid equal, good, go on
417 * 4) src equal, bssid not equal
418 */
419
420 if (!memcmp(mcast_src_mac, zero_mac, ETH_ALEN)) {
421 memcpy(mcast_bssid_mac, res->bssid, ETH_ALEN);
422 memcpy(mcast_src_mac, res->src, ETH_ALEN);
423 } else {
424 /* case 1, 2 */
425 if (memcmp(mcast_src_mac, res->src, ETH_ALEN)) {
426 return FAILURE_RETURN;
427 }
428 }
429
430 /* lock channel */
431 if (0 == find_channel_from_aplist) {
432 lock_mcast_channel(res, encry_type);
433 }
434 processed_packet++;
435
436 awss_debug("mcast: index is %d, %d, %d, %d\n", index, payload1, payload2,
437 len);
438
439 mcast_smartconfig_data.data[index] = payload1;
440 receive_record[index] = 1;
441 index++;
442 mcast_smartconfig_data.data[index] = payload2;
443 receive_record[index] = 1;
444
445 if (0 != receive_record[0]) {
446 int remain = -1;
447 mcast_smartconfig_data.tlen = mcast_smartconfig_data.data[0];
448 remain = mcast_receive_done();
449 if (0 == remain) {
450 get_all = 1;
451 parse_result();
452 }
453 }
454 return PKG_MCAST_FRAME;
455 }
456 #endif
457 #if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
458
459 #endif
460