Bluetooth: controller: Fix for CPR with/without Feature Exchange

Fix implementation to support Connection Parameter Request
Procedure initiation with and without use of Feature
Exchange Procedure being performed in a connection.

Fixes LL.TS.5.0.2 conformance tests:
LL/CON/MAS/BV-81-C [Initiating Connection Parameter Request
	- Unsupported Without Feature Exchange]
LL/CON/MAS/BV-82-C [Initiating Connection Parameter Request
	- Unsupported With Feature Exchange]
LL/CON/SLA/BV-85-C [Initiating Connection Parameter Request
	- Unsupported Without Feature Exchange]
LL/CON/SLA/BV-86-C [Initiating Connection Parameter Request
	- Unsupported With Feature Exchange]

Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
Vinayak Kariappa Chettimada 2018-01-29 14:52:54 +01:00 committed by Carles Cufí
commit 7af9c7108f
3 changed files with 88 additions and 18 deletions

View file

@ -1089,13 +1089,10 @@ static void le_conn_update(struct net_buf *buf, struct net_buf **evt)
conn_latency = sys_le16_to_cpu(cmd->conn_latency);
supervision_timeout = sys_le16_to_cpu(cmd->supervision_timeout);
/** @todo if peer supports LE Conn Param Req,
* use Req cmd (1) instead of Initiate cmd (0).
*/
status = ll_conn_update(handle, 0, 0, conn_interval_max,
conn_latency, supervision_timeout);
*evt = cmd_status((!status) ? 0x00 : BT_HCI_ERR_CMD_DISALLOWED);
*evt = cmd_status(status);
}
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
@ -1118,7 +1115,7 @@ static void le_conn_param_req_reply(struct net_buf *buf, struct net_buf **evt)
timeout);
rp = cmd_complete(evt, sizeof(*rp));
rp->status = (!status) ? 0x00 : BT_HCI_ERR_CMD_DISALLOWED;
rp->status = status;
rp->handle = sys_cpu_to_le16(handle);
}
@ -1134,7 +1131,7 @@ static void le_conn_param_req_neg_reply(struct net_buf *buf,
status = ll_conn_update(handle, 2, cmd->reason, 0, 0, 0);
rp = cmd_complete(evt, sizeof(*rp));
rp->status = (!status) ? 0x00 : BT_HCI_ERR_CMD_DISALLOWED;
rp->status = status;
rp->handle = sys_cpu_to_le16(handle);
}
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */

View file

@ -2846,6 +2846,68 @@ isr_rx_conn_pkt_ctrl(struct radio_pdu_node_rx *radio_pdu_node_rx,
case PDU_DATA_LLCTRL_TYPE_UNKNOWN_RSP:
if (0) {
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
} else if (_radio.conn_curr->llcp_conn_param.ack !=
_radio.conn_curr->llcp_conn_param.req) {
struct connection *conn = _radio.conn_curr;
struct radio_le_conn_update_cmplt *cp;
/* Mark CPR as unsupported */
conn->llcp_conn_param.disabled = 1;
/* TODO: check for unsupported remote feature reason */
if (!conn->role) {
LL_ASSERT(conn->llcp_req == conn->llcp_ack);
conn->llcp_conn_param.state =
LLCP_CPR_STATE_UPD;
conn->llcp.conn_upd.win_size = 1;
conn->llcp.conn_upd.win_offset_us = 0;
conn->llcp.conn_upd.interval =
conn->llcp_conn_param.interval;
conn->llcp.conn_upd.latency =
conn->llcp_conn_param.latency;
conn->llcp.conn_upd.timeout =
conn->llcp_conn_param.timeout;
/* conn->llcp.conn_upd.instant = 0; */
conn->llcp.conn_upd.state = LLCP_CUI_STATE_USE;
conn->llcp.conn_upd.is_internal =
!conn->llcp_conn_param.cmd;
conn->llcp_type = LLCP_CONN_UPD;
conn->llcp_ack--;
break;
}
LL_ASSERT(_radio.conn_upd == conn);
/* reset mutex */
_radio.conn_upd = NULL;
/* Procedure complete */
conn->llcp_conn_param.ack = conn->llcp_conn_param.req;
/* skip event generation if not cmd initiated */
if (!conn->llcp_conn_param.cmd) {
break;
}
/* generate conn upd complete event with error code */
radio_pdu_node_rx->hdr.type = NODE_RX_TYPE_CONN_UPDATE;
/* prepare connection update complete structure */
pdu_data_rx = (void *)radio_pdu_node_rx->pdu_data;
cp = (void *)&pdu_data_rx->payload;
cp->status = BT_HCI_ERR_UNSUPP_REMOTE_FEATURE;
cp->interval = conn->conn_interval;
cp->latency = conn->latency;
cp->timeout = conn->supervision_reload *
conn->conn_interval * 125 / 1000;
*rx_enqueue = 1;
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
} else if (_radio.conn_curr->llcp_length.req !=
_radio.conn_curr->llcp_length.ack) {
@ -8923,9 +8985,10 @@ static u32_t conn_update_req(struct connection *conn)
return 0;
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
} else if (conn->common.fex_valid &&
(conn->llcp_features &
BIT(BT_LE_FEAT_BIT_CONN_PARAM_REQ))) {
} else if (!conn->llcp_conn_param.disabled &&
(!conn->common.fex_valid ||
(conn->llcp_features &
BIT(BT_LE_FEAT_BIT_CONN_PARAM_REQ)))) {
/** Perform slave intiated conn param req */
conn->llcp_conn_param.status = 0;
conn->llcp_conn_param.interval = conn->conn_interval;
@ -9838,6 +9901,7 @@ u32_t radio_adv_enable(u16_t interval, u8_t chan_map, u8_t filter_policy,
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
conn->llcp_conn_param.req = 0;
conn->llcp_conn_param.ack = 0;
conn->llcp_conn_param.disabled = 0;
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
@ -10317,6 +10381,7 @@ u32_t radio_connect_enable(u8_t adv_addr_type, u8_t *adv_addr, u16_t interval,
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
conn->llcp_conn_param.req = 0;
conn->llcp_conn_param.ack = 0;
conn->llcp_conn_param.disabled = 0;
#endif /* CONFIG_BT_CTLR_CONN_PARAM_REQ */
#if defined(CONFIG_BT_CTLR_DATA_LENGTH)
@ -10376,22 +10441,29 @@ u32_t ll_conn_update(u16_t handle, u8_t cmd, u8_t status, u16_t interval,
conn = connection_get(handle);
if (!conn) {
return 1;
return BT_HCI_ERR_CMD_DISALLOWED;
}
if (!cmd) {
if (conn->common.fex_valid &&
(conn->llcp_features &
BIT(BT_LE_FEAT_BIT_CONN_PARAM_REQ))) {
#if defined(CONFIG_BT_CTLR_CONN_PARAM_REQ)
if (!conn->llcp_conn_param.disabled &&
(!conn->common.fex_valid ||
(conn->llcp_features &
BIT(BT_LE_FEAT_BIT_CONN_PARAM_REQ)))) {
cmd++;
} else if (conn->role) {
return 1;
return BT_HCI_ERR_UNSUPP_REMOTE_FEATURE;
}
#else /* !CONFIG_BT_CTLR_CONN_PARAM_REQ */
if (conn->role) {
return BT_HCI_ERR_CMD_DISALLOWED;
}
#endif /* !CONFIG_BT_CTLR_CONN_PARAM_REQ */
}
if (!cmd) {
if (conn->llcp_req != conn->llcp_ack) {
return 1;
return BT_HCI_ERR_CMD_DISALLOWED;
}
conn->llcp.conn_upd.win_size = 1;
@ -10414,7 +10486,7 @@ u32_t ll_conn_update(u16_t handle, u8_t cmd, u8_t status, u16_t interval,
conn->llcp_conn_param.ack) ||
(conn->llcp_conn_param.state !=
LLCP_CPR_STATE_APP_WAIT)) {
return 1;
return BT_HCI_ERR_CMD_DISALLOWED;
}
conn->llcp_conn_param.status = status;
@ -10423,7 +10495,7 @@ u32_t ll_conn_update(u16_t handle, u8_t cmd, u8_t status, u16_t interval,
} else {
if (conn->llcp_conn_param.req !=
conn->llcp_conn_param.ack) {
return 1;
return BT_HCI_ERR_CMD_DISALLOWED;
}
conn->llcp_conn_param.status = 0;
@ -10437,7 +10509,7 @@ u32_t ll_conn_update(u16_t handle, u8_t cmd, u8_t status, u16_t interval,
#else /* !CONFIG_BT_CTLR_CONN_PARAM_REQ */
/* CPR feature not supported */
return 1;
return BT_HCI_ERR_CMD_DISALLOWED;
#endif /* !CONFIG_BT_CTLR_CONN_PARAM_REQ */
}

View file

@ -208,6 +208,7 @@ struct connection {
LLCP_CPR_STATE_UPD
} state:3 __packed;
u8_t cmd:1;
u8_t disabled:1;
u8_t status;
u16_t interval;
u16_t latency;