LV02-01-天猫精灵IOT-03-零配-02-零配代码分析

本文主要是天猫精灵IOT零配——零配代码分析的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。

点击查看使用工具及版本
Windows版本 windows11
Ubuntu版本 Ubuntu22.04的64位版本
VMware® Workstation 16 Pro 16.2.3 build-19376536
终端软件 MobaXterm(Professional Edition v23.0 Build 5042 (license))
点击查看本文参考资料
分类 网址 说明
官方网站 阿里云 阿里云官网主页
阿里生活物联平台 生活物联网平台(飞燕平台)主页
AliGenie 天猫精灵开放平台AliGenie主页
阿里物联网平台 阿里物联网平台主页
Bluetooth 技术网站 蓝牙协议规范什么的可以来这里找
Telink Telink | Chips for a Smarter IoT (telink-semi.com)
Telink中文官网
开发手册 AliOS Things开发指南 AliOS Things开发指南,这里是最新版本,可以直接从官网找到
AliOS Things开发指南 AliOS Things应用开发指南,这里应该是3.3版本的完整开发文档
AliOS Things开发指南(3.0) AliOS Things应用开发指南,这里应该是3.0版本的完整开发文档
生活物联网平台开发文档 生活物联网平台(飞燕平台)开发文档
《设备端开发指南》
Wi-Fi IoT品类定义与功能开发 天猫精灵IoT开放平台——Wi-Fi IoT品类定义与功能开发
硬件平台 mk3080 WiFi开发板 WiFi开发板使用指南-阿里云开发者社区
esp8266开发板 一个教程:ESP8266-NodeMCU开发板详解-太极创客 (taichi-maker.com)
TLSR8258 Datasheet Datasheet for Telink BLE + IEEE802.15.4 MultiStandard Wireless SoC TLSR8258
参考资料 AliOS Things 3.0 应用开发指南 这个只是一篇参考文章,里面是一些环境搭建相关的,可以参考
IP知识百科 - 华为 (huawei.com) IP的一些相关知识点
点击查看相关文件下载
分类 网址 说明
蓝牙规范相关文档 Core Specification 5.2 核心规格 5.2,该规范定义了创建可互操作的Bluetooth 设备所需的技术。
《Core_v5.2.pdf》
Mesh Model(v1.1) 本Bluetooth 规范定义了模型(以及它们所需的状态和消息),这些模型用于在mesh 网络中的节点上执行基本功能,超出了Bluetooth Mesh 配置文件 规范中定义的基础模型。
本规范包括定义跨设备类型标准功能的通用模型,以及支持关键mesh 场景的模型,如照明控制、传感器、时间和场景。
《MshMDL_v1.1.pdf》
Mesh Profile(v1.0.1) 该Bluetooth 规范定义了基本要求,以实现可互操作的mesh 网络解决方案,用于Bluetooth 低能量无线技术。
《MshPRFv1.0.1.pdf》
Mesh Device Properties 本规范包含Bluetooth Mesh 配置文件 和Bluetooth Mesh 模型规范所要求的设备属性的定义。
但是跟之前的有些区别,我主要看的之前的版本:《MMeshDeviceProperties_v1.2.pdf》
GATT Specification Supplement GATT Specification Supplement | Bluetooth® Technology Website。
好像可以在线看:《GATT Specification Supplement》
Assigned Numbers GATT的一些类型定义可以在这里找。
AliOS Things alios-things/AliOS-Things Gitee上的AliOSThings SDK源码仓库
alibaba/AliOS-Things GitHub上的AliOSThings SDK源码仓库
天猫精灵蓝牙Mesh协议栈 alibaba-archive/genie-bt-mesh-stack GitHub上的天猫精灵蓝牙Mesh协议栈源码仓库。
之前是在alibaba/genie-bt-mesh-stack这个仓库。
写笔记的时候最新提交为faf523618a6a2560090fc423222b9db80984bb7a
蓝牙Mesh设备开发指南 阿里云生活服务平台开发手册——蓝牙设备开发一节中的内容

这一节课我们可以看这里的代码:linkkit_mk3080 · sumumm/AliOS-Things-Prj - 码云 - 开源中国 (gitee.com)

一、主要流程

  • 第一步:发送probe request帧。

怎么让天猫精灵发现我们的物联网设备?这就需要设备在配网模式下自己去不断发probe request帧。当天猫精灵接收到这个probe request帧的时候,天猫精灵会从probe request帧中获取设备的相关信息(设备号、密钥等),并通过云端进行一个校验,由于设备的信息都在云端注册好了,所以天猫精灵才会知道我们这是一台什么样的设备,当在云端有相关信息,天猫精灵就会提示找到什么什么智能设备,这个时候,否则天猫精灵是不会有提醒的。

  • 第二步:收到天猫精灵的回复。

当我们说出连接的时候,天猫精灵就会将WiFi的SSID和密码通过Probe response帧发送给物联网设备,在配网模式下,物联网设备会监听所有信道的数据包,当收到天猫精灵回复的数据包的时候,就会从中解析出WiFi的SSID和密码。

  • 第三步:连接路由器。

通过解析出来的SSID和密码进行路由器的连接。

二、代码分析

代码阅读的话,其实还是使用Source Insight比较方便一些,这一部分代码的走读,就使用这个软件进行。我在windows下面解压了一份AliOSThings源码,并创建Source Insight工程。其实vscode也能看,但是函数关系查找这一方面,确实不如Source Insight。

1. SDK中涉及的代码

AliOSThings中相关的代码在这里:AOS_SDK_PATH/components/linkkit/wifi_provision

image-20231217105454536

主要是这一些代码:

1
2
3
4
5
6
7
8
9
hk@vm:~/AliOS-Things-SDK/components/linkkit/wifi_provision$ tree -L 2
.
├── # ......
├── frameworks
├── # ......
└── zero_config # 零配入网
├── awss_enrollee.c # 零配入网处理
├── awss_enrollee.h
└── awss_registrar.c

frameworks下面的相关文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
hk@vm:~/AliOS-Things-SDK/components/linkkit/wifi_provision/frameworks$ tree -L 2.
├── aplist
│   ├── awss_aplist.c
│   └── awss_aplist.h
├── aws_lib.h
├── awss.c
├── awss_discover.c
├── awss_discover.h
├── awss_main.c # 零配入口
├── awss_main.h
├── awss_smartconfig.h
├── connect_ap.c # 零配结束连接路由器
├── connect_ap.h
├── ieee80211
│   ├── zconfig_ieee80211.c # 零配WiFi报文解析
│   └── zconfig_ieee80211.h
├── statics
│   ├── awss_statis.c
│   └── awss_statis.h
├── utils # 零配使用的一些工具函数
│   ├── awss_crypt.c
│   ├── awss_crypt.h
│   ├── zconfig_utils.c
│   └── zconfig_utils.h
├── zconfig_lib.h
├── zconfig_protocol.c # 零配主流程,初始化
├── zconfig_protocol.h
└── zconfig_vendor_common.c

4 directories, 23 files

2. awss.c:awss_start()函数

这个函数是配网的入口函数,它的调用也挺麻烦:

0

3. 零配初始化

零配的初始化基本都是这里面完成的,具体的可以去阅读代码,这里就梳理一下函数调用关系:

1

4. 解析配网报文

4.1 解析配网报文函数调用过程

2

4.2 ieee80211_data_extract()

上图为函数调用关系,我们来看一下这个函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// AOS_SDK_PATH/components/linkkit/wifi_provision/frameworks/ieee80211/zconfig_ieee80211.c
/**
* ieee80211_data_extratct - extract 80211 frame info
*
* @in: [IN] 80211 frame
* @len: [IN] 80211 frame len
* @link_type: [IN] link type @see enum AWS_LINK_TYPE
* @res: [OUT] 80211 frame parser result, see struct parser_res.
*
* @warning: encry_type may collision with aes & tpip in some cases,
* then encry_type will be set to INVALID.
* @Return:
* @see enum ALINK_TYPE
*
* @Note: howto deal with radio RSSI signal
*/
int ieee80211_data_extract(uint8_t *in, int len, int link_type, struct parser_res *res, signed char rssi)
{
struct ieee80211_hdr *hdr;
int alink_type = ALINK_INVALID;
int pkt_type = PKG_INVALID;
int i, fc;
// 去掉头部
hdr = (struct ieee80211_hdr *)zconfig_remove_link_header(&in, &len, link_type);
if (len <= 0)
goto drop;
fc = hdr->frame_control;
// 遍历
for (i = 0; i < sizeof(awss_protocol_couple_array) / sizeof(awss_protocol_couple_array[0]); i ++) {
awss_protocol_process_func_type protocol_func = awss_protocol_couple_array[i].awss_protocol_process_func;
if (protocol_func == NULL)
continue;
alink_type = protocol_func((uint8_t *)hdr, len, link_type, res, rssi);
if (alink_type != ALINK_INVALID)
break;
}

if (alink_type == ALINK_INVALID)
goto drop;

if (alink_type != ALINK_HT_CTRL) {
/* convert IEEE 802.11 header + possible LLC headers into Ethernet header
* IEEE 802.11 address fields:
* ToDS FromDS Addr1 Addr2 Addr3 Addr4
* 0 0 DA SA BSSID n/a
* 0 1 DA BSSID SA n/a
* 1 0 BSSID SA DA n/a
* 1 1 RA TA DA SA
*/
res->src = ieee80211_get_SA(hdr);
res->dst = ieee80211_get_DA(hdr);
res->bssid = ieee80211_get_BSSID(hdr);
res->tods = ieee80211_has_tods(fc);
}

do {
awss_protocol_finish_func_type finish_func = awss_protocol_couple_array[i].awss_protocol_finish_func;
if (finish_func)
pkt_type = finish_func(res);
} while(0);

drop:
return pkt_type;
}

#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
}

可以看到该函数中主要是遍历了一个数组,并且执行了两个函数指针指向的函数。awss_protocol_couple_array数组内容如下,这里会支持零配、smart config广播配网和smartconfig多播配网的数据包解析,后面会学习到的,这里简单了解一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// components/linkkit/wifi_provision/frameworks/ieee80211/zconfig_ieee80211.c

struct awss_protocol_couple_type awss_protocol_couple_array[] = {
#ifdef AWSS_SUPPORT_HT40
{ALINK_HT_CTRL, awss_ieee80211_ht_ctrl_process, awss_recv_callback_ht_ctrl},
#endif
#ifdef AWSS_SUPPORT_APLIST
{ALINK_APLIST, awss_ieee80211_aplist_process, NULL},
#endif
#ifdef AWSS_SUPPORT_AHA
{ALINK_DEFAULT_SSID, awss_ieee80211_aha_process, awss_recv_callback_aha_ssid},
#endif
#ifndef AWSS_DISABLE_ENROLLEE
{ALINK_ZERO_CONFIG, awss_ieee80211_zconfig_process, awss_recv_callback_zconfig},
#endif
#ifdef AWSS_SUPPORT_SMARTCONFIG_WPS
{ALINK_WPS, awss_ieee80211_wps_process, awss_recv_callback_wps},
#endif
#ifdef AWSS_SUPPORT_SMARTCONFIG
{ALINK_BROADCAST, awss_ieee80211_smartconfig_process, awss_recv_callback_smartconfig},
#endif
#ifdef AWSS_SUPPORT_SMARTCONFIG_MCAST
{ALINK_BROADCAST, awss_ieee80211_mcast_smartconfig_process, awss_recv_callback_mcast_smartconfig},
#endif
#ifdef AWSS_SUPPORT_DISCOVER
{ALINK_BROADCAST, aws_discover_callback, NULL},
#endif
};

6. 连接路由器

上面解析报文之后,会停止扫描信道,之后就该连接路由器了。

3