static void l2cap_le_sig(struct bthost *bthost, struct btconn *conn, const void *data, uint16_t len) { const struct bt_l2cap_hdr_sig *hdr = data; struct bt_l2cap_pdu_cmd_reject rej; uint16_t hdr_len; bool ret; if (len < sizeof(*hdr)) goto reject; hdr_len = le16_to_cpu(hdr->len); if (sizeof(*hdr) + hdr_len != len) goto reject; switch (hdr->code) { case BT_L2CAP_PDU_CMD_REJECT: ret = l2cap_cmd_rej(bthost, conn, hdr->ident, data + sizeof(*hdr), hdr_len); break; case BT_L2CAP_PDU_CONN_PARAM_REQ: ret = l2cap_conn_param_req(bthost, conn, hdr->ident, data + sizeof(*hdr), hdr_len); break; case BT_L2CAP_PDU_CONN_PARAM_RSP: ret = l2cap_conn_param_rsp(bthost, conn, hdr->ident, data + sizeof(*hdr), hdr_len); break; default: printf("Unknown L2CAP code 0x%02x\n", hdr->code); ret = false; } handle_pending_l2reqs(bthost, conn, hdr->ident, hdr->code, data + sizeof(*hdr), hdr_len); if (ret) return; reject: memset(&rej, 0, sizeof(rej)); l2cap_sig_send(bthost, conn, BT_L2CAP_PDU_CMD_REJECT, 0, &rej, sizeof(rej)); }
static bool l2cap_info_req(struct bthost *bthost, struct btconn *conn, uint8_t ident, const void *data, uint16_t len) { const struct bt_l2cap_pdu_info_req *req = data; struct bt_l2cap_pdu_info_rsp rsp; if (len < sizeof(*req)) return false; rsp.type = req->type; rsp.result = cpu_to_le16(0x0001); /* Not Supported */ l2cap_sig_send(bthost, conn, BT_L2CAP_PDU_INFO_RSP, ident, &rsp, sizeof(rsp)); return true; }
static bool l2cap_disconn_req(struct bthost *bthost, struct btconn *conn, uint8_t ident, const void *data, uint16_t len) { const struct bt_l2cap_pdu_disconn_req *req = data; struct bt_l2cap_pdu_disconn_rsp rsp; if (len < sizeof(*req)) return false; memset(&rsp, 0, sizeof(rsp)); rsp.dcid = req->dcid; rsp.scid = req->scid; l2cap_sig_send(bthost, conn, BT_L2CAP_PDU_DISCONN_RSP, ident, &rsp, sizeof(rsp)); return true; }
bool bthost_l2cap_req(struct bthost *bthost, uint16_t handle, uint8_t code, const void *data, uint16_t len, bthost_l2cap_rsp_cb cb, void *user_data) { struct l2cap_pending_req *req; struct btconn *conn; uint8_t ident; conn = bthost_find_conn(bthost, handle); if (!conn) return false; if (code == BT_L2CAP_PDU_CONN_REQ && len == sizeof(struct bt_l2cap_pdu_conn_req)) { const struct bt_l2cap_pdu_conn_req *req = data; bthost_add_l2cap_conn(bthost, conn, le16_to_cpu(req->scid), le16_to_cpu(req->scid), le16_to_cpu(req->psm)); } ident = l2cap_sig_send(bthost, conn, code, 0, data, len); if (!ident) return false; if (!cb) return true; req = malloc(sizeof(*req)); if (!req) return false; memset(req, 0, sizeof(*req)); req->ident = ident; req->cb = cb; req->user_data = user_data; req->next = bthost->l2reqs; bthost->l2reqs = req; return true; }
static bool l2cap_conn_rsp(struct bthost *bthost, struct btconn *conn, uint8_t ident, const void *data, uint16_t len) { const struct bt_l2cap_pdu_conn_rsp *rsp = data; if (len < sizeof(*rsp)) return false; bthost_add_l2cap_conn(bthost, conn, le16_to_cpu(rsp->scid), le16_to_cpu(rsp->dcid)); if (le16_to_cpu(rsp->result) == 0x0001) { struct bt_l2cap_pdu_config_req req; memset(&req, 0, sizeof(req)); req.dcid = rsp->dcid; l2cap_sig_send(bthost, conn, BT_L2CAP_PDU_CONFIG_REQ, 0, &req, sizeof(req)); } return true; }