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