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));
}
示例#3
0
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;
}