/* * Copyright (c) 2006-2018, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2019-05-16 heyuanjie87 first version */ #include "airkiss.h" #include #ifdef AIRKISS_LOG_ENABLE #define AKLOG_D(fmt, ...) lc->cfg->printf(fmt, ##__VA_ARGS__) #else #define AKLOG_D(...) #endif #define NULL 0 #define AKMEMCPY(dst, src, len) lc->cfg->memcpy(dst, src, len) #define AKMEMSET(ptr, value, len) lc->cfg->memset(ptr, value, len) #define AKMEMCMP(ptr1, ptr2, len) lc->cfg->memcmp(ptr1, ptr2, len) #define AKSTATE_WFG 0 #define AKSTATE_WFM 1 #define AKSTATE_WFP 2 #define AKSTATE_WFD 4 #define AKSTATE_CMP 5 typedef uint16_t akwire_seq_t; typedef struct { uint16_t val[6]; uint8_t pos; uint8_t scnt; /* 成功计数 */ uint8_t err; uint8_t rcnt; /* 接收计数 */ } akcode_t; typedef struct { akwire_seq_t ws; uint8_t crc; uint8_t ind; }akdatf_seq_t; typedef struct { uint8_t crc; uint8_t ind; }akdatf_header_t; typedef struct { uint8_t id[4]; }akaddr_t; typedef struct { akwire_seq_t ws; uint8_t val[4]; uint8_t pos : 4; uint8_t scnt : 4; uint8_t err; uint8_t wval; uint8_t seqcnt; akaddr_t sa; } akcode_guide_t; typedef struct { char data[16]; /* 保留后4个 */ uint8_t pos[16]; }akdatf_conflict_t; typedef struct { union { akcode_guide_t code1[3]; akcode_t code2[1]; } uc; akdatf_conflict_t dcfl; /* 记录有冲突的数据 */ akwire_seq_t prews; akdatf_seq_t preseq; akdatf_seq_t curseq; akdatf_header_t pendseq[10]; /* 未完成的序列 */ akaddr_t locked; uint8_t seqstep;/* 序列增量 */ uint8_t reclen; uint8_t state; uint8_t nossid; uint8_t seq[16]; /* 标记已完成的序列 */ char data[66]; uint8_t random; uint8_t baselen; uint8_t prslen; uint8_t ssidcrc; uint8_t pwdlen; const airkiss_config_t *cfg; } akloc_context_t; #define AKLOC_CODE1(x, i) ((x)->uc.code1[i]) #define AKLOC_CODE2(x) (&(x)->uc.code2[0]) #define AKLOC_DFSEQ_PREV(lc) ((lc)->preseq) #define AKLOC_DFSEQ_CUR(lc) ((lc)->curseq) unsigned char airkiss_crc8(unsigned char *message, unsigned char len) { uint8_t crc = 0; uint8_t i; while (len--) { crc ^= *message++; for (i = 0; i < 8; i++) { if (crc & 0x01) crc = (crc >> 1) ^ 0x8c; else crc >>= 1; } } return crc; } static akwire_seq_t akwseq_make(uint8_t seq[2]) { akwire_seq_t ws = 0; ws = (seq[1] << 4) | (seq[0] >> 4); return ws; } static void akloc_reset(akloc_context_t *lc) { const airkiss_config_t *cfg; cfg = lc->cfg; AKMEMSET(lc, 0, sizeof(*lc)); lc->cfg = cfg; } static uint8_t akinfo_getu8(uint16_t v[2]) { uint8_t ret = 0; ret = ((v[0] & 0xF) << 4) | (v[1] & 0xF); return ret; } static uint16_t aklen_udp(akloc_context_t *lc, uint16_t len) { return (len - lc->baselen); } static int ak_get_magicfield(akloc_context_t *lc, akcode_t *ac) { int ret = 1; if (ac->val[0] == 8) ac->val[0] = 0; lc->prslen = akinfo_getu8(&ac->val[0]); lc->ssidcrc = akinfo_getu8(&ac->val[2]); if (lc->prslen > (sizeof(lc->data) - 1)) { ret = 0; AKLOG_D("prslen(%d) large than(%d)", lc->prslen, (sizeof(lc->data) - 1)); } return ret; } static int ak_magicfield_input(akcode_t *ac, uint16_t len) { int mc; mc = len >> 4; if (mc == 0) { ac->val[0] = len; ac->pos = 1; } else if (mc == ac->pos) { ac->val[ac->pos] = len; ac->pos ++; } else { ac->pos = 0; } return (ac->pos == 4); } static int ak_get_prefixfield(akloc_context_t *lc, akcode_t *ac) { int ret = 1; uint8_t crc; lc->pwdlen = akinfo_getu8(&ac->val[0]); crc = akinfo_getu8(&ac->val[2]); if (airkiss_crc8(&lc->pwdlen, 1) != crc) ret = 0; return ret; } static int ak_prefixfield_input(akcode_t *ac, uint16_t len) { int mc; mc = len >> 4; if (mc == 4) { ac->val[0] = len; ac->pos = 1; } else if (mc == (ac->pos + 4)) { ac->val[ac->pos] = len; ac->pos ++; } else { ac->pos = 0; } return (ac->pos == 4); } static int ak_get_datafield(akloc_context_t *lc, akcode_t *ac) { uint8_t tmp[6]; int n; int ret = 0; int pos; int seqi; seqi = ac->val[1] & 0x7f; if (seqi > (lc->prslen/4)) { return 0; } if (lc->seq[seqi]) return 0; pos = seqi * 4; n = lc->prslen - pos; if (n > 4) n = 4; tmp[0] = ac->val[0] & 0x7F; tmp[1] = ac->val[1] & 0x7F; tmp[2] = ac->val[2] & 0xFF; tmp[3] = ac->val[3] & 0xFF; tmp[4] = ac->val[4] & 0xFF; tmp[5] = ac->val[5] & 0xFF; ret = ((airkiss_crc8(&tmp[1], n + 1) & 0x7F) == tmp[0]); if (ret) { AKMEMCPY(&lc->data[pos], &tmp[2], n); lc->reclen += n; lc->seq[seqi] = 1; #ifdef AIRKISS_LOG_GDO_ENABLE AKLOG_D("getdata(%d, %d)\n", seqi, n); #endif } return ret; } static void akaddr_fromframe(akaddr_t *a, uint8_t *f) { f += 10; a->id[0] = f[4]; a->id[1] = f[5]; a->id[2] = f[10]; a->id[3] = f[11]; } static akcode_guide_t *ak_guide_getcode(akloc_context_t *lc, unsigned char *f) { akcode_guide_t *ac; if (f == NULL) /* 是模拟测试 */ { ac = &AKLOC_CODE1(lc, 2); } else { akaddr_t sa; unsigned i; int found = 0; akcode_guide_t *imin; akaddr_fromframe(&sa, f); imin = &AKLOC_CODE1(lc, 0); ac = imin; for (i = 0; i < sizeof(lc->uc.code1) / sizeof(lc->uc.code1[0]); i++) { /* 匹配地址 */ found = !AKMEMCMP(&sa, &ac->sa, sizeof(ac->sa)); if (found) break; /* 记录权值最小的 */ if (ac->wval < imin->wval) imin = ac; ac++; } if (!found) { /* 淘汰输入最少的 */ ac = imin; ac->pos = 0; ac->err = 0; ac->scnt = 0; ac->wval = 0; ac->sa = sa; } } return ac; } static int ak_guidefield_input(akcode_guide_t *ac, uint8_t *f, uint16_t len) { akwire_seq_t ws = 0; if (f) ws = akwseq_make(f + 22); if (ac->pos < 4) { if ((ac->pos != 0) && ((len - ac->val[ac->pos - 1]) != 1)) { ac->pos = 0; if (ac->wval > 0) ac->wval--; } if (ac->pos == 0) { ac->ws = ws; ac->seqcnt = 0; } ac->seqcnt += (ws - ac->ws); ac->val[ac->pos] = len; ac->pos++; ac->wval += ac->pos; } return (ac->pos == 4); } static int ak_waitfor_guidefield(akloc_context_t *lc, uint8_t *f, uint16_t len) { int ret = AIRKISS_STATUS_CONTINUE; akcode_guide_t *ac; ac = ak_guide_getcode(lc, f); if (ak_guidefield_input(ac, f, len)) { ac->pos = 0; ac->scnt++; /* 至少两次相同的guide code才算获取成功 */ if ((ac->scnt >= 2) && ac->wval >= 20) { lc->state = AKSTATE_WFM; lc->baselen = ac->val[0] - 1; lc->seqstep = ac->seqcnt/6; AKLOG_D("guide baselen(%d) seqstep(%d)\n", lc->baselen, lc->seqstep); } if (lc->state == AKSTATE_WFM) { lc->locked = ac->sa; AKMEMSET(&lc->uc, 0, sizeof(lc->uc)); ret = AIRKISS_STATUS_CHANNEL_LOCKED; } } return ret; } static int ak_waitfor_magicfield(akloc_context_t *lc, uint16_t len) { int ret = AIRKISS_STATUS_CONTINUE; akcode_t *ac = AKLOC_CODE2(lc); int udplen; udplen = aklen_udp(lc, len); if (ak_magicfield_input(ac, udplen)) { ac->pos = 0; if (ak_get_magicfield(lc, ac)) { lc->state = AKSTATE_WFP; AKLOG_D("magic: prslen(%d) ssidcrc(%X)\n", lc->prslen, lc->ssidcrc); } } if (ac->rcnt++ > 250) { akloc_reset(lc); AKLOG_D("reset from magic\n"); } return ret; } static int ak_waitfor_prefixfield(akloc_context_t *lc, uint16_t len) { int ret = AIRKISS_STATUS_CONTINUE; akcode_t *ac = AKLOC_CODE2(lc); int udplen; udplen = aklen_udp(lc, len); if (ak_prefixfield_input(ac, udplen)) { ac->pos = 0; if (ak_get_prefixfield(lc, ac)) { lc->state = AKSTATE_WFD; AKLOG_D("prefix: pwdlen(%d)\n", lc->pwdlen); } } return ret; } #ifdef AIRKISS_LOG_DFDUMP_ENABLE static void akdata_dump(akloc_context_t *lc, uint8_t *f, uint16_t len) { uint8_t seq[2]; uint16_t dseq; seq[0] = f[22]; seq[1] = f[23]; dseq = (seq[1] << 4) | (seq[0]>> 4); if (len & 0x100) { AKLOG_D("(%d) %X %c", dseq, len, len & 0xff); } else { AKLOG_D("(%d) %X", dseq, len); } } #endif /* 只判断密码和random是否收完 */ static int ak_is_pwdrand_complete(akloc_context_t *lc) { int ret = 0; unsigned i; int n = 0; for (i = 0; i < (sizeof(lc->seq) / sizeof(lc->seq[0])); i++) { if (lc->seq[i] == 0) break; n += 4; if (n >= (lc->pwdlen + 1)) { ret = 1; break; } } return ret; } static int ak_datainput_onlylength(akloc_context_t *lc, akcode_t *ac, uint16_t len) { int n = 6; if (len & 0x100) { if (ac->pos > 1) { int size; ac->val[ac->pos] = len; ac->pos ++; size = (ac->val[1] & 0x7f) * 4; if (size < lc->prslen) { size = lc->prslen - size; if (size < 4) /* 最后一个包不足4 */ { n = size + 2; } } } else { ac->pos = 0; } } else { if (ac->pos < 2) { ac->val[ac->pos] = len; ac->pos ++; } else { ac->val[0] = len; ac->pos = 1; } } return (ac->pos == n); } static akdatf_header_t* akseq_getpend(akloc_context_t *lc, uint8_t ind) { akdatf_header_t* ret = 0; unsigned i; for (i = 0; i < sizeof(lc->pendseq)/sizeof(lc->pendseq[0]); i ++) { akdatf_header_t *p = &lc->pendseq[i]; if (p->ind == ind) { ret = p; break; } } return ret; } static int ak_pendinput_mark(akloc_context_t *lc, uint8_t ind) { int ret = 0; akdatf_header_t* pd; pd = akseq_getpend(lc, ind); if (pd) { int size, pos, i; char d[6] = {0}; uint8_t crc; ind = ind & 0x7f; pos = ind * 4; size = lc->prslen - pos; if (size > 4) size = 4; for (i = 0; i < size; i ++) { if (lc->data[pos + i] == 0) return 0; } d[0] = ind; AKMEMCPY(&d[1], &lc->data[pos], size); crc = airkiss_crc8((uint8_t*)d, size + 1) & 0x7f; if (crc == (pd->crc & 0x7f)) { AKMEMSET(pd, 0, sizeof(*pd)); lc->seq[ind] = 1; lc->reclen += size; ret = 1; #ifdef AIRKISS_LOG_GDO_ENABLE AKLOG_D("getdata-p(%d, %d)[%s]", ind, size, &d[1]); #endif } } return ret; } static int ak_penddata_getpos(akloc_context_t *lc, akdatf_seq_t *ref, akwire_seq_t ws) { int ret = -1; uint8_t refind, ind; int offs; if (ws < ref->ws) {//todo AKLOG_D("ws-d overflow(%d, %d)", ws, ref->ws); } else { int maxoffs; int fmpos; offs = (ws - ref->ws)/lc->seqstep; if ((offs % 6) < 2) return -1; maxoffs = lc->prslen + ((lc->prslen + 3)/4) * 2; if (offs > maxoffs) /* 相差太大出错几率增大 */ return ret; refind = ref->ind & 0x7f; fmpos = refind * 6 + offs; fmpos = fmpos % maxoffs; /* 指向下一轮 */ ind = fmpos/6; ret = ind * 4 + (fmpos % 6) - 2; } return ret; } static int ak_pendcrc_getpos(akloc_context_t *lc, akdatf_seq_t *ref, akwire_seq_t ws) { int offs; int pos = -1; int maxoffs; maxoffs = lc->prslen + ((lc->prslen + 3)/4) * 2; if (ws < ref->ws) {//todo AKLOG_D("ws-c overflow(%d, %d)", ws, ref->ws); } else { offs = (ws - ref->ws)/lc->seqstep; if (offs > maxoffs) return -1; offs = offs + (ref->ind & 0x7f) * 6; offs = offs % maxoffs; pos = (offs/6) | 0x80; } return pos; } static void ak_dataconflict_add(akloc_context_t *lc, uint8_t pos, uint8_t d, int mode) { unsigned i; int zi = -1; int s, e; pos ++; if (mode == 0) { s = 0; e = sizeof(lc->dcfl.pos) - 4; } else { s = sizeof(lc->dcfl.pos) - 4; e = sizeof(lc->dcfl.pos); } for (i = s; i < e; i ++) { if ((lc->dcfl.pos[i] == pos) && (lc->dcfl.data[i] == d)) return; if (lc->dcfl.pos[i] == 0) zi = i; } if (zi >= 0) { lc->dcfl.data[zi] = d; lc->dcfl.pos[zi] = pos; } } static int ak_dataconflict_getchar(akloc_context_t *lc, uint8_t pos, uint8_t *cpos) { int ch = -1; uint8_t i; if (*cpos >= sizeof(lc->dcfl.pos)) return -1; pos ++; for (i = *cpos; i < sizeof(lc->dcfl.pos); i ++) { if (lc->dcfl.pos[i] == pos) { ch = lc->dcfl.data[i]; i ++; break; } } *cpos = i; return ch; } static void ak_dataconflict_clear(akloc_context_t *lc, int pos) { unsigned i; if (pos < 0) { i = sizeof(lc->dcfl.pos) - 4; for (; i < sizeof(lc->dcfl.pos); i ++) { lc->dcfl.pos[i] = 0; lc->dcfl.data[i] = 0; } } else { pos ++; for (i = 0; i < sizeof(lc->dcfl.pos) - 4; i ++) { if (lc->dcfl.pos[i] == pos) { lc->dcfl.pos[i] = 0; lc->dcfl.data[i] = 0; } } } } static int _dataconflict_crccheck(akloc_context_t *lc, akdatf_header_t* pd, uint8_t dpos, char *d, int size) { int ret = 0; uint8_t crc; crc = airkiss_crc8((uint8_t*)d, size + 1) & 0x7f; if (crc == (pd->crc & 0x7f)) { int pos; pos = (pd->ind & 0x7f) * 4; AKMEMCPY(&lc->data[pos], &d[1], size); AKMEMSET(pd, 0, sizeof(*pd)); lc->seq[(uint8_t)d[0]] = 1; lc->reclen += size; ak_dataconflict_clear(lc, dpos); ret = 1; #ifdef AIRKISS_LOG_GDO_ENABLE AKLOG_D("getdata-c(%d, %d)[%s]", d[0], size, &d[1]); #endif } return ret; } static int ak_dataconflict_crccheck(akloc_context_t *lc, akdatf_header_t* pd, int size) { char d[6] = {0}; uint8_t spos; uint8_t cflpos0 = 0, cflpos1 = 0, cflpos2 = 0, cflpos3 = 0; int i; d[0] = pd->ind & 0x7f; spos = d[0] * 4; /* 把所有冲突的数据都校验一遍 */ for (i = 0; i < size; i ++) { ak_dataconflict_add(lc, spos + i, lc->data[spos + i], 1); } while (size > 0) { int ch; ch = ak_dataconflict_getchar(lc, spos + 0, &cflpos0); if (ch < 0) break; d[1] = ch; cflpos1 = 0; while (size > 1) { int ch; ch = ak_dataconflict_getchar(lc, spos + 1, &cflpos1); if (ch < 0) break; d[2] = ch; cflpos2 = 0; while (size > 2) { int ch; ch = ak_dataconflict_getchar(lc, spos + 2, &cflpos2); if (ch < 0) break; d[3] = ch; cflpos3 = 0; while (size > 3) { int ch; ch = ak_dataconflict_getchar(lc, spos + 3, &cflpos3); if (ch < 0) break; d[4] = ch; if (_dataconflict_crccheck(lc, pd, spos + 3, d, size)) { goto _out; } } } } } _out: ak_dataconflict_clear(lc, -1); return 0; } static int ak_dataconflict_input(akloc_context_t *lc, uint8_t ind, uint8_t pos, uint8_t data) { int ret = 0; int i; int size; int spos; akdatf_header_t* pd; spos = ind * 4; size = lc->prslen - spos; if (size > 4) size = 4; ak_dataconflict_add(lc, pos, data, 0); /* 检查接收是否足够 */ for (i = 0; i < size; i ++) { if (lc->data[spos + i] == 0) { return 0; } } /* 查找包头 */ pd = akseq_getpend(lc, ind | 0x80); if (!pd) return 0; ret = ak_dataconflict_crccheck(lc, pd, size); return ret; } static int ak_databody_input(akloc_context_t *lc, akdatf_seq_t *ref, akwire_seq_t ws, uint8_t data) { int pos; uint8_t ind; uint8_t dif; /* 与上一个帧相差太大则不接受 */ dif = (ws - lc->prews)/lc->seqstep; if (dif > 5) return 0; pos = ak_penddata_getpos(lc, ref, ws); if (pos < 0) { return 0; } ind = pos / 4; if (lc->seq[ind]) { return 0; } #if AIRKISS_LOG_RIO_ENABLE AKLOG_D("ref(%d %X) input(%d) %c", ref->ws, ref->ind, pos, data); #endif if (lc->data[pos] == 0) { lc->data[pos] = data; ak_pendinput_mark(lc, ind | 0x80); } else if (lc->data[pos] != data) { /* 出现数据冲突 */ ak_dataconflict_input(lc, ind, (uint8_t)pos, data); } return 1; } static void akseq_allocpend(akloc_context_t *lc, uint8_t crc, uint8_t ind) { akdatf_header_t *found = 0, *idle = 0; unsigned i; if (lc->seq[ind & 0x7f]) return; AKLOG_D("{%X %X}", crc, ind); idle = &lc->pendseq[0]; for (i = 0; i < sizeof(lc->pendseq)/sizeof(lc->pendseq[0]); i ++) { akdatf_header_t *p = &lc->pendseq[i]; if (p->ind == ind) { found = p; p->crc = crc; break; } if (p->crc == 0) idle = p; } if (found == NULL) { found = idle; found->crc = crc; found->ind = ind; } } static void ak_datahead_input(akloc_context_t *lc, akdatf_seq_t *cur, akwire_seq_t ws, uint8_t head) { int seqmax; uint8_t dif; seqmax = (lc->prslen/4) | 0x80; if (cur->crc != 0) { dif = (ws - cur->ws)/lc->seqstep; if (head <= seqmax) { cur->ind = head; cur->ws = ws - lc->seqstep; AKLOC_DFSEQ_PREV(lc) = *cur; if (dif < 3) { /* 暂存包头 */ akseq_allocpend(lc, cur->crc, cur->ind); } } if (head > seqmax) { cur->crc = head; cur->ind = 0; cur->ws = ws; } } else { if (head > seqmax) //很大几率是crc { cur->crc = head; cur->ws = ws; cur->ind = 0; } else if (ak_pendcrc_getpos(lc, cur, ws) == head) { /* 没收到crc */ cur->ind = head; cur->ws = ws - lc->seqstep; /* 设置crc的帧序号 */ } } } static int ak_datainput_withwireseq(akloc_context_t *lc, uint8_t *f, uint16_t len) { akwire_seq_t ws; akdatf_seq_t *cur; ws = akwseq_make(f + 22); cur = &AKLOC_DFSEQ_CUR(lc); if (len & 0x100) /* 输入数据 */ { akdatf_seq_t *ref; ref = &AKLOC_DFSEQ_PREV(lc); if ((cur->ind == 0) && (cur->crc != 0)) { int pos; /* 如果只收到了crc就根据前一个包推测一个序号 */ pos = ak_pendcrc_getpos(lc, ref, ws); if (pos > 0) { cur->ind = (uint8_t)pos; akseq_allocpend(lc, cur->crc, cur->ind); } } if (cur->ind) { if (!ak_databody_input(lc, cur, ws, len)) { AKMEMSET(&AKLOC_DFSEQ_CUR(lc), 0 , sizeof(*cur)); } if (lc->reclen == lc->prslen) { lc->state = AKSTATE_CMP; } } AKLOC_DFSEQ_CUR(lc).crc = 0;/* 标记已收到数据 */ } else { /* 输入包头 */ ak_datahead_input(lc, cur, ws, len); } lc->prews = ws; return 0; } static int ak_waitfor_datafield(akloc_context_t *lc, uint8_t *f, uint16_t len, int nossid) { int ret = AIRKISS_STATUS_CONTINUE; akcode_t *ac = AKLOC_CODE2(lc); uint16_t udplen; udplen = aklen_udp(lc, len); if (udplen < 0x80) { return ret; } #ifdef AIRKISS_LOG_DFDUMP_ENABLE if (f) { akdata_dump(lc, f, udplen); } #endif if (ak_datainput_onlylength(lc, ac, udplen)) { ac->pos = 0; ak_get_datafield(lc, ac); if (lc->reclen == lc->prslen) { lc->state = AKSTATE_CMP; goto _out; } } if (f) { ak_datainput_withwireseq(lc, f, udplen); } if (nossid && ak_is_pwdrand_complete(lc)) { lc->state = AKSTATE_CMP; AKLOG_D("data complete nossid\n"); } _out: if (lc->state == AKSTATE_CMP) { lc->nossid = nossid; ret = AIRKISS_STATUS_COMPLETE; } return ret; } static int ak_sa_filter(akloc_context_t *lc, uint8_t *f) { int ret = 0; if (lc->state != AKSTATE_WFG) { akaddr_t sa; akaddr_fromframe(&sa, f); ret = AKMEMCMP(&lc->locked, &sa, sizeof(sa)); } return ret; } int airkiss_filter(const void *f, int len) { int ret = 0; unsigned char *da, *p; int i; p = (unsigned char *)f; if ((len < 25) || (p[0] != 0x08)) return 1; da = p + 4; for (i = 0; i < 6; i++) { if (da[i] != 0xFF) { ret = 1; break; } } return ret; } static int _ak_recv(airkiss_context_t *c, const void *frame, uint16_t length, int nossid) { int ret = AIRKISS_STATUS_CONTINUE; akloc_context_t *lc = (akloc_context_t *)c; unsigned char *f = (unsigned char *)frame; if (frame != NULL) /* 模拟测试时可只传length */ { if (airkiss_filter(frame, length)) return ret; if (ak_sa_filter(lc, f)) return ret; } switch (lc->state) { case AKSTATE_WFG: { ret = ak_waitfor_guidefield(lc, f, length); } break; case AKSTATE_WFM: { ret = ak_waitfor_magicfield(lc, length); } break; case AKSTATE_WFP: { ret = ak_waitfor_prefixfield(lc, length); } break; case AKSTATE_WFD: { ret = ak_waitfor_datafield(lc, f, length, nossid); } break; case AKSTATE_CMP: { ret = AIRKISS_STATUS_COMPLETE; } break; } return ret; } const char *airkiss_version(void) { return "airkiss-1.0.0-open"; } int airkiss_init(airkiss_context_t *c, const airkiss_config_t *config) { akloc_context_t *lc = (akloc_context_t *)c; if (!c | !config | !config->memcpy | !config->memset | !config->memcmp #ifdef AIRKISS_LOG_ENABLE | !config->printf #endif /* AIRKISS_LOG_ENABLE */ ) { return -1; } lc->cfg = config; akloc_reset(lc); return 0; } int airkiss_recv(airkiss_context_t *c, const void *frame, unsigned short length) { return _ak_recv(c, frame, length, 0); } int airkiss_get_result(airkiss_context_t *c, airkiss_result_t *res) { akloc_context_t *lc = (akloc_context_t *)c; if (lc->state != AKSTATE_CMP) return -1; res->pwd = (char *)&lc->data[0]; res->pwd_length = lc->pwdlen; if (lc->data[lc->pwdlen] == 0) { res->random = lc->random; } else { res->random = lc->data[lc->pwdlen]; lc->random = lc->data[lc->pwdlen]; lc->data[lc->pwdlen] = 0; } res->ssid_crc = lc->ssidcrc; if (lc->nossid) { res->ssid = ""; res->ssid_length = 0; } else { res->ssid = (char *)&lc->data[lc->pwdlen + 1]; res->ssid_length = lc->prslen - lc->pwdlen - 1; } lc->data[lc->prslen] = 0; return 0; } int airkiss_recv_nossid(airkiss_context_t *c, const void *frame, unsigned short length) { return _ak_recv(c, frame, length, 1); } int airkiss_change_channel(airkiss_context_t *c) { akloc_context_t *lc = (akloc_context_t *)c; akloc_reset(lc); return 0; }