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