bool bthost_connect_rfcomm(struct bthost *bthost, uint16_t handle, uint8_t channel, bthost_rfcomm_connect_cb func, void *user_data) { struct rfcomm_connection_data *data; struct bt_l2cap_pdu_conn_req req; struct btconn *conn; if (bthost->rfcomm_conn_data) return false; conn = bthost_find_conn(bthost, handle); if (!conn) return false; data = malloc(sizeof(struct rfcomm_connection_data)); if (!data) return false; data->channel = channel; data->conn = conn; data->cb = func; data->user_data = user_data; bthost->rfcomm_conn_data = data; req.psm = cpu_to_le16(0x0003); req.scid = cpu_to_le16(conn->next_cid++); return bthost_l2cap_req(bthost, handle, BT_L2CAP_PDU_CONN_REQ, &req, sizeof(req), NULL, NULL); }
static void evt_le_ltk_request(struct bthost *bthost, const void *data, uint8_t len) { const struct bt_hci_evt_le_long_term_key_request *ev = data; struct bt_hci_cmd_le_ltk_req_reply cp; struct bt_hci_cmd_le_ltk_req_neg_reply *neg_cp = (void *) &cp; uint16_t handle, div; struct btconn *conn; int err; if (len < sizeof(*ev)) return; handle = acl_handle(ev->handle); conn = bthost_find_conn(bthost, handle); if (!conn) return; div = le16_to_cpu(ev->diversifier); cp.handle = ev->handle; err = smp_get_ltk(conn->smp_data, ev->number, div, cp.ltk); if (err < 0) send_command(bthost, BT_HCI_CMD_LE_LTK_REQ_NEG_REPLY, neg_cp, sizeof(*neg_cp)); else send_command(bthost, BT_HCI_CMD_LE_LTK_REQ_REPLY, &cp, sizeof(cp)); }
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; 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 void process_acl(struct bthost *bthost, const void *data, uint16_t len) { const struct bt_hci_acl_hdr *acl_hdr = data; const struct bt_l2cap_hdr *l2_hdr = data + sizeof(*acl_hdr); uint16_t handle, cid, acl_len, l2_len; struct cid_hook *hook; struct btconn *conn; struct l2conn *l2conn; const void *l2_data; if (len < sizeof(*acl_hdr) + sizeof(*l2_hdr)) return; acl_len = le16_to_cpu(acl_hdr->dlen); if (len != sizeof(*acl_hdr) + acl_len) return; handle = acl_handle(acl_hdr->handle); conn = bthost_find_conn(bthost, handle); if (!conn) { printf("ACL data for unknown handle 0x%04x\n", handle); return; } l2_len = le16_to_cpu(l2_hdr->len); if (len - sizeof(*acl_hdr) != sizeof(*l2_hdr) + l2_len) return; l2_data = data + sizeof(*acl_hdr) + sizeof(*l2_hdr); cid = le16_to_cpu(l2_hdr->cid); hook = find_cid_hook(conn, cid); if (hook) { hook->func(l2_data, l2_len, hook->user_data); return; } switch (cid) { case 0x0001: l2cap_sig(bthost, conn, l2_data, l2_len); break; case 0x0005: l2cap_le_sig(bthost, conn, l2_data, l2_len); break; case 0x0006: smp_data(conn->smp_data, l2_data, l2_len); break; default: l2conn = btconn_find_l2cap_conn_by_scid(conn, cid); if (l2conn && l2conn->psm == 0x0003) process_rfcomm(bthost, conn, l2conn, l2_data, l2_len); else printf("Packet for unknown CID 0x%04x (%u)\n", cid, cid); break; } }
void bthost_send_cid(struct bthost *bthost, uint16_t handle, uint16_t cid, const void *data, uint16_t len) { struct btconn *conn; conn = bthost_find_conn(bthost, handle); if (!conn) return; send_acl(bthost, handle, cid, data, len); }
static void evt_encrypt_change(struct bthost *bthost, const void *data, uint8_t len) { const struct bt_hci_evt_encrypt_change *ev = data; struct btconn *conn; uint16_t handle; if (len < sizeof(*ev)) return; handle = acl_handle(ev->handle); conn = bthost_find_conn(bthost, handle); if (!conn) return; conn->encr_mode = ev->encr_mode; }
void bthost_request_auth(struct bthost *bthost, uint16_t handle) { struct btconn *conn; conn = bthost_find_conn(bthost, handle); if (!conn) return; if (conn->addr_type == BDADDR_BREDR) { struct bt_hci_cmd_auth_requested cp; cp.handle = cpu_to_le16(handle); send_command(bthost, BT_HCI_CMD_AUTH_REQUESTED, &cp, sizeof(cp)); } else { smp_pair(conn->smp_data); } }
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; }
void bthost_add_cid_hook(struct bthost *bthost, uint16_t handle, uint16_t cid, bthost_cid_hook_func_t func, void *user_data) { struct cid_hook *hook; struct btconn *conn; conn = bthost_find_conn(bthost, handle); if (!conn) return; hook = malloc(sizeof(*hook)); if (!hook) return; memset(hook, 0, sizeof(*hook)); hook->cid = cid; hook->func = func; hook->user_data = user_data; hook->next = conn->cid_hooks; conn->cid_hooks = hook; }