GCC Code Coverage Report


Directory: main/
File: bluetooth/l2cap.c
Date: 2025-10-04 14:03:00
Exec Total Coverage
Lines: 0 246 0.0%
Functions: 0 20 0.0%
Branches: 0 94 0.0%

Line Branch Exec Source
1 /*
2 * Copyright (c) 2019-2024, Jacques Gagnon
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #include <stdio.h>
7 #include "host.h"
8 #include "hci.h"
9 #include "l2cap.h"
10 #include "sdp.h"
11
12 #define BT_HOST_SDP_RX_CHAN 0x0060
13 #define BT_HOST_SDP_TX_CHAN 0x0070
14 #define BT_HOST_HID_CTRL_CHAN 0x0080
15 #define BT_HOST_HID_INTR_CHAN 0x0090
16
17 #define BT_L2CAP_DEFAULT_MTU 672
18
19 static uint8_t tx_ident = 0;
20
21 static void bt_l2cap_cmd(uint16_t handle, uint16_t cid, uint8_t code, uint8_t ident, uint16_t len);
22 static void bt_l2cap_cmd_conn_req(uint16_t handle, uint8_t ident, uint16_t psm, uint16_t scid);
23 static void bt_l2cap_cmd_conn_rsp(uint16_t handle, uint8_t ident, uint16_t dcid, uint16_t scid, uint16_t result);
24 static void bt_l2cap_cmd_conf_req(uint16_t handle, uint8_t ident, uint16_t dcid);
25 static void bt_l2cap_cmd_conf_rsp(uint16_t handle, uint8_t ident, uint16_t scid, uint16_t mtu);
26 static void bt_l2cap_cmd_disconn_req(uint16_t handle, uint8_t ident, uint16_t dcid, uint16_t scid);
27 static void bt_l2cap_cmd_disconn_rsp(uint16_t handle, uint8_t ident, uint16_t dcid, uint16_t scid);
28 static void bt_l2cap_cmd_conn_param_rsp(uint16_t handle, uint8_t ident, uint16_t result);
29
30 static uint8_t get_tx_ident(void) {
31 tx_ident++;
32 if (tx_ident == 0) {
33 tx_ident++;
34 }
35 return tx_ident;
36 }
37
38 static void bt_l2cap_cmd(uint16_t handle, uint16_t cid, uint8_t code, uint8_t ident, uint16_t len) {
39 uint16_t packet_len = (BT_HCI_H4_HDR_SIZE + BT_HCI_ACL_HDR_SIZE
40 + sizeof(struct bt_l2cap_hdr) + sizeof(struct bt_l2cap_sig_hdr) + len);
41
42 bt_hci_pkt_tmp.h4_hdr.type = BT_HCI_H4_TYPE_ACL;
43
44 bt_hci_pkt_tmp.acl_hdr.handle = bt_acl_handle_pack(handle, 0x2);
45 bt_hci_pkt_tmp.acl_hdr.len = packet_len - BT_HCI_H4_HDR_SIZE - BT_HCI_ACL_HDR_SIZE;
46
47 bt_hci_pkt_tmp.l2cap_hdr.len = bt_hci_pkt_tmp.acl_hdr.len - sizeof(bt_hci_pkt_tmp.l2cap_hdr);
48 bt_hci_pkt_tmp.l2cap_hdr.cid = cid;
49
50 bt_hci_pkt_tmp.sig_hdr.code = code;
51 bt_hci_pkt_tmp.sig_hdr.ident = ident;
52 bt_hci_pkt_tmp.sig_hdr.len = len;
53
54 bt_host_txq_add((uint8_t *)&bt_hci_pkt_tmp, packet_len);
55 }
56
57 static void bt_l2cap_cmd_info_req(uint16_t handle, uint8_t ident, uint16_t type) {
58 struct bt_l2cap_info_req *info_req = (struct bt_l2cap_info_req *)bt_hci_pkt_tmp.sig_data;
59
60 info_req->type = type;
61
62 bt_l2cap_cmd(handle, BT_L2CAP_CID_BR_SIG, BT_L2CAP_INFO_REQ, ident, sizeof(*info_req));
63 }
64
65 static void bt_l2cap_cmd_conn_req(uint16_t handle, uint8_t ident, uint16_t psm, uint16_t scid) {
66 struct bt_l2cap_conn_req *conn_req = (struct bt_l2cap_conn_req *)bt_hci_pkt_tmp.sig_data;
67
68 conn_req->psm = psm;
69 conn_req->scid = scid;
70
71 bt_l2cap_cmd(handle, BT_L2CAP_CID_BR_SIG, BT_L2CAP_CONN_REQ, ident, sizeof(*conn_req));
72 }
73
74 static void bt_l2cap_cmd_conn_rsp(uint16_t handle, uint8_t ident, uint16_t dcid, uint16_t scid, uint16_t result) {
75 struct bt_l2cap_conn_rsp *conn_rsp = (struct bt_l2cap_conn_rsp *)bt_hci_pkt_tmp.sig_data;
76
77 conn_rsp->dcid = dcid;
78 conn_rsp->scid = scid;
79 conn_rsp->result = result;
80 conn_rsp->status = BT_L2CAP_CS_NO_INFO;
81
82 bt_l2cap_cmd(handle, BT_L2CAP_CID_BR_SIG, BT_L2CAP_CONN_RSP, ident, sizeof(*conn_rsp));
83 }
84
85 static void bt_l2cap_cmd_conf_req(uint16_t handle, uint8_t ident, uint16_t dcid) {
86 struct bt_l2cap_conf_req *conf_req = (struct bt_l2cap_conf_req *)bt_hci_pkt_tmp.sig_data;
87 struct bt_l2cap_conf_opt *conf_opt = (struct bt_l2cap_conf_opt *)conf_req->data;
88
89 conf_req->dcid = dcid;
90 conf_req->flags = 0x0000;
91 conf_opt->type = BT_L2CAP_CONF_OPT_MTU;
92 conf_opt->len = sizeof(uint16_t);
93 *(uint16_t *)conf_opt->data = BT_L2CAP_DEFAULT_MTU;
94
95 bt_l2cap_cmd(handle, BT_L2CAP_CID_BR_SIG, BT_L2CAP_CONF_REQ, ident,
96 ((sizeof(*conf_req) - sizeof(conf_req->data)) + (sizeof(*conf_opt) - sizeof(conf_opt->data)) + sizeof(uint16_t)));
97 }
98
99 static void bt_l2cap_cmd_conf_rsp(uint16_t handle, uint8_t ident, uint16_t scid, uint16_t mtu) {
100 struct bt_l2cap_conf_rsp *conf_rsp = (struct bt_l2cap_conf_rsp *)bt_hci_pkt_tmp.sig_data;
101 struct bt_l2cap_conf_opt *conf_opt = (struct bt_l2cap_conf_opt *)conf_rsp->data;
102
103 conf_rsp->scid = scid;
104 conf_rsp->flags = 0x0000;
105 conf_rsp->result = BT_L2CAP_CONF_SUCCESS;
106 conf_opt->type = BT_L2CAP_CONF_OPT_MTU;
107 conf_opt->len = sizeof(uint16_t);
108 *(uint16_t *)conf_opt->data = mtu ? mtu : BT_L2CAP_DEFAULT_MTU;
109
110 bt_l2cap_cmd(handle, BT_L2CAP_CID_BR_SIG, BT_L2CAP_CONF_RSP, ident,
111 ((sizeof(*conf_rsp) - sizeof(conf_rsp->data)) + (sizeof(*conf_opt) - sizeof(conf_opt->data)) + sizeof(uint16_t)));
112 }
113
114 static void bt_l2cap_cmd_disconn_req(uint16_t handle, uint8_t ident, uint16_t dcid, uint16_t scid) {
115 struct bt_l2cap_disconn_req *disconn_req = (struct bt_l2cap_disconn_req *)bt_hci_pkt_tmp.sig_data;
116
117 disconn_req->dcid = dcid;
118 disconn_req->scid = scid;
119
120 bt_l2cap_cmd(handle, BT_L2CAP_CID_BR_SIG, BT_L2CAP_DISCONN_REQ, ident, sizeof(*disconn_req));
121 }
122
123 static void bt_l2cap_cmd_disconn_rsp(uint16_t handle, uint8_t ident, uint16_t dcid, uint16_t scid) {
124 struct bt_l2cap_disconn_rsp *disconn_rsp = (struct bt_l2cap_disconn_rsp *)bt_hci_pkt_tmp.sig_data;
125
126 disconn_rsp->dcid = dcid;
127 disconn_rsp->scid = scid;
128
129 bt_l2cap_cmd(handle, BT_L2CAP_CID_BR_SIG, BT_L2CAP_DISCONN_RSP, ident, sizeof(*disconn_rsp));
130 }
131
132 static void bt_l2cap_cmd_conn_param_rsp(uint16_t handle, uint8_t ident, uint16_t result) {
133 struct bt_l2cap_conn_param_rsp *conn_param_rsp = (struct bt_l2cap_conn_param_rsp *)bt_hci_pkt_tmp.sig_data;
134
135 conn_param_rsp->result = result;
136
137 bt_l2cap_cmd(handle, BT_L2CAP_CID_LE_SIG, BT_L2CAP_CONN_PARAM_RSP, ident, sizeof(*conn_param_rsp));
138 }
139
140 void bt_l2cap_init_dev_scid(struct bt_dev *device) {
141 device->sdp_rx_chan.scid = device->ids.id | BT_HOST_SDP_RX_CHAN;
142 device->sdp_tx_chan.scid = device->ids.id | BT_HOST_SDP_TX_CHAN;
143 device->ctrl_chan.scid = device->ids.id | BT_HOST_HID_CTRL_CHAN;
144 device->intr_chan.scid = device->ids.id | BT_HOST_HID_INTR_CHAN;
145 }
146
147 void bt_l2cap_cmd_ext_feat_mask_req(void *bt_dev) {
148 struct bt_dev *device = (struct bt_dev *)bt_dev;
149 printf("# %s\n", __FUNCTION__);
150 bt_l2cap_cmd_info_req(device->acl_handle, get_tx_ident(), BT_L2CAP_INFO_FEAT_MASK);
151 }
152
153 void bt_l2cap_cmd_sdp_conn_req(void *bt_dev) {
154 struct bt_dev *device = (struct bt_dev *)bt_dev;
155 printf("# %s\n", __FUNCTION__);
156 bt_l2cap_cmd_conn_req(device->acl_handle, get_tx_ident(), BT_L2CAP_PSM_SDP, device->sdp_tx_chan.scid);
157 }
158
159 void bt_l2cap_cmd_hid_ctrl_conn_req(void *bt_dev) {
160 struct bt_dev *device = (struct bt_dev *)bt_dev;
161 printf("# %s\n", __FUNCTION__);
162 bt_l2cap_cmd_conn_req(device->acl_handle, get_tx_ident(), BT_L2CAP_PSM_HID_CTRL, device->ctrl_chan.scid);
163 }
164
165 void bt_l2cap_cmd_hid_intr_conn_req(void *bt_dev) {
166 struct bt_dev *device = (struct bt_dev *)bt_dev;
167 printf("# %s\n", __FUNCTION__);
168 bt_l2cap_cmd_conn_req(device->acl_handle, get_tx_ident(), BT_L2CAP_PSM_HID_INTR, device->intr_chan.scid);
169 }
170
171 void bt_l2cap_cmd_sdp_disconn_req(void *bt_dev) {
172 struct bt_dev *device = (struct bt_dev *)bt_dev;
173 printf("# %s\n", __FUNCTION__);
174 bt_l2cap_cmd_disconn_req(device->acl_handle, get_tx_ident(), device->sdp_tx_chan.dcid, device->sdp_tx_chan.scid);
175 }
176
177 void bt_l2cap_cmd_hid_ctrl_disconn_req(void *bt_dev) {
178 struct bt_dev *device = (struct bt_dev *)bt_dev;
179 printf("# %s\n", __FUNCTION__);
180 bt_l2cap_cmd_disconn_req(device->acl_handle, get_tx_ident(), device->ctrl_chan.dcid, device->ctrl_chan.scid);
181 atomic_clear_bit(&device->flags, BT_DEV_HID_CTRL_PENDING);
182 }
183
184 void bt_l2cap_cmd_hid_intr_disconn_req(void *bt_dev) {
185 struct bt_dev *device = (struct bt_dev *)bt_dev;
186 printf("# %s\n", __FUNCTION__);
187 bt_l2cap_cmd_disconn_req(device->acl_handle, get_tx_ident(), device->intr_chan.dcid, device->intr_chan.scid);
188 atomic_clear_bit(&device->flags, BT_DEV_HID_INTR_PENDING);
189 atomic_clear_bit(&device->flags, BT_DEV_HID_INTR_READY);
190 }
191
192 void bt_l2cap_sig_hdlr(struct bt_dev *device, struct bt_hci_pkt *bt_hci_acl_pkt) {
193 uint8_t rx_ident = bt_hci_acl_pkt->sig_hdr.ident;
194 switch (bt_hci_acl_pkt->sig_hdr.code) {
195 case BT_L2CAP_CONN_REQ:
196 {
197 struct bt_l2cap_conn_req *conn_req = (struct bt_l2cap_conn_req *)bt_hci_acl_pkt->sig_data;
198 printf("# BT_L2CAP_CONN_REQ\n");
199 switch (conn_req->psm) {
200 case BT_L2CAP_PSM_SDP:
201 device->sdp_rx_chan.dcid = conn_req->scid;
202 bt_l2cap_cmd_conn_rsp(device->acl_handle, rx_ident, device->sdp_rx_chan.scid,
203 device->sdp_rx_chan.dcid, BT_L2CAP_BR_SUCCESS);
204 bt_l2cap_cmd_conf_req(device->acl_handle, get_tx_ident(), device->sdp_rx_chan.dcid);
205 break;
206 case BT_L2CAP_PSM_HID_CTRL:
207 device->ctrl_chan.dcid = conn_req->scid;
208 bt_l2cap_cmd_conn_rsp(device->acl_handle, rx_ident, device->ctrl_chan.scid,
209 device->ctrl_chan.dcid, BT_L2CAP_BR_SUCCESS);
210 bt_l2cap_cmd_conf_req(device->acl_handle, get_tx_ident(), device->ctrl_chan.dcid);
211 break;
212 case BT_L2CAP_PSM_HID_INTR:
213 device->intr_chan.dcid = conn_req->scid;
214 bt_l2cap_cmd_conn_rsp(device->acl_handle, rx_ident, device->intr_chan.scid,
215 device->intr_chan.dcid, BT_L2CAP_BR_SUCCESS);
216 bt_l2cap_cmd_conf_req(device->acl_handle, get_tx_ident(), device->intr_chan.dcid);
217 break;
218 }
219 break;
220 }
221 case BT_L2CAP_CONN_RSP:
222 {
223 struct bt_l2cap_conn_rsp *conn_rsp = (struct bt_l2cap_conn_rsp *)bt_hci_acl_pkt->sig_data;
224 printf("# BT_L2CAP_CONN_RSP\n");
225 if (conn_rsp->result == BT_L2CAP_BR_SUCCESS && conn_rsp->status == BT_L2CAP_CS_NO_INFO) {
226 if (conn_rsp->scid == device->sdp_tx_chan.scid) {
227 device->sdp_tx_chan.dcid = conn_rsp->dcid;
228 bt_l2cap_cmd_conf_req(device->acl_handle, get_tx_ident(), device->sdp_tx_chan.dcid);
229 }
230 else if (conn_rsp->scid == device->ctrl_chan.scid) {
231 device->ctrl_chan.dcid = conn_rsp->dcid;
232 bt_l2cap_cmd_conf_req(device->acl_handle, get_tx_ident(), device->ctrl_chan.dcid);
233 }
234 else if (conn_rsp->scid == device->intr_chan.scid) {
235 device->intr_chan.dcid = conn_rsp->dcid;
236 bt_l2cap_cmd_conf_req(device->acl_handle, get_tx_ident(), device->intr_chan.dcid);
237 }
238 }
239 break;
240 }
241 case BT_L2CAP_CONF_REQ:
242 {
243 struct bt_l2cap_conf_req *conf_req = (struct bt_l2cap_conf_req *)bt_hci_acl_pkt->sig_data;
244 printf("# BT_L2CAP_CONF_REQ\n");
245 if (conf_req->dcid == device->sdp_tx_chan.scid) {
246 if (conf_req->data[0] == BT_L2CAP_CONF_OPT_MTU && conf_req->data[1] == 2) {
247 device->sdp_tx_chan.mtu = *(uint16_t *)&conf_req->data[2];
248 }
249 bt_l2cap_cmd_conf_rsp(device->acl_handle, rx_ident, device->sdp_tx_chan.dcid, device->sdp_tx_chan.mtu);
250 if (!atomic_test_bit(&device->flags, BT_DEV_SDP_TX_PENDING)) {
251 atomic_set_bit(&device->flags, BT_DEV_SDP_TX_PENDING);
252 }
253 else {
254 uint8_t cont = 0x00;
255 bt_sdp_cmd_svc_search_attr_req(device, &cont, 1);
256 }
257 }
258 else if (conf_req->dcid == device->sdp_rx_chan.scid) {
259 if (conf_req->data[0] == BT_L2CAP_CONF_OPT_MTU && conf_req->data[1] == 2) {
260 device->sdp_rx_chan.mtu = *(uint16_t *)&conf_req->data[2];
261 }
262 bt_l2cap_cmd_conf_rsp(device->acl_handle, rx_ident, device->sdp_rx_chan.dcid, device->sdp_rx_chan.mtu);
263 }
264 else if (conf_req->dcid == device->ctrl_chan.scid) {
265 if (conf_req->data[0] == BT_L2CAP_CONF_OPT_MTU && conf_req->data[1] == 2) {
266 device->ctrl_chan.mtu = *(uint16_t *)&conf_req->data[2];
267 }
268 bt_l2cap_cmd_conf_rsp(device->acl_handle, rx_ident, device->ctrl_chan.dcid, device->ctrl_chan.mtu);
269 if (!atomic_test_bit(&device->flags, BT_DEV_PAGE)) {
270 if (!atomic_test_bit(&device->flags, BT_DEV_HID_CTRL_PENDING)) {
271 atomic_set_bit(&device->flags, BT_DEV_HID_CTRL_PENDING);
272 }
273 else {
274 bt_l2cap_cmd_hid_intr_conn_req(device);
275 }
276 }
277 }
278 else if (conf_req->dcid == device->intr_chan.scid) {
279 if (conf_req->data[0] == BT_L2CAP_CONF_OPT_MTU && conf_req->data[1] == 2) {
280 device->intr_chan.mtu = *(uint16_t *)&conf_req->data[2];
281 }
282 bt_l2cap_cmd_conf_rsp(device->acl_handle, rx_ident, device->intr_chan.dcid, device->intr_chan.mtu);
283 if (!atomic_test_bit(&device->flags, BT_DEV_HID_INTR_PENDING)) {
284 atomic_set_bit(&device->flags, BT_DEV_HID_INTR_PENDING);
285 }
286 else {
287 atomic_set_bit(&device->flags, BT_DEV_HID_INTR_READY);
288 bt_l2cap_cmd_sdp_conn_req(device);
289 bt_hid_init(device);
290 }
291 }
292 break;
293 }
294 case BT_L2CAP_CONF_RSP:
295 {
296 struct bt_l2cap_conf_rsp *conf_rsp = (struct bt_l2cap_conf_rsp *)bt_hci_acl_pkt->sig_data;
297 printf("# BT_L2CAP_CONF_RSP\n");
298 if (conf_rsp->scid == device->sdp_tx_chan.scid) {
299 if (conf_rsp->data[0] == BT_L2CAP_CONF_OPT_MTU && conf_rsp->data[1] == 2) {
300 device->sdp_tx_chan.mtu = *(uint16_t *)&conf_rsp->data[2];
301 }
302 if (!atomic_test_bit(&device->flags, BT_DEV_SDP_TX_PENDING)) {
303 atomic_set_bit(&device->flags, BT_DEV_SDP_TX_PENDING);
304 }
305 else {
306 uint8_t cont = 0x00;
307 bt_sdp_cmd_svc_search_attr_req(device, &cont, 1);
308 }
309 }
310 else if (conf_rsp->scid == device->ctrl_chan.scid) {
311 if (conf_rsp->data[0] == BT_L2CAP_CONF_OPT_MTU && conf_rsp->data[1] == 2) {
312 device->ctrl_chan.mtu = *(uint16_t *)&conf_rsp->data[2];
313 }
314 if (!atomic_test_bit(&device->flags, BT_DEV_PAGE)) {
315 if (!atomic_test_bit(&device->flags, BT_DEV_HID_CTRL_PENDING)) {
316 atomic_set_bit(&device->flags, BT_DEV_HID_CTRL_PENDING);
317 }
318 else {
319 bt_l2cap_cmd_hid_intr_conn_req(device);
320 }
321 }
322 }
323 else if (conf_rsp->scid == device->intr_chan.scid) {
324 if (conf_rsp->data[0] == BT_L2CAP_CONF_OPT_MTU && conf_rsp->data[1] == 2) {
325 device->intr_chan.mtu = *(uint16_t *)&conf_rsp->data[2];
326 }
327 if (!atomic_test_bit(&device->flags, BT_DEV_HID_INTR_PENDING)) {
328 atomic_set_bit(&device->flags, BT_DEV_HID_INTR_PENDING);
329 }
330 else {
331 atomic_set_bit(&device->flags, BT_DEV_HID_INTR_READY);
332 bt_l2cap_cmd_sdp_conn_req(device);
333 bt_hid_init(device);
334 }
335 }
336 break;
337 }
338 case BT_L2CAP_DISCONN_REQ:
339 {
340 struct bt_l2cap_disconn_req *disconn_req = (struct bt_l2cap_disconn_req *)bt_hci_acl_pkt->sig_data;
341 printf("# BT_L2CAP_DISCONN_REQ\n");
342 if (disconn_req->dcid == device->sdp_tx_chan.scid) {
343 bt_l2cap_cmd_disconn_rsp(device->acl_handle, rx_ident, device->sdp_tx_chan.scid, device->sdp_tx_chan.dcid);
344 }
345 if (disconn_req->dcid == device->sdp_rx_chan.scid) {
346 bt_l2cap_cmd_disconn_rsp(device->acl_handle, rx_ident, device->sdp_rx_chan.scid, device->sdp_rx_chan.dcid);
347 }
348 else if (disconn_req->dcid == device->ctrl_chan.scid) {
349 bt_l2cap_cmd_disconn_rsp(device->acl_handle, rx_ident, device->ctrl_chan.scid, device->ctrl_chan.dcid);
350 }
351 else if (disconn_req->dcid == device->intr_chan.scid) {
352 bt_l2cap_cmd_disconn_rsp(device->acl_handle, rx_ident, device->intr_chan.scid, device->intr_chan.dcid);
353 }
354 break;
355 }
356 case BT_L2CAP_DISCONN_RSP:
357 printf("# BT_L2CAP_DISCONN_RSP\n");
358 break;
359 case BT_L2CAP_INFO_RSP:
360 printf("# BT_L2CAP_INFO_RSP\n");
361 break;
362 }
363 }
364
365 void bt_l2cap_le_sig_hdlr(struct bt_dev *device, struct bt_hci_pkt *bt_hci_acl_pkt, uint32_t len) {
366 uint8_t rx_ident = bt_hci_acl_pkt->sig_hdr.ident;
367 switch (bt_hci_acl_pkt->sig_hdr.code) {
368 case BT_L2CAP_CONN_PARAM_REQ:
369 {
370 struct bt_l2cap_conn_param_req *conn_param_req = (struct bt_l2cap_conn_param_req *)bt_hci_acl_pkt->sig_data;
371 struct hci_cp_le_conn_update le_conn_update = {0};
372 printf("# BT_L2CAP_CONN_PARAM_REQ\n");
373
374 le_conn_update.handle = device->acl_handle;
375 le_conn_update.conn_interval_min = conn_param_req->min_interval;
376 le_conn_update.conn_interval_max = conn_param_req->max_interval;
377 le_conn_update.conn_latency = conn_param_req->latency;
378 le_conn_update.supervision_timeout = conn_param_req->timeout;
379 le_conn_update.min_ce_len = 0;
380 le_conn_update.max_ce_len = 0;
381
382 bt_l2cap_cmd_conn_param_rsp(device->acl_handle, rx_ident, BT_L2CAP_CONN_PARAM_ACCEPTED);
383 bt_hci_le_conn_update(&le_conn_update);
384 break;
385 }
386 }
387 }
388