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 send_req_new_conn(uint16_t handle, void *user_data) { struct test_data *data = user_data; const struct l2cap_data *l2data = data->test_data; struct bthost *bthost; tester_print("New client connection with handle 0x%04x", handle); data->handle = handle; if (l2data->send_cmd) { bthost_l2cap_rsp_cb cb; if (l2data->expect_cmd_code) cb = client_l2cap_rsp; else cb = NULL; tester_print("Sending L2CAP Request from client"); bthost = hciemu_client_get_host(data->hciemu); bthost_l2cap_req(bthost, handle, l2data->send_cmd_code, l2data->send_cmd, l2data->send_cmd_len, cb, data); } }
static void client_l2cap_rsp(uint8_t code, const void *data, uint16_t len, void *user_data) { struct test_data *t_data = tester_get_data(); struct bthost *bthost = hciemu_client_get_host(t_data->hciemu); struct emu_l2cap_cid_data *cid_data = user_data; const uint16_t *psm = data; const struct iovec con_req = raw_pdu(0x13, 0x00, /* PSM */ 0x41, 0x00); /* Source CID */ if (len < sizeof(*psm)) { tester_warn("Invalid l2cap response."); return; } switch (*psm) { case 0x40: bthost_add_cid_hook(bthost, cid_data->handle, 0x40, hid_ctrl_cid_hook_cb, cid_data); bthost_l2cap_req(bthost, cid_data->handle, 0x02, con_req.iov_base, con_req.iov_len, client_l2cap_rsp, cid_data); break; case 0x41: bthost_add_cid_hook(bthost, cid_data->handle, 0x41, hid_intr_cid_hook_cb, cid_data); break; default: break; } }
static void hidhost_conn_cb(uint16_t handle, void *user_data) { const struct iovec con_req = raw_pdu(0x11, 0x00, /* PSM */ 0x40, 0x00); /* Source CID */ struct test_data *data = tester_get_data(); struct bthost *bthost = hciemu_client_get_host(data->hciemu); if (data->hciemu_type == HCIEMU_TYPE_BREDR) { tester_warn("Not handled device type."); return; } ctrl_cid_data.cid = 0x40; ctrl_cid_data.handle = handle; tester_print("Sending L2CAP Request from remote"); bthost_l2cap_req(bthost, handle, 0x02, con_req.iov_base, con_req.iov_len, client_l2cap_rsp, &ctrl_cid_data); }