总述
WIFI配网种类很多,在之前的博客中有讲述过。WIFI热点配网是一种比较成熟的配网方式,且配网成功率很高。
详解
原理
WIFI分为AP和STA模式,在WIFI未连接上路由器前,STA模式基本是没啥用的,这个时候就可以利用AP模式进行配网。AP模式下WIFI设备相当于是一个路由器,手机等其它设备可以进行连接。WIFI设备里做一个简单的WebServer,只要访问IP地址时直接发送页面内容就好了,涉及的通信协议就是http了。当然这个网页也可以包含固件升级以及相关设备信息的展示。
简单页面展示
配网流程
1、 浏览器访问wifi设备IP,弹出页面
2、 输入热点名以及密码,等待配网成功
固件升级流程
1、选择文件
2、分包进行get/post请求
3、设备端收到数据进行写Flash
4、轮询设备端写Flash是否成功
5、第四步成功则从2循环直到更新成功
强制弹出网页
手机连接有些热点时,我们会发现会直接弹出认证界面,如果热点配网加上这个功能就比较人性化了。这个功能的原理是DNS劫持,在手机等设备连接上热点后,会尝试去请求DNS服务器获取一些网址的IP地址,此时wifi设备端就可以监听请求包,然后将自己的IP地址作为DNS解析结果返回给连接设备。
DNS采用UDP通信协议,端口号是53,数据协议如下:
相关代码如下:
void ap_dns_intercept()
{
uint8_t data[128];
int len = 0;
struct sockaddr_in client = { 0 };
socklen_t client_len=sizeof(struct sockaddr_in);
uint32_t i = 0;
printf("DNS server start ...\r\n");
int sock = create_socket_udp(); //创建udp
if (sock < 0) {
printf("Failed to create IPv4 multicast socket\r\n");
}
while(1)
{
len=recvfrom(sock,data,100,0,(struct sockaddr *)&client,&client_len);
if((len < 0) || ( len > 100))
{
printf("recvfrom error\n");
continue;
}
printf("DNS request:");
for(i = 0x4; i< len;i++)
{
if((data[i] >= 'a' && data[i] <= 'z') || (data[i] >= 'A' && data[i] <= 'Z') ||(data[i] >= '0' && data[i] <= '9'))
printf("%c",data[i]);
else
printf("_");
}
printf("\r\n");
if( strstr((const char *)data+0xc,"taobao")||
strstr((const char *)data+0xc,"qq") ||
strstr((const char *)data+0xc,"sogou") ||
strstr((const char *)data+0xc,"amap") ||
strstr((const char *)data+0xc,"alipay")||
strstr((const char *)data+0xc,"youku") ||
strstr((const char *)data+0xc,"iqiyi") ||
strstr((const char *)data+0xc,"baidu"))
{
continue;
}
data[2] |= 0x80; //
data[3] |= 0x80; //与接收的高位不同之处
data[7] =1; //问题个数
//与接收的域名相同可用指针代替
//前两位表示最高两bit为11,表示指正方式(非指正方式,最高两bit为00)
//后14为表示前面接收的域名的为止 这里从11位开始
data[len++] =0xc0;
data[len++] =0x0c;
//不变的
data[len++] =0x00;
data[len++] =0x01;
data[len++] =0x00;
data[len++] =0x01;
//有效时间
data[len++] =0x00;
data[len++] =0x00;
data[len++] =0x00;
data[len++] =0x0A;
//下面的数据长度
data[len++] =0x00;
data[len++] =0x04;
data[len++] =192;
data[len++] =168;
data[len++] =88;
data[len++] =1;
sendto(sock,data,len,0,(struct sockaddr*)&client,client_len);
OS_MSleep(10);
}
printf("DNS server stop ...\r\n");
shutdown(sock, 0);
close(sock);
OS_ThreadDelete(NULL);
}