Bluetooth: controller: Fix master terminate procedure

Fix master terminate procedure so that if slave responded to
the ack from master for the LL_TERMINATE_IND then the master
correctly disconnected.

This fixes TP/CON/MAS/BV-09-C [Master Accepting Termination]
in LL.TS.5.0.0.

Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
Tested-by: Ulrich Myhre <ulmy@nordicsemi.no>
This commit is contained in:
Vinayak Kariappa Chettimada 2017-07-05 12:09:40 +02:00 committed by Johan Hedberg
commit 52ee6622c0
2 changed files with 37 additions and 37 deletions

View file

@ -3011,6 +3011,7 @@ static inline void isr_close_conn(void)
u16_t ticks_drift_minus; u16_t ticks_drift_minus;
u16_t latency_event; u16_t latency_event;
u16_t elapsed_event; u16_t elapsed_event;
u8_t reason_peer;
u16_t lazy; u16_t lazy;
u8_t force; u8_t force;
@ -3019,11 +3020,13 @@ static inline void isr_close_conn(void)
return; return;
} }
/* Remote Initiated terminate happened in this event for Slave */ /* Master transmitted ack for the received terminate ind or
if ((_radio.role == ROLE_SLAVE) && * Slave received terminate ind.
_radio.conn_curr->llcp_terminate.reason_peer) { */
terminate_ind_rx_enqueue(_radio.conn_curr, reason_peer = _radio.conn_curr->llcp_terminate.reason_peer;
_radio.conn_curr->llcp_terminate.reason_peer); if (reason_peer && ((_radio.role == ROLE_SLAVE) ||
_radio.conn_curr->master.terminate_ack)) {
terminate_ind_rx_enqueue(_radio.conn_curr, reason_peer);
connection_release(_radio.conn_curr); connection_release(_radio.conn_curr);
_radio.conn_curr = NULL; _radio.conn_curr = NULL;
@ -3037,8 +3040,8 @@ static inline void isr_close_conn(void)
elapsed_event = latency_event + 1; elapsed_event = latency_event + 1;
/* calculate drift if anchor point sync-ed */ /* calculate drift if anchor point sync-ed */
if ((_radio.packet_counter != 0) && ((!SILENT_CONNECTION) || if (_radio.packet_counter &&
(_radio.packet_counter != 0xFF))) { (!SILENT_CONNECTION || (_radio.packet_counter != 0xFF))) {
if (_radio.role == ROLE_SLAVE) { if (_radio.role == ROLE_SLAVE) {
u32_t start_to_address_expected_us; u32_t start_to_address_expected_us;
u32_t start_to_address_actual_us; u32_t start_to_address_actual_us;
@ -3092,23 +3095,14 @@ static inline void isr_close_conn(void)
_radio.conn_curr->latency_event = _radio.conn_curr->latency_event =
_radio.conn_curr->latency; _radio.conn_curr->latency;
} }
} else if (reason_peer) {
_radio.conn_curr->master.terminate_ack = 1;
} }
/* Reset connection failed to establish procedure */ /* Reset connection failed to establish procedure */
_radio.conn_curr->connect_expire = 0; _radio.conn_curr->connect_expire = 0;
} }
/* Remote Initiated terminate happened in previous event for Master */
else if (_radio.conn_curr->llcp_terminate.reason_peer) {
terminate_ind_rx_enqueue(_radio.conn_curr,
_radio.conn_curr->llcp_terminate.reason_peer);
connection_release(_radio.conn_curr);
_radio.conn_curr = NULL;
return;
}
/* check connection failed to establish */ /* check connection failed to establish */
else if (_radio.conn_curr->connect_expire) { else if (_radio.conn_curr->connect_expire) {
if (_radio.conn_curr->connect_expire > elapsed_event) { if (_radio.conn_curr->connect_expire > elapsed_event) {
@ -7504,8 +7498,7 @@ static void terminate_ind_rx_enqueue(struct connection *conn, u8_t reason)
void *link; void *link;
/* Prepare the rx packet structure */ /* Prepare the rx packet structure */
radio_pdu_node_rx = radio_pdu_node_rx = (void *)&conn->llcp_terminate.radio_pdu_node_rx;
(struct radio_pdu_node_rx *)&conn->llcp_terminate.radio_pdu_node_rx;
LL_ASSERT(radio_pdu_node_rx->hdr.onion.link); LL_ASSERT(radio_pdu_node_rx->hdr.onion.link);
radio_pdu_node_rx->hdr.handle = conn->handle; radio_pdu_node_rx->hdr.handle = conn->handle;
@ -8765,6 +8758,7 @@ u32_t radio_connect_enable(u8_t adv_addr_type, u8_t *adv_addr, u16_t interval,
conn->role = 0; conn->role = 0;
conn->connect_expire = 6; conn->connect_expire = 6;
conn->master.terminate_ack = 0;
conn_interval_us = conn_interval_us =
(u32_t)_radio.scanner.conn_interval * 1250; (u32_t)_radio.scanner.conn_interval * 1250;
conn->supervision_reload = conn->supervision_reload =

View file

@ -90,19 +90,25 @@ struct connection {
u16_t apto_expire; u16_t apto_expire;
#endif /* CONFIG_BLUETOOTH_CONTROLLER_LE_PING */ #endif /* CONFIG_BLUETOOTH_CONTROLLER_LE_PING */
struct { union {
u8_t latency_enabled:1; struct {
u8_t latency_cancel:1; u8_t terminate_ack:1;
u8_t sca:3; } master;
u32_t window_widening_periodic_us;
u32_t window_widening_max_us; struct {
u32_t window_widening_prepare_us; u8_t latency_enabled:1;
u32_t window_widening_event_us; u8_t latency_cancel:1;
u32_t window_size_prepare_us; u8_t sca:3;
u32_t window_size_event_us; u32_t window_widening_periodic_us;
u32_t force; u32_t window_widening_max_us;
u32_t ticks_to_offset; u32_t window_widening_prepare_us;
} slave; u32_t window_widening_event_us;
u32_t window_size_prepare_us;
u32_t window_size_event_us;
u32_t force;
u32_t ticks_to_offset;
} slave;
};
u8_t llcp_req; u8_t llcp_req;
u8_t llcp_ack; u8_t llcp_ack;
@ -174,10 +180,10 @@ struct connection {
} llcp_version; } llcp_version;
struct { struct {
u8_t req; u8_t req;
u8_t ack; u8_t ack;
u8_t reason_own; u8_t reason_own;
u8_t reason_peer; u8_t reason_peer;
struct { struct {
struct radio_pdu_node_rx_hdr hdr; struct radio_pdu_node_rx_hdr hdr;
u8_t reason; u8_t reason;