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 
7 /* following is broadcast protocol related code */
is_start_frame(uint16_t len)8 uint8_t is_start_frame(uint16_t len)
9 {
10     return (len == START_FRAME);
11 }
12 
is_group_frame(uint16_t len)13 uint8_t is_group_frame(uint16_t len)
14 {
15     /* is group frame? */
16     return (len > GROUP_FRAME && len <= GROUP_FRAME_END);
17 }
18 
is_data_frame(uint16_t len)19 uint8_t is_data_frame(uint16_t len)
20 {
21     uint8_t group_frame, index;
22     /* is start frame */
23     if (is_start_frame(len)) {
24         return 0;
25     }
26 
27     /* is group frame? */
28     group_frame = is_group_frame(len);
29     if (group_frame) {
30         return 0;
31     }
32 
33     index = (len >> PAYLOAD_BITS_CNT) & 0xF;
34     return (index >= ZC_GRP_PKT_IDX_START && index <= ZC_GRP_PKT_IDX_END);
35 }
36 
get_group_index(uint16_t len)37 uint8_t get_group_index(uint16_t len)
38 {
39     if (is_start_frame(len)) {
40         return 0;
41     }
42 
43     return (len - GROUP_FRAME) * GROUP_NUMBER;
44 }
45 
get_data_index(uint16_t len)46 uint8_t get_data_index(uint16_t len)
47 {
48     uint8_t index = (len >> PAYLOAD_BITS_CNT) & 0xF; /* from 2 to 9 */
49     return index - (ZC_GRP_PKT_IDX_START - 1);       /* adjust, from 1 to 8 */
50 }
51 
52 #define sn_minus(a, b) (((a) - (b)) & 0xfff)
53 
54 /* a, b must be serial seq number */
sn_compare(uint16_t a,uint16_t b)55 static int sn_compare(uint16_t a, uint16_t b)
56 {
57     /*
58         case1: sn = 3, sn_prev = 5;            a < b
59         case2: sn = 0, sn_prev = 0xfff;        a > b
60         case3: sn = 4, sn_prev = 3;            a > b
61     */
62     uint16_t res = sn_minus(a, b);
63 
64     return res < 1000 ? res : -1;
65 }
66 
67 /*
68  * zconfig_get_data_len()
69  *     here we guess the total_len of protocl message,
70  *     base on the score of tods and fromds side.
71  */
zconfig_get_data_len(void)72 int zconfig_get_data_len(void)
73 {
74     uint8_t len; /* total len, include len(1B) & crc(2B) */
75     uint8_t score;
76 
77     /* tods > fromds */
78     if (zconfig_data->pkg[1][1].score > zconfig_data->pkg[0][1].score) {
79         len = zconfig_data->pkg[1][1].len & PAYLOAD_BITS_MASK;
80         score = zconfig_data->pkg[1][1].score;
81     } else {
82         len = zconfig_data->pkg[0][1].len & PAYLOAD_BITS_MASK;
83         score = zconfig_data->pkg[0][1].score;
84     }
85 
86     if (len && score > score_mid) {
87         /* awss_debug("zconfig_get_data_len = %d\r\n", len); */
88         goto out;
89     }
90 
91     if (zconfig_data->data[1].max_pos > zconfig_data->data[0].max_pos) {
92         len = zconfig_data->data[1].max_pos;
93     } else {
94         len = zconfig_data->data[0].max_pos;
95     }
96 out:
97     if (len < GROUP_NUMBER) {
98         return GROUP_NUMBER;
99     } else {
100         return len >= MAX_PKG_NUMS ? (MAX_PKG_NUMS - GROUP_NUMBER - 1) : len;
101     }
102 }
103 
104 /* check recv completed or not */
zconfig_recv_completed(uint8_t tods)105 int zconfig_recv_completed(uint8_t tods)
106 {
107     int i;
108     uint8_t len, flag, ssid_len, passwd_len;
109     /*
110         byte:    0    1        2    3        4        5    6
111         name:        total_len    flag    ssid_len    passwd_len    ssid    ...
112         index:        0x100        0x180    0x200        0x280        0x300
113        0x380
114     */
115     len = pkg_len(1) &
116           PAYLOAD_BITS_MASK; /* total len, include len(1B) & crc(2B) */
117     flag = pkg_len(2) & PAYLOAD_BITS_MASK;
118     if (flag & SSID_EXIST_MASK) { /* ssid exist */
119         ssid_len = pkg_len(3) & PAYLOAD_BITS_MASK;
120         passwd_len = pkg_len(4) & PAYLOAD_BITS_MASK;
121     } else {
122         ssid_len = 0;
123         passwd_len = pkg_len(3) & PAYLOAD_BITS_MASK;
124     }
125 
126     if (!len || pkg_score(1) <= score_min) {
127         /* awss_trace("len=%d, pkg_score(1)=%d\r\n", len, pkg_score(1));*/
128         return 0;
129     }
130 
131 #ifndef DISABLE_SSID_AUTO_COMPLETE
132 #define SSID_AUTO_COMPLETE_SCORE (score_max + 1)
133     /* ssid atuo-completion */
134     if (zc_ssid[0] != '\0' && (flag & SSID_EXIST_MASK) &&
135         pkg_score(2) < SSID_AUTO_COMPLETE_SCORE && pkg_score(3) > score_mid &&
136         !zc_ssid_auto_complete_disable) {
137         /* over-written ssid_len here */
138         ssid_len = strlen((char const *)zc_ssid);
139         if (ssid_len > ZC_MAX_SSID_LEN - 1) {
140             ssid_len = ZC_MAX_SSID_LEN - 1;
141         }
142 
143         if (!(flag & SSID_ENCODE_MASK)) { /* ASCLL ssid */
144             if ((ssid_len | 0x200) != pkg_len(3)) {
145                 awss_warn("ssid len not match! ssid:%s != %d\r\n", zc_ssid,
146                           (pkg_len(3) & ~0x200));
147                 zc_ssid_auto_complete_disable = 1;
148                 goto skip_ssid_auto_complete;
149             }
150 
151             awss_trace("ssid auto-complete: %s\r\n", zc_ssid);
152             pkg_score(2) = SSID_AUTO_COMPLETE_SCORE;
153 
154             pkg_len(3) = ssid_len | 0x200; /* 0x200 is the index 3 */
155             pkg_score(3) = SSID_AUTO_COMPLETE_SCORE;
156 
157             for (i = 5; i < ssid_len + 5; i++) {
158                 pkg_len(i) = (zc_ssid[i - 5] - 32) |
159                              (0x100 + 0x80 * ((i - 1) % GROUP_NUMBER));
160                 pkg_score(i) = SSID_AUTO_COMPLETE_SCORE;
161             }
162         } else if ((flag & SSID_ENCODE_MASK)) { /* include chinese ssid */
163             uint8_t *buf, buf_len = 0;
164 
165             uint8_t ssid_encode_len = (ssid_len * 8 + 5) / 6;
166 
167             /*
168              * for GBK encoded chinese, ssid auto-completion lead to crc error.
169              * because Android APP may send utf8 encoded ssid.
170              */
171             if ((ssid_encode_len | 0x200) != pkg_len(3)) {
172                 zc_ssid_is_gbk = 1;
173                 zc_ssid_auto_complete_disable = 1;
174                 goto skip_ssid_auto_complete;
175             } else {
176                 zc_ssid_is_gbk = 0;
177             }
178 
179             buf = awss_zalloc(ssid_encode_len + 1);
180             if (buf == NULL) {
181                 awss_crit("malloc failed!\r\n");
182                 return 0;
183             }
184 
185             awss_trace("chinese ssid auto-complete: %s\r\n", zc_ssid);
186             encode_chinese(zc_ssid, ssid_len, buf, &buf_len, 6);
187 
188             pkg_score(2) = SSID_AUTO_COMPLETE_SCORE;
189 
190             pkg_len(3) = buf_len | 0x200; /* 0x200 is the index 3 */
191             pkg_score(3) = SSID_AUTO_COMPLETE_SCORE;
192 
193             for (i = 5; i < buf_len + 5; i++) {
194                 pkg_len(i) =
195                     buf[i - 5] | (0x100 + 0x80 * ((i - 1) % GROUP_NUMBER));
196                 pkg_score(i) = SSID_AUTO_COMPLETE_SCORE;
197             }
198             HAL_Free(buf);
199         }
200     }
201 #endif
202 
203 skip_ssid_auto_complete:
204     /* awss_debug("expect len = %d, max len = %d\r\n", len, zc_max_pos); */
205     if (zc_max_pos < len) {
206         return 0; /* receive all the packets */
207     }
208 
209     for (i = 1; i <= len; i++) { /* check score for all the packets */
210         if (pkg_score(i) <= score_min) {
211             return 0;
212         }
213     }
214 
215     /* 4 for total_len, flag, ssid_len, passwd_len, 2 for crc */
216     if (flag & SSID_EXIST_MASK) { /* ssid exist */
217         if (len != ssid_len + passwd_len + 4 + 2) {
218             return 0;
219         }
220     } else if (len != passwd_len + 3 + 2) {
221         return 0;
222     }
223 
224     return 1;
225 }
226 
zconfig_get_ssid_passwd(uint8_t tods)227 int zconfig_get_ssid_passwd(uint8_t tods)
228 {
229     int i, ssid_len, package_num, passwd_len, ret;
230     uint8_t *buf, *pbuf, *tmp, flag, passwd_encrypt, passwd_cipher_len = 0;
231     uint16_t crc, cal_crc;
232     uint8_t data, score;
233     uint8_t tods_tmp;
234 
235     if (!zconfig_recv_completed(tods)) {
236         return -1;
237     }
238 
239     buf = awss_zalloc(256);
240     if (NULL == buf) {
241         awss_crit("malloc failed!\r\n");
242         return -1;
243     }
244     tmp = awss_zalloc(128);
245     if (NULL == tmp) {
246         HAL_Free(buf);
247         awss_crit("malloc failed!\r\n");
248         return -1;
249     }
250 
251     /* package num */
252     package_num = pkg_len(1) &
253                   PAYLOAD_BITS_MASK; /* total len, include len(1B) & crc(2B) */
254 
255     awss_trace("\r\n");
256     for (i = 1; i <= package_num; i++) {
257         data = pkg_len(i);
258         score = pkg_score(i);
259         buf[i - 1] = data & PAYLOAD_BITS_MASK;
260         tmp[i - 1] = score;
261     }
262 
263     dump_hex(&tmp[0], package_num, GROUP_NUMBER);
264     awss_trace("\r\n");
265     dump_hex(&buf[0], package_num, GROUP_NUMBER);
266     awss_trace("\r\n");
267 
268     crc = os_get_unaligned_be16(&buf[package_num - 2]);
269 
270     pbuf = &buf[0]; /* len @ [0] */
271 
272     flag = pbuf[1]; /* flag @ [1] */
273     pbuf += 2;      /* 2B for total_len, flag */
274 
275     passwd_encrypt = (flag & PASSWD_ENCRYPT_MASK) >> PASSWD_ENCRYPT_BIT_OFFSET;
276 
277     if (passwd_encrypt == PASSWD_ENCRYPT_CIPHER ||
278         passwd_encrypt == PASSWD_ENCRYPT_OPEN) {
279         awss_trace("!aes128-cfb is not support: flag 0x%x\r\n", flag);
280         ret = -1;
281         goto exit;
282     } else {
283         cal_crc = zconfig_checksum_v3(buf, package_num - 2);
284     }
285 
286     if (crc != cal_crc) {
287         awss_trace("crc error: recv 0x%x != 0x%x\r\n", crc, cal_crc);
288         /* memset(zconfig_data, 0, sizeof(*zconfig_data)); */
289         tods_tmp = tods;
290         for (tods = 0; tods < 2; tods++) {
291             for (i = 1; i <= package_num; i++) {
292                 score = pkg_score(i);
293                 if (score > 0x60) {
294                     pkg_score(i) = 0x60;
295                 } else {
296                     pkg_score(i) = score >> 1;
297                 }
298             }
299         }
300         tods = tods_tmp;
301         ret = -1;
302         awss_event_post(IOTX_AWSS_CS_ERR);
303         AWSS_UPDATE_STATIS(AWSS_STATIS_SM_IDX, AWSS_STATIS_TYPE_CRC_ERR);
304         goto exit;
305     }
306 
307     if (flag & SSID_EXIST_MASK) { /* ssid exist */
308         ssid_len = pbuf[0];
309         passwd_len = pbuf[1];
310         pbuf += 2; /* 2B for ssid_len, passwd_len */
311 
312         if (!(flag & SSID_ENCODE_MASK)) { /* ascii */
313             /* CAN'T use snprintf here, because of SPACE char */
314             memcpy((char *)tmp, pbuf, ssid_len);
315             tmp[ssid_len] = '\0';
316             for (i = 0; i < ssid_len; i++) {
317                 tmp[i] += 32;
318             }
319         } else { /* chinese format */
320             decode_chinese(pbuf, ssid_len, tmp, NULL, 6);
321             /* make sure 'tmp' is null-terminated */
322         }
323         pbuf += ssid_len; /* ssid */
324 
325         if (zc_ssid[0] == '\0' || zc_ssid_auto_complete_disable) {
326             strncpy((char *)zc_ssid, (const char *)tmp, ZC_MAX_SSID_LEN - 1);
327             awss_trace("SSID0: [%s]\r\n", zc_ssid);
328         } else {
329             if (!strncmp((const char *)tmp, (char *)zc_ssid,
330                          ZC_MAX_SSID_LEN - 1)) {
331                 awss_trace("SSID1: [%s]\r\n", zc_ssid);
332             } else {
333                 awss_trace("gbk%s SSID:[%s]\r\n", zc_ssid_is_gbk ? "" : "?",
334                            zc_ssid);
335             }
336         }
337 #ifdef AWSS_SUPPORT_APLIST
338         do { /* amend SSID automatically */
339             struct ap_info *ap = NULL;
340             int ssid_len = ZC_MAX_SSID_LEN - 1;
341             ap = zconfig_get_apinfo(zc_bssid);
342             if (ap == NULL || ap->ssid[0] == '\0') {
343                 break;
344             }
345 #if defined(AWSS_SUPPORT_AHA)
346             if (strncmp(ap->ssid, zc_default_ssid, ZC_MAX_SSID_LEN) == 0) {
347                 memset(zc_bssid, 0, ETH_ALEN);
348                 break;
349             }
350 #endif
351             ssid_len = strlen((const char *)ap->ssid) > ssid_len
352                            ? ssid_len
353                            : strlen((const char *)ap->ssid);
354             if (is_utf8((const char *)ap->ssid, ssid_len) == 0) {
355                 strncpy((char *)zc_ssid, (const char *)ap->ssid,
356                         ZC_MAX_SSID_LEN - 1);
357             }
358         } while (0);
359 #endif
360     } else {
361         passwd_len = pbuf[0];
362         pbuf += 1; /* 1B for passwd_len */
363     }
364 
365     /* CAN'T use snprintf here, because of SPACE char */
366     if (passwd_encrypt > PASSWD_ENCRYPT_CIPHER) {
367         /* decypt passwd using aes128-cfb */
368         decode_chinese(pbuf, passwd_len, tmp, &passwd_cipher_len, 6);
369         passwd_len = passwd_cipher_len;
370         memset(zc_passwd, 0, ZC_MAX_PASSWD_LEN);
371         aes_decrypt_string((char *)tmp, (char *)zc_passwd, passwd_len, 1,
372                            awss_get_encrypt_type(), 0, NULL);
373         if (is_utf8((const char *)zc_passwd, passwd_len) == 0) {
374             void *tmp_mutex = zc_mutex;
375             awss_trace("passwd err\r\n");
376             memset(zconfig_data, 0, sizeof(*zconfig_data));
377             zc_mutex = tmp_mutex;
378             awss_event_post(IOTX_AWSS_PASSWD_ERR);
379             AWSS_UPDATE_STATIS(AWSS_STATIS_SM_IDX, AWSS_STATIS_TYPE_PASSWD_ERR);
380             ret = -1;
381             goto exit;
382         }
383     } else {
384         void *temp_mutex;
385         memcpy((void *)tmp, (const void *)pbuf, passwd_len);
386         tmp[passwd_len] = '\0';
387         for (i = 0; i < passwd_len; i++) {
388             tmp[i] += 32;
389         }
390         strncpy((char *)zc_passwd, (const char *)tmp, ZC_MAX_PASSWD_LEN - 1);
391         awss_trace("encrypt:%d not support\r\n", passwd_encrypt);
392         temp_mutex = zc_mutex;
393         memset(zconfig_data, 0, sizeof(*zconfig_data));
394         zc_mutex = temp_mutex;
395         ret = -1;
396         goto exit;
397     }
398 
399     /* awss_debug("PASSWD: [%s]\r\n", zc_passwd); */
400     pbuf += passwd_len; /* passwd */
401     ret = 0;
402 exit:
403     HAL_Free(buf);
404     HAL_Free(tmp);
405 
406     return ret;
407 }
408 
package_cmp(uint8_t * package,uint8_t * src,uint8_t * dst,uint8_t tods,uint16_t len)409 int package_cmp(uint8_t *package, uint8_t *src, uint8_t *dst, uint8_t tods,
410                 uint16_t len)
411 {
412     struct package *pkg = (struct package *)package;
413 
414     if (pkg->len != len) {
415         return 1;
416     }
417     return 0;
418 }
419 
package_save(uint8_t * package,uint8_t * src,uint8_t * dst,uint8_t tods,uint16_t len)420 int package_save(uint8_t *package, uint8_t *src, uint8_t *dst, uint8_t tods,
421                  uint16_t len)
422 {
423     struct package *pkg = (struct package *)package;
424 
425     pkg->len = len;
426     return 0;
427 }
428 
429 const uint16_t zconfig_hint_frame[] = {
430     /* GROUP_FRAME is not used, gourp 0 - 7 */
431     START_FRAME,     GROUP_FRAME + 1, GROUP_FRAME + 2,
432     GROUP_FRAME + 3, GROUP_FRAME + 4, GROUP_FRAME + 5,
433     GROUP_FRAME + 6, GROUP_FRAME + 7, 0 /* NULL terminated */
434 };
435 
436 /*
437  * is_hint_frame()
438  *
439  * start frame or group frame can be used as a hint frame
440  *
441  * @Return:
442  *     1/is start or group frame, otherwise return 0.
443  */
is_hint_frame(uint8_t encry,int len,uint8_t * bssid,uint8_t * src,uint8_t channel,uint8_t tods,uint16_t sn)444 int is_hint_frame(uint8_t encry, int len, uint8_t *bssid, uint8_t *src,
445                   uint8_t channel, uint8_t tods, uint16_t sn)
446 {
447     int i;
448 
449     if (encry > ZC_ENC_TYPE_MAX) {
450         return 0;
451     }
452 
453     len -= zconfig_fixed_offset[encry][0]; /* dont't care about tkip-aes */
454 
455     for (i = 0; zconfig_hint_frame[i]; i++) {
456         if (zconfig_hint_frame[i] == len) {
457             goto found_match;
458         }
459     }
460 
461     return 0;
462 
463 found_match:
464     /* tods/fromds already locked? */
465     if (!memcmp(zc_bssid, zero_mac, ETH_ALEN)) {
466         /* zero mac means not locked */
467         memcpy(zc_bssid, bssid, ETH_ALEN);
468         memcpy(zc_src_mac, src, ETH_ALEN);
469     } else {
470         /*
471          * 1) src not equal, bssid equal, interference
472          * 2) src not equal, bssid not equal, interference
473          * 3) src equal, bssid equal, good, go on
474          * 4) src equal, bssid not equal
475          *     if tods is true, replace old ssid in case of WDS
476          *     if fromds is true, APP change the AP?? or WDS??
477          *         in this situation, zc_bssid is set by tods,
478          *         in WDS case, zc_bssid should be unchanged
479          */
480 
481         if (memcmp(zc_src_mac, src, ETH_ALEN)) { /* case 1,2 */
482             /* someone must be working in aws at the same time */
483             awss_warn("%c interference src:" MAC_FORMAT ", bssid:" MAC_FORMAT
484                       "\r\n",
485                       flag_tods(tods), MAC_VALUE(src), MAC_VALUE(bssid));
486             return 0;
487         } else {
488             if (memcmp(zc_bssid, bssid, ETH_ALEN)) { /* case 4 */
489                 if (tods) {
490                     memcpy(zc_bssid, bssid, ETH_ALEN);
491                     memcpy(zc_src_mac, src, ETH_ALEN);
492                     /* TODO: clear previous buffer, channel lock state? */
493                     if (zconfig_data->data[0].state_machine ==
494                         STATE_CHN_LOCKED_BY_BR) {
495                         zconfig_data->data[0].state_machine =
496                             STATE_CHN_SCANNING;
497                     }
498                     awss_warn("%c WDS! bssid:" MAC_FORMAT
499                               " -> bssid:" MAC_FORMAT "\r\n",
500                               flag_tods(tods), MAC_VALUE(zc_bssid),
501                               MAC_VALUE(bssid));
502                 } else {
503                     awss_trace("%c WDS? src:" MAC_FORMAT " -> bssid:" MAC_FORMAT
504                                "\r\n",
505                                flag_tods(tods), MAC_VALUE(src),
506                                MAC_VALUE(bssid));
507                     return 0;
508                 }
509             } /* else case  */
510         }
511     }
512 
513     zc_frame_offset =
514         zconfig_fixed_offset[encry][0]; /* delta, len(80211) - len(8023) */
515     zc_group_pos = i * GROUP_NUMBER;
516     zc_cur_pos = zc_group_pos;
517     zc_group_sn = sn;
518     zc_prev_sn = sn;
519     zc_score_uplimit = score_max;
520 
521     memset(zc_ssid, 0, ZC_MAX_SSID_LEN);
522 #ifdef AWSS_SUPPORT_APLIST
523     /* fix channel with apinfo if exist, otherwise return anyway. */
524     do {
525         struct ap_info *ap_info = zconfig_get_apinfo(bssid);
526         extern void aws_set_dst_chan(int channel);
527         if (ap_info && ap_info->encry[tods] > ZC_ENC_TYPE_MAX) {
528             awss_warn("invalid apinfo ssid:%s\r\n", ap_info->ssid);
529         }
530 
531         if (ap_info && ap_info->encry[tods] == encry && ap_info->channel) {
532             if (channel != ap_info->channel) {
533                 awss_info("fix channel from %d to %d\r\n", channel,
534                           ap_info->channel);
535                 zc_channel = ap_info->channel; /* fix by ap_info channel */
536                 aws_set_dst_chan(zc_channel);
537             }
538         } else {
539             /* warning: channel may eq 0! */
540         };
541 
542         if (ap_info) { /* save ssid */
543             strncpy((char *)zc_ssid, (const char *)ap_info->ssid,
544                     ZC_MAX_SSID_LEN - 1);
545         }
546     } while (0);
547 #endif
548 
549     return 1;
550 }
551 
552 /*
553  * get_data_score()
554  *
555  * calc package score
556  *
557  * @Return:
558  *     score between [0, 100]
559  */
get_data_score(uint16_t group_sn,uint16_t sn_now,uint16_t sn_last,uint8_t index_now,uint8_t index_last,uint8_t tods)560 uint8_t get_data_score(uint16_t group_sn, uint16_t sn_now, uint16_t sn_last,
561                        uint8_t index_now, uint8_t index_last, uint8_t tods)
562 {
563     /*
564     example: 1
565      8+3 250 0  d0e cc:fa:00:c8:cf:d2 > ff:ff:ff:ff:ff:ff
566      8+4 2bf 0  d15 cc:fa:00:c8:cf:d2 > ff:ff:ff:ff:ff:ff //两个包index_delta=1,
567     sn_delta=7
568 
569     example: 2
570      8+0, 3e1,  9a5
571      8+1, 13f,  9a7
572              group_sn=9a7, sn=9ab-9a7, pos=e-9, len=3ce        //here,
573     index_delta=5, sn_delta=4 group_sn=9a7, sn=9ac-9ab, pos=f-9, len=454
574              group_sn=9a7, sn=9ad-9ac, pos=10-9, len=4d2
575     example: 3
576      8+3, 225,  a32
577      8+6, 3c7,  a39        //此处应该是16+6, index_delta=3, sn_delta=7
578     example: 4
579      0+0, 4e0,  da5
580      0+7, 441,  dab        //此处应该是8+7, index_delta=7, sn_delta=6
581      0+0, 4e0,  d89
582      0+8, 4c2,  d8f        //此处应该是8+8, index_delta=8, sn_delta=6
583 
584     //example: 4
585      0+0 [100] 294 0 4e0
586      0+1 [60] 2a2 0 11a
587      0+2 [40] 2aa 0 181
588              group_sn:2aa, sn:2b8-2aa=14, pos:3-2, len:20a
589              group_sn:2aa, sn:2bc-2b8=18, pos:4-2, len:28a
590              group_sn:2aa, sn:2c0-2bc=22, pos:5-2, len:310
591              group_sn:2aa, sn:2c4-2c0=26, pos:6-2, len:391
592              group_sn:2aa, sn:2c8-2c4=30, pos:7-2, len:412
593              group_sn:2aa, sn:2cc-2c8=34, pos:8-2, len:493
594     */
595     static const uint16_t score_level[][2] = {
596         { 0, 0 },
597         { 1, 2 }, /* include, example 1, 3 */
598         { 4, 8 },
599         { 8, 16 }, /* example 1 */
600         { 15, 30 },
601         { 40, 40 },
602         { 0xFFFF, score_max } /* the end missing seq, example 2 */
603     };
604 
605     uint16_t sn_delta = sn_minus(sn_now, group_sn) - 1;
606     uint16_t index_delta = (index_now - index_last) - 1;
607     uint16_t delta = sn_delta + index_delta;
608 
609     uint8_t i = 0;
610     uint8_t res;
611 
612     /* suppose: sn > zc_prev_sn, pos > zc_cur_pos */
613     if (sn_compare(sn_now, group_sn) <= 0 ||
614         sn_compare(sn_now, zc_prev_sn) <= 0) {
615         return score_min;
616     } else if (index_now <= index_last) {
617         return score_min;
618     }
619 
620     while (delta > score_level[i][0]) { /* include */
621         i++;
622     }
623 
624     res = score_level[i][1];
625 
626     if (zc_score_uplimit > res) {
627         return zc_score_uplimit - res;
628     } else {
629         return score_low;
630     }
631 }
632 
633 /*
634     遍历所有分组,找到最多匹配的分组: 分组号,匹配的起止位置,匹配的最小score
635     遍历分两步:遍历相等的数量 和 遍历空位置的数量
636     guess_pos: 根据前后位置确定的pos
637     match_pos: 根据匹配计算的pos
638 
639     1) 如果guess_pos && match_pos存在,且相等,则score += 5, pos = match_pos
640     2)                                    不相等,则score -= 5, pos = match_pos
641     3) 只有guess_pos存在,则score = 2
642     4) 只有match_pos存在,则score不变
643 */
try_to_sync_pos(uint8_t tods,uint16_t last_sn,uint8_t sn,int last_group_pos,int group_pos)644 int try_to_sync_pos(uint8_t tods, uint16_t last_sn, uint8_t sn,
645                     int last_group_pos, int group_pos)
646 {
647     int ret = -1, empty_match = 0, reason = 0;
648     int guess_pos = -1, final_pos = -1;
649 
650     int max_match = 0, match_group = -1, match_end = GROUP_NUMBER,
651         match_score = 0;
652     int match, i, j, score; /* loop variable */
653 
654 retry:
655     for (i = 0; i <= zconfig_get_data_len(); i += GROUP_NUMBER) {
656         for (match = 0, score = score_max, j = 1; j <= GROUP_NUMBER; j++) {
657             if (!tmp_score(j)) {
658                 continue;
659             }
660 
661             if (empty_match) {
662                 if (pkg_score(i + j) <= 1) {
663                     match++;
664                     score = 1;
665                 }
666             } else {
667                 if (!pkg_len(i + j)) {
668                     continue;
669                 }
670                 if (pkg_len(i + j) == tmp_len(j)) {
671                     match++;
672                     score =
673                         (score > pkg_score(i + j)) ? pkg_score(i + j) : score;
674                 } else { /* encounter first unmatch */
675                     awss_trace("[%d]=%x, [%d]=%x\r\n", i + j, pkg_len(i + j), j,
676                                tmp_len(j));
677                     break;
678                 }
679             }
680         }
681         if (match > max_match) {
682             max_match = match;
683             match_group = i;
684             match_end = j - 1;
685             match_score = score;
686             awss_trace("match=%d, match_group=%d, match_end=%d\r\n", match,
687                        match_group, match_end);
688         }
689     }
690 
691     if (!max_match && !empty_match) { /* retry empty place match */
692         empty_match = 1;
693         goto retry;
694     }
695 
696     if (group_pos != -1) {                    /* 根据后位置确定 */
697         guess_pos = group_pos - GROUP_NUMBER; /* 前一组 */
698         if (guess_pos < 0) {
699             guess_pos = (zconfig_get_data_len() / GROUP_NUMBER) * GROUP_NUMBER;
700         }
701 
702         if (!max_match || empty_match) { /* case 3 */
703             match_score = 2;
704             final_pos = guess_pos;
705             reason = 3;
706             goto replace;
707             /* can not del goto, cause guess_pos has higher priority than empty
708              * match */
709         }
710     }
711     /* 前位置 有效性难以判断,忽略 */
712 
713     if (max_match > 0) {
714         if (max_match == 1) {
715             match_score = match_score > 10 ? 10 : match_score;
716         } else if (max_match == 2) {
717             match_score = match_score > 20 ? 20 : match_score;
718         } else if (max_match <= GROUP_NUMBER) {
719             match_score = match_score > 30 ? 30 : match_score;
720         } else {
721             goto clear;
722         }
723 
724         if (guess_pos != -1) {
725             if (guess_pos == match_group) { /* case 1 */
726                 match_end = GROUP_NUMBER;
727                 match_score += 2; /*bonus */
728                 final_pos = match_group;
729                 reason = 1;
730             } else {              /*case 2*/
731                 match_score -= 0; /*bonus*/
732                 if (max_match >= 2 && !empty_match) {
733                     final_pos = match_group;
734                 } else {
735                     final_pos = guess_pos;
736                 }
737                 reason = 2;
738             }
739         } else { /*case 4: 只有match_pos存在*/
740             final_pos = match_group;
741 
742             reason = 4;
743         }
744     } else {
745         goto clear;
746     }
747 
748 replace:
749     if (final_pos != -1) {
750         reason = reason;
751         awss_trace("\tX = %d, score=%d, match=%d, reason=%d\r\n", final_pos,
752                    match_score, max_match, reason);
753         if (match_end != GROUP_NUMBER) {
754             awss_trace("\t match from [1-%d]\r\n", match_end);
755         }
756         for (i = final_pos + 1, j = 1; i <= final_pos + match_end; i++, j++) {
757             if (j > GROUP_NUMBER || i >= MAX_PKG_NUMS) {
758                 break;
759             }
760             if (pkg_score(i) < match_score && tmp_score(j)) {
761                 pkg_len(i) = tmp_len(j);
762                 pkg_score(i) = (match_score > tmp_score(j) - 1)
763                                    ? (match_score - (tmp_score(j) - 1))
764                                    : match_score; /*TODO*/
765                 awss_trace("\t%d+%d [%d] %c %-3x\r\n", final_pos, j,
766                            pkg_score(i), flag_tods(tods), tmp_len(j));
767 
768                 zc_replace = 1;
769                 if (zc_max_pos < i) {
770                     zc_max_pos = i;
771                 }
772 
773                 ret = 0;
774             }
775         }
776     }
777 
778 clear:
779     zc_pos_unsync = 0;
780     memset((uint8_t *)tmp(0), 0, sizeof(zconfig_data->tmp_pkg[0]));
781     return ret;
782 }
783 
784 /*
785     判断同一个位置是否应发生替换
786     调用该函数的前提: 同一个位置pos, 相同的得分score, 不同的数据
787     替换条件: 在各分组相同位置下,旧的数据有重复,新的数据无重复
788 */
try_to_replace_same_pos(int tods,int pos,int new_len)789 int try_to_replace_same_pos(int tods, int pos, int new_len)
790 {
791     int replace = 0, i, old_match = 0, new_match = 0;
792 
793     for (i = pos % GROUP_NUMBER; i <= zconfig_get_data_len();
794          i += GROUP_NUMBER) {
795         if (i != pos && pkg_len(i) == pkg_len(pos)) {
796             old_match = 1;
797         }
798 
799         if (pkg_len(i) == new_len) {
800             new_match = 1;
801         }
802     }
803 
804     if ((old_match && !new_match) || tods == 0) {
805         replace = 1;
806         pkg_len(pos) = new_len;
807     }
808 
809     return replace;
810 }
811 
awss_ieee80211_smartconfig_process(uint8_t * ieee80211,int len,int link_type,struct parser_res * res,signed char rssi)812 int awss_ieee80211_smartconfig_process(uint8_t *ieee80211, int len,
813                                        int link_type, struct parser_res *res,
814                                        signed char rssi)
815 {
816     int hdrlen, fc, seq_ctrl;
817     struct ieee80211_hdr *hdr;
818     uint8_t *data, *bssid_mac, *dst_mac;
819     uint8_t encry = ZC_ENC_TYPE_INVALID;
820     uint8_t tods;
821 
822     /*
823      * when device try to connect current router (include aha)
824      * skip the new packet.
825      */
826     if (ieee80211 == NULL || zconfig_finished) {
827         return ALINK_INVALID;
828     }
829 
830     /*
831      * we don't process smartconfig until user press configure button
832      */
833     if (awss_get_config_press() == 0) {
834         return ALINK_INVALID;
835     }
836 
837     hdr = (struct ieee80211_hdr *)ieee80211;
838     fc = hdr->frame_control;
839     seq_ctrl = hdr->seq_ctrl;
840 
841     /*
842      * for smartconfig with bcast of data
843      */
844     if (!ieee80211_is_data_exact(fc)) {
845         return ALINK_INVALID;
846     }
847 
848     /* tods = 1, fromds = 0 || tods = 0, fromds = 1 */
849     if (ieee80211_has_tods(fc) == ieee80211_has_fromds(fc)) {
850         return ALINK_INVALID;
851     }
852     /* drop frag, more, order*/
853     if (ieee80211_has_frags(fc)) {
854         return ALINK_INVALID;
855     }
856 
857     dst_mac = (uint8_t *)ieee80211_get_DA(hdr);
858     if (memcmp(dst_mac, br_mac, ETH_ALEN)) {
859         return ALINK_INVALID; /* only handle br frame */
860     }
861 
862     bssid_mac = (uint8_t *)ieee80211_get_BSSID(hdr);
863 
864     /*
865      * payload len = frame.len - (radio_header + wlan_hdr)
866      */
867     hdrlen = ieee80211_hdrlen_2(fc);
868     if (hdrlen > len) {
869         return ALINK_INVALID;
870     }
871 
872 #ifdef _PLATFORM_QCOM_
873     /* Note: http://stackoverflow.com/questions/17688710/802-11-qos-data-frames
874      */
875     hdrlen = (hdrlen + 3) & 0xFC; /* align header to 32bit boundary */
876 #endif
877 
878     res->u.br.data_len = len - hdrlen; /* eating the hdr */
879     res->u.br.sn = IEEE80211_SEQ_TO_SN(os_le16toh(seq_ctrl));
880 
881     data = ieee80211 + hdrlen; /* eating the hdr */
882     tods = ieee80211_has_tods(fc);
883 
884     do {
885 #ifdef AWSS_SUPPORT_APLIST
886         struct ap_info *ap_info;
887         ap_info = zconfig_get_apinfo(bssid_mac);
888         if (ap_info && ZC_ENC_TYPE_INVALID != ap_info->encry[tods]) {
889             encry = ap_info->encry[tods];
890         } else {
891 #endif
892             if (!ieee80211_has_protected(fc)) {
893                 encry = ZC_ENC_TYPE_NONE;
894             } else {
895                 /* Note: avoid empty null data */
896                 if (len < 8) { /* IV + ICV + DATA >= 8 */
897                     return ALINK_INVALID;
898                 }
899                 if (!(ieee80211[3] & 0x3F)) {
900                     encry = ZC_ENC_TYPE_WEP;
901                 } else if (data[3] & (1 << 5)) { /* Extended IV */
902                     if (data[1] ==
903                         ((data[0] | 0x20) &
904                          0x7F)) { /* tkip, WEPSeed  = (TSC1 | 0x20 ) & 0x7F */
905                         encry = ZC_ENC_TYPE_TKIP;
906                     }
907                     if (data[2] == 0 && (!(data[3] & 0x0F))) {
908                         encry = ZC_ENC_TYPE_AES;
909                     }
910 
911                     /*
912                      * Note: above code use if(tkip) and if(ase)
913                      * instead of if(tkip) else if(aes)
914                      * beacause two condition may bother match.
915                      */
916                 }
917             }
918 #ifdef AWSS_SUPPORT_APLIST
919         }
920 #endif
921     } while (0);
922 
923     if (encry == ZC_ENC_TYPE_INVALID) {
924         awss_warn("invalid encry type!\r\n");
925     }
926     res->u.br.encry_type = encry;
927 
928     /* convert IEEE 802.11 header + possible LLC headers into Ethernet header
929      * IEEE 802.11 address fields:
930      * ToDS FromDS Addr1 Addr2 Addr3 Addr4
931      *   0     0   DA    SA    BSSID n/a
932      *   0     1   DA    BSSID SA    n/a
933      *   1     0   BSSID SA    DA    n/a
934      *   1     1   RA    TA    DA    SA
935      */
936     res->src = ieee80211_get_SA(hdr);
937     res->dst = ieee80211_get_DA(hdr);
938     res->bssid = ieee80211_get_BSSID(hdr);
939     res->tods = ieee80211_has_tods(fc);
940 
941     return ALINK_BROADCAST;
942 }
943 
awss_recv_callback_smartconfig(struct parser_res * res)944 int awss_recv_callback_smartconfig(struct parser_res *res)
945 {
946     static char statis = 0;
947     uint32_t timestamp = os_get_time_ms();
948 
949     uint8_t *src = res->src;
950     uint8_t *dst = res->dst;
951     uint8_t *bssid = res->bssid;
952     uint8_t tods = res->tods;
953     uint8_t channel = res->channel;
954 
955     uint16_t sn = res->u.br.sn;
956     uint16_t len = res->u.br.data_len;
957     uint8_t encry_type = res->u.br.encry_type;
958 
959     int ret, pkg_type = PKG_INVALID;
960     uint8_t score = 0, timeout = 0, equal = 0;
961 
962     uint16_t pos = 0, index = 0;
963 
964     awss_flow(
965         "len=%d, %c, sn=%d, enc=%d, chn=%d, src=%02x%02x%02x%02x%02x%02x\r\n",
966         len, flag_tods(tods), sn, encry_type, channel, src[0], src[1], src[2],
967         src[3], src[4], src[5]);
968     /*
969      * STATE_CHN_LOCKED_BY_P2P is set by v2 wps/action frame, which means
970      * APP is sending v2, but if v2 is fail, APP will rollback to v1,
971      * so still need to parse br frame here
972      * even zc_state == STATE_CHN_LOCKED_BY_P2P.
973      */
974     if (zc_state == STATE_CHN_LOCKED_BY_P2P ||
975         zc_state == STATE_CHN_LOCKED_BY_MCAST ||
976         zc_state == STATE_CHN_SCANNING) {
977         if (is_hint_frame(encry_type, len, bssid, src, channel, tods, sn)) {
978             if (statis == 0) {
979                 statis = 1;
980                 AWSS_UPDATE_STATIS(AWSS_STATIS_SM_IDX,
981                                    AWSS_STATIS_TYPE_TIME_START);
982             }
983             awss_trace("hint frame: offset:%d, %c, sn:%x\r\n", zc_frame_offset,
984                        flag_tods(tods), sn);
985 
986             awss_trace(
987                 "src:%02x%02x%02x%02x%02x%02x, "
988                 "bssid:%02x%02x%02x%02x%02x%02x\r\n",
989                 src[0], src[1], src[2], src[3], src[4], src[5], bssid[0],
990                 bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
991 
992             pkg_type = PKG_START_FRAME;
993             zconfig_set_state(STATE_CHN_LOCKED_BY_BR, tods, channel);
994 
995             goto update_sn;
996         } else if (!memcmp(zc_android_src, src, ETH_ALEN)) {
997 #ifdef AWSS_SUPPORT_APLIST
998             struct ap_info *ap_info = zconfig_get_apinfo(bssid);
999             if (ap_info) {
1000                 if (ap_info->ssid[0] != 0x00 && ap_info->ssid[0] != 0xFF) {
1001                     strncpy((char *)zc_android_ssid,
1002                             (const char *)ap_info->ssid, ZC_MAX_SSID_LEN - 1);
1003                 }
1004                 memcpy(zc_android_bssid, bssid, ETH_ALEN);
1005                 awss_trace("src %02x%02x%02x match %02x%02x%02x\r\n",
1006                            zc_android_src[0], zc_android_src[1],
1007                            zc_android_src[2], zc_android_bssid[0],
1008                            zc_android_bssid[1], zc_android_bssid[2]);
1009             }
1010 #endif
1011         }
1012     } else if (zc_state == STATE_CHN_LOCKED_BY_BR) {
1013         /* same src mac & br & bssid */
1014         if (memcmp(&src[0], zc_src_mac, ETH_ALEN) ||
1015             memcmp(&dst[0], br_mac, sizeof(br_mac)) ||
1016             memcmp(bssid, zc_bssid, ETH_ALEN)) { /* in case of WDS */
1017             goto drop;
1018         }
1019 
1020         if (timestamp - zc_timestamp > time_interval) {
1021             awss_debug("\t\t\t\t\ttimestamp = %d\r\n",
1022                        timestamp - zc_timestamp);
1023             timeout = 1;
1024         }
1025 
1026         ret = sn_compare(sn, zc_prev_sn);
1027         if (ret <= 0) { /* retry packet, update timestamp */
1028             zc_timestamp = timestamp;
1029         }
1030         if (ret == 0) {
1031             awss_debug("drop: %3x == %3x\r\n", sn,
1032                        zc_prev_sn); /* log level, too many retry pkg */
1033             goto drop;
1034         } else if (ret < 0 && !timeout) { /* if timeout, goto pos_unsync */
1035             awss_debug("drop: %3x < %3x\r\n", sn,
1036                        zc_prev_sn); /* TODO: better not drop */
1037             goto update_sn;         /* FIXME: update sn??? */
1038         }
1039 
1040         /* assert(sn > zc_prev_sn && !timeout); */
1041 
1042         if (len <= zc_frame_offset) { /* length invalid */
1043             goto drop;
1044         }
1045 
1046         len -= zc_frame_offset;
1047 
1048         if (is_data_frame(len)) {
1049             pkg_type = PKG_DATA_FRAME;
1050             index = get_data_index(len);
1051             pos = zc_group_pos + index;
1052 
1053             if (index > GROUP_NUMBER || pos >= MAX_PKG_NUMS) {
1054                 goto drop;
1055             }
1056             /*
1057              * pos_unsync: 进入条件,任一条
1058              *     case1: index rollback
1059              *     case2: index equal but len not equal
1060              *     case3: data frame & timeout
1061              * 退出条件:
1062              *     case1: 进入条件同时也是退出条件
1063              *     case2: 收到同步帧
1064              */
1065             if (index < zc_last_index ||
1066                 (index == zc_last_index && len != zc_last_len) || timeout) {
1067                 if (zc_pos_unsync) { /* already in pos_unsync state */
1068                     awss_trace("\texit try_to_sync_pos: re-enter!\r\n");
1069                     try_to_sync_pos(tods, zc_prev_sn, sn, zc_group_pos, -1);
1070                 }
1071                 zc_pos_unsync = 1; /* also a new start */
1072                 if (index < zc_last_index) {
1073                     awss_trace("\tenter try_to_sync_pos: rollback \r\n");
1074                 } else if (timeout) {
1075                     awss_trace("\tenter try_to_sync_pos: timeout \r\n");
1076                 } else {
1077                     awss_trace("\tenter try_to_sync_pos: != \r\n");
1078                 }
1079             }
1080         pos_unsync:
1081             if (zc_pos_unsync) { /* tmp save */
1082                 package_save((uint8_t *)tmp(index), src, dst, tods, len);
1083                 if (zc_pos_unsync == 1) {
1084                     tmp_score(index) = 1;
1085                 } else {
1086                     tmp_score(index) =
1087                         (sn - zc_prev_sn); /* TODO: index? last_tmp_score */
1088                 }
1089                 zc_pos_unsync++; /* unsync pkg counter */
1090                 awss_trace("\tX+%d [%d] %-3x %c %-3x\r\n", index,
1091                            tmp_score(index), sn, flag_tods(tods), len);
1092                 goto update_sn; /* FIXME: update prev_sn or not? */
1093             }
1094 
1095             /* assert(sn > zc_prev_sn && pos > zc_cur_pos) */
1096             score = get_data_score(zc_group_sn, sn, zc_prev_sn, pos, zc_cur_pos,
1097                                    tods);
1098             if (score == score_min) { /* better not drop any pkg here */
1099                 awss_trace(
1100                     "\t drop: group_sn:%x, sn:%x-%x=%x, pos:%d-%d, len:%x\r\n",
1101                     zc_group_sn, sn, zc_prev_sn, sn_minus(sn, zc_group_sn), pos,
1102                     zc_cur_pos, len);
1103                 goto update_sn;
1104             } else {
1105                 if (zc_score_uplimit > score) {
1106                     zc_score_uplimit = score; /* inherit last limit */
1107                 }
1108 
1109                 zc_group_sn = sn; /* TODO */
1110                 awss_trace("%d+%d [%d] %-3x %c %-3x\r\n", zc_group_pos, index,
1111                            score, sn, flag_tods(tods), len);
1112             }
1113         } else {
1114             if (is_start_frame(len) || is_group_frame(len)) {
1115                 uint8_t group = get_group_index(len);
1116 
1117                 if (zc_pos_unsync) {
1118                     awss_trace("\texit try_to_sync_pos: group frame\r\n");
1119                     try_to_sync_pos(tods, zc_prev_sn, sn, zc_group_pos, group);
1120                 }
1121 
1122                 zc_cur_pos = group;
1123                 zc_group_pos = group;
1124                 zc_group_sn = sn;
1125                 zc_score_uplimit = score_max;
1126 
1127                 awss_trace("%d+%d [%d] %-3x %c %-3x\r\n", group, 0,
1128                            zc_score_uplimit, sn, flag_tods(tods), len);
1129 
1130                 /* ignore PKG_GROUP_FRAME here */
1131                 pkg_type = PKG_START_FRAME;
1132 
1133                 /*
1134                  * keep calling zconfig_set_state(), see Note about
1135                  * zconfig_callback_channel_locked()
1136                  */
1137                 zconfig_set_state(STATE_CHN_LOCKED_BY_BR, tods, channel);
1138 
1139                 /* zc_replace may happen in try_to_sync_pos(), so goto
1140                  * is_recv_completed */
1141                 goto is_recv_completed;
1142             } else {
1143                 awss_trace("\t invalid len = %d\r\n", len + zc_frame_offset);
1144                 goto drop;
1145             }
1146         }
1147 
1148         /* start from pkg(1), leave pkg(0) for start frame */
1149         if (pos >= MAX_PKG_NUMS || pos <= 0) {
1150             awss_warn("msg index(%d) out of range!\r\n", pos);
1151             goto drop;
1152         }
1153 
1154         zc_cur_pos = pos;
1155 
1156         /*
1157            score now > last:
1158            1) data equal:    pkg_score = now
1159            2) not equal:    pkg_score = now, data replace
1160            score now == last:
1161            1) data equal:    pkg_score++    and ???
1162            2) not equal:    pkg_score cut down & give warning & try_to_replace
1163            score now < last:
1164            1) data equal:    score_uplimit up???
1165            2) not equal:    goto pos_unsync
1166          */
1167         for (tods = 0; tods < 2; tods++) {
1168             equal = !package_cmp((uint8_t *)pkg(pos), src, dst, tods, len);
1169 
1170             if (score > pkg_score(pos)) {
1171                 pkg_score(pos) = score; /* update score first */
1172                 if (equal) {
1173                     continue;
1174                 }
1175                 /* not equal */
1176                 zc_replace = 1;
1177                 package_save((uint8_t *)pkg(pos), src, dst, tods, len);
1178             } else if (score == pkg_score(pos)) { /* range check ? */
1179                 int replace;
1180                 if (equal) {
1181                     pkg_score(pos)++;
1182                     continue;
1183                 }
1184                 /* not equal */
1185                 replace = try_to_replace_same_pos(tods, pos, len);
1186                 if (replace) {
1187                     awss_trace("\t replace @ %d, len=%x\r\n", pos, len);
1188                     continue;
1189                 }
1190                 pkg_score(pos) /= 2;
1191                 if (score >= score_mid) /* better not happen */
1192                     awss_warn("xxxxxxxx warn: pos=%d, score=[%d], %x != %x\r\n",
1193                               pos, score, pkg_len(pos), len);
1194 
1195             } else if (tods == res->tods) { /* pkg_score(pos) > score */
1196                 if (!equal) {               /* data not equal */
1197                     if (zc_pos_unsync) {
1198                         continue;
1199                     }
1200                     zc_pos_unsync = 1;
1201                     awss_trace("\tenter try_to_sync_pos: data mismatch\r\n");
1202                     tods = res->tods;
1203                     goto pos_unsync;
1204                 } else if (zc_score_uplimit >= score_mid &&
1205                            pkg_score(pos) - score < 10) { /* data equal */
1206                     uint8_t uplimit = (zc_score_uplimit + pkg_score(pos)) / 2;
1207                     if (zc_score_uplimit != uplimit) {
1208                         awss_trace("\t\t\t uplimit [%d] -> [%d]\r\n",
1209                                    zc_score_uplimit, uplimit);
1210                     }
1211                     zc_score_uplimit = uplimit;
1212                 }
1213             }
1214         }
1215         tods = res->tods;
1216 
1217     is_recv_completed:
1218         zc_max_pos = (zc_max_pos < zc_cur_pos) ? zc_cur_pos : zc_max_pos;
1219         if (zc_replace && zconfig_recv_completed(tods)) {
1220             zc_replace = 0;
1221             memcpy(zc_bssid, res->bssid, ETH_ALEN);
1222             if (!zconfig_get_ssid_passwd(tods)) {
1223                 /* we got it! */
1224                 AWSS_UPDATE_STATIS(AWSS_STATIS_SM_IDX,
1225                                    AWSS_STATIS_TYPE_TIME_SUC);
1226                 statis = 0;
1227                 zconfig_set_state(STATE_RCV_DONE, tods, channel);
1228                 return PKG_END;
1229             }
1230         }
1231     }
1232 
1233 update_sn:
1234     zc_prev_sn = sn;
1235 
1236     zc_timestamp = timestamp;
1237     zc_last_index = index;
1238     zc_last_len = len;
1239 
1240     return pkg_type;
1241 
1242 drop:
1243     return PKG_INVALID;
1244 }
1245 
1246 #if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
1247 }
1248 #endif
1249