1 /*
2  * Copyright (c) 2020 Demant
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/sys/byteorder.h>
9 
10 #include <zephyr/bluetooth/hci_types.h>
11 #include <zephyr/bluetooth/conn.h>
12 
13 #include "util/util.h"
14 #include "util/memq.h"
15 #include "util/mayfly.h"
16 #include "util/dbuf.h"
17 
18 #include "hal/ccm.h"
19 #include "hal/ticker.h"
20 
21 #include "ticker/ticker.h"
22 
23 #include "pdu_df.h"
24 #include "lll/pdu_vendor.h"
25 #include "pdu.h"
26 
27 #include "lll.h"
28 #include "lll_clock.h"
29 #include "lll/lll_vendor.h"
30 #include "lll/lll_df_types.h"
31 #include "lll_conn.h"
32 #include "lll_conn_iso.h"
33 #include "lll_peripheral_iso.h"
34 
35 
36 #include "ll_sw/ull_tx_queue.h"
37 
38 #include "ull_conn_types.h"
39 
40 #include "isoal.h"
41 #include "ull_iso_types.h"
42 #include "ull_conn_iso_types.h"
43 
44 #include "ull_llcp.h"
45 
46 #include "ull_internal.h"
47 #include "ull_conn_internal.h"
48 #include "ull_conn_iso_internal.h"
49 #include "ull_llcp_internal.h"
50 
51 #include "hal/debug.h"
52 
53 #define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL
54 #include <zephyr/logging/log.h>
55 LOG_MODULE_REGISTER(bt_ctlr_ull_peripheral_iso);
56 
ll_cis_get_acl_awaiting_reply(uint16_t handle,uint8_t * error)57 static struct ll_conn *ll_cis_get_acl_awaiting_reply(uint16_t handle, uint8_t *error)
58 {
59 	struct ll_conn *acl_conn = NULL;
60 
61 	if (!IS_CIS_HANDLE(handle) || ll_conn_iso_stream_get(handle)->group == NULL) {
62 		LOG_ERR("Unknown CIS handle %u", handle);
63 		*error = BT_HCI_ERR_UNKNOWN_CONN_ID;
64 		return NULL;
65 	}
66 
67 	for (int h = 0; h < CONFIG_BT_MAX_CONN; h++) {
68 		struct ll_conn *conn = ll_conn_get(h);
69 		uint16_t cis_handle = ull_cp_cc_ongoing_handle(conn);
70 
71 		if (handle == cis_handle) {
72 			/* ACL connection found */
73 			acl_conn = conn;
74 			break;
75 		}
76 	}
77 
78 	if (!acl_conn) {
79 		LOG_ERR("No connection found for handle %u", handle);
80 		*error = BT_HCI_ERR_CMD_DISALLOWED;
81 		return NULL;
82 	}
83 
84 	if (acl_conn->lll.role == BT_CONN_ROLE_CENTRAL) {
85 		LOG_ERR("Not allowed for central");
86 		*error = BT_HCI_ERR_CMD_DISALLOWED;
87 		return NULL;
88 	}
89 
90 	if (!ull_cp_cc_awaiting_reply(acl_conn)) {
91 		LOG_ERR("Not allowed in current procedure state");
92 		*error = BT_HCI_ERR_CMD_DISALLOWED;
93 		return NULL;
94 	}
95 
96 	return acl_conn;
97 }
98 
ll_cis_accept(uint16_t handle)99 uint8_t ll_cis_accept(uint16_t handle)
100 {
101 	uint8_t status = BT_HCI_ERR_SUCCESS;
102 	struct ll_conn *conn = ll_cis_get_acl_awaiting_reply(handle, &status);
103 
104 	if (conn) {
105 		uint32_t cis_offset_min;
106 
107 		if (IS_ENABLED(CONFIG_BT_CTLR_PERIPHERAL_ISO_EARLY_CIG_START) ||
108 		    !IS_ENABLED(CONFIG_BT_CTLR_CIS_ACCEPT_MIN_OFFSET_STRICT)) {
109 			/* Early start allows offset down to spec defined minimum */
110 			cis_offset_min = CIS_MIN_OFFSET_MIN;
111 		} else {
112 			cis_offset_min = HAL_TICKER_TICKS_TO_US(conn->ull.ticks_slot) +
113 					 (EVENT_TICKER_RES_MARGIN_US << 1U);
114 
115 			if (!IS_ENABLED(CONFIG_BT_CTLR_EVENT_OVERHEAD_RESERVE_MAX)) {
116 				cis_offset_min += EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US;
117 			}
118 		}
119 
120 		/* Accept request */
121 		ull_cp_cc_accept(conn, cis_offset_min);
122 	}
123 
124 	return status;
125 }
126 
ll_cis_reject(uint16_t handle,uint8_t reason)127 uint8_t ll_cis_reject(uint16_t handle, uint8_t reason)
128 {
129 	uint8_t status = BT_HCI_ERR_SUCCESS;
130 	struct ll_conn *acl_conn = ll_cis_get_acl_awaiting_reply(handle, &status);
131 
132 	if (acl_conn) {
133 		/* Reject request */
134 		ull_cp_cc_reject(acl_conn, reason);
135 	}
136 
137 	return status;
138 }
139 
ull_peripheral_iso_init(void)140 int ull_peripheral_iso_init(void)
141 {
142 	return 0;
143 }
144 
ull_peripheral_iso_reset(void)145 int ull_peripheral_iso_reset(void)
146 {
147 	return 0;
148 }
149 
150 /* Use this function to release CIS/CIG resources on an aborted CIS setup
151  * ie if CIS setup is 'cancelled' after call to ull_peripheral_iso_acquire()
152  * because of a rejection of the CIS request
153  */
ull_peripheral_iso_release(uint16_t cis_handle)154 void ull_peripheral_iso_release(uint16_t cis_handle)
155 {
156 	struct ll_conn_iso_stream *cis;
157 	struct ll_conn_iso_group *cig;
158 
159 	cis = ll_conn_iso_stream_get(cis_handle);
160 	LL_ASSERT(cis);
161 
162 	cig = cis->group;
163 
164 	ll_conn_iso_stream_release(cis);
165 	cig->lll.num_cis--;
166 
167 	if (!cig->lll.num_cis) {
168 		ll_conn_iso_group_release(cig);
169 	}
170 }
171 
ull_peripheral_iso_acquire(struct ll_conn * acl,struct pdu_data_llctrl_cis_req * req,uint16_t * cis_handle)172 uint8_t ull_peripheral_iso_acquire(struct ll_conn *acl,
173 				   struct pdu_data_llctrl_cis_req *req,
174 				   uint16_t *cis_handle)
175 {
176 	struct ll_conn_iso_group *cig;
177 	struct ll_conn_iso_stream *cis;
178 	uint32_t iso_interval_us;
179 	uint16_t handle;
180 
181 	/* Get CIG by id */
182 	cig = ll_conn_iso_group_get_by_id(req->cig_id);
183 	if (!cig) {
184 		/* CIG does not exist - create it */
185 		cig = ll_conn_iso_group_acquire();
186 		if (!cig) {
187 			/* No space for new CIG */
188 			return BT_HCI_ERR_INSUFFICIENT_RESOURCES;
189 		}
190 
191 		memset(&cig->lll, 0, sizeof(cig->lll));
192 
193 		cig->iso_interval = sys_le16_to_cpu(req->iso_interval);
194 		iso_interval_us = cig->iso_interval * CONN_INT_UNIT_US;
195 		cig->lll.iso_interval_us = iso_interval_us;
196 
197 		cig->cig_id = req->cig_id;
198 		cig->lll.handle = LLL_HANDLE_INVALID;
199 		cig->lll.role = acl->lll.role;
200 		cig->lll.resume_cis = LLL_HANDLE_INVALID;
201 
202 		/* Calculate CIG default maximum window widening. NOTE: This calculation
203 		 * does not take into account that leading CIS with NSE>=3 must reduce
204 		 * the maximum window widening to one sub-interval. This must be applied
205 		 * in LLL (BT Core 5.3, Vol 6, Part B, section 4.2.4).
206 		 */
207 		cig->lll.window_widening_max_us = (iso_interval_us >> 1) -
208 						  EVENT_IFS_US;
209 		cig->lll.window_widening_periodic_us_frac =
210 			DIV_ROUND_UP(((lll_clock_ppm_local_get() +
211 					 lll_clock_ppm_get(acl->periph.sca)) *
212 					 EVENT_US_TO_US_FRAC(iso_interval_us)), USEC_PER_SEC);
213 
214 		lll_hdr_init(&cig->lll, cig);
215 	}
216 
217 	if (cig->lll.num_cis == CONFIG_BT_CTLR_CONN_ISO_STREAMS_PER_GROUP) {
218 		/* No space in CIG for new CIS */
219 		return BT_HCI_ERR_INSUFFICIENT_RESOURCES;
220 	}
221 
222 	for (handle = LL_CIS_HANDLE_BASE; handle <= LL_CIS_HANDLE_LAST;
223 	     handle++) {
224 		cis = ll_iso_stream_connected_get(handle);
225 		if (cis && cis->group && cis->cis_id == req->cis_id) {
226 			/* CIS ID already in use */
227 			return BT_HCI_ERR_INVALID_LL_PARAM;
228 		}
229 	}
230 
231 	/* Acquire new CIS */
232 	cis = ll_conn_iso_stream_acquire();
233 	if (cis == NULL) {
234 		if (!cig->lll.num_cis) {
235 			/* No CIS's in CIG, so this was just allocated
236 			 * so release as we can't use it
237 			 */
238 			ll_conn_iso_group_release(cig);
239 		}
240 		/* No space for new CIS */
241 		return BT_HCI_ERR_INSUFFICIENT_RESOURCES;
242 	}
243 
244 	/* Read 20-bit SDU intervals (mask away RFU bits) */
245 	cig->c_sdu_interval = sys_get_le24(req->c_sdu_interval) & 0x0FFFFF;
246 	cig->p_sdu_interval = sys_get_le24(req->p_sdu_interval) & 0x0FFFFF;
247 
248 	cis->cis_id = req->cis_id;
249 	cis->framed = (req->c_max_sdu_packed[1] & BIT(7)) >> 7;
250 	cis->established = 0;
251 	cis->group = cig;
252 	cis->teardown = 0;
253 	cis->released_cb = NULL;
254 	cis->c_max_sdu = (uint16_t)(req->c_max_sdu_packed[1] & 0x0F) << 8 |
255 				    req->c_max_sdu_packed[0];
256 	cis->p_max_sdu = (uint16_t)(req->p_max_sdu[1] & 0x0F) << 8 |
257 				    req->p_max_sdu[0];
258 
259 	cis->lll.active = 0U;
260 	cis->lll.handle = LLL_HANDLE_INVALID;
261 	cis->lll.acl_handle = acl->lll.handle;
262 	cis->lll.sub_interval = sys_get_le24(req->sub_interval);
263 	cis->lll.nse = req->nse;
264 
265 	cis->lll.rx.phy = req->c_phy;
266 	cis->lll.rx.phy_flags = PHY_FLAGS_S8;
267 	cis->lll.rx.bn = req->c_bn;
268 	cis->lll.rx.ft = req->c_ft;
269 	cis->lll.rx.max_pdu = sys_le16_to_cpu(req->c_max_pdu);
270 
271 	cis->lll.tx.phy = req->p_phy;
272 	cis->lll.tx.phy_flags = PHY_FLAGS_S8;
273 	cis->lll.tx.bn = req->p_bn;
274 	cis->lll.tx.ft = req->p_ft;
275 	cis->lll.tx.max_pdu = sys_le16_to_cpu(req->p_max_pdu);
276 
277 	if (!cis->lll.link_tx_free) {
278 		cis->lll.link_tx_free = &cis->lll.link_tx;
279 	}
280 
281 	memq_init(cis->lll.link_tx_free, &cis->lll.memq_tx.head,
282 		  &cis->lll.memq_tx.tail);
283 	cis->lll.link_tx_free = NULL;
284 
285 	*cis_handle = ll_conn_iso_stream_handle_get(cis);
286 	cig->lll.num_cis++;
287 
288 	return 0;
289 }
290 
ull_peripheral_iso_setup(struct pdu_data_llctrl_cis_ind * ind,uint8_t cig_id,uint16_t cis_handle,uint16_t * conn_event_count)291 uint8_t ull_peripheral_iso_setup(struct pdu_data_llctrl_cis_ind *ind,
292 				 uint8_t cig_id, uint16_t cis_handle,
293 				 uint16_t *conn_event_count)
294 {
295 	struct ll_conn_iso_stream *cis = NULL;
296 	struct ll_conn_iso_group *cig;
297 	uint32_t cis_offset;
298 
299 	/* Get CIG by id */
300 	cig = ll_conn_iso_group_get_by_id(cig_id);
301 	if (!cig) {
302 		return BT_HCI_ERR_UNSPECIFIED;
303 	}
304 
305 	cig->lll.handle = ll_conn_iso_group_handle_get(cig);
306 	cig->sync_delay = sys_get_le24(ind->cig_sync_delay);
307 
308 	cis = ll_conn_iso_stream_get(cis_handle);
309 	if (!cis) {
310 		return BT_HCI_ERR_UNSPECIFIED;
311 	}
312 
313 	cis_offset = sys_get_le24(ind->cis_offset);
314 
315 #if defined(CONFIG_BT_CTLR_PERIPHERAL_ISO_EARLY_CIG_START)
316 	if (cig->state != CIG_STATE_ACTIVE) {
317 		/* This is the first CIS. Make sure we can make the anchorpoint, otherwise
318 		 * we need to move up the instant up by one connection interval.
319 		 */
320 		if (cis_offset < EVENT_OVERHEAD_START_US) {
321 			/* Start one connection event earlier */
322 			(*conn_event_count)--;
323 		}
324 	}
325 #endif /* CONFIG_BT_CTLR_PERIPHERAL_ISO_EARLY_CIG_START */
326 
327 	cis->sync_delay = sys_get_le24(ind->cis_sync_delay);
328 	cis->offset = cis_offset;
329 	memcpy(cis->lll.access_addr, ind->aa, sizeof(ind->aa));
330 #if defined(CONFIG_BT_CTLR_ISOAL_PSN_IGNORE)
331 	cis->pkt_seq_num = 0U;
332 #endif /* CONFIG_BT_CTLR_ISOAL_PSN_IGNORE */
333 	cis->lll.event_count = LLL_CONN_ISO_EVENT_COUNT_MAX;
334 	cis->lll.next_subevent = 0U;
335 	cis->lll.sn = 0U;
336 	cis->lll.nesn = 0U;
337 	cis->lll.cie = 0U;
338 	cis->lll.npi = 0U;
339 	cis->lll.flush = LLL_CIS_FLUSH_NONE;
340 	cis->lll.datapath_ready_rx = 0U;
341 	cis->lll.tx.payload_count = 0U;
342 	cis->lll.rx.payload_count = 0U;
343 	cis->lll.rx.bn_curr = 1U;
344 	cis->lll.tx.bn_curr = 1U;
345 
346 	return 0;
347 }
348 
ticker_op_cb(uint32_t status,void * param)349 static void ticker_op_cb(uint32_t status, void *param)
350 {
351 	ARG_UNUSED(param);
352 
353 	LL_ASSERT(status == TICKER_STATUS_SUCCESS);
354 }
355 
ull_peripheral_iso_update_ticker(struct ll_conn_iso_group * cig,uint32_t ticks_at_expire,uint32_t iso_interval_us_frac)356 void ull_peripheral_iso_update_ticker(struct ll_conn_iso_group *cig,
357 				      uint32_t ticks_at_expire,
358 				      uint32_t iso_interval_us_frac)
359 {
360 
361 	/* stop/start with new updated timings */
362 	uint8_t ticker_id_cig = TICKER_ID_CONN_ISO_BASE + ll_conn_iso_group_handle_get(cig);
363 	uint32_t ticker_status = ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_HIGH,
364 				    ticker_id_cig, ticker_op_cb, NULL);
365 	LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
366 		  (ticker_status == TICKER_STATUS_BUSY));
367 
368 	ticker_status = ticker_start(TICKER_INSTANCE_ID_CTLR,
369 				     TICKER_USER_ID_ULL_HIGH,
370 				     ticker_id_cig,
371 				     ticks_at_expire,
372 				     EVENT_US_FRAC_TO_TICKS(iso_interval_us_frac),
373 				     EVENT_US_FRAC_TO_TICKS(iso_interval_us_frac),
374 				     EVENT_US_FRAC_TO_REMAINDER(iso_interval_us_frac),
375 				     TICKER_NULL_LAZY,
376 				     0,
377 				     ull_conn_iso_ticker_cb, cig,
378 				     ticker_op_cb, NULL);
379 
380 	LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
381 		  (ticker_status == TICKER_STATUS_BUSY));
382 
383 }
384 
ull_peripheral_iso_update_peer_sca(struct ll_conn * acl)385 void ull_peripheral_iso_update_peer_sca(struct ll_conn *acl)
386 {
387 	uint8_t cig_handle;
388 
389 	/* Find CIG associated with ACL conn */
390 	for (cig_handle = 0; cig_handle < CONFIG_BT_CTLR_CONN_ISO_GROUPS; cig_handle++) {
391 		/* Go through all ACL affiliated CIGs and update peer SCA */
392 		struct ll_conn_iso_stream *cis;
393 		struct ll_conn_iso_group *cig;
394 
395 		cig = ll_conn_iso_group_get(cig_handle);
396 		if (!cig || !cig->lll.num_cis) {
397 			continue;
398 		}
399 		cis = ll_conn_iso_stream_get_by_group(cig, NULL);
400 		LL_ASSERT(cis);
401 
402 		uint16_t cis_handle = cis->lll.handle;
403 
404 		cis = ll_iso_stream_connected_get(cis_handle);
405 		if (!cis) {
406 			continue;
407 		}
408 
409 		if (cis->lll.acl_handle == acl->lll.handle) {
410 			cig->sca_update = acl->periph.sca + 1;
411 		}
412 	}
413 }
414