nodemcu-firmware/app/smart/smart.c

725 lines
22 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "user_interface.h"
#include "user_config.h"
#include "smart.h"
#include "esp_wifi.h"
#include "esp_libc.h"
#define ADDR_MAP_NUM 10
static os_timer_t smart_timer;
static smart_addr_map *am[ADDR_MAP_NUM];
static smart_addr_map *matched = NULL;
static struct station_config *sta_conf;
static int cur_channel = 1;
static uint8_t mode = STATION_MODE;
static uint8_t alldone = 0;
// 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000(LSB)
// when the bit is set, means the ssid byte is got
static uint8_t *got_ssid = NULL;
static uint8_t *got_password = NULL;
static uint8_t *ssid_nibble = NULL;
static uint8_t *password_nibble = NULL;
static smart_succeed succeed = NULL;
static void *smart_succeed_arg = NULL;
void smart_end();
int smart_check(uint8_t *nibble, uint16_t len, uint8_t *dst, uint8_t *got){
if(len == 0)
return 0;
uint16_t dst_len = len/NIBBLE_PER_BYTE;
uint16_t byte_num = 0, bit_num = 0;
int i = 0, res = 1; // assume ok.
memset(dst,0,dst_len);
if(NIBBLE_PER_BYTE==1){
for(i=0;i<len;i++){
byte_num = (i) / 8;
bit_num = (i) % 8;
if(0x20>nibble[i] || nibble[i]>=0x7F){ // not printable
NODE_DBG("Smart: got np byte %d:%02x\n", i, nibble[i]);
nibble[i] = 0;
got[byte_num] &= ~(0x1 << bit_num); // clear the bit
res = 0; // not ok
} else {
dst[i] = nibble[i];
}
}
return res;
}
// NIBBLE_PER_BYTE == 2
if((len%NIBBLE_PER_BYTE) != 0){
// this should not happen
NODE_DBG("Smart: smart_check got odd len\n");
return 0;
}
if(len == 2){
// only one byte
if(nibble[0]<=0xF && ((nibble[0]^0x1)&0xF == (nibble[1]>>4)) ){
dst[0] = ((nibble[0]&0xF)<<4) + (nibble[1]&0xF);
res = 1;
}else{
nibble[0] = 0;
nibble[1] = 0;
got[0] &= ~(0x3 << 0); // clear the 0 bit
res = 0; // not ok
}
return res;
}
res = 1; // assume ok.
for(i=len-2;i>0;i--){
bool forward = ( ((nibble[i]&0xF)^((i+1)&0xF)) == (nibble[i+1]>>4) );
bool back = ( ((nibble[i-1]&0xF)^(i&0xF)) == (nibble[i]>>4) );
if(!forward || !back){
// wrong forward, or wrong back, replace i-1, i and i+1, until get right back, forward
NODE_DBG("check: wf %d:%02x %02x %02x\n",i,nibble[i-1],nibble[i], nibble[i+1]);
byte_num = (i-1) / 8;
bit_num = (i-1) % 8;
nibble[i-1] = 0;
got[byte_num] &= ~(0x1 << bit_num); // clear the bit
byte_num = (i) / 8;
bit_num = (i) % 8;
nibble[i] = 0;
got[byte_num] &= ~(0x1 << bit_num); // clear the bit
byte_num = (i+1) / 8;
bit_num = (i+1) % 8;
nibble[i+1] = 0;
got[byte_num] &= ~(0x1 << bit_num); // clear the bit
res = 0;
return res; // once there is error,
}
if((i%NIBBLE_PER_BYTE) == 0) { // i == even
dst[i/NIBBLE_PER_BYTE] = ((nibble[i]&0xF)<<4) + (nibble[i+1]&0xF);
}
}
if(i==0){
dst[0] = ((nibble[0]&0xF)<<4) + (nibble[1]&0xF);
}
for(i=0;i<dst_len;i++){ // check for non-printable byte
// NODE_DBG("nibble %d:%02x %02x->%02x\n", i, nibble[i*NIBBLE_PER_BYTE], nibble[i*NIBBLE_PER_BYTE+1], dst[i]);
byte_num = (i*NIBBLE_PER_BYTE) / 8;
bit_num = (i*NIBBLE_PER_BYTE) % 8;
if(0x20>dst[i] || dst[i]>=0x7F){ // not printable
NODE_DBG("Smart: got np byte %d:%02x\n", i, dst[i]);
dst[i] = 0; // reset byte
nibble[i*NIBBLE_PER_BYTE] = 0; // reset hi-nibble
nibble[i*NIBBLE_PER_BYTE+1] = 0; // reset lo-nibble
got[byte_num] &= ~(0x3 << bit_num); // clear the bit
res = 0; // not ok
}
}
return res;
}
void detect(uint8 *arg, uint16 len){
uint16_t seq;
int16_t seq_delta = 0;
uint16_t byte_num = 0, bit_num = 0;
int16_t c = 0;
uint8 *buf = NULL;
if( len == 12 ){
return;
} else if (len >= 64){
buf = arg + sizeof(struct RxControl);
} else {
return;
}
if( ( (buf[0]) & TYPE_SUBTYPE_MASK) != TYPE_SUBTYPE_QOS_DATA){
return;
}
if( (buf[1] & DS_RETRY_MASK) != NO_RETRY )
return;
if( buf[SEQ_ADDR] & 0xF != 0 ) // Fragment Number should = 0
return;
// calculate current seq number
seq = buf[SEQ_ADDR+1];
seq = seq<<4;
seq += buf[SEQ_ADDR]>>4;
if(!matched){ // cur_base_seq is ref to flag[0] when finding the patern
int i;
for (i = 0; i < ADDR_MAP_NUM; i++) // for each source-dest adress pair in the map
{
if ( am[i]->flag_match_num == 0 ){ // not in the map yet
if ( len - am[i]->base_len == am[i]->flag[0]) // store new source-dest adress pair to the map until flag[0] is got
{
// BSSID, SA, DA, store the SA, DA
memcpy(am[i]->addr, &buf[ADDR_MATCH_START], ADDR_MATCH_LENGTH);
am[i]->flag_match_num++; // =1
am[i]->cur_base_seq = seq; // assume the first seq is found
am[i]->base_seq_valid = 1;
// NODE_DBG("Smart: new addr pair found\n");
}
break; // break any way for the next packet to come
}
else if(0 == memcmp(am[i]->addr, &buf[ADDR_MATCH_START], ADDR_MATCH_LENGTH)){ // source-dest adress pair match
if(am[i]->base_seq_valid == 0){
if ( len - am[i]->base_len == am[i]->flag[0]) { // found the new flag[0]
// here flag_match_num is already = 1
am[i]->cur_base_seq = seq;
am[i]->base_seq_valid = 1; // the seq number is valid now
// NODE_DBG("Smart: new base_seq found\n");
}
break; // break any way for the next packet to come
}
// base seq number is valid, cal the delta
if(seq >= am[i]->cur_base_seq){
seq_delta = seq - am[i]->cur_base_seq;
} else {
seq_delta = SEQ_MAX - am[i]->cur_base_seq + seq;
}
if(seq_delta < 0){ // this should never happen
am[i]->base_seq_valid = 0; // the seq number is not valid
break;
}
if(seq_delta == 0){ // base_seq is not valid any more
if ( len - am[i]->base_len != am[i]->flag[0]) { // lost the flag[0]
am[i]->base_seq_valid = 0; // the seq number is not valid
}
break; // break any way for the next packet to come
}
// delta is out of range, need to find the next flag[0] to start again
if (seq_delta>=FLAG_NUM){
am[i]->flag_match_num = 1; // reset to 1
if ( len - am[i]->base_len == am[i]->flag[0]) { // found the new flag[0]
// here flag_match_num is already = 1
am[i]->cur_base_seq = seq;
am[i]->base_seq_valid = 1; // the seq number is valid now
} else {
am[i]->base_seq_valid = 0;
}
break; // done for this packet
}
// NODE_DBG("Smart: match_num:%d seq_delta:%d len:%d\n",am[i]->flag_match_num,seq_delta,len-am[i]->base_len);
// seq_delta now from 1 to FLAG_NUM-1
// flag[] == 0 ,means skip this flag.
if ( (am[i]->flag_match_num==seq_delta) && \
( (am[i]->flag[am[i]->flag_match_num]==len-am[i]->base_len) || (am[i]->flag[am[i]->flag_match_num]==0) ) ){
am[i]->flag_match_num++;
if(am[i]->flag_match_num == FLAG_MATCH_NUM){ //every thing is match.
NODE_ERR("Smart: got matched sender\n");
matched = am[i]; // got the matched source-dest adress pair who is sending the udp data
matched->base_seq_valid = 0; // set to 0, and start to reference to the SSID_FLAG from now on
os_timer_disarm(&smart_timer); // note: may start a longer timeout
}
break;
}
// non match, reset, need to find next flag[0] to start again
am[i]->flag_match_num = 1;
am[i]->base_seq_valid = 0;
break;
} // non-match source-dest adress pair, continue to next pair in the map.
} // for loop
// break out, or loop done.
goto end;
} else { // cur_base_seq is ref to SSID_FLAG when patern is alread found
if(0 != memcmp(matched->addr, &buf[ADDR_MATCH_START], ADDR_MATCH_LENGTH)){ // source-dest adress pair not match, ignore it
return;
}
if (matched->base_seq_valid == 0){ // SSID_FLAG seq invalid, need to find the next valid seq number
// base_seq not valid, find it
if (len - matched->base_len == SSID_FLAG){
matched->cur_base_seq = seq;
matched->base_seq_valid = 1;
}
goto end;
}
if(seq >= matched->cur_base_seq){
seq_delta = seq - matched->cur_base_seq;
} else {
seq_delta = SEQ_MAX - matched->cur_base_seq + seq;
}
if(seq_delta < 0){ // this should never happen
matched->base_seq_valid = 0; // the seq number is not valid
goto end;
}
if(seq_delta == 0){ // base_seq is not valid any more
if ( len - matched->base_len != SSID_FLAG) { // lost the SSID_FLAG
matched->base_seq_valid = 0; // the seq number is not valid
}
goto end; // exit for the next packet to come
}
if ( seq_delta > (SEP_NUM + 1)*(1+NIBBLE_PER_BYTE*matched->ssid_len) +\
1 + (SEP_NUM + 1)*(1+NIBBLE_PER_BYTE*matched->pwd_len) ){
// delta out of the range
if (len - matched->base_len == SSID_FLAG){
matched->cur_base_seq = seq;
matched->base_seq_valid = 1;
} else {
matched->base_seq_valid = 0;
}
goto end;
}
// delta in the range
if (seq_delta==1){
int16_t ssid_len = len - matched->base_len - L_FLAG;
if ( matched->ssid_len == 0 ){ // update the ssid_len
if ( (ssid_len <=32) && (ssid_len >0) ){
matched->ssid_len = ssid_len;
NODE_DBG("Smart: found the ssid_len %d\n", matched->ssid_len);
}
goto end;
}
if (ssid_len != matched->ssid_len){ // ssid_len not match
matched->base_seq_valid = 0;
// note: not match, save the new one or old one? for now save the new one.
matched->ssid_len = ssid_len;
NODE_DBG("Smart: ssid_len not match\n");
}
goto end; // to the next packet
}
if( (SEP_NUM==2)&&(seq_delta==2 || seq_delta==3) ) {
if (len - matched->base_len != matched->flag[seq_delta-2+SEP_1_INDEX]){ // SEP not match
matched->base_seq_valid = 0;
NODE_DBG("Smart: SEP-L not match\n");
}
goto end; // to the next packet
}
if( seq_delta==(SEP_NUM + 1)*(1+NIBBLE_PER_BYTE*matched->ssid_len) + 1) {
if (len - matched->base_len != PWD_FLAG){ // PWD_FLAG not match
matched->base_seq_valid = 0;
NODE_DBG("Smart: PWD_FLAG not match\n");
}
goto end; // to the next packet
}
if (seq_delta==(SEP_NUM + 1)*(1+NIBBLE_PER_BYTE*matched->ssid_len) + 1 + 1){
int16_t pwd_len = len - matched->base_len - L_FLAG;
if ( matched->pwd_len == 0){
if ( (pwd_len <=64) && (pwd_len>0)){
matched->pwd_len = pwd_len;
NODE_DBG("Smart: found the pwd_len %d\n", matched->pwd_len);
}
goto end; // to the next packet
}
if (pwd_len != matched->pwd_len){ // pwd_len not match
matched->base_seq_valid = 0;
// note: not match, save the new one or old one? for now save the new one.
matched->pwd_len = pwd_len; // reset pwd_len to 0
NODE_DBG("Smart: pwd_len not match\n");
}
goto end;
}
if (seq_delta <= (SEP_NUM + 1)*(1+NIBBLE_PER_BYTE*matched->ssid_len) ){ // in the ssid zone
uint16_t it = (seq_delta-1-SEP_NUM-1) / (SEP_NUM + 1); // the number of ssid nibble: 0~31 or 0~63
uint16_t m = (seq_delta-1-SEP_NUM-1) % (SEP_NUM + 1); // 0~2
switch(m){
case 0: // the ssid hi/lo-nibble itself
c = (int16_t)(len - matched->base_len - C_FLAG);
if (c>255 || c<0){
matched->base_seq_valid = 0;
NODE_DBG("Smart: wrong ssid nibble\n");
goto end;
}
byte_num = it / 8; // 0~7
bit_num = it % 8; // 0~7
if( (got_ssid[byte_num] & (0x1 << bit_num)) == 0){
got_ssid[byte_num] |= 0x1 << bit_num; // set the bit
ssid_nibble[it] = c;
}
break;
case 1: // seperator 1
case 2: // seperator 2
if(len - matched->base_len != matched->flag[m-1+SEP_1_INDEX]){
NODE_DBG("Smart: SEP-S not match\n");
matched->base_seq_valid = 0;
goto end;
}
break;
default:
break;
}
} else { // in the pwd zone
uint16_t it = (seq_delta -1 -(SEP_NUM + 1)*(1+NIBBLE_PER_BYTE*matched->ssid_len) - 2 - SEP_NUM) / (SEP_NUM + 1); // the number of pwd byte
uint16_t m = (seq_delta -1 -(SEP_NUM + 1)*(1+NIBBLE_PER_BYTE*matched->ssid_len) - 2 - SEP_NUM) % (SEP_NUM + 1);
switch(m){
case 0: // the pwd hi/lo-nibble itself
c = (int16_t)(len - matched->base_len - C_FLAG);
if (c>255 || c<0){
matched->base_seq_valid = 0;
NODE_DBG("Smart: wrong password nibble\n");
goto end;
}
byte_num = it / 8; // 0~15 / 7
bit_num = it % 8; // 0~7
if( (got_password[byte_num] & (0x1 << bit_num)) == 0){
got_password[byte_num] |= 0x1 << bit_num; // set the bit
password_nibble[it] = c;
}
break;
case 1: // seperator 1
case 2: // seperator 2
if(len - matched->base_len != matched->flag[m-1+SEP_1_INDEX]){
NODE_DBG("Smart: SEP-P not match\n");
matched->base_seq_valid = 0;
goto end;
}
break;
default:
break;
}
}
// check if all done
// NODE_DBG("Smart: ssid got %02x %02x\n", got_ssid[0], got_ssid[1]);
// NODE_DBG("Smart: password got %02x %02x %02x\n", got_password[0], got_password[1], got_password[2]);
int i,j;
for(i=0;i<NIBBLE_PER_BYTE*matched->ssid_len;i++){
byte_num = (i) / 8;
bit_num = (i) % 8;
if( (got_ssid[byte_num] & (0x1 << bit_num) ) != (0x1 << bit_num) ){ // check the bit == 1
break;
}
}
for(j=0;j<NIBBLE_PER_BYTE*matched->pwd_len;j++){
byte_num = (j) / 8;
bit_num = (j) % 8;
if( (got_password[byte_num] & (0x1 << bit_num) ) != (0x1 << bit_num) ){ // check the 2 bit == 11
break;
}
}
if(matched->ssid_len > 0 && matched->pwd_len > 0 && i==NIBBLE_PER_BYTE*matched->ssid_len && j==NIBBLE_PER_BYTE*matched->pwd_len){ // get everything, check it.
if( smart_check(ssid_nibble, NIBBLE_PER_BYTE*matched->ssid_len, sta_conf->ssid, got_ssid) && \
smart_check(password_nibble, NIBBLE_PER_BYTE*matched->pwd_len, sta_conf->password, got_password) ){
// all done
alldone = 1;
NODE_ERR(sta_conf->ssid);
NODE_ERR(" %d\n", matched->ssid_len);
NODE_ERR(sta_conf->password);
NODE_ERR(" %d\n", matched->pwd_len);
smart_end();
// if(succeed){
// succeed(smart_succeed_arg);
// succeed = NULL; // reset to NULL when succeed
// smart_succeed_arg = NULL;
// }
return;
}
}
}
end:
#if 0
NODE_DBG("%d:\t0x%x 0x%x\t", len-BASE_LENGTH, buf[0],buf[1]);
NODE_DBG(MACSTR, MAC2STR(&(buf[BSSID_ADDR])));
NODE_DBG("\t");
NODE_DBG(MACSTR, MAC2STR(&(buf[SOURCE_ADDR])));
NODE_DBG("\t");
NODE_DBG(MACSTR, MAC2STR(&(buf[DEST_ADDR])));
uint16_t tseq = buf[SEQ_ADDR+1];
tseq = tseq<<4;
tseq += buf[SEQ_ADDR]>>4;
NODE_DBG("\t0x%04x\n", tseq);
#endif
return;
}
void reset_map(smart_addr_map **am, size_t num){
int i;
for (i = 0; i < num; ++i)
{
am[i]->flag_match_num = 0;
am[i]->addr_len = ADDR_MATCH_LENGTH;
am[i]->base_len = BASE_LENGTH;
am[i]->cur_base_seq = -1;
am[i]->base_seq_valid = 0;
am[i]->ssid_len = 0;
am[i]->pwd_len = 0;
memset(am[i]->addr, 0, ADDR_MATCH_LENGTH);
if(SEP_1_INDEX==0){
am[i]->flag[0] = SEP_1;
am[i]->flag[1] = SEP_2;
am[i]->flag[2] = SSID_FLAG;
}
if(SEP_1_INDEX==2){
am[i]->flag[0] = SSID_FLAG;
am[i]->flag[1] = 0; // skip this flag
am[i]->flag[2] = SEP_1;
am[i]->flag[3] = SEP_2;
}
}
}
void smart_enable(void){
wifi_promiscuous_enable(1);
}
void smart_disable(void){
wifi_promiscuous_enable(0);
}
void smart_end(){
int i;
os_timer_disarm(&smart_timer);
smart_disable();
wifi_set_channel(cur_channel);
if(NULL_MODE != mode){
wifi_set_opmode(mode);
} else {
wifi_set_opmode(STATION_MODE);
}
mode = wifi_get_opmode();
if(sta_conf && alldone){
if( (STATION_MODE == mode) || (mode == STATIONAP_MODE) ){
wifi_station_set_config(sta_conf);
wifi_station_set_auto_connect(true);
wifi_station_disconnect();
wifi_station_connect();
os_timer_disarm(&smart_timer);
os_timer_setfn(&smart_timer, (os_timer_func_t *)station_check_connect, (void *)1);
os_timer_arm(&smart_timer, STATION_CHECK_TIME, 0); // no repeat
}
}
for (i = 0; i < ADDR_MAP_NUM; ++i)
{
if(am[i]){
free(am[i]);
am[i] = NULL;
}
matched = NULL;
}
if(sta_conf){
free(sta_conf);
sta_conf = NULL;
}
if(got_password){
free(got_password);
got_password = NULL;
}
if(got_ssid){
free(got_ssid);
got_ssid = NULL;
}
if(password_nibble){
free(password_nibble);
password_nibble = NULL;
}
if(ssid_nibble){
free(ssid_nibble);
ssid_nibble = NULL;
}
// system_restart(); // restart to enable the mode
}
void smart_next_channel(){
smart_disable();
switch(cur_channel){
case 1:
cur_channel = MAX_CHANNEL;
break;
case 2:
case 3:
case 4:
cur_channel++;
break;
case 5:
cur_channel = 7;
break;
case 6:
cur_channel = 1;
break;
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
cur_channel++;
break;
case 13:
cur_channel = 6;
break;
case MAX_CHANNEL:
cur_channel = 2;
break;
default:
cur_channel = 6;
break;
}
NODE_ERR("switch to channel %d\n", cur_channel);
wifi_set_channel(cur_channel);
reset_map(am, ADDR_MAP_NUM);
memset(sta_conf->ssid, 0, sizeof(sta_conf->ssid));
memset(sta_conf->password, 0, sizeof(sta_conf->password));
memset(got_ssid, 0, SSID_BIT_MAX);
memset(got_password, 0, PWD_BIT_MAX);
memset(ssid_nibble, 0, SSID_NIBBLE_MAX);
memset(password_nibble, 0, PWD_NIBBLE_MAX);
os_timer_disarm(&smart_timer);
os_timer_arm(&smart_timer, TIME_OUT_PER_CHANNEL, 0); // no repeat
smart_enable();
}
void smart_begin(int chnl, smart_succeed s, void *arg){
int i;
alldone = 0;
for (i = 0; i < ADDR_MAP_NUM; ++i)
{
if(!am[i]){
am[i] = (smart_addr_map*)zalloc(sizeof(smart_addr_map));
if(!am[i]){
NODE_DBG("smart_begin map no memory\n");
smart_end();
return;
}
}
}
if(!sta_conf){
sta_conf = (struct station_config *)zalloc(sizeof(struct station_config));
if(!sta_conf){
NODE_DBG("smart_begin sta_conf no memory\n");
smart_end();
return;
}
}
if(!ssid_nibble){
ssid_nibble = (uint8_t *)zalloc(SSID_NIBBLE_MAX);
if(!ssid_nibble){
NODE_DBG("smart_begin sta_conf no memory\n");
smart_end();
return;
}
}
if(!password_nibble){
password_nibble = (uint8_t *)zalloc(PWD_NIBBLE_MAX);
if(!password_nibble){
NODE_DBG("smart_begin sta_conf no memory\n");
smart_end();
return;
}
}
if(!got_ssid){
got_ssid = (uint8_t *)zalloc(SSID_BIT_MAX);
if(!got_ssid){
NODE_DBG("smart_begin sta_conf no memory\n");
smart_end();
return;
}
}
if(!got_password){
got_password = (uint8_t *)zalloc(PWD_BIT_MAX);
if(!got_password){
NODE_DBG("smart_begin sta_conf no memory\n");
smart_end();
return;
}
}
reset_map(am, ADDR_MAP_NUM);
// memset(sta_conf->ssid, 0, sizeof(sta_conf->ssid));
// memset(sta_conf->password, 0, sizeof(sta_conf->password));
// memset(got_ssid, 0, SSID_BIT_MAX);
// memset(got_password, 0, PWD_BIT_MAX);
// memset(ssid_nibble, 0, SSID_NIBBLE_MAX);
// memset(password_nibble, 0, PWD_NIBBLE_MAX);
mode = wifi_get_opmode();
if( (STATION_MODE == mode) || (mode == STATIONAP_MODE) ){
wifi_station_set_auto_connect(false);
wifi_station_disconnect();
}
cur_channel = chnl;
NODE_ERR("set channel to %d\n", cur_channel);
wifi_set_channel(cur_channel);
wifi_set_promiscuous_rx_cb(detect);
os_timer_disarm(&smart_timer);
os_timer_setfn(&smart_timer, (os_timer_func_t *)smart_next_channel, NULL);
os_timer_arm(&smart_timer, TIME_OUT_PER_CHANNEL, 0); // no repeat
if(s){
succeed = s; // init the succeed call back
smart_succeed_arg = arg;
}
smart_enable();
}
void station_check_connect(bool smart){
mode = wifi_get_opmode();
if( (STATION_MODE != mode) && (mode != STATIONAP_MODE) ){
return;
}
uint8_t status = wifi_station_get_connect_status();
switch(status){
case STATION_GOT_IP:
NODE_DBG("station_check_connect is called with status: GOT_IP\n");
if(succeed){
succeed(smart_succeed_arg);
succeed = NULL; // reset to NULL when succeed
smart_succeed_arg = NULL;
}
return;
case STATION_CONNECTING:
NODE_DBG("station_check_connect is called with status: CONNECTING\n");
break;
case STATION_IDLE:
wifi_station_set_auto_connect(true);
case STATION_CONNECT_FAIL:
case STATION_NO_AP_FOUND:
wifi_station_disconnect();
wifi_station_connect();
NODE_DBG("station_check_connect is called with smart: %d\n", smart);
break;
case STATION_WRONG_PASSWORD:
if(smart)
smart_begin(cur_channel, succeed, smart_succeed_arg);
return;
default:
break;
}
os_timer_disarm(&smart_timer);
os_timer_setfn(&smart_timer, (os_timer_func_t *)station_check_connect, (void *)(int)smart);
os_timer_arm(&smart_timer, STATION_CHECK_TIME, 0); // no repeat
}