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