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