Commit 236759b1 authored by Andrzej Kaczmarek's avatar Andrzej Kaczmarek Committed by Carles Cufi
Browse files

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: default avatarAndrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
parent c6db3c27
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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;
+11 −0
Original line number Diff line number Diff line
@@ -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
+78 −11
Original line number Diff line number Diff line
@@ -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,11 +1793,16 @@ 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,
		status = ll_adv_enable(handle, cmd->enable,
				       s->duration, s->max_ext_adv_evts);
#endif /* !CONFIG_BT_HCI_MESH_EXT */
		if (status) {
@@ -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);
}
+20 −0
Original line number Diff line number Diff line
@@ -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);
+50 −0
Original line number Diff line number Diff line
@@ -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,
Loading