diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv.c b/subsys/bluetooth/controller/ll_sw/ull_adv.c index f061ab9774b4b..a036b19fe4b0a 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv.c @@ -91,6 +91,7 @@ static void conn_release(struct ll_adv_set *adv); #endif /* CONFIG_BT_PERIPHERAL */ #if defined(CONFIG_BT_CTLR_ADV_EXT) +static uint8_t leg_adv_type_get(uint8_t evt_prop); static void adv_max_events_duration_set(struct ll_adv_set *adv, uint16_t duration, uint8_t max_ext_adv_evts); @@ -255,24 +256,25 @@ uint8_t ll_adv_params_set(uint16_t interval, uint8_t adv_type, if (adv_type == PDU_ADV_TYPE_EXT_IND) { /* legacy */ if (evt_prop & BT_HCI_LE_ADV_PROP_LEGACY) { - /* lookup evt_prop to PDU type in pdu_adv_type[] */ - uint8_t const leg_adv_type[] = { - 0x03, /* PDU_ADV_TYPE_NONCONN_IND */ - 0x04, /* PDU_ADV_TYPE_DIRECT_IND */ - 0x02, /* PDU_ADV_TYPE_SCAN_IND */ - 0x00 /* PDU_ADV_TYPE_ADV_IND */ - }; - if (evt_prop & BT_HCI_LE_ADV_PROP_ANON) { return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL; } - adv_type = leg_adv_type[evt_prop & 0x03]; +#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) + /* disallow changing to legacy advertising while + * periodic advertising enabled. + */ + if (adv->lll.sync) { + const struct ll_adv_sync_set *sync; - /* high duty cycle directed */ - if (evt_prop & BT_HCI_LE_ADV_PROP_HI_DC_CONN) { - adv_type = 0x01; /* PDU_ADV_TYPE_DIRECT_IND */ + sync = HDR_LLL2ULL(adv->lll.sync); + if (sync->is_enabled) { + return BT_HCI_ERR_INVALID_PARAM; + } } +#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ + + adv_type = leg_adv_type_get(evt_prop); adv->lll.phy_p = PHY_1M; } else { @@ -287,6 +289,20 @@ uint8_t ll_adv_params_set(uint16_t interval, uint8_t adv_type, return BT_HCI_ERR_INVALID_PARAM; } +#if defined(CONFIG_BT_CTLR_ADV_PERIODIC) + if (adv->lll.sync && + (evt_prop & (BT_HCI_LE_ADV_PROP_ANON | + BT_HCI_LE_ADV_PROP_CONN | + BT_HCI_LE_ADV_PROP_SCAN))) { + const struct ll_adv_sync_set *sync; + + sync = HDR_LLL2ULL(adv->lll.sync); + if (sync->is_enabled) { + return BT_HCI_ERR_INVALID_PARAM; + } + } +#endif /* CONFIG_BT_CTLR_ADV_PERIODIC */ + #if (CONFIG_BT_CTLR_ADV_AUX_SET == 0) /* Connectable or scannable requires aux */ if (evt_prop & (BT_HCI_LE_ADV_PROP_CONN | @@ -295,8 +311,8 @@ uint8_t ll_adv_params_set(uint16_t interval, uint8_t adv_type, } #endif - adv_type = 0x05; /* PDU_ADV_TYPE_EXT_IND in */ - /* pdu_adv_type array. */ + adv_type = 0x05; /* index of PDU_ADV_TYPE_EXT_IND in */ + /* pdu_adv_type[] */ adv->lll.phy_p = phy_p; adv->lll.phy_flags = PHY_FLAGS_S8; @@ -463,9 +479,8 @@ uint8_t ll_adv_params_set(uint16_t interval, uint8_t adv_type, pri_dptr_prev += BDADDR_SIZE; } if (!pri_com_hdr->adv_mode && - (!pri_hdr_prev.aux_ptr || - (!(evt_prop & BT_HCI_LE_ADV_PROP_ANON) && - (phy_p != PHY_CODED)))) { + !(evt_prop & BT_HCI_LE_ADV_PROP_ANON) && + (!pri_hdr_prev.aux_ptr || (phy_p != PHY_CODED))) { /* TODO: optional on 1M with Aux Ptr */ pri_hdr->adv_addr = 1; @@ -2421,6 +2436,28 @@ static void conn_release(struct ll_adv_set *adv) #endif /* CONFIG_BT_PERIPHERAL */ #if defined(CONFIG_BT_CTLR_ADV_EXT) +static uint8_t leg_adv_type_get(uint8_t evt_prop) +{ + /* We take advantage of the fact that 2 LS bits + * of evt_prop can be used in a lookup to return + * PDU type value in the pdu_adv_type[] lookup. + */ + uint8_t const leg_adv_type[] = { + 0x03, /* index of PDU_ADV_TYPE_NONCONN_IND in pdu_adv_type[] */ + 0x04, /* index of PDU_ADV_TYPE_DIRECT_IND in pdu_adv_type[] */ + 0x02, /* index of PDU_ADV_TYPE_SCAN_IND in pdu_adv_type[] */ + 0x00 /* index of PDU_ADV_TYPE_ADV_IND in pdu_adv_type[] */ + }; + + /* if high duty cycle directed */ + if (evt_prop & BT_HCI_LE_ADV_PROP_HI_DC_CONN) { + /* index of PDU_ADV_TYPE_DIRECT_IND in pdu_adv_type[] */ + return 0x01; + } + + return leg_adv_type[evt_prop & 0x03]; +} + static void adv_max_events_duration_set(struct ll_adv_set *adv, uint16_t duration, uint8_t max_ext_adv_evts) diff --git a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c index 4b36a64c0d770..bd235f0798a49 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c +++ b/subsys/bluetooth/controller/ll_sw/ull_adv_sync.c @@ -48,6 +48,7 @@ #include "hal/debug.h" static int init_reset(void); +static uint8_t adv_type_check(struct ll_adv_set *adv); static inline struct ll_adv_sync_set *sync_acquire(void); static inline void sync_release(struct ll_adv_sync_set *sync); static inline uint16_t sync_handle_get(struct ll_adv_sync_set *sync); @@ -350,6 +351,15 @@ uint8_t ll_adv_sync_param_set(uint8_t handle, uint16_t interval, uint16_t flags) return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER; } + if (IS_ENABLED(CONFIG_BT_CTLR_PARAM_CHECK)) { + uint8_t err; + + err = adv_type_check(adv); + if (err) { + return err; + } + } + lll_sync = adv->lll.sync; if (!lll_sync) { struct pdu_adv *ter_pdu; @@ -455,6 +465,15 @@ uint8_t ll_adv_sync_ad_data_set(uint8_t handle, uint8_t op, uint8_t len, return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER; } + if (IS_ENABLED(CONFIG_BT_CTLR_PARAM_CHECK)) { + uint8_t err; + + err = adv_type_check(adv); + if (err) { + return err; + } + } + lll_sync = adv->lll.sync; if (!lll_sync) { return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER; @@ -549,6 +568,15 @@ uint8_t ll_adv_sync_enable(uint8_t handle, uint8_t enable) return err; } + if (IS_ENABLED(CONFIG_BT_CTLR_PARAM_CHECK)) { + uint8_t err; + + err = adv_type_check(adv); + if (err) { + return BT_HCI_ERR_CMD_DISALLOWED; + } + } + /* TODO: Check for periodic data being complete */ /* TODO: Check packet too long */ @@ -1454,6 +1482,41 @@ static int init_reset(void) return 0; } +static uint8_t adv_type_check(struct ll_adv_set *adv) +{ + struct pdu_adv_com_ext_adv *pri_com_hdr; + struct pdu_adv_ext_hdr *pri_hdr; + struct pdu_adv *pri_pdu; + + pri_pdu = lll_adv_data_latest_peek(&adv->lll); + if (pri_pdu->type != PDU_ADV_TYPE_EXT_IND) { + return BT_HCI_ERR_INVALID_PARAM; + } + + pri_com_hdr = (void *)&pri_pdu->adv_ext_ind; + if (pri_com_hdr->adv_mode != 0U) { + return BT_HCI_ERR_INVALID_PARAM; + } + + pri_hdr = (void *)pri_com_hdr->ext_hdr_adv_data; + if (pri_hdr->aux_ptr) { + struct pdu_adv_com_ext_adv *sec_com_hdr; + struct pdu_adv_ext_hdr *sec_hdr; + struct pdu_adv *sec_pdu; + + sec_pdu = lll_adv_aux_data_latest_peek(adv->lll.aux); + sec_com_hdr = (void *)&sec_pdu->adv_ext_ind; + sec_hdr = (void *)sec_com_hdr->ext_hdr_adv_data; + if (!pri_hdr->adv_addr && !sec_hdr->adv_addr) { + return BT_HCI_ERR_INVALID_PARAM; + } + } else if (!pri_hdr->adv_addr) { + return BT_HCI_ERR_INVALID_PARAM; + } + + return 0; +} + static inline struct ll_adv_sync_set *sync_acquire(void) { return mem_acquire(&adv_sync_free);