static gboolean l2cap_listen_cb(GIOChannel *io, GIOCondition cond,
							gpointer user_data)
{
	struct test_data *data = tester_get_data();
	const struct l2cap_data *l2data = data->test_data;
	int sk, new_sk;

	data->io_id = 0;

	sk = g_io_channel_unix_get_fd(io);

	new_sk = accept(sk, NULL, NULL);
	if (new_sk < 0) {
		tester_warn("accept failed: %s (%u)", strerror(errno), errno);
		tester_test_failed();
		return FALSE;
	}

	if (l2data->read_data) {
		struct bthost *bthost;
		GIOChannel *new_io;

		new_io = g_io_channel_unix_new(new_sk);
		g_io_channel_set_close_on_unref(new_io, TRUE);

		bthost = hciemu_client_get_host(data->hciemu);
		g_io_add_watch(new_io, G_IO_IN, server_received_data, NULL);
		bthost_send_cid(bthost, data->handle, data->dcid,
					l2data->read_data, l2data->data_len);

		g_io_channel_unref(new_io);

		return FALSE;
	} else if (l2data->write_data) {
		struct bthost *bthost;
		ssize_t ret;

		bthost = hciemu_client_get_host(data->hciemu);
		bthost_add_cid_hook(bthost, data->handle, data->scid,
					server_bthost_received_data, NULL);

		ret = write(new_sk, l2data->write_data, l2data->data_len);
		close(new_sk);

		if (ret != l2data->data_len) {
			tester_warn("Unable to write all data");
			tester_test_failed();
		}

		return FALSE;
	}

	tester_print("Successfully connected");

	close(new_sk);

	tester_test_passed();

	return FALSE;
}
Пример #2
0
static void smp_new_conn(uint16_t handle, void *user_data)
{
	struct test_data *data = user_data;
	const struct smp_data *smp = data->test_data;
	struct bthost *bthost = hciemu_client_get_host(data->hciemu);
	const struct smp_req_rsp *req;
	const void *pdu;

	tester_print("New SMP client connection with handle 0x%04x", handle);

	data->handle = handle;

	bthost_add_cid_hook(bthost, handle, SMP_CID, smp_server, data);

	if (smp->req_count == data->counter)
		return;

	req = &smp->req[data->counter];

	if (!req->send)
		return;

	tester_print("Sending SMP PDU");

	pdu = get_pdu(req->send);
	bthost_send_cid(bthost, handle, SMP_CID, pdu, req->send_len);

	if (!req->expect)
		test_condition_complete(data);
}
static gboolean l2cap_connect_cb(GIOChannel *io, GIOCondition cond,
							gpointer user_data)
{
	struct test_data *data = tester_get_data();
	const struct l2cap_data *l2data = data->test_data;
	int err, sk_err, sk;
	socklen_t len = sizeof(sk_err);

	data->io_id = 0;

	sk = g_io_channel_unix_get_fd(io);

	if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
		err = -errno;
	else
		err = -sk_err;

	if (err < 0)
		tester_warn("Connect failed: %s (%d)", strerror(-err), -err);
	else
		tester_print("Successfully connected");

	if (l2data->read_data) {
		struct bthost *bthost;

		bthost = hciemu_client_get_host(data->hciemu);
		g_io_add_watch(io, G_IO_IN, client_received_data, NULL);

		bthost_send_cid(bthost, data->handle, data->dcid,
					l2data->read_data, l2data->data_len);

		return FALSE;
	} else if (l2data->write_data) {
		struct bthost *bthost;
		ssize_t ret;

		bthost = hciemu_client_get_host(data->hciemu);
		bthost_add_cid_hook(bthost, data->handle, data->dcid,
					bthost_received_data, NULL);

		ret = write(sk, l2data->write_data, l2data->data_len);
		if (ret != l2data->data_len) {
			tester_warn("Unable to write all data");
			tester_test_failed();
		}

		return FALSE;
	}

	if (-err != l2data->expect_err)
		tester_test_failed();
	else
		tester_test_passed();

	return FALSE;
}
static void distribute_keys(struct smp_conn *conn)
{
	uint8_t buf[17];
	struct bthost *bthost = conn->smp->bthost;

	if (conn->local_key_dist & DIST_ENC_KEY) {
		memset(buf, 0, sizeof(buf));

		buf[0] = BT_L2CAP_SMP_ENCRYPT_INFO;
		bthost_send_cid(bthost, conn->handle, SMP_CID, buf, 17);

		buf[0] = BT_L2CAP_SMP_MASTER_IDENT;
		bthost_send_cid(bthost, conn->handle, SMP_CID, buf, 11);
	}

	if (conn->local_key_dist & DIST_ID_KEY) {
		memset(buf, 0, sizeof(buf));

		buf[0] = BT_L2CAP_SMP_IDENT_ADDR_INFO;
		if (conn->out) {
			buf[1] = conn->ia_type;
			memcpy(&buf[2], conn->ia, 6);
		} else {
			buf[1] = conn->ra_type;
			memcpy(&buf[2], conn->ra, 6);
		}
		bthost_send_cid(bthost, conn->handle, SMP_CID, buf, 8);

		buf[0] = BT_L2CAP_SMP_IDENT_INFO;
		memset(&buf[1], 0, 16);
		bthost_send_cid(bthost, conn->handle, SMP_CID, buf, 17);
	}

	if (conn->local_key_dist & DIST_SIGN) {
		memset(buf, 0, sizeof(buf));
		buf[0] = BT_L2CAP_SMP_SIGNING_INFO;
		bthost_send_cid(bthost, conn->handle, SMP_CID, buf, 17);
	}
}
void smp_pair(void *conn_data, uint8_t io_cap, uint8_t auth_req)
{
	struct smp_conn *conn = conn_data;
	struct bthost *bthost = conn->smp->bthost;
	const uint8_t req[] = {	BT_L2CAP_SMP_PAIRING_REQUEST,
				io_cap,		/* IO Capability */
				0x00,		/* OOB Flag */
				auth_req,	/* Auth requirement */
				0x10,		/* Max key size */
				KEY_DIST,	/* Init. key dist. */
				KEY_DIST,	/* Rsp. key dist. */
			};

	memcpy(conn->preq, req, sizeof(req));

	bthost_send_cid(bthost, conn->handle, SMP_CID, req, sizeof(req));
}
static void pairing_rsp(struct smp_conn *conn, const void *data, uint16_t len)
{
	struct smp *smp = conn->smp;
	uint8_t cfm[17];

	memcpy(conn->prsp, data, sizeof(conn->prsp));

	conn->local_key_dist = conn->prsp[5];
	conn->remote_key_dist = conn->prsp[6];

	cfm[0] = BT_L2CAP_SMP_PAIRING_CONFIRM;
	bt_crypto_c1(smp->crypto, conn->tk, conn->prnd, conn->prsp,
			conn->preq, conn->ia_type, conn->ia,
			conn->ra_type, conn->ra, &cfm[1]);

	bthost_send_cid(smp->bthost, conn->handle, SMP_CID, cfm, sizeof(cfm));
}
static void pairing_rnd(struct smp_conn *conn, const void *data, uint16_t len)
{
	struct bthost *bthost = conn->smp->bthost;
	uint8_t rsp[17];

	memcpy(conn->rrnd, data + 1, 16);

	if (!verify_random(conn, data + 1))
		return;

	if (conn->out)
		return;

	rsp[0] = BT_L2CAP_SMP_PAIRING_RANDOM;
	memset(&rsp[1], 0, 16);

	bthost_send_cid(bthost, conn->handle, SMP_CID, rsp, sizeof(rsp));
}
static void pairing_cfm(struct smp_conn *conn, const void *data, uint16_t len)
{
	struct bthost *bthost = conn->smp->bthost;
	uint8_t rsp[17];

	memcpy(conn->pcnf, data + 1, 16);

	if (conn->out) {
		rsp[0] = BT_L2CAP_SMP_PAIRING_RANDOM;
		memset(&rsp[1], 0, 16);
	} else {
		rsp[0] = BT_L2CAP_SMP_PAIRING_CONFIRM;
		bt_crypto_c1(conn->smp->crypto, conn->tk, conn->prnd,
				conn->prsp, conn->preq, conn->ia_type,
				conn->ia, conn->ra_type, conn->ra, &rsp[1]);
	}

	bthost_send_cid(bthost, conn->handle, SMP_CID, rsp, sizeof(rsp));
}
static void pairing_req(struct smp_conn *conn, const void *data, uint16_t len)
{
	struct bthost *bthost = conn->smp->bthost;
	uint8_t rsp[7];

	memcpy(conn->preq, data, sizeof(conn->preq));

	rsp[0] = BT_L2CAP_SMP_PAIRING_RESPONSE;
	rsp[1] = bthost_get_io_capability(bthost);
	rsp[2] = 0x00;				/* OOB Flag */
	rsp[3] = bthost_get_auth_req(bthost);
	rsp[4] = 0x10;				/* Max key size */
	rsp[5] = conn->preq[5] & KEY_DIST;	/* Init. key dist. */
	rsp[6] = conn->preq[6] & KEY_DIST;	/* Rsp. key dist. */

	memcpy(conn->prsp, rsp, sizeof(rsp));

	conn->local_key_dist = rsp[6];
	conn->remote_key_dist = rsp[5];

	bthost_send_cid(bthost, conn->handle, SMP_CID, rsp, sizeof(rsp));
}
Пример #10
0
static void bthost_send_rsp(const void *buf, uint16_t len, void *user_data)
{
	struct test_data *data = tester_get_data();
	const struct l2cap_data *l2data = data->test_data;
	struct bthost *bthost;

	if (l2data->expect_cmd_len && len != l2data->expect_cmd_len) {
		tester_test_failed();
		return;
	}

	if (l2data->expect_cmd && memcmp(buf, l2data->expect_cmd,
						l2data->expect_cmd_len)) {
		tester_test_failed();
		return;
	}

	if (!l2data->send_cmd)
		return;

	bthost = hciemu_client_get_host(data->hciemu);
	bthost_send_cid(bthost, data->handle, data->dcid,
				l2data->send_cmd, l2data->send_cmd_len);
}
Пример #11
0
static void smp_server(const void *data, uint16_t len, void *user_data)
{
	struct test_data *test_data = user_data;
	struct bthost *bthost = hciemu_client_get_host(test_data->hciemu);
	const struct smp_data *smp = test_data->test_data;
	const struct smp_req_rsp *req;
	const void *pdu;
	uint8_t opcode;

	if (len < 1) {
		tester_warn("Received too small SMP PDU");
		goto failed;
	}

	opcode = *((const uint8_t *) data);

	tester_print("Received SMP opcode 0x%02x", opcode);

	if (test_data->counter >= smp->req_count) {
		test_condition_complete(test_data);
		return;
	}

	req = &smp->req[test_data->counter++];
	if (!req->expect)
		goto next;

	if (req->expect_len != len) {
		tester_warn("Unexpected SMP PDU length (%u != %u)",
							len, req->expect_len);
		goto failed;
	}

	switch (opcode) {
	case 0x01: /* Pairing Request */
		memcpy(test_data->preq, data, sizeof(test_data->preq));
		break;
	case 0x02: /* Pairing Response */
		memcpy(test_data->prsp, data, sizeof(test_data->prsp));
		break;
	case 0x03: /* Pairing Confirm */
		memcpy(test_data->pcnf, data + 1, 16);
		goto next;
	case 0x04: /* Pairing Random */
		memcpy(test_data->rrnd, data + 1, 16);
		if (!verify_random(data + 1))
			goto failed;
		goto next;
	default:
		break;
	}

	if (memcmp(req->expect, data, len) != 0) {
		tester_warn("Unexpected SMP PDU");
		goto failed;
	}

next:
	if (smp->req_count == test_data->counter) {
		test_condition_complete(test_data);
		return;
	}

	req = &smp->req[test_data->counter];

	pdu = get_pdu(req->send);
	bthost_send_cid(bthost, test_data->handle, SMP_CID, pdu,
							req->send_len);

	if (!req->expect)
		test_condition_complete(test_data);

	return;

failed:
	tester_test_failed();
}