Smart配网模式
Smart配网需要网卡支持进入sniffer模式,捕获空气中的所有无线包以获取手机APP广播的ssid,passwd,token配网信息;
Smart配网数据链路图
Title:
participant TuyaApp
participant 用户层
participant tuya_sdk
participant TuyaCloud
tuya_sdk->用户层: hwl_wf_wk_mode_set(WWM_STATION)
tuya_sdk->用户层: hwl_wf_all_ap_scan
tuya_sdk->用户层: hwl_wf_wk_mode_set(WWM_SNIFFER)
tuya_sdk->用户层: create func_Sniffer thread
TuyaApp->TuyaApp:用户选择Smart模式添加设备
Note over TuyaApp: 广播发送ssid/passwd/token
tuya_sdk->用户层: hwl_wf_set_cur_channel
Note over 用户层: 切换信道捕捉报文
用户层->用户层:捕捉到合法的网络报文
用户层-->tuya_sdk:s_pSnifferCall(rev_buf,len)
tuya_sdk->tuya_sdk:解析出ssid/passwd/token
tuya_sdk->用户层: exit func_Sniffer thread
tuya_sdk->用户层: hwl_wf_wk_mode_set(WWM_STATION)
tuya_sdk->用户层: hwl_wf_station_connect(ssid,passwd)
用户层-->tuya_sdk: return OPRT_OK
tuya_sdk->用户层: hwl_wf_station_stat_get
Note over tuya_sdk: 每隔1s查询一次网络状态
用户层-->tuya_sdk: WSS_GOT_IP
tuya_sdk->TuyaCloud: 请求设备激活
TuyaCloud-->tuya_sdk: 设备激活成功
tuya_sdk->用户层: GET_WF_NW_STAT_CB(STAT_CLOUD_CONN)\n通知设备配网成功
TuyaApp->TuyaCloud:刷新设备列表
TuyaCloud-->TuyaApp:设备列表新增设备
用户需实现的接口说明
说明:如下接口涉及wifi网卡操作,请根据设备系统实现,demo里的实现仅供参考,未必适配你的设备;tuya_sdk未对wifi网卡驱动层做限制,比如没有要求必须支持ifconfig命令。 接口位置:tuya_iot_sdk/demo_soc_dev_wifi/tuya_iot_wifi_net.c文件中
hwl_wf_all_ap_scan
/***********************************************************
* @Function:hwl_wf_all_ap_scan
* @Desc: 扫描设备周围热点信息
* @Return: OPRT_OK: success Other: fail
* @Note: tuya_sdk的demo使用iwlist实现,如果网卡驱动支持,可不用修改
***********************************************************/
OPERATE_RET hwl_wf_all_ap_scan(OUT AP_IF_S **ap_ary,OUT UINT_T *num)
{
// UserTODO
return OPRT_OK;
}
hwl_wf_set_cur_channel
/***********************************************************
* @Function:hwl_wf_set_cur_channel
* @Desc: 设置wifi工作信道
* @Return: OPRT_OK: success Other: fail
* @Note:
***********************************************************/
OPERATE_RET hwl_wf_set_cur_channel(IN CONST BYTE_T chan)
{
PR_DEBUG("WIFI Set Channel:%d", chan);
// UserTODO
return OPRT_OK;
}
hwl_wf_get_cur_channel
/***********************************************************
* @Function:hwl_wf_get_cur_channel
* @Desc: 获取wifi工作信道
* @Return: OPRT_OK: success Other: fail
* @Note:
***********************************************************/
OPERATE_RET hwl_wf_get_cur_channel(OUT BYTE_T *chan)
{
// UserTODO
*chan = ?;
PR_DEBUG("WIFI Get Curr Channel:%d", *chan);
return OPRT_OK;
}
tuya-sdk抓包线程
/*
* Function: func_Sniffer 抓包线程实现
* Note: Smart配网模式时,tuya_sdk自动调用,无需应用层调用
* Return: NULL
*/
#pragma pack(1)
/* http://www.radiotap.org/ */
typedef struct {
BYTE_T it_version;
BYTE_T it_pad;
USHORT_T it_len;
UINT_T it_present;
}ieee80211_radiotap_header;
#pragma pack()
static volatile SNIFFER_CALLBACK s_pSnifferCall = NULL;
static volatile int s_enable_sniffer = 0;
static void * func_Sniffer(void *pReserved)
{
PR_DEBUG("Sniffer Thread Create");
int sock = socket(PF_PACKET, SOCK_RAW, htons(0x03));//ETH_P_ALL
if(sock < 0)
{
printf("Sniffer Socket Alloc Fails %d \r\n", sock);
perror("Sniffer Socket Alloc");
return (void *)0;
}
{/* 强制绑定到WLAN_DEV 上。后续可以考虑去掉 */
struct ifreq ifr;
memset(&ifr, 0x00, sizeof(ifr));
strncpy(ifr.ifr_name, WLAN_DEV , strlen(WLAN_DEV) + 1);
setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (char *)&ifr, sizeof(ifr));
}
#define MAX_REV_BUFFER 512
BYTE_T rev_buffer[MAX_REV_BUFFER];
int skipLen = 26;/* radiotap 默认长度为26 */
while((s_pSnifferCall != NULL) && (s_enable_sniffer == 1))
{
int rev_num = recvfrom(sock, rev_buffer, MAX_REV_BUFFER, 0, NULL, NULL);
ieee80211_radiotap_header *pHeader = (ieee80211_radiotap_header *)rev_buffer;
skipLen = pHeader->it_len;
#ifdef WIFI_CHIP_7601
skipLen = 144;
#endif
if(skipLen >= MAX_REV_BUFFER)
{/* 有出现过header全ff的情况,这里直接丢掉这个包 */
continue;
}
#if 0
{
printf("skipLen:%d ", skipLen);
int index = 0;
for(index = 0; index < 180; index++)
{
printf("%02X-", rev_buffer[index]);
}
printf("\r\n");
}
#endif
/* wifi recv from packages from the air, and send these
packages to tuya-sdk with hwl_wf_sniffer_set of callback <cb> */
if(rev_num > skipLen)
{
s_pSnifferCall(rev_buffer + skipLen, rev_num - skipLen);
}
PR_DEBUG("s_enable_sniffer");
}
s_pSnifferCall = NULL;
close(sock);
PR_DEBUG("Sniffer Proc Finish");
return (void *)0;
}
// 开启或退出抓包线程,tuya-sdk会调用
static pthread_t sniffer_thId; // 抓包线程ID
OPERATE_RET hwl_wf_sniffer_set(IN CONST BOOL_T en,IN CONST SNIFFER_CALLBACK cb)
{
if(en == TRUE)
{
PR_DEBUG("Enable Sniffer");
hwl_wf_wk_mode_set(WWM_SNIFFER);
s_pSnifferCall = cb;
if(s_enable_sniffer == 1){
return;
}
s_enable_sniffer = 1;
pthread_create(&sniffer_thId, NULL, func_Sniffer, NULL);
}else
{
PR_DEBUG("Disable Sniffer");
s_enable_sniffer = 0;
pthread_join(sniffer_thId, NULL);
hwl_wf_wk_mode_set(WWM_STATION);
}
return OPRT_OK;
}