1 /* conn_br.c - Bluetooth Classic connection handling */
2
3 /*
4 * Copyright (c) 2015-2016 Intel Corporation
5 * Copyright (c) 2025 Nordic Semiconductor ASA
6 *
7 * SPDX-License-Identifier: Apache-2.0
8 */
9
10 #include <zephyr/bluetooth/iso.h>
11 #include <zephyr/kernel.h>
12 #include <string.h>
13 #include <errno.h>
14 #include <stdbool.h>
15 #include <zephyr/sys/atomic.h>
16 #include <zephyr/sys/byteorder.h>
17 #include <zephyr/sys/check.h>
18 #include <zephyr/sys/iterable_sections.h>
19 #include <zephyr/sys/util.h>
20 #include <zephyr/sys/util_macro.h>
21 #include <zephyr/sys/slist.h>
22 #include <zephyr/debug/stack.h>
23 #include <zephyr/sys/__assert.h>
24
25 #include <zephyr/bluetooth/hci.h>
26 #include <zephyr/bluetooth/bluetooth.h>
27 #include <zephyr/bluetooth/direction.h>
28 #include <zephyr/bluetooth/conn.h>
29 #include <zephyr/bluetooth/hci_vs.h>
30 #include <zephyr/bluetooth/att.h>
31
32 #include "common/assert.h"
33 #include "common/bt_str.h"
34
35 #include "host/conn_internal.h"
36 #include "host/l2cap_internal.h"
37 #include "host/keys.h"
38 #include "host/smp.h"
39 #include "ssp.h"
40 #include "sco_internal.h"
41
42 #define LOG_LEVEL CONFIG_BT_CONN_LOG_LEVEL
43 #include <zephyr/logging/log.h>
44 LOG_MODULE_REGISTER(bt_conn_br);
45
bt_sco_cleanup(struct bt_conn * sco_conn)46 void bt_sco_cleanup(struct bt_conn *sco_conn)
47 {
48 bt_sco_cleanup_acl(sco_conn);
49 bt_conn_unref(sco_conn);
50 }
51
bt_conn_create_br(const bt_addr_t * peer,const struct bt_br_conn_param * param)52 struct bt_conn *bt_conn_create_br(const bt_addr_t *peer,
53 const struct bt_br_conn_param *param)
54 {
55 struct bt_hci_cp_connect *cp;
56 struct bt_conn *conn;
57 struct net_buf *buf;
58
59 conn = bt_conn_lookup_addr_br(peer);
60 if (conn) {
61 switch (conn->state) {
62 case BT_CONN_INITIATING:
63 case BT_CONN_CONNECTED:
64 return conn;
65 default:
66 bt_conn_unref(conn);
67 return NULL;
68 }
69 }
70
71 conn = bt_conn_add_br(peer);
72 if (!conn) {
73 return NULL;
74 }
75
76 buf = bt_hci_cmd_alloc(K_FOREVER);
77 if (!buf) {
78 bt_conn_unref(conn);
79 return NULL;
80 }
81
82 cp = net_buf_add(buf, sizeof(*cp));
83
84 (void)memset(cp, 0, sizeof(*cp));
85
86 memcpy(&cp->bdaddr, peer, sizeof(cp->bdaddr));
87 cp->packet_type = sys_cpu_to_le16(0xcc18); /* DM1 DH1 DM3 DH5 DM5 DH5 */
88 cp->pscan_rep_mode = 0x02; /* R2 */
89 cp->allow_role_switch = param->allow_role_switch ? 0x01 : 0x00;
90 cp->clock_offset = 0x0000; /* TODO used cached clock offset */
91
92 if (bt_hci_cmd_send_sync(BT_HCI_OP_CONNECT, buf, NULL) < 0) {
93 bt_conn_unref(conn);
94 return NULL;
95 }
96
97 bt_conn_set_state(conn, BT_CONN_INITIATING);
98 conn->role = BT_CONN_ROLE_CENTRAL;
99
100 return conn;
101 }
102
bt_hci_connect_br_cancel(struct bt_conn * conn)103 int bt_hci_connect_br_cancel(struct bt_conn *conn)
104 {
105 struct bt_hci_cp_connect_cancel *cp;
106 struct bt_hci_rp_connect_cancel *rp;
107 struct net_buf *buf, *rsp;
108 int err;
109
110 buf = bt_hci_cmd_alloc(K_FOREVER);
111 if (!buf) {
112 return -ENOBUFS;
113 }
114
115 cp = net_buf_add(buf, sizeof(*cp));
116 memcpy(&cp->bdaddr, &conn->br.dst, sizeof(cp->bdaddr));
117
118 err = bt_hci_cmd_send_sync(BT_HCI_OP_CONNECT_CANCEL, buf, &rsp);
119 if (err) {
120 return err;
121 }
122
123 rp = (void *)rsp->data;
124
125 err = rp->status ? -EIO : 0;
126
127 net_buf_unref(rsp);
128
129 return err;
130 }
131
bt_conn_get_dst_br(const struct bt_conn * conn)132 const bt_addr_t *bt_conn_get_dst_br(const struct bt_conn *conn)
133 {
134 if (conn == NULL) {
135 LOG_DBG("Invalid connect");
136 return NULL;
137 }
138
139 if (!bt_conn_is_type(conn, BT_CONN_TYPE_BR)) {
140 LOG_DBG("Invalid connection type: %u for %p", conn->type, conn);
141 return NULL;
142 }
143
144 return &conn->br.dst;
145 }
146
bt_br_acl_recv(struct bt_conn * conn,struct net_buf * buf,bool complete)147 void bt_br_acl_recv(struct bt_conn *conn, struct net_buf *buf, bool complete)
148 {
149 uint16_t acl_total_len;
150 struct bt_l2cap_hdr *hdr;
151 struct net_buf_simple_state state;
152
153 do {
154 net_buf_simple_save(&buf->b, &state);
155
156 hdr = (void *)buf->data;
157 acl_total_len = sys_le16_to_cpu(hdr->len) + sizeof(*hdr);
158 if (buf->len > acl_total_len) {
159 LOG_DBG("Multiple L2CAP packet (%u > %u)", buf->len, acl_total_len);
160 buf->len = acl_total_len;
161 } else if (buf->len < acl_total_len) {
162 LOG_ERR("Short packet (%u < %u)", buf->len, acl_total_len);
163 break;
164 }
165 bt_l2cap_recv(conn, net_buf_ref(buf), complete);
166
167 net_buf_simple_restore(&buf->b, &state);
168 net_buf_pull(buf, acl_total_len);
169 } while (buf->len > 0);
170
171 net_buf_unref(buf);
172 }
173
bt_conn_br_switch_role(const struct bt_conn * conn,uint8_t role)174 int bt_conn_br_switch_role(const struct bt_conn *conn, uint8_t role)
175 {
176 struct net_buf *buf;
177 struct bt_hci_cp_switch_role *cp;
178
179 CHECKIF(conn == NULL) {
180 LOG_DBG("conn is NULL");
181 return -EINVAL;
182 }
183
184 if (!bt_conn_is_type(conn, BT_CONN_TYPE_BR)) {
185 LOG_DBG("Invalid connection type: %u for %p", conn->type, conn);
186 return -EINVAL;
187 }
188
189 buf = bt_hci_cmd_alloc(K_FOREVER);
190 if (!buf) {
191 return -ENOBUFS;
192 }
193
194 cp = net_buf_add(buf, sizeof(*cp));
195 bt_addr_copy(&cp->bdaddr, &conn->br.dst);
196 cp->role = role;
197
198 return bt_hci_cmd_send_sync(BT_HCI_OP_SWITCH_ROLE, buf, NULL);
199 }
200
bt_conn_br_read_link_policy_settings(const struct bt_conn * conn,uint16_t * link_policy_settings)201 static int bt_conn_br_read_link_policy_settings(const struct bt_conn *conn,
202 uint16_t *link_policy_settings)
203 {
204 int err;
205 struct net_buf *buf;
206 struct bt_hci_cp_read_link_policy_settings *cp;
207 struct bt_hci_rp_read_link_policy_settings *rp;
208 struct net_buf *rsp;
209
210 buf = bt_hci_cmd_alloc(K_FOREVER);
211 if (!buf) {
212 return -ENOBUFS;
213 }
214
215 cp = net_buf_add(buf, sizeof(*cp));
216 cp->handle = sys_cpu_to_le16(conn->handle);
217
218 err = bt_hci_cmd_send_sync(BT_HCI_OP_READ_LINK_POLICY_SETTINGS, buf, &rsp);
219 if (!err) {
220 rp = (void *)rsp->data;
221 *link_policy_settings = rp->link_policy_settings;
222 }
223
224 return err;
225 }
226
bt_conn_br_write_link_policy_settings(const struct bt_conn * conn,uint16_t link_policy_settings)227 static int bt_conn_br_write_link_policy_settings(const struct bt_conn *conn,
228 uint16_t link_policy_settings)
229 {
230 struct net_buf *buf;
231 struct bt_hci_cp_write_link_policy_settings *cp;
232
233 buf = bt_hci_cmd_alloc(K_FOREVER);
234 if (!buf) {
235 return -ENOBUFS;
236 }
237
238 cp = net_buf_add(buf, sizeof(*cp));
239 cp->handle = sys_cpu_to_le16(conn->handle);
240 cp->link_policy_settings = link_policy_settings;
241
242 return bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_LINK_POLICY_SETTINGS, buf, NULL);
243 }
244
bt_conn_br_set_role_switch_enable(const struct bt_conn * conn,bool enable)245 int bt_conn_br_set_role_switch_enable(const struct bt_conn *conn, bool enable)
246 {
247 int err;
248 uint16_t link_policy_settings;
249 bool is_enabled;
250
251 CHECKIF(conn == NULL) {
252 LOG_DBG("conn is NULL");
253 return -EINVAL;
254 }
255
256 if (!bt_conn_is_type(conn, BT_CONN_TYPE_BR)) {
257 LOG_DBG("Invalid connection type: %u for %p", conn->type, conn);
258 return -EINVAL;
259 }
260
261 err = bt_conn_br_read_link_policy_settings(conn, &link_policy_settings);
262 if (err) {
263 return err;
264 }
265
266 is_enabled = (link_policy_settings & BT_HCI_LINK_POLICY_SETTINGS_ENABLE_ROLE_SWITCH);
267 if (enable == is_enabled) {
268 return 0;
269 }
270
271 link_policy_settings ^= BT_HCI_LINK_POLICY_SETTINGS_ENABLE_ROLE_SWITCH;
272 return bt_conn_br_write_link_policy_settings(conn, link_policy_settings);
273 }
274