1 /* sco.c - Bluetooth sco handling */
2 
3 /*
4  * Copyright (c) 2015-2016 Intel Corporation
5  * Copyright 2024 NXP
6  *
7  * SPDX-License-Identifier: Apache-2.0
8  */
9 
10 #include <zephyr/kernel.h>
11 #include <errno.h>
12 
13 #include <zephyr/sys/atomic.h>
14 #include <zephyr/sys/check.h>
15 
16 #include <zephyr/bluetooth/hci.h>
17 #include <zephyr/bluetooth/bluetooth.h>
18 #include <zephyr/bluetooth/conn.h>
19 
20 #include "common/bt_str.h"
21 
22 #include "host/addr_internal.h"
23 #include "host/hci_core.h"
24 #include "br.h"
25 #include "host/conn_internal.h"
26 #include "sco_internal.h"
27 
28 #define LOG_LEVEL CONFIG_BT_CONN_LOG_LEVEL
29 #include <zephyr/logging/log.h>
30 LOG_MODULE_REGISTER(bt_sco);
31 
32 struct bt_sco_server *sco_server;
33 
34 #define SCO_CHAN(_sco) ((_sco)->sco.chan);
35 
bt_sco_server_register(struct bt_sco_server * server)36 int bt_sco_server_register(struct bt_sco_server *server)
37 {
38 	CHECKIF(!server) {
39 		LOG_DBG("Invalid parameter: server %p", server);
40 		return -EINVAL;
41 	}
42 
43 	if (sco_server) {
44 		return -EADDRINUSE;
45 	}
46 
47 	if (!server->accept) {
48 		return -EINVAL;
49 	}
50 
51 	if (server->sec_level > BT_SECURITY_L3) {
52 		return -EINVAL;
53 	}
54 
55 	LOG_DBG("%p", server);
56 
57 	sco_server = server;
58 
59 	return 0;
60 }
61 
bt_sco_server_unregister(struct bt_sco_server * server)62 int bt_sco_server_unregister(struct bt_sco_server *server)
63 {
64 	CHECKIF(!server) {
65 		LOG_DBG("Invalid parameter: server %p", server);
66 		return -EINVAL;
67 	}
68 
69 	if (sco_server != server) {
70 		return -EINVAL;
71 	}
72 
73 	sco_server = NULL;
74 
75 	return 0;
76 }
77 
bt_sco_connected(struct bt_conn * sco)78 void bt_sco_connected(struct bt_conn *sco)
79 {
80 	struct bt_sco_chan *chan;
81 
82 	if (sco == NULL || sco->type != BT_CONN_TYPE_SCO) {
83 		LOG_ERR("Invalid parameters: sco %p sco->type %u", sco, sco ? sco->type : 0);
84 		return;
85 	}
86 
87 	LOG_DBG("%p", sco);
88 
89 	chan = SCO_CHAN(sco);
90 
91 	if (chan == NULL) {
92 		LOG_ERR("Could not lookup chan from connected SCO");
93 		return;
94 	}
95 
96 	bt_sco_chan_set_state(chan, BT_SCO_STATE_CONNECTED);
97 
98 	if (chan->ops && chan->ops->connected) {
99 		chan->ops->connected(chan);
100 	}
101 }
102 
bt_sco_disconnected(struct bt_conn * sco)103 void bt_sco_disconnected(struct bt_conn *sco)
104 {
105 	struct bt_sco_chan *chan;
106 
107 	if (sco == NULL || sco->type != BT_CONN_TYPE_SCO) {
108 		LOG_ERR("Invalid parameters: sco %p sco->type %u", sco, sco ? sco->type : 0);
109 		return;
110 	}
111 	LOG_DBG("%p", sco);
112 
113 	chan = SCO_CHAN(sco);
114 	if (chan == NULL) {
115 		LOG_ERR("Could not lookup chan from connected SCO");
116 		return;
117 	}
118 
119 	bt_sco_chan_set_state(chan, BT_SCO_STATE_DISCONNECTED);
120 
121 	bt_sco_cleanup_acl(sco);
122 
123 	chan->sco = NULL;
124 
125 	if (chan->ops && chan->ops->disconnected) {
126 		chan->ops->disconnected(chan, sco->err);
127 	}
128 }
129 
sco_server_check_security(struct bt_conn * conn)130 static uint8_t sco_server_check_security(struct bt_conn *conn)
131 {
132 	if (IS_ENABLED(CONFIG_BT_CONN_DISABLE_SECURITY)) {
133 		return BT_HCI_ERR_SUCCESS;
134 	}
135 
136 	if (conn->sec_level >= sco_server->sec_level) {
137 		return BT_HCI_ERR_SUCCESS;
138 	}
139 
140 	return BT_HCI_ERR_INSUFFICIENT_SECURITY;
141 }
142 
143 #if defined(CONFIG_BT_CONN_LOG_LEVEL_DBG)
bt_sco_chan_state_str(uint8_t state)144 const char *bt_sco_chan_state_str(uint8_t state)
145 {
146 	switch (state) {
147 	case BT_SCO_STATE_DISCONNECTED:
148 		return "disconnected";
149 	case BT_SCO_STATE_CONNECTING:
150 		return "connecting";
151 	case BT_SCO_STATE_ENCRYPT_PENDING:
152 		return "encryption pending";
153 	case BT_SCO_STATE_CONNECTED:
154 		return "connected";
155 	case BT_SCO_STATE_DISCONNECTING:
156 		return "disconnecting";
157 	default:
158 		return "unknown";
159 	}
160 }
161 
bt_sco_chan_set_state_debug(struct bt_sco_chan * chan,enum bt_sco_state state,const char * func,int line)162 void bt_sco_chan_set_state_debug(struct bt_sco_chan *chan,
163 				 enum bt_sco_state state,
164 				 const char *func, int line)
165 {
166 	LOG_DBG("chan %p sco %p %s -> %s", chan, chan->sco, bt_sco_chan_state_str(chan->state),
167 		bt_sco_chan_state_str(state));
168 
169 	/* check transitions validness */
170 	switch (state) {
171 	case BT_SCO_STATE_DISCONNECTED:
172 		/* regardless of old state always allows this states */
173 		break;
174 	case BT_SCO_STATE_ENCRYPT_PENDING:
175 		__fallthrough;
176 	case BT_SCO_STATE_CONNECTING:
177 		if (chan->state != BT_SCO_STATE_DISCONNECTED) {
178 			LOG_WRN("%s()%d: invalid transition", func, line);
179 		}
180 		break;
181 	case BT_SCO_STATE_CONNECTED:
182 		if (chan->state != BT_SCO_STATE_CONNECTING) {
183 			LOG_WRN("%s()%d: invalid transition", func, line);
184 		}
185 		break;
186 	case BT_SCO_STATE_DISCONNECTING:
187 		if (chan->state != BT_SCO_STATE_CONNECTING &&
188 			chan->state != BT_SCO_STATE_CONNECTED) {
189 			LOG_WRN("%s()%d: invalid transition", func, line);
190 		}
191 		break;
192 	default:
193 		LOG_ERR("%s()%d: unknown (%u) state was set", func, line, state);
194 		return;
195 	}
196 
197 	chan->state = state;
198 }
199 #else
bt_sco_chan_set_state(struct bt_sco_chan * chan,enum bt_sco_state state)200 void bt_sco_chan_set_state(struct bt_sco_chan *chan, enum bt_sco_state state)
201 {
202 	chan->state = state;
203 }
204 #endif /* CONFIG_BT_CONN_LOG_LEVEL_DBG */
205 
206 
bt_sco_chan_add(struct bt_conn * sco,struct bt_sco_chan * chan)207 static void bt_sco_chan_add(struct bt_conn *sco, struct bt_sco_chan *chan)
208 {
209 	/* Attach SCO channel to the connection */
210 	chan->sco = sco;
211 	sco->sco.chan = chan;
212 
213 	LOG_DBG("sco %p chan %p", sco, chan);
214 }
215 
sco_accept(struct bt_conn * acl,struct bt_conn * sco)216 static int sco_accept(struct bt_conn *acl, struct bt_conn *sco)
217 {
218 	struct bt_sco_accept_info accept_info;
219 	struct bt_sco_chan *chan;
220 	int err;
221 
222 	CHECKIF(!sco || sco->type != BT_CONN_TYPE_SCO) {
223 		LOG_ERR("Invalid parameters: sco %p sco->type %u", sco, sco ? sco->type : 0);
224 		return -EINVAL;
225 	}
226 
227 	LOG_DBG("%p", sco);
228 
229 	accept_info.acl = acl;
230 	memcpy(accept_info.dev_class, sco->sco.dev_class, sizeof(accept_info.dev_class));
231 	accept_info.link_type = sco->sco.link_type;
232 
233 	err = sco_server->accept(&accept_info, &chan);
234 	if (err < 0) {
235 		LOG_ERR("Server failed to accept: %d", err);
236 		return err;
237 	}
238 
239 	if (chan->ops == NULL) {
240 		LOG_ERR("invalid parameter: chan %p chan->ops %p", chan, chan->ops);
241 		return -EINVAL;
242 	}
243 
244 	bt_sco_chan_add(sco, chan);
245 	bt_sco_chan_set_state(chan, BT_SCO_STATE_CONNECTING);
246 
247 	return 0;
248 }
249 
accept_sco_conn(const bt_addr_t * bdaddr,struct bt_conn * sco_conn)250 static int accept_sco_conn(const bt_addr_t *bdaddr, struct bt_conn *sco_conn)
251 {
252 	struct bt_hci_cp_accept_sync_conn_req *cp;
253 	struct net_buf *buf;
254 	int err;
255 
256 	err = sco_accept(sco_conn->sco.acl, sco_conn);
257 	if (err) {
258 		return err;
259 	}
260 
261 	buf = bt_hci_cmd_create(BT_HCI_OP_ACCEPT_SYNC_CONN_REQ, sizeof(*cp));
262 	if (!buf) {
263 		return -ENOBUFS;
264 	}
265 
266 	cp = net_buf_add(buf, sizeof(*cp));
267 	bt_addr_copy(&cp->bdaddr, bdaddr);
268 	cp->pkt_type = sco_conn->sco.pkt_type;
269 	cp->tx_bandwidth = 0x00001f40;
270 	cp->rx_bandwidth = 0x00001f40;
271 	cp->max_latency = 0x0007;
272 	cp->retrans_effort = 0x01;
273 	cp->content_format = BT_VOICE_CVSD_16BIT;
274 
275 	err = bt_hci_cmd_send_sync(BT_HCI_OP_ACCEPT_SYNC_CONN_REQ, buf, NULL);
276 	if (err) {
277 		return err;
278 	}
279 
280 	return 0;
281 }
282 
bt_esco_conn_req(struct bt_hci_evt_conn_request * evt)283 uint8_t bt_esco_conn_req(struct bt_hci_evt_conn_request *evt)
284 {
285 	struct bt_conn *sco_conn;
286 	uint8_t sec_err;
287 
288 	if (sco_server == NULL) {
289 		LOG_ERR("No SCO server registered");
290 		return BT_HCI_ERR_UNSPECIFIED;
291 	}
292 
293 	sco_conn = bt_conn_add_sco(&evt->bdaddr, evt->link_type);
294 	if (!sco_conn) {
295 		return BT_HCI_ERR_INSUFFICIENT_RESOURCES;
296 	}
297 
298 	sec_err = sco_server_check_security(sco_conn->sco.acl);
299 	if (BT_HCI_ERR_SUCCESS != sec_err) {
300 		LOG_DBG("Insufficient security %u", sec_err);
301 		bt_sco_cleanup(sco_conn);
302 		return sec_err;
303 	}
304 
305 	memcpy(sco_conn->sco.dev_class, evt->dev_class, sizeof(sco_conn->sco.dev_class));
306 	sco_conn->sco.link_type = evt->link_type;
307 
308 	if (accept_sco_conn(&evt->bdaddr, sco_conn)) {
309 		LOG_ERR("Error accepting connection from %s", bt_addr_str(&evt->bdaddr));
310 		bt_sco_cleanup(sco_conn);
311 		return BT_HCI_ERR_UNSPECIFIED;
312 	}
313 
314 	sco_conn->role = BT_HCI_ROLE_PERIPHERAL;
315 	bt_conn_set_state(sco_conn, BT_CONN_INITIATING);
316 	bt_conn_unref(sco_conn);
317 
318 	return BT_HCI_ERR_SUCCESS;
319 }
320 
bt_sco_cleanup_acl(struct bt_conn * sco)321 void bt_sco_cleanup_acl(struct bt_conn *sco)
322 {
323 	LOG_DBG("%p", sco);
324 
325 	if (sco->sco.acl) {
326 		bt_conn_unref(sco->sco.acl);
327 		sco->sco.acl = NULL;
328 	}
329 }
330 
sco_setup_sync_conn(struct bt_conn * sco_conn)331 static int sco_setup_sync_conn(struct bt_conn *sco_conn)
332 {
333 	struct net_buf *buf;
334 	struct bt_hci_cp_setup_sync_conn *cp;
335 	int err;
336 
337 	buf = bt_hci_cmd_create(BT_HCI_OP_SETUP_SYNC_CONN, sizeof(*cp));
338 	if (!buf) {
339 		return -ENOBUFS;
340 	}
341 
342 	cp = net_buf_add(buf, sizeof(*cp));
343 
344 	(void)memset(cp, 0, sizeof(*cp));
345 
346 	LOG_DBG("handle : %x", sco_conn->sco.acl->handle);
347 
348 	cp->handle = sco_conn->sco.acl->handle;
349 	cp->pkt_type = sco_conn->sco.pkt_type;
350 	cp->tx_bandwidth = 0x00001f40;
351 	cp->rx_bandwidth = 0x00001f40;
352 	cp->max_latency = 0x0007;
353 	cp->retrans_effort = 0x01;
354 	cp->content_format = BT_VOICE_CVSD_16BIT;
355 
356 	err = bt_hci_cmd_send_sync(BT_HCI_OP_SETUP_SYNC_CONN, buf, NULL);
357 	if (err < 0) {
358 		return err;
359 	}
360 	return 0;
361 }
362 
bt_conn_create_sco(const bt_addr_t * peer,struct bt_sco_chan * chan)363 struct bt_conn *bt_conn_create_sco(const bt_addr_t *peer, struct bt_sco_chan *chan)
364 {
365 	struct bt_conn *sco_conn;
366 	int link_type;
367 
368 	sco_conn = bt_conn_lookup_addr_sco(peer);
369 	if (sco_conn) {
370 		switch (sco_conn->state) {
371 		case BT_CONN_INITIATING:
372 		case BT_CONN_CONNECTED:
373 			return sco_conn;
374 		default:
375 			bt_conn_unref(sco_conn);
376 			return NULL;
377 		}
378 	}
379 
380 	if (BT_FEAT_LMP_ESCO_CAPABLE(bt_dev.features)) {
381 		link_type = BT_HCI_ESCO;
382 	} else {
383 		link_type = BT_HCI_SCO;
384 	}
385 
386 	sco_conn = bt_conn_add_sco(peer, link_type);
387 	if (!sco_conn) {
388 		return NULL;
389 	}
390 
391 	sco_conn->sco.link_type = link_type;
392 
393 	bt_sco_chan_add(sco_conn, chan);
394 	bt_conn_set_state(chan->sco, BT_CONN_INITIATING);
395 	bt_sco_chan_set_state(chan, BT_SCO_STATE_CONNECTING);
396 
397 	if (sco_setup_sync_conn(sco_conn) < 0) {
398 		bt_conn_set_state(chan->sco, BT_CONN_DISCONNECTED);
399 		bt_sco_chan_set_state(chan, BT_SCO_STATE_DISCONNECTED);
400 		bt_sco_cleanup(sco_conn);
401 		return NULL;
402 	}
403 
404 	return sco_conn;
405 }
406