Bluetooth: controller: Do not use LL procedures not supported by remote

Update LLCP handling during PHY update and Data Length update to not
start the LL control procedure if the remote has already indicated that
the procedure is not supported.

This fulfills the following requirement from the BT Core Specification
(Core_v5.2, Vol 6, Part B, Section 4.6):

Except where explicitly stated elsewhere in this specification, if the
peer Link Layer has indicated either during a feature exchange procedure
or by responding with an LL_UNKNOWN_RSP PDU that it does not support a
procedure, then the Link Layer shall not use that procedure.

Re-use the connection parameter request handling for PHY and
data length update procedures.

Signed-off-by: Joakim Andersson <joakim.andersson@nordicsemi.no>
This commit is contained in:
Joakim Andersson 2020-02-26 16:14:29 +01:00 committed by Carles Cufí
commit 8514794ed3
6 changed files with 48 additions and 0 deletions

View file

@ -3454,6 +3454,9 @@ isr_rx_conn_pkt_ctrl(struct radio_pdu_node_rx *node_rx,
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
} else if (_radio.conn_curr->llcp_length.req !=
_radio.conn_curr->llcp_length.ack) {
/* Mark length update as unsupported */
_radio.conn_curr->llcp_length.disabled = 1U;
/* Procedure complete */
_radio.conn_curr->llcp_length.ack =
_radio.conn_curr->llcp_length.req;
@ -3469,6 +3472,9 @@ isr_rx_conn_pkt_ctrl(struct radio_pdu_node_rx *node_rx,
_radio.conn_curr->llcp_phy.ack) {
struct radio_le_phy_upd_cmplt *p;
/* Mark phy update as unsupported */
_radio.conn_curr->llcp_phy.disabled = 1U;
/* Procedure complete */
_radio.conn_curr->llcp_phy.ack =
_radio.conn_curr->llcp_phy.req;
@ -12168,12 +12174,14 @@ u32_t radio_connect_enable(u8_t adv_addr_type, u8_t *adv_addr, u16_t interval,
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
conn->llcp_length.disabled = 0U;
conn->llcp_length.req = 0U;
conn->llcp_length.ack = 0U;
conn->llcp_length.cache.tx_octets = 0U;
#endif /* CONFIG_BT_CTLR_DATA_LENGTH */
#if defined(CONFIG_BT_CTLR_PHY)
conn->llcp_phy.disabled = 0U;
conn->llcp_phy.req = 0U;
conn->llcp_phy.ack = 0U;
#endif /* CONFIG_BT_CTLR_PHY */
@ -12607,6 +12615,12 @@ u32_t ll_length_req_send(u16_t handle, u16_t tx_octets, u16_t tx_time)
return BT_HCI_ERR_UNKNOWN_CONN_ID;
}
if (conn->llcp_length.disabled ||
(conn->common.fex_valid &&
!(conn->llcp_feature.features & BIT(BT_LE_FEAT_BIT_DLE)))) {
return BT_HCI_ERR_UNSUPP_REMOTE_FEATURE;
}
if (conn->llcp_length.req != conn->llcp_length.ack) {
switch (conn->llcp_length.state) {
case LLCP_LENGTH_STATE_RSP_ACK_WAIT:
@ -12702,6 +12716,13 @@ u8_t ll_phy_req_send(u16_t handle, u8_t tx, u8_t flags, u8_t rx)
return BT_HCI_ERR_UNKNOWN_CONN_ID;
}
if (conn->llcp_phy.disabled ||
(conn->common.fex_valid &&
!(conn->llcp_feature.features & BIT(BT_LE_FEAT_BIT_PHY_2M)) &&
!(conn->llcp_feature.features & BIT(BT_LE_FEAT_BIT_PHY_CODED)))) {
return BT_HCI_ERR_UNSUPP_REMOTE_FEATURE;
}
if (conn->llcp_phy.req != conn->llcp_phy.ack) {
return BT_HCI_ERR_CMD_DISALLOWED;
}

View file

@ -268,6 +268,7 @@ struct connection {
#define LLCP_LENGTH_STATE_RESIZE 4
#define LLCP_LENGTH_STATE_RESIZE_RSP 5
#define LLCP_LENGTH_STATE_RESIZE_RSP_ACK_WAIT 6
u8_t disabled:1;
u16_t rx_octets;
u16_t tx_octets;
#if defined(CONFIG_BT_CTLR_PHY)
@ -296,6 +297,7 @@ struct connection {
u8_t rx:3;
u8_t flags:1;
u8_t cmd:1;
u8_t disabled:1;
} llcp_phy;
#endif /* CONFIG_BT_CTLR_PHY */

View file

@ -674,6 +674,7 @@ u8_t ll_adv_enable(u8_t enable)
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
conn->llcp_length.req = conn->llcp_length.ack = 0U;
conn->llcp_length.disabled = 0U;
conn->llcp_length.cache.tx_octets = 0U;
conn->default_tx_octets = ull_conn_default_tx_octets_get();
@ -684,6 +685,7 @@ u8_t ll_adv_enable(u8_t enable)
#if defined(CONFIG_BT_CTLR_PHY)
conn->llcp_phy.req = conn->llcp_phy.ack = 0;
conn->llcp_phy.disabled = 0U;
conn->llcp_phy.pause_tx = 0U;
conn->phy_pref_tx = ull_conn_default_phy_tx_get();
conn->phy_pref_rx = ull_conn_default_phy_rx_get();

View file

@ -425,6 +425,12 @@ u32_t ll_length_req_send(u16_t handle, u16_t tx_octets, u16_t tx_time)
return BT_HCI_ERR_UNKNOWN_CONN_ID;
}
if (conn->llcp_length.disabled ||
(conn->common.fex_valid &&
!(conn->llcp_feature.features & BIT(BT_LE_FEAT_BIT_DLE)))) {
return BT_HCI_ERR_UNSUPP_REMOTE_FEATURE;
}
if (conn->llcp_length.req != conn->llcp_length.ack) {
switch (conn->llcp_length.state) {
case LLCP_LENGTH_STATE_RSP_ACK_WAIT:
@ -526,6 +532,13 @@ u8_t ll_phy_req_send(u16_t handle, u8_t tx, u8_t flags, u8_t rx)
return BT_HCI_ERR_UNKNOWN_CONN_ID;
}
if (conn->llcp_phy.disabled ||
(conn->common.fex_valid &&
!(conn->llcp_feature.features & BIT(BT_LE_FEAT_BIT_PHY_2M)) &&
!(conn->llcp_feature.features & BIT(BT_LE_FEAT_BIT_PHY_CODED)))) {
return BT_HCI_ERR_UNSUPP_REMOTE_FEATURE;
}
if ((conn->llcp_req != conn->llcp_ack) ||
(conn->llcp_phy.req != conn->llcp_phy.ack)) {
return BT_HCI_ERR_CMD_DISALLOWED;
@ -5878,6 +5891,9 @@ static inline int ctrl_rx(memq_link_t *link, struct node_rx_pdu **rx,
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
} else if (conn->llcp_length.req != conn->llcp_length.ack) {
/* Mark length update as unsupported */
conn->llcp_length.disabled = 1U;
/* Procedure complete */
conn->llcp_length.ack = conn->llcp_length.req;
@ -5891,6 +5907,9 @@ static inline int ctrl_rx(memq_link_t *link, struct node_rx_pdu **rx,
conn->llcp_phy.ack) {
struct lll_conn *lll = &conn->lll;
/* Mark phy update as unsupported */
conn->llcp_phy.disabled = 1U;
/* Procedure complete */
conn->llcp_phy.ack = conn->llcp_phy.req;
conn->llcp_phy.pause_tx = 0U;

View file

@ -222,6 +222,7 @@ struct ll_conn {
#define LLCP_LENGTH_STATE_RESIZE 4
#define LLCP_LENGTH_STATE_RESIZE_RSP 5
#define LLCP_LENGTH_STATE_RESIZE_RSP_ACK_WAIT 6
u8_t disabled:1;
u16_t rx_octets;
u16_t tx_octets;
#if defined(CONFIG_BT_CTLR_PHY)
@ -251,6 +252,7 @@ struct ll_conn {
u8_t pause_tx:1;
u8_t flags:1;
u8_t cmd:1;
u8_t disabled:1;
} llcp_phy;
u8_t phy_pref_tx:3;

View file

@ -221,6 +221,7 @@ u8_t ll_create_connection(u16_t scan_interval, u16_t scan_window,
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
conn->llcp_length.req = conn->llcp_length.ack = 0U;
conn->llcp_length.disabled = 0U;
conn->llcp_length.cache.tx_octets = 0U;
conn->default_tx_octets = ull_conn_default_tx_octets_get();
@ -231,6 +232,7 @@ u8_t ll_create_connection(u16_t scan_interval, u16_t scan_window,
#if defined(CONFIG_BT_CTLR_PHY)
conn->llcp_phy.req = conn->llcp_phy.ack = 0U;
conn->llcp_phy.disabled = 0U;
conn->llcp_phy.pause_tx = 0U;
conn->phy_pref_tx = ull_conn_default_phy_tx_get();
conn->phy_pref_rx = ull_conn_default_phy_rx_get();