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