LE Peripheral Privacy
LE Peripheral Privacy示例工程用于展示Privacy管理模块的使用。Peripheral privacy示例工程基于Peripheral示例工程实现一个Privacy管理模块。
更多关于Peripheral role的信息可参考 LE Peripheral。
更多关于Privacy管理模块的信息可参考 代码介绍 中的 Privacy管理模块。
环境需求
该示例支持以下开发工具包:
Hardware Platforms |
Board Name |
---|---|
RTL87x2G HDK |
RTL87x2G EVB |
为快速搭建起开发环境,可参考 快速入门 中提供的详细指导。
硬件连线
该示例工程需要支持用户命令接口。连线请参考 User Command Interface 中的 Data UART连接。
配置
配置选项
该示例工程全部配置选项在
samples\bluetooth\ble_peripheral_privacy\src\app_flags.h
中,
开发者可以根据实际需求配置。
/** @brief Configure APP LE link number */
#define APP_MAX_LINKS 1
/** @brief User command: 0-Close user command, 1-Open user command */
#define USER_CMD_EN 1
/** @brief Configure Privacy1.2 feature: 0-Closed, 1-Open */
#define APP_PRIVACY_EN 1
#if APP_PRIVACY_EN
/** @brief Configure the authentication requirement of simple_ble_service.c */
#define SIMP_SRV_AUTHEN_EN 1
#endif
- Privacy配置
所有privacy相关的代码用宏
APP_PRIVACY_EN
隔开。- Service的Security Requirement
所有service security相关的代码用宏
SIMP_SRV_AUTHEN_EN
隔开。如果开发者想使用prrivacy,就要打开security。更多信息请参考 代码介绍 中的 Service的Security要求。
生成系统配置文件
开发者可以通过MP Tool配置以下项目:
Configurable Item |
Value |
---|---|
LE Slave Link Num |
≥ APP_MAX_LINKS |
更多有关于MP Tool配置的信息请参考 快速入门 中的 生成System Config File。
编译和下载
该示例可以在SDK文件夹中找到:
Project file: samples\bluetooth\ble_peripheral_privacy\proj\rtl87x2g\mdk
Project file: samples\bluetooth\ble_peripheral_privacy\proj\rtl87x2g\gcc
编译和运行该示例请遵循以下步骤:
打开项目文件。
要编译目标文件,请参考 快速入门 的 编译APP Image 中列出的步骤。
编译成功后,目录
samples\bluetooth\ble_peripheral_privacy\proj\rtl87x2g\mdk\bin
下会生成app bin文件app_MP_sdk_xxx.bin
。要下载app bin到 EVB,请参考 快速入门 的 MP Tool 下载 中列出的步骤。
在EVB上按下 reset 键,程序将开始运行。
测试验证
将示例工程烧录到EVB后,开发者可以使用一个装有 LightBlue
之类LE应用的手机与之对测。
准备开发板
准备步骤
使用MP Tool将 DUT 地址设为[00:11:22:33:44:80],然后编译LE Peripheral privacy示例工程,并下载images到 DUT。 开发者可以在电脑的串口辅助工具端输入用户命令,请参考 User Command Interface 中的 如何使用命令。
更多关于如何修改 蓝牙地址 的细节请查阅 快速入门 中的 生成System Config File。
测试步骤
按 DUT 上的
reset
键,开发者可以在电脑的串口辅助工具端输入用户命令。在iOS设备上打开
LightBlue
,搜索并连接 DUT,如图所示:开发者可以在手机端与peripheral设备进行扫描,连接,配对,查服务,删除绑定信息,断线等交互。
DUT 也可以使用以下用户命令主动断开连线及清除绑定信息:
DUT User Command
Description
DUT Log
disc 0
DUT 断开连线
Serial port assistant tool shows:
Disconnect conn_id 0
bondclear
清除 DUT 端的绑定信息
Debug Analyzer shows:
[GAP] !**le_clear_all_keys
代码介绍
本章将按照以下几个部分进行介绍:
源码路径 中介绍项目目录和源代码文件。
Bluetooth Host介绍 中介绍了Bluetooth Host相关信息。
初始化 中介绍可配参数和Bluetooth Host初始化。
Privacy管理模块 中介绍了Privacy管理模块。
Privacy使用流程 中介绍了Privacy管理模块的使用流程。
Service的Security要求 中介绍了服务的Security要求。
源码路径
工程目录:
samples\bluetooth\ble_peripheral_privacy\proj
。源码目录:
samples\bluetooth\ble_peripheral_privacy\src
。
LE peripheral privacy示例工程中的源文件当前被分为几个组,如下所示。
└── Project: peripheral_privacy
└── secure_only_app
└── Device includes startup code
├── CMSE Library Non-secure callable library
├── Lib includes all binary symbol files that user application is built on
├── ROM_NS.lib
└── lowerstack.lib
└── rtl87x2g_sdk.lib
└── gap_utils.lib
├── peripheral includes all peripheral drivers and module code used by the application
├── Profile includes LE profiles or services used by the sample application
└── APP includes the ble_peripheral_privacy user application implementation
├── app_task.c
├── main.c
├── peripheral_privacy_app.c
├── user_cmd.c
├── privacy_mgnt.c
├── data_uart.c
└── user_cmd_parse.c
示例工程使用与 bt_host_0_0
匹配的默认GAP LIB,请参阅文档 Bluetooth Host Image 中的 GAP LIB的使用方法 以获取更多信息。
Bluetooth Host介绍
示例工程默认使用Bluetooth Host image版本 bt_host_0_0
,更多信息可参阅
Bluetooth Host Image。
关于Bluetooth Host所支持的蓝牙功能的详细信息,请参阅文件 bin\rtl87x2g\bt_host_image\bt_host_0_0\bt_host_config.h
。
初始化
当EVB启动并且芯片复位时, main()
函数将被调用,它执行以下初始化函数:
int main(void)
{
board_init();
le_gap_init(APP_MAX_LINKS);
gap_lib_init();
app_le_gap_init();
app_le_profile_init();
pwr_mgr_init();
task_init();
os_sched_start();
return 0;
}
le_gap_init()
用于初始化GAP并配置链接个数。app_le_profile_init()
用于初始化profile。app_le_gap_init()
用于初始化GAP参数,开发者可以自行配置以下参数:Device name和device appearance,Advertising参数,GAP Bond Manager参数(请参考 LE Host 中的 Device Name和Device Appearance的配置, Advertising参数的配置, Bond Manager参数的配置 , 其它参数的配置)。
void app_le_gap_init(void)
{
/* Device name and device appearance */
......
/* Advertising parameters */
......
/* GAP Bond Manager parameters */
......
/* Set device name and device appearance */
le_set_gap_param(GAP_PARAM_DEVICE_NAME, GAP_DEVICE_NAME_LEN, device_name);
le_set_gap_param(GAP_PARAM_APPEARANCE, sizeof(appearance), &appearance);
le_set_gap_param(GAP_PARAM_SLAVE_INIT_GATT_MTU_REQ, sizeof(slave_init_mtu_req),
&slave_init_mtu_req);
/* Set advertising parameters */
le_adv_set_param(GAP_PARAM_ADV_EVENT_TYPE, sizeof(adv_evt_type), &adv_evt_type);
le_adv_set_param(GAP_PARAM_ADV_DIRECT_ADDR_TYPE, sizeof(adv_direct_type), &adv_direct_type);
le_adv_set_param(GAP_PARAM_ADV_DIRECT_ADDR, sizeof(adv_direct_addr), adv_direct_addr);
le_adv_set_param(GAP_PARAM_ADV_CHANNEL_MAP, sizeof(adv_chann_map), &adv_chann_map);
le_adv_set_param(GAP_PARAM_ADV_FILTER_POLICY, sizeof(adv_filter_policy), &adv_filter_policy);
le_adv_set_param(GAP_PARAM_ADV_INTERVAL_MIN, sizeof(adv_int_min), &adv_int_min);
le_adv_set_param(GAP_PARAM_ADV_INTERVAL_MAX, sizeof(adv_int_max), &adv_int_max);
le_adv_set_param(GAP_PARAM_ADV_DATA, sizeof(adv_data), (void *)adv_data);
le_adv_set_param(GAP_PARAM_SCAN_RSP_DATA, sizeof(scan_rsp_data), (void *)scan_rsp_data);
/* Setup the GAP Bond Manager */
gap_set_param(GAP_PARAM_BOND_PAIRING_MODE, sizeof(auth_pair_mode), &auth_pair_mode);
gap_set_param(GAP_PARAM_BOND_AUTHEN_REQUIREMENTS_FLAGS, sizeof(auth_flags), &auth_flags);
gap_set_param(GAP_PARAM_BOND_IO_CAPABILITIES, sizeof(auth_io_cap), &auth_io_cap);
gap_set_param(GAP_PARAM_BOND_OOB_ENABLED, sizeof(auth_oob), &auth_oob);
le_bond_set_param(GAP_PARAM_BOND_FIXED_PASSKEY, sizeof(auth_fix_passkey), &auth_fix_passkey);
le_bond_set_param(GAP_PARAM_BOND_FIXED_PASSKEY_ENABLE, sizeof(auth_use_fix_passkey),
&auth_use_fix_passkey);
le_bond_set_param(GAP_PARAM_BOND_SEC_REQ_REQUIREMENT, sizeof(auth_sec_req_flags),
&auth_sec_req_flags);
/* register gap message callback */
le_register_app_cb(app_gap_callback);
#if APP_PRIVACY_EN
privacy_init(app_privacy_callback, true);
#endif
}
Privacy管理模块
Privacy管理模块的开发是基于头文件 gap_privacy.h
的。
若开发者需要使用Privacy管理模块,可以使用头文件 privacy_mgnt.h
用于开发privacy相关应用。
对于RTL87x2G,Privacy管理模块的文件路径如下:
源文件:
samples\bluetooth\ble_peripheral_privacy\src\privacy_mgnt.c
头文件:
samples\bluetooth\ble_peripheral_privacy\src\privacy_mgnt.h
开发者需要在工程的 app group 中添加 privacy_mgnt.c
文件,在 Include Paths 中添加头文件路径。
接口
Privacy管理模块的接口都在头文件 privacy_mgnt.h
中定义。
/* privacy_mgnt.h APIs */
typedef void(*P_FUN_PRIVACY_STATE_CB)(T_PRIVACY_CB_TYPE type, T_PRIVACY_CB_DATA cb_data);
void privacy_init(P_FUN_PRIVACY_STATE_CB p_fun, bool whitelist);
T_PRIVACY_STATE privacy_handle_resolv_list(void);
void privacy_handle_bond_modify_msg(T_LE_BOND_MODIFY_TYPE type, T_LE_KEY_ENTRY *p_entry,
bool handle_add);
bool privacy_add_device(T_LE_KEY_ENTRY *p_entry);
T_GAP_CAUSE privacy_set_addr_resolution(bool enable);
T_GAP_CAUSE privacy_read_peer_resolv_addr(T_GAP_REMOTE_ADDR_TYPE peer_address_type,
uint8_t *peer_address);
T_GAP_CAUSE privacy_read_local_resolv_addr(T_GAP_REMOTE_ADDR_TYPE peer_address_type,
uint8_t *peer_address);
Privacy管理模块的使用方法
Privacy管理模块初始化
APP需要调用 privacy_init()
,以初始化Privacy管理模块并注册回调函数。
void app_le_gap_init(void)
{
/* register gap message callback */
le_register_app_cb(app_gap_callback);
#if APP_PRIVACY_EN
privacy_init(app_privacy_callback, true);
#endif
}
privacy_init()
的参数 whitelist
用于配置对white list的管理。若whitelist参数为true,当Privacy管理模块修改resolving list时,Privacy管理模块会管理white list。若whitelist参数为false,APP需要管理white list。
回调函数用于处理Privacy管理模块发送的消息。
void app_privacy_callback(T_PRIVACY_CB_TYPE type, T_PRIVACY_CB_DATA cb_data)
{
APP_PRINT_INFO1("app_privacy_callback: type %d", type);
switch (type)
{
case PRIVACY_STATE_MSGTYPE:
app_privacy_state = cb_data.privacy_state;
APP_PRINT_INFO1("PRIVACY_STATE_MSGTYPE: status %d", app_privacy_state);
break;
case PRIVACY_RESOLUTION_STATUS_MSGTYPE:
app_privacy_resolution_state = cb_data.resolution_state;
APP_PRINT_INFO1("PRIVACY_RESOLUTION_STATUS_MSGTYPE: status %d", app_privacy_resolution_state);
break;
default:
break;
}
}
Resolving List的管理
Privacy管理模块的关键功能是当绑定信息变化时,用于管理resolving list和white list。white list的管理是可选特性, privacy_init()
的 whitelist
参数用于配置对white list的管理。
当APP处理 GAP_MSG_LE_BOND_MODIFY_INFO
消息时,APP必须调用函数 privacy_handle_bond_modify_msg()
。
Privacy管理模块将根据绑定信息的修改类型管理resolving list,流程如下:
LE_BOND_DELETE:在resolving list删除该设备。
LE_BOND_ADD:在resolving list中加入该设备。
LE_BOND_CLEAR:清除resolving list。
T_APP_RESULT app_gap_callback(uint8_t cb_type, void *p_cb_data)
{
T_APP_RESULT result = APP_RESULT_SUCCESS;
T_LE_CB_DATA *p_data = (T_LE_CB_DATA *)p_cb_data;
switch (cb_type)
{
#if APP_PRIVACY_EN
case GAP_MSG_LE_BOND_MODIFY_INFO:
APP_PRINT_INFO1("GAP_MSG_LE_BOND_MODIFY_INFO: type 0x%x",
p_data->p_le_bond_modify_info->type);
privacy_handle_bond_modify_msg(p_data->p_le_bond_modify_info->type,
p_data->p_le_bond_modify_info->p_entry, true);
break;
#endif
......
}
当address resolution已启用,在以下场景,不能执行对resolving list的修改流程:
已启用advertising。
已启用scanning。
正在创建连线
当address resolution未启用,resolving list的修改流程可以在任何时候执行。
当GAP设备状态为idle状态时,APP必须调用函数 privacy_handle_resolv_list()
。 privacy_handle_resolv_list()
用于处理挂起的resolving list修改流程。
void app_handle_dev_state_evt(T_GAP_DEV_STATE new_state, uint16_t cause)
{
APP_PRINT_INFO3("app_handle_dev_state_evt: init state %d, adv state %d, cause 0x%x",
new_state.gap_init_state, new_state.gap_adv_state, cause);
#if APP_PRIVACY_EN
if ((new_state.gap_init_state == GAP_INIT_STATE_STACK_READY)
&& (new_state.gap_adv_state == GAP_ADV_STATE_IDLE)
&& (new_state.gap_conn_state == GAP_CONN_DEV_STATE_IDLE))
{
privacy_handle_resolv_list();
}
#endif
......
}
回调类型 PRIVACY_STATE_MSGTYPE
用于通知resolving list修改流程的状态。回调数据为 T_PRIVACY_STATE
。
typedef enum
{
PRIVACY_STATE_INIT, //!< Privacy management module is not initialization.
PRIVACY_STATE_IDLE, //!< Idle. No pending resolving list modification procedure.
PRIVACY_STATE_BUSY //!< Busy. Resolving list modification procedure is not completed.
} T_PRIVACY_STATE;
Address Resolution
若对端设备使用resolvable private address,APP希望使用white list过滤该对端设备。APP需要调用函数 privacy_set_addr_resolution()
以启用address resolution。
若APP希望与新的设备配对,APP需要调用函数 privacy_set_addr_resolution()
以禁用address resolution。当address resolution已启用,本地设备不能与不属于resolving list的设备建立连线。示例代码如下:
void app_adv_start(void)
{
uint8_t adv_evt_type = GAP_ADTYPE_ADV_IND;
uint8_t adv_filter_policy = GAP_ADV_FILTER_ANY;
#if APP_PRIVACY_EN
T_LE_KEY_ENTRY *p_entry;
p_entry = le_get_high_priority_bond();
if (p_entry == NULL)
{
/* No bonded device, send connectable undirected advertising event without using whitelist*/
app_work_mode = APP_PAIRABLE_MODE;
adv_filter_policy = GAP_ADV_FILTER_ANY;
if (app_privacy_resolution_state == PRIVACY_ADDR_RESOLUTION_ENABLED)
{
privacy_set_addr_resolution(false);
}
}
else
{
app_work_mode = APP_RECONNECTION_MODE;
adv_filter_policy = GAP_ADV_FILTER_WHITE_LIST_ALL;
if (app_privacy_resolution_state == PRIVACY_ADDR_RESOLUTION_DISABLED)
{
privacy_set_addr_resolution(true);
}
}
#endif
le_adv_set_param(GAP_PARAM_ADV_EVENT_TYPE, sizeof(adv_evt_type), &adv_evt_type);
le_adv_set_param(GAP_PARAM_ADV_FILTER_POLICY, sizeof(adv_filter_policy), &adv_filter_policy);
le_adv_start();
}
函数 privacy_set_addr_resolution()
用于启用Controller中对resolvable private address的解析功能。这将使得Controller收到本地或对端的resolvable private address时,Controller将使用resolving list。
除了以下场景,其它时间均可启用调用该函数:
已启用advertising。
已启用scanning。
正在创建连线。
回调类型 PRIVACY_RESOLUTION_STATUS_MSGTYPE
用于通知address resolution的状态。回调数据为 T_PRIVACY_ADDR_RESOLUTION_STATE
。
/** @brief Define the privacy address resolution state */
typedef enum
{
PRIVACY_ADDR_RESOLUTION_DISABLED,
PRIVACY_ADDR_RESOLUTION_DISABLING,
PRIVACY_ADDR_RESOLUTION_ENABLING,
PRIVACY_ADDR_RESOLUTION_ENABLED
} T_PRIVACY_ADDR_RESOLUTION_STATE;
Privacy使用流程
在APP中有两种模式:配对模式和回连模式。处于配对模式的设备可以与任何设备建立连线,必须禁用address resolution和white list filter policy;处于回连模式的设备只能与在resolving list和white list中的设备建立连线。若APP希望过滤使用resolvable private address的设备,则必须调用函数 privacy_set_addr_resolution()
以启用address resolution。
peripheral privacy应用的流程如图所示:
Service的Security要求
所有service security相关的代码通过宏定义 SIMP_SRV_AUTHEN_EN
分隔。
若APP希望使用privacy,那么APP需要启用security。
更多信息参见 LE Host 中的 Service的security要求。
/* client characteristic configuration */
{
ATTRIB_FLAG_VALUE_INCL | ATTRIB_FLAG_CCCD_APPL, /* flags */
{ /* type_value */
LO_WORD(GATT_UUID_CHAR_CLIENT_CONFIG),
HI_WORD(GATT_UUID_CHAR_CLIENT_CONFIG),
/* NOTE: this value has an instantiation for each client, a write to */
/* this attribute does not modify this default value: */
LO_WORD(GATT_CLIENT_CHAR_CONFIG_DEFAULT), /* client char. config. bit field */
HI_WORD(GATT_CLIENT_CHAR_CONFIG_DEFAULT)
},
2, /* bValueLen */
NULL,
#if SIMP_SRV_AUTHEN_EN
(GATT_PERM_READ_AUTHEN_REQ | GATT_PERM_WRITE_AUTHEN_REQ) /* permissions */
#else
(GATT_PERM_READ | GATT_PERM_WRITE) /* permissions */
#endif
},