| 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 |