airkiss.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836
  1. /*
  2. * Copyright (c) 2006-2018, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2019-05-16 heyuanjie87 first version
  9. */
  10. #include "airkiss.h"
  11. #include <string.h>
  12. #include <stdint.h>
  13. #ifdef AIRKISS_LOG_ENABLE
  14. #define AKLOG_D \
  15. if (lc->cfg && lc->cfg->printf) \
  16. lc->cfg->printf
  17. #else
  18. #define AKLOG_D(...)
  19. #endif
  20. #define AKSTATE_WFG 0
  21. #define AKSTATE_WFM 1
  22. #define AKSTATE_WFP 2
  23. #define AKSTATE_WFD 4
  24. #define AKSTATE_CMP 5
  25. typedef struct
  26. {
  27. uint16_t val[6];
  28. uint8_t pos;
  29. uint8_t scnt;
  30. uint8_t err;
  31. } akcode_t;
  32. typedef struct
  33. {
  34. uint8_t val[4];
  35. uint8_t pos : 4;
  36. uint8_t scnt : 4;
  37. uint8_t err;
  38. uint16_t icnt;
  39. uint8_t sa[12];
  40. } akcode_guide_t;
  41. typedef struct
  42. {
  43. union {
  44. akcode_guide_t code1[3];
  45. akcode_t code2[2];
  46. } uc;
  47. uint8_t reclen;
  48. uint8_t state;
  49. uint8_t nossid;
  50. char seq[16];
  51. uint8_t data[66];
  52. uint8_t random;
  53. uint8_t baselen;
  54. uint8_t prslen;
  55. uint8_t ssidcrc;
  56. uint8_t pwdlen;
  57. uint8_t pwdcrc;
  58. const airkiss_config_t *cfg;
  59. } akloc_context_t;
  60. #define AKLOC_CODE1(x, i) ((x)->uc.code1[i])
  61. #define AKLOC_CODE2(x) (&(x)->uc.code2[0])
  62. #define AKLOC_CODE3(x) (&(x)->uc.code2[1])
  63. unsigned char airkiss_crc8(unsigned char *message, unsigned char len)
  64. {
  65. uint8_t crc = 0;
  66. uint8_t i;
  67. while (len--)
  68. {
  69. crc ^= *message++;
  70. for (i = 0; i < 8; i++)
  71. {
  72. if (crc & 0x01)
  73. crc = (crc >> 1) ^ 0x8c;
  74. else
  75. crc >>= 1;
  76. }
  77. }
  78. return crc;
  79. }
  80. static void akloc_reset(akloc_context_t *lc)
  81. {
  82. lc->state = 0;
  83. lc->reclen = 0;
  84. lc->baselen = 0;
  85. memset(lc->seq, 0xff, sizeof(lc->seq));
  86. memset(&lc->uc, 0, sizeof(lc->uc));
  87. }
  88. static uint8_t akinfo_getu8(uint16_t v[2])
  89. {
  90. uint8_t ret = 0;
  91. ret = ((v[0] & 0xF) << 4) | (v[1] & 0xF);
  92. return ret;
  93. }
  94. static uint16_t aklen_udp(akloc_context_t *lc, uint16_t len)
  95. {
  96. return (len - lc->baselen);
  97. }
  98. static int aklen_input(akloc_context_t *lc, akcode_t *ac, int fmlen, int num)
  99. {
  100. if (ac->pos < num)
  101. {
  102. ac->val[ac->pos] = aklen_udp(lc, fmlen);
  103. ac->pos++;
  104. }
  105. return (ac->pos == num);
  106. }
  107. static void ak_codemve(akcode_t *ac, int pos, int n)
  108. {
  109. int i;
  110. for (i = 0; i < n; i++)
  111. {
  112. ac->val[i] = ac->val[pos + i];
  113. }
  114. ac->pos = n;
  115. }
  116. static int akseq_num(akloc_context_t *lc)
  117. {
  118. int n;
  119. n = lc->prslen - lc->reclen;
  120. if (n > 4)
  121. n = 6;
  122. else if (n != 0)
  123. n += 2;
  124. return n;
  125. }
  126. static int akseq_input(akloc_context_t *lc, uint8_t *d, int n, int seqi)
  127. {
  128. int i;
  129. int ret;
  130. if (lc->seq[seqi] != seqi)
  131. {
  132. int pos;
  133. lc->seq[seqi] = seqi;
  134. n -= 2;
  135. pos = seqi * 4;
  136. for (i = 0; i < n; i++)
  137. {
  138. lc->data[pos] = d[i];
  139. lc->reclen++;
  140. pos++;
  141. }
  142. }
  143. ret = lc->prslen - lc->reclen;
  144. return ret;
  145. }
  146. static int ak_is_guidefield(akcode_t *ac)
  147. {
  148. int ret = 0;
  149. if ((ac->val[1] - ac->val[0] == 1) &&
  150. (ac->val[2] - ac->val[0] == 2) &&
  151. (ac->val[3] - ac->val[0] == 3))
  152. {
  153. ret = 1;
  154. }
  155. return ret;
  156. }
  157. /*
  158. 在接收magicfield阶段检查是否收到乱序的guide code
  159. */
  160. static int ak_is_guidefield_errseq(akcode_t *ac)
  161. {
  162. int ret = 0;
  163. if ((ac->val[0] < 5) &&
  164. (ac->val[1] < 5) &&
  165. (ac->val[2] < 5) &&
  166. (ac->val[3] < 5))
  167. {
  168. ret = 1;
  169. }
  170. return ret;
  171. }
  172. /*
  173. 在4个包中从指定位置找出符合magicfield的序列
  174. */
  175. static int ak_is_magicfield_corseq(akcode_t *ac, int pos, int n)
  176. {
  177. int ret;
  178. uint8_t v[4];
  179. uint8_t vd[4] = {0, 1, 2, 3};
  180. int i;
  181. for (i = 0; i < n; i++)
  182. {
  183. v[i] = ac->val[pos + i] >> 4;
  184. }
  185. ret = !memcmp(v, vd, n);
  186. return ret;
  187. }
  188. /*
  189. 检查是否是错误的magicfield序列
  190. */
  191. static int ak_is_magicfield_errseq(akcode_t *ac)
  192. {
  193. int i;
  194. for (i = 0; i < 4; i++)
  195. {
  196. if ((ac->val[i] >> 4) > 3)
  197. break;
  198. }
  199. return (i == 4);
  200. }
  201. /*
  202. 剔除错误的magicfield序列
  203. */
  204. static int ak_realign_magicfield(akcode_t *ac)
  205. {
  206. int r = 1;
  207. while (r < 4)
  208. {
  209. if (ak_is_magicfield_corseq(ac, r, 4 - r))
  210. {
  211. ak_codemve(ac, r, 4 - r);
  212. r = -1;
  213. break;
  214. }
  215. r++;
  216. }
  217. return (r == -1);
  218. }
  219. static int ak_get_magicfield(akloc_context_t *lc, akcode_t *ac)
  220. {
  221. int ret;
  222. if ((ret = ak_is_magicfield_corseq(ac, 0, 4)) != 0)
  223. {
  224. if (ac->val[0] == 8)
  225. ac->val[0] = 0;
  226. lc->prslen = akinfo_getu8(&ac->val[0]);
  227. lc->ssidcrc = akinfo_getu8(&ac->val[2]);
  228. }
  229. return ret;
  230. }
  231. static int ak_is_prefixfield_corseq(akcode_t *ac, int pos, int n)
  232. {
  233. uint8_t v[4];
  234. uint8_t vd[4] = {4, 5, 6, 7};
  235. int i;
  236. int ret;
  237. for (i = 0; i < n; i++)
  238. {
  239. v[i] = ac->val[pos + i] >> 4;
  240. }
  241. ret = !memcmp(v, vd, n);
  242. return ret;
  243. }
  244. static int ak_get_prefixfield(akloc_context_t *lc, akcode_t *ac)
  245. {
  246. int ret;
  247. if ((ret = ak_is_prefixfield_corseq(ac, 0, 4)) != 0)
  248. {
  249. lc->pwdlen = akinfo_getu8(&ac->val[0]);
  250. lc->pwdcrc = akinfo_getu8(&ac->val[2]);
  251. }
  252. return ret;
  253. }
  254. static int ak_realign_prefixfield(akcode_t *ac)
  255. {
  256. int r;
  257. r = 1;
  258. while (r < 4)
  259. {
  260. if (ak_is_prefixfield_corseq(ac, r, 4 - r))
  261. {
  262. ak_codemve(ac, r, 4 - r);
  263. r = -1;
  264. break;
  265. }
  266. r++;
  267. }
  268. return (r == -1);
  269. }
  270. static int ak_is_datafield_corseq(akcode_t *ac, int pos, int n)
  271. {
  272. int ret;
  273. int i;
  274. uint8_t v[6];
  275. uint8_t vd[6] = {1, 1, 2, 2, 2, 2};
  276. for (i = 0; i < n; i++)
  277. {
  278. if (i < 2)
  279. v[i] = ac->val[i + pos] >> 7;
  280. else
  281. v[i] = (ac->val[i + pos] & 0x100) >> 7;
  282. }
  283. ret = !memcmp(v, vd, n);
  284. return ret;
  285. }
  286. static int ak_get_datafield(akcode_t *ac, uint8_t data[4], int *seqi, int n)
  287. {
  288. int i = 0;
  289. int fail = 1;
  290. uint8_t tmp[6] = {0};
  291. if (n < 3 || n > 6)
  292. goto _out;
  293. if (!ak_is_datafield_corseq(ac, 0, n))
  294. goto _out;
  295. tmp[0] = ac->val[i++] & 0x7F;
  296. tmp[1] = ac->val[i++] & 0x7F;
  297. tmp[2] = ac->val[i++] & 0xFF;
  298. tmp[3] = ac->val[i++] & 0xFF;
  299. tmp[4] = ac->val[i++] & 0xFF;
  300. tmp[5] = ac->val[i++] & 0xFF;
  301. fail = ((airkiss_crc8(&tmp[1], n - 1) & 0x7F) != tmp[0]);
  302. if (!fail)
  303. {
  304. memcpy(data, &tmp[2], 4);
  305. *seqi = tmp[1];
  306. }
  307. _out:
  308. return (!fail);
  309. }
  310. static int ak_realign_datafield(akcode_t *ac)
  311. {
  312. int r = 1;
  313. while (r < 6)
  314. {
  315. if (ak_is_datafield_corseq(ac, r, 6 - r))
  316. {
  317. ak_codemve(ac, r, 6 - r);
  318. r = -1;
  319. break;
  320. }
  321. r++;
  322. }
  323. return (r == -1);
  324. }
  325. static akcode_guide_t *ak_guide_getcode(akloc_context_t *lc, unsigned char *f)
  326. {
  327. akcode_guide_t *ac;
  328. if (f == NULL) /* 是模拟测试 */
  329. {
  330. ac = &AKLOC_CODE1(lc, 2);
  331. }
  332. else
  333. {
  334. unsigned char *sa;
  335. unsigned i;
  336. int found = 0;
  337. akcode_guide_t *imin;
  338. sa = f + 10;
  339. imin = &AKLOC_CODE1(lc, 0);
  340. ac = imin;
  341. for (i = 0; i < sizeof(lc->uc.code1) / sizeof(lc->uc.code1[0]); i++)
  342. {
  343. /* 匹配地址 */
  344. found = !memcmp(ac->sa, sa, sizeof(ac->sa));
  345. if (found)
  346. break;
  347. /* 记录输入最少的 */
  348. if (ac->icnt < imin->icnt)
  349. imin = ac;
  350. ac++;
  351. }
  352. if (!found)
  353. {
  354. /* 淘汰输入最少的 */
  355. ac = imin;
  356. ac->pos = 0;
  357. ac->err = 0;
  358. ac->scnt = 0;
  359. ac->icnt = 0;
  360. memcpy(ac->sa, sa, sizeof(ac->sa));
  361. }
  362. }
  363. return ac;
  364. }
  365. static int ak_guidefield_input(akcode_guide_t *ac, uint16_t len)
  366. {
  367. if (ac->pos < 4)
  368. {
  369. if ((ac->pos != 0) && ((len - ac->val[ac->pos - 1]) != 1))
  370. {
  371. ac->pos = 0;
  372. if (ac->icnt > 0)
  373. ac->icnt--;
  374. }
  375. ac->val[ac->pos] = len;
  376. ac->pos++;
  377. ac->icnt += ac->pos;
  378. }
  379. return (ac->pos == 4);
  380. }
  381. static int ak_waitfor_guidefield(akloc_context_t *lc, uint8_t *f, uint16_t len)
  382. {
  383. int ret = AIRKISS_STATUS_CONTINUE;
  384. akcode_guide_t *ac;
  385. ac = ak_guide_getcode(lc, f);
  386. if (ak_guidefield_input(ac, len))
  387. {
  388. ac->pos = 0;
  389. ac->scnt++;
  390. /* 至少两次相同的guide code才算获取成功 */
  391. if ((ac->scnt >= 2) && ac->icnt >= 20)
  392. {
  393. lc->state = AKSTATE_WFM;
  394. lc->baselen = ac->val[0] - 1;
  395. ac->scnt = 0;
  396. ac->err = 0;
  397. ac->icnt = 0;
  398. AKLOG_D("guide baselen %d\n", lc->baselen);
  399. }
  400. }
  401. if (lc->state == AKSTATE_WFM)
  402. {
  403. if (ac != &AKLOC_CODE1(lc, 2))
  404. {
  405. memcpy(AKLOC_CODE1(lc, 2).sa, ac->sa, sizeof(ac->sa));
  406. }
  407. memset(AKLOC_CODE2(lc), 0, sizeof(akcode_t) * 2);
  408. ret = AIRKISS_STATUS_CHANNEL_LOCKED;
  409. }
  410. return ret;
  411. }
  412. static int ak_waitfor_magicfield(akloc_context_t *lc, uint16_t len)
  413. {
  414. int ret = AIRKISS_STATUS_CONTINUE;
  415. akcode_t *ac = AKLOC_CODE2(lc);
  416. if (aklen_input(lc, ac, len, 4))
  417. {
  418. ac->pos = 0;
  419. if (ak_get_magicfield(lc, ac))
  420. {
  421. lc->state = AKSTATE_WFP;
  422. ac->err = 0;
  423. AKLOG_D("magic: prslen(%d) ssidcrc(%X)\n", lc->prslen, lc->ssidcrc);
  424. }
  425. else if (ak_is_guidefield(ac) ||
  426. ak_is_guidefield_errseq(ac))
  427. {
  428. /* 收到的还是或乱序的guidecode则忽略 */
  429. }
  430. else if (ak_realign_magicfield(ac))
  431. {
  432. /* 保留符合要求的序列 */
  433. }
  434. else
  435. {
  436. if (ac->err++ > 6)
  437. {
  438. akloc_reset(lc);
  439. AKLOG_D("airkiis reset from magic\n");
  440. }
  441. }
  442. }
  443. return ret;
  444. }
  445. static int ak_waitfor_prefixfield(akloc_context_t *lc, uint16_t len)
  446. {
  447. int ret = AIRKISS_STATUS_CONTINUE;
  448. akcode_t *ac = AKLOC_CODE2(lc);
  449. if (aklen_input(lc, ac, len, 4))
  450. {
  451. ac->pos = 0;
  452. if (ak_get_prefixfield(lc, ac))
  453. {
  454. lc->state = AKSTATE_WFD;
  455. ac->err = 0;
  456. AKLOG_D("prefix: pwdlen(%d) pwdcrc(%X)\n", lc->pwdlen, lc->pwdcrc);
  457. }
  458. else if (ak_is_magicfield_corseq(ac, 0, 4) ||
  459. ak_is_magicfield_errseq(ac))
  460. {
  461. /* 收到magicfield 忽略 */
  462. }
  463. else if (ak_realign_prefixfield(ac))
  464. {
  465. /* 保留符合要求的 */
  466. }
  467. else
  468. {
  469. if (ac->err++ > 5)
  470. {
  471. akloc_reset(lc);
  472. AKLOG_D("airkiss reset from prefix");
  473. }
  474. }
  475. }
  476. return ret;
  477. }
  478. /*
  479. 只判断密码和random是否收完
  480. */
  481. static int ak_is_pwdrand_complete(akloc_context_t *lc)
  482. {
  483. int ret = 0;
  484. unsigned i;
  485. int n = 0;
  486. for (i = 0; i < (sizeof(lc->seq) / sizeof(lc->seq[0])); i++)
  487. {
  488. if (lc->seq[i] == 0xff)
  489. break;
  490. n += 4;
  491. if (n >= (lc->pwdlen + 1))
  492. {
  493. ret = 1;
  494. break;
  495. }
  496. }
  497. return ret;
  498. }
  499. static int _datafield_input(akloc_context_t *lc, akcode_t *ac, uint16_t len, int n, int nossid)
  500. {
  501. int ret = 0;
  502. if (n && aklen_input(lc, ac, len, n))
  503. {
  504. uint8_t data[4];
  505. int seqi;
  506. ac->pos = 0;
  507. if ((ret = ak_get_datafield(ac, data, &seqi, n)) == 1)
  508. {
  509. if (akseq_input(lc, data, n, seqi) == 0)
  510. {
  511. lc->state = AKSTATE_CMP;
  512. AKLOG_D("data complete %d\n", n);
  513. }
  514. else if (nossid && ak_is_pwdrand_complete(lc))
  515. {
  516. lc->state = AKSTATE_CMP;
  517. AKLOG_D("data nossid complete\n");
  518. }
  519. }
  520. else
  521. {
  522. if (!ak_realign_datafield(ac))
  523. {
  524. ac->err++;
  525. }
  526. }
  527. }
  528. return ret;
  529. }
  530. static int ak_waitfor_datafield(akloc_context_t *lc, uint16_t len, int nossid)
  531. {
  532. int ret = AIRKISS_STATUS_CONTINUE;
  533. akcode_t *ac = AKLOC_CODE2(lc);
  534. int n;
  535. uint16_t udplen;
  536. udplen = aklen_udp(lc, len);
  537. if (udplen < 0x80)
  538. {
  539. return ret;
  540. }
  541. n = lc->prslen & 0x03;
  542. if (n && (lc->prslen > 8) && !nossid)
  543. {
  544. akcode_t *ac3 = AKLOC_CODE3(lc);
  545. if (_datafield_input(lc, ac3, len, n + 2, 0))
  546. {
  547. if ((n = akseq_num(lc)) == 0)
  548. goto _out;
  549. ac->pos = 0;
  550. return ret;
  551. }
  552. }
  553. /* 期望当前序列的包数(6, <6, 0) */
  554. n = akseq_num(lc);
  555. _datafield_input(lc, ac, len, n, nossid);
  556. if (ac->err > 20)
  557. {
  558. akloc_reset(lc);
  559. AKLOG_D("airkiss reset from data\n");
  560. }
  561. _out:
  562. if ((lc->state == AKSTATE_CMP) || (n == 0))
  563. {
  564. lc->nossid = nossid;
  565. lc->state = AKSTATE_CMP;
  566. ret = AIRKISS_STATUS_COMPLETE;
  567. }
  568. return ret;
  569. }
  570. static int ak_sa_filter(akloc_context_t *lc, uint8_t *f)
  571. {
  572. unsigned char *sa;
  573. sa = f + 10;
  574. return memcmp(AKLOC_CODE1(lc, 2).sa, sa, sizeof(AKLOC_CODE1(lc, 2).sa));
  575. }
  576. int airkiss_filter(const void *f, int len)
  577. {
  578. int ret = 0;
  579. unsigned char *da, *p;
  580. int i;
  581. p = (unsigned char *)f;
  582. if ((len < 25) || (p[0] != 0x08))
  583. return 1;
  584. da = p + 4;
  585. for (i = 0; i < 6; i++)
  586. {
  587. if (da[i] != 0xFF)
  588. {
  589. ret = 1;
  590. break;
  591. }
  592. }
  593. return ret;
  594. }
  595. static int _ak_recv(airkiss_context_t *c, const void *frame, uint16_t length, int nossid)
  596. {
  597. int ret = AIRKISS_STATUS_CONTINUE;
  598. akloc_context_t *lc = (akloc_context_t *)c;
  599. unsigned char *f = (unsigned char *)frame;
  600. if (frame != NULL) /* 模拟测试时可只传length */
  601. {
  602. if (airkiss_filter(frame, length))
  603. return ret;
  604. if ((lc->state != AKSTATE_WFG) && ak_sa_filter(lc, f))
  605. return ret;
  606. }
  607. switch (lc->state)
  608. {
  609. case AKSTATE_WFG:
  610. {
  611. ret = ak_waitfor_guidefield(lc, f, length);
  612. }
  613. break;
  614. case AKSTATE_WFM:
  615. {
  616. ret = ak_waitfor_magicfield(lc, length);
  617. }
  618. break;
  619. case AKSTATE_WFP:
  620. {
  621. ret = ak_waitfor_prefixfield(lc, length);
  622. }
  623. break;
  624. case AKSTATE_WFD:
  625. {
  626. ret = ak_waitfor_datafield(lc, length, nossid);
  627. }
  628. break;
  629. case AKSTATE_CMP:
  630. {
  631. ret = AIRKISS_STATUS_COMPLETE;
  632. }
  633. break;
  634. }
  635. return ret;
  636. }
  637. const char *airkiss_version(void)
  638. {
  639. return "airkiss-1.0.0-open";
  640. }
  641. int airkiss_init(airkiss_context_t *c, const airkiss_config_t *config)
  642. {
  643. akloc_context_t *lc = (akloc_context_t *)c;
  644. lc->cfg = config;
  645. akloc_reset(lc);
  646. return 0;
  647. }
  648. int airkiss_recv(airkiss_context_t *c, const void *frame, unsigned short length)
  649. {
  650. return _ak_recv(c, frame, length, 0);
  651. }
  652. int airkiss_get_result(airkiss_context_t *c, airkiss_result_t *res)
  653. {
  654. akloc_context_t *lc = (akloc_context_t *)c;
  655. if (lc->state != AKSTATE_CMP)
  656. return -1;
  657. res->pwd = (char *)&lc->data[0];
  658. res->pwd_length = lc->pwdlen;
  659. if (lc->data[lc->pwdlen] == 0)
  660. {
  661. res->random = lc->random;
  662. }
  663. else
  664. {
  665. res->random = lc->data[lc->pwdlen];
  666. lc->random = lc->data[lc->pwdlen];
  667. lc->data[lc->pwdlen] = 0;
  668. }
  669. res->ssid_crc = lc->ssidcrc;
  670. if (lc->nossid)
  671. {
  672. res->ssid = "";
  673. res->ssid_length = 0;
  674. }
  675. else
  676. {
  677. res->ssid = (char *)&lc->data[lc->pwdlen + 1];
  678. res->ssid_length = lc->prslen - lc->pwdlen - 1;
  679. }
  680. lc->data[lc->prslen] = 0;
  681. return 0;
  682. }
  683. int airkiss_recv_nossid(airkiss_context_t *c, const void *frame, unsigned short length)
  684. {
  685. return _ak_recv(c, frame, length, 1);
  686. }
  687. int airkiss_change_channel(airkiss_context_t *c)
  688. {
  689. akloc_context_t *lc = (akloc_context_t *)c;
  690. akloc_reset(lc);
  691. return 0;
  692. }