Bluetooth: controller: Add advertising set handle mapping

Core 5.2, Vol 4, Part E, section 5.3.1 clarifies that advertising set
handle is assigned by host when advertising set is created and this
happens only on LE Set Extended Advertising Parameters.

An advertising set handle is an arbitrary number within allowed range,
i.e. 0x00-0xEF and not 0..max_supported-1.

This patch adds option to enable advertising set handle mapping from
HCI range as defined by Core specification to zero-based handles used
by LL. If enabled, HCI handle will be remapped to LL handle for each
command, otherwise HCI handle will be used as an LL handle. The latter
effectively skips mapping logic and should be used with Zephyr host
which uses zero based indexes.

Signed-off-by: Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
This commit is contained in:
Andrzej Kaczmarek 2020-06-30 15:18:40 +02:00 committed by Carles Cufí
commit 236759b18a
6 changed files with 164 additions and 11 deletions

View file

@ -1039,6 +1039,8 @@ struct bt_hci_cp_le_set_adv_set_random_addr {
#define BT_HCI_LE_ADV_TX_POWER_NO_PREF 0x7F
#define BT_HCI_LE_ADV_HANDLE_MAX 0xEF
#define BT_HCI_OP_LE_SET_EXT_ADV_PARAM BT_OP(BT_OGF_LE, 0x0036)
struct bt_hci_cp_le_set_ext_adv_param {
uint8_t handle;

View file

@ -94,6 +94,17 @@ config BT_CTLR_HCI_VS_BUILD_INFO
character is required at the beginning to separate it from the
already included information.
config BT_CTLR_HCI_ADV_HANDLE_MAPPING
bool "Enable advertising set handle mapping between HCI and LL"
depends on BT_CTLR_ADV_EXT
default y if BT_HCI_RAW
help
Enable mapping of advertising set handles between HCI and LL when
using external host since it can use arbitrary numbers as set handles
(as defined by Core specification) as opposed to LL which always uses
zero-based numbering. When using with Zephyr host this option can be
disabled to remove extra mapping logic.
config BT_CTLR_DUP_FILTER_LEN
int "Number of addresses in the scan duplicate filter"
depends on BT_OBSERVER

View file

@ -1658,12 +1658,19 @@ static void le_set_adv_set_random_addr(struct net_buf *buf,
{
struct bt_hci_cp_le_set_adv_set_random_addr *cmd = (void *)buf->data;
uint8_t status;
uint8_t handle;
if (adv_cmds_ext_check(evt)) {
return;
}
status = ll_adv_aux_random_addr_set(cmd->handle, &cmd->bdaddr.val[0]);
status = ll_adv_set_by_hci_handle_get(cmd->handle, &handle);
if (status) {
*evt = cmd_complete_status(status);
return;
}
status = ll_adv_aux_random_addr_set(handle, &cmd->bdaddr.val[0]);
*evt = cmd_complete_status(status);
}
@ -1678,18 +1685,30 @@ static void le_set_ext_adv_param(struct net_buf *buf, struct net_buf **evt)
uint8_t status;
uint8_t phy_p;
uint8_t phy_s;
uint8_t handle;
if (adv_cmds_ext_check(evt)) {
return;
}
if (cmd->handle > BT_HCI_LE_ADV_HANDLE_MAX) {
*evt = cmd_complete_status(BT_HCI_ERR_INVALID_PARAM);
return;
}
status = ll_adv_set_by_hci_handle_get_or_new(cmd->handle, &handle);
if (status) {
*evt = cmd_complete_status(status);
return;
}
evt_prop = sys_le16_to_cpu(cmd->props);
min_interval = sys_get_le24(cmd->prim_min_interval);
tx_pwr = cmd->tx_power;
phy_p = BIT(cmd->prim_adv_phy - 1);
phy_s = BIT(cmd->sec_adv_phy - 1);
status = ll_adv_params_set(cmd->handle, evt_prop, min_interval,
status = ll_adv_params_set(handle, evt_prop, min_interval,
PDU_ADV_TYPE_EXT_IND, cmd->own_addr_type,
cmd->peer_addr.type, cmd->peer_addr.a.val,
cmd->prim_channel_map, cmd->filter_policy,
@ -1705,12 +1724,19 @@ static void le_set_ext_adv_data(struct net_buf *buf, struct net_buf **evt)
{
struct bt_hci_cp_le_set_ext_adv_data *cmd = (void *)buf->data;
uint8_t status;
uint8_t handle;
if (adv_cmds_ext_check(evt)) {
return;
}
status = ll_adv_aux_ad_data_set(cmd->handle, cmd->op, cmd->frag_pref,
status = ll_adv_set_by_hci_handle_get(cmd->handle, &handle);
if (status) {
*evt = cmd_complete_status(status);
return;
}
status = ll_adv_aux_ad_data_set(handle, cmd->op, cmd->frag_pref,
cmd->len, cmd->data);
*evt = cmd_complete_status(status);
@ -1720,12 +1746,19 @@ static void le_set_ext_scan_rsp_data(struct net_buf *buf, struct net_buf **evt)
{
struct bt_hci_cp_le_set_ext_scan_rsp_data *cmd = (void *)buf->data;
uint8_t status;
uint8_t handle;
if (adv_cmds_ext_check(evt)) {
return;
}
status = ll_adv_aux_sr_data_set(cmd->handle, cmd->op, cmd->frag_pref,
status = ll_adv_set_by_hci_handle_get(cmd->handle, &handle);
if (status) {
*evt = cmd_complete_status(status);
return;
}
status = ll_adv_aux_sr_data_set(handle, cmd->op, cmd->frag_pref,
cmd->len, cmd->data);
*evt = cmd_complete_status(status);
@ -1738,6 +1771,7 @@ static void le_set_ext_adv_enable(struct net_buf *buf, struct net_buf **evt)
uint8_t set_num;
uint8_t enable;
uint8_t status;
uint8_t handle;
if (adv_cmds_ext_check(evt)) {
return;
@ -1759,12 +1793,17 @@ static void le_set_ext_adv_enable(struct net_buf *buf, struct net_buf **evt)
s = (void *) cmd->s;
enable = cmd->enable;
do {
status = ll_adv_set_by_hci_handle_get(s->handle, &handle);
if (status) {
break;
}
/* TODO: duration and events parameter use. */
#if defined(CONFIG_BT_HCI_MESH_EXT)
status = ll_adv_enable(s->handle, cmd->enable, 0, 0, 0, 0, 0);
status = ll_adv_enable(handle, cmd->enable, 0, 0, 0, 0, 0);
#else /* !CONFIG_BT_HCI_MESH_EXT */
status = ll_adv_enable(s->handle, cmd->enable,
s->duration, s->max_ext_adv_evts);
status = ll_adv_enable(handle, cmd->enable,
s->duration, s->max_ext_adv_evts);
#endif /* !CONFIG_BT_HCI_MESH_EXT */
if (status) {
/* TODO: how to handle succeeded ones before this
@ -1814,12 +1853,19 @@ static void le_remove_adv_set(struct net_buf *buf, struct net_buf **evt)
{
struct bt_hci_cp_le_remove_adv_set *cmd = (void *)buf->data;
uint8_t status;
uint8_t handle;
if (adv_cmds_ext_check(evt)) {
return;
}
status = ll_adv_aux_set_remove(cmd->handle);
status = ll_adv_set_by_hci_handle_get(cmd->handle, &handle);
if (status) {
*evt = cmd_complete_status(status);
return;
}
status = ll_adv_aux_set_remove(handle);
*evt = cmd_complete_status(status);
}
@ -1844,15 +1890,22 @@ static void le_set_per_adv_param(struct net_buf *buf, struct net_buf **evt)
uint16_t interval;
uint16_t flags;
uint8_t status;
uint8_t handle;
if (adv_cmds_ext_check(evt)) {
return;
}
status = ll_adv_set_by_hci_handle_get(cmd->handle, &handle);
if (status) {
*evt = cmd_complete_status(status);
return;
}
interval = sys_le16_to_cpu(cmd->max_interval);
flags = sys_le16_to_cpu(cmd->props);
status = ll_adv_sync_param_set(cmd->handle, interval, flags);
status = ll_adv_sync_param_set(handle, interval, flags);
*evt = cmd_complete_status(status);
}
@ -1861,12 +1914,19 @@ static void le_set_per_adv_data(struct net_buf *buf, struct net_buf **evt)
{
struct bt_hci_cp_le_set_per_adv_data *cmd = (void *)buf->data;
uint8_t status;
uint8_t handle;
if (adv_cmds_ext_check(evt)) {
return;
}
status = ll_adv_sync_ad_data_set(cmd->handle, cmd->op, cmd->len,
status = ll_adv_set_by_hci_handle_get(cmd->handle, &handle);
if (status) {
*evt = cmd_complete_status(status);
return;
}
status = ll_adv_sync_ad_data_set(handle, cmd->op, cmd->len,
cmd->data);
*evt = cmd_complete_status(status);
@ -1876,12 +1936,19 @@ static void le_set_per_adv_enable(struct net_buf *buf, struct net_buf **evt)
{
struct bt_hci_cp_le_set_per_adv_enable *cmd = (void *)buf->data;
uint8_t status;
uint8_t handle;
if (adv_cmds_ext_check(evt)) {
return;
}
status = ll_adv_sync_enable(cmd->handle, cmd->enable);
status = ll_adv_set_by_hci_handle_get(cmd->handle, &handle);
if (status) {
*evt = cmd_complete_status(status);
return;
}
status = ll_adv_sync_enable(handle, cmd->enable);
*evt = cmd_complete_status(status);
}

View file

@ -17,6 +17,26 @@ void ll_reset(void);
uint8_t *ll_addr_get(uint8_t addr_type, uint8_t *p_bdaddr);
uint8_t ll_addr_set(uint8_t addr_type, uint8_t const *const p_bdaddr);
#if defined(CONFIG_BT_CTLR_HCI_ADV_HANDLE_MAPPING)
uint8_t ll_adv_set_by_hci_handle_get(uint8_t hci_handle, uint8_t *handle);
uint8_t ll_adv_set_by_hci_handle_get_or_new(uint8_t hci_handle,
uint8_t *handle);
#else
static inline uint8_t ll_adv_set_by_hci_handle_get(uint8_t hci_handle,
uint8_t *handle)
{
*handle = hci_handle;
return 0;
}
static inline uint8_t ll_adv_set_by_hci_handle_get_or_new(uint8_t hci_handle,
uint8_t *handle)
{
*handle = hci_handle;
return 0;
}
#endif
#if defined(CONFIG_BT_CTLR_ADV_EXT)
#if defined(CONFIG_BT_HCI_RAW)
int ll_adv_cmds_set(uint8_t adv_cmds);

View file

@ -91,6 +91,9 @@ int ll_adv_cmds_set(uint8_t adv_cmds)
if (adv_cmds == LL_ADV_CMDS_LEGACY) {
struct ll_adv_set *adv = &ll_adv[0];
#if defined(CONFIG_BT_CTLR_HCI_ADV_HANDLE_MAPPING)
adv->hci_handle = 0;
#endif
adv->is_created = 1;
}
}
@ -108,6 +111,53 @@ int ll_adv_cmds_is_ext(void)
}
#endif
#if defined(CONFIG_BT_CTLR_HCI_ADV_HANDLE_MAPPING)
uint8_t ll_adv_set_by_hci_handle_get(uint8_t hci_handle, uint8_t *handle)
{
struct ll_adv_set *adv;
uint8_t idx;
adv = &ll_adv[0];
for (idx = 0U; idx < BT_CTLR_ADV_SET; idx++, adv++) {
if (adv->is_created && (adv->hci_handle == hci_handle)) {
*handle = idx;
return 0;
}
}
return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
}
uint8_t ll_adv_set_by_hci_handle_get_or_new(uint8_t hci_handle, uint8_t *handle)
{
struct ll_adv_set *adv, *adv_empty;
uint8_t idx;
adv = &ll_adv[0];
adv_empty = NULL;
for (idx = 0U; idx < BT_CTLR_ADV_SET; idx++, adv++) {
if (adv->is_created) {
if (adv->hci_handle == hci_handle) {
*handle = idx;
return 0;
}
} else if (!adv_empty) {
adv_empty = adv;
}
}
if (adv_empty) {
adv_empty->hci_handle = hci_handle;
*handle = ull_adv_handle_get(adv_empty);
return 0;
}
return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
}
#endif
#if defined(CONFIG_BT_CTLR_ADV_EXT)
uint8_t ll_adv_params_set(uint8_t handle, uint16_t evt_prop, uint32_t interval,
uint8_t adv_type, uint8_t own_addr_type,

View file

@ -19,6 +19,9 @@ struct ll_adv_set {
uint8_t rnd_addr[BDADDR_SIZE];
uint8_t sid:4;
uint8_t is_created:1;
#if defined(CONFIG_BT_CTLR_HCI_ADV_HANDLE_MAPPING)
uint8_t hci_handle;
#endif
uint16_t event_counter;
uint16_t max_events;
uint32_t ticks_remain_duration;