static void test_pre_setup(const void *test_data) { struct user_data *user = tester_get_data(); user->hci_ut = bt_hci_new_user_channel(user->index_ut); if (!user->hci_ut) { tester_warn("Failed to setup upper tester user channel"); tester_pre_setup_failed(); return; } if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_RESET, NULL, 0, test_pre_setup_ut_complete, NULL, NULL)) { tester_warn("Failed to reset upper tester"); tester_pre_setup_failed(); return; } }
static int accept_connection(int sk) { int err; struct pollfd pfd; int new_sk; memset(&pfd, 0 , sizeof(pfd)); pfd.fd = sk; pfd.events = POLLIN; err = poll(&pfd, 1, CONNECT_TIMEOUT); if (err < 0) { err = errno; tester_warn("Failed to poll: %d (%s)", err, strerror(err)); return -errno; } if (err == 0) { tester_warn("bluetoothd connect timeout"); return -errno; } new_sk = accept(sk, NULL, NULL); if (new_sk < 0) { err = errno; tester_warn("Failed to accept socket: %d (%s)", err, strerror(err)); return -errno; } return new_sk; }
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; }
static int connect_l2cap_sock(struct test_data *data, int sk, uint16_t psm) { const uint8_t *client_bdaddr; struct sockaddr_l2 addr; int err; client_bdaddr = hciemu_get_client_bdaddr(data->hciemu); if (!client_bdaddr) { tester_warn("No client bdaddr"); return -ENODEV; } memset(&addr, 0, sizeof(addr)); addr.l2_family = AF_BLUETOOTH; bacpy(&addr.l2_bdaddr, (void *) client_bdaddr); addr.l2_psm = htobs(psm); if (data->hciemu_type == HCIEMU_TYPE_LE) addr.l2_bdaddr_type = BDADDR_LE_PUBLIC; else addr.l2_bdaddr_type = BDADDR_BREDR; err = connect(sk, (struct sockaddr *) &addr, sizeof(addr)); if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) { err = -errno; tester_warn("Can't connect socket: %s (%d)", strerror(errno), errno); return err; } return 0; }
static void test_pre_setup_ut_address(const void *data, uint8_t size, void *user_data) { struct user_data *user = tester_get_data(); const struct bt_hci_rsp_read_bd_addr *rsp = data; if (rsp->status) { tester_warn("Read upper tester address failed (0x%02x)", rsp->status); tester_pre_setup_failed(); return; } memcpy(user->bdaddr_ut, rsp->bdaddr, 6); user->hci_lt = bt_hci_new_user_channel(user->index_lt); if (!user->hci_lt) { tester_warn("Failed to setup lower tester user channel"); tester_pre_setup_failed(); return; } if (!bt_hci_send(user->hci_lt, BT_HCI_CMD_RESET, NULL, 0, test_pre_setup_lt_complete, NULL, NULL)) { tester_warn("Failed to reset lower tester"); tester_pre_setup_failed(); return; } }
static void command_hci_callback(uint16_t opcode, const void *param, uint8_t length, void *user_data) { struct test_data *data = user_data; const struct smp_data *smp = data->test_data; const void *expect_hci_param = smp->expect_hci_param; uint8_t expect_hci_len = smp->expect_hci_len; tester_print("HCI Command 0x%04x length %u", opcode, length); if (opcode != smp->expect_hci_command) return; if (smp->expect_hci_func) expect_hci_param = smp->expect_hci_func(&expect_hci_len); if (length != expect_hci_len) { tester_warn("Invalid parameter size for HCI command"); tester_test_failed(); return; } if (memcmp(param, expect_hci_param, length) != 0) { tester_warn("Unexpected HCI command parameter value"); tester_test_failed(); return; } test_condition_complete(data); }
static void init_bdaddr(struct test_data *data) { const uint8_t *master_bdaddr, *client_bdaddr; master_bdaddr = hciemu_get_master_bdaddr(data->hciemu); if (!master_bdaddr) { tester_warn("No master bdaddr"); tester_test_failed(); return; } client_bdaddr = hciemu_get_client_bdaddr(data->hciemu); if (!client_bdaddr) { tester_warn("No client bdaddr"); tester_test_failed(); return; } data->ia_type = LE_PUBLIC_ADDRESS; data->ra_type = LE_PUBLIC_ADDRESS; if (data->out) { memcpy(data->ia, client_bdaddr, sizeof(data->ia)); memcpy(data->ra, master_bdaddr, sizeof(data->ra)); } else { memcpy(data->ia, master_bdaddr, sizeof(data->ia)); memcpy(data->ra, client_bdaddr, sizeof(data->ra)); } }
static void test_getpeername_not_connected(const void *test_data) { struct test_data *data = tester_get_data(); struct sockaddr_l2 addr; socklen_t len; int sk; sk = create_l2cap_sock(data, 0, 0, 0); if (sk < 0) { tester_test_failed(); return; } len = sizeof(addr); if (getpeername(sk, (struct sockaddr *) &addr, &len) == 0) { tester_warn("getpeername succeeded on non-connected socket"); tester_test_failed(); goto done; } if (errno != ENOTCONN) { tester_warn("Unexpexted getpeername error: %s (%d)", strerror(errno), errno); tester_test_failed(); goto done; } tester_test_passed(); done: close(sk); }
static void setup_le_read_local_pk_complete(const void *data, uint8_t size, void *user_data) { const uint8_t *event = data; const struct bt_hci_evt_le_read_local_pk256_complete *evt; struct le_keys *keys = user_data; if (*event != BT_HCI_EVT_LE_READ_LOCAL_PK256_COMPLETE) { tester_warn("Failed Read Local PK256 command"); tester_setup_failed(); return; } evt = (void *)(event + 1); if (evt->status) { tester_warn("HCI Read Local PK complete failed (0x%02x)", evt->status); tester_setup_failed(); return; } memcpy(keys->local_pk, evt->local_pk256, 64); util_hexdump('>', evt->local_pk256, 64, test_debug, NULL); tester_setup_complete(); }
static void test_pre_setup(const void *test_data) { struct test_data *data = tester_get_data(); data->crypto = bt_crypto_new(); if (!data->crypto) { tester_warn("Failed to setup crypto"); tester_pre_setup_failed(); return; } data->mgmt = mgmt_new_default(); if (!data->mgmt) { tester_warn("Failed to setup management interface"); bt_crypto_unref(data->crypto); tester_pre_setup_failed(); return; } if (tester_use_debug()) mgmt_set_debug(data->mgmt, mgmt_debug, "mgmt: ", NULL); mgmt_send(data->mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL, read_index_list_callback, NULL, NULL); }
static int connect_sco_sock(struct test_data *data, int sk) { const uint8_t *client_bdaddr; struct sockaddr_sco addr; int err; client_bdaddr = hciemu_get_client_bdaddr(data->hciemu); if (!client_bdaddr) { tester_warn("No client bdaddr"); return -ENODEV; } memset(&addr, 0, sizeof(addr)); addr.sco_family = AF_BLUETOOTH; bacpy(&addr.sco_bdaddr, (void *) client_bdaddr); err = connect(sk, (struct sockaddr *) &addr, sizeof(addr)); if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) { err = -errno; tester_warn("Can't connect socket: %s (%d)", strerror(errno), errno); return err; } return 0; }
static int create_sco_sock(struct test_data *data) { const uint8_t *master_bdaddr; struct sockaddr_sco addr; int sk, err; sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_NONBLOCK, BTPROTO_SCO); if (sk < 0) { err = -errno; tester_warn("Can't create socket: %s (%d)", strerror(errno), errno); return err; } master_bdaddr = hciemu_get_master_bdaddr(data->hciemu); if (!master_bdaddr) { tester_warn("No master bdaddr"); return -ENODEV; } memset(&addr, 0, sizeof(addr)); addr.sco_family = AF_BLUETOOTH; bacpy(&addr.sco_bdaddr, (void *) master_bdaddr); if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { err = -errno; tester_warn("Can't bind socket: %s (%d)", strerror(errno), errno); close(sk); return err; } return sk; }
static int create_l2cap_sock(struct test_data *data, uint16_t psm, uint16_t cid, int sec_level) { const uint8_t *master_bdaddr; struct sockaddr_l2 addr; int sk, err; sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_NONBLOCK, BTPROTO_L2CAP); if (sk < 0) { err = -errno; tester_warn("Can't create socket: %s (%d)", strerror(errno), errno); return err; } master_bdaddr = hciemu_get_master_bdaddr(data->hciemu); if (!master_bdaddr) { tester_warn("No master bdaddr"); close(sk); return -ENODEV; } memset(&addr, 0, sizeof(addr)); addr.l2_family = AF_BLUETOOTH; addr.l2_psm = htobs(psm); addr.l2_cid = htobs(cid); bacpy(&addr.l2_bdaddr, (void *) master_bdaddr); if (data->hciemu_type == HCIEMU_TYPE_LE) addr.l2_bdaddr_type = BDADDR_LE_PUBLIC; else addr.l2_bdaddr_type = BDADDR_BREDR; if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { err = -errno; tester_warn("Can't bind socket: %s (%d)", strerror(errno), errno); close(sk); return err; } if (sec_level) { struct bt_security sec; memset(&sec, 0, sizeof(sec)); sec.level = sec_level; if (setsockopt(sk, SOL_BLUETOOTH, BT_SECURITY, &sec, sizeof(sec)) < 0) { err = -errno; tester_warn("Can't set security level: %s (%d)", strerror(errno), errno); close(sk); return err; } } return sk; }
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 test_server(const void *test_data) { struct test_data *data = tester_get_data(); const struct l2cap_data *l2data = data->test_data; const uint8_t *master_bdaddr; uint8_t addr_type; struct bthost *bthost; GIOChannel *io; int sk; if (l2data->server_psm || l2data->cid) { sk = create_l2cap_sock(data, l2data->server_psm, l2data->cid, l2data->sec_level); if (sk < 0) { tester_test_failed(); return; } if (listen(sk, 5) < 0) { tester_warn("listening on socket failed: %s (%u)", strerror(errno), errno); tester_test_failed(); close(sk); return; } io = g_io_channel_unix_new(sk); g_io_channel_set_close_on_unref(io, TRUE); data->io_id = g_io_add_watch(io, G_IO_IN, l2cap_listen_cb, NULL); g_io_channel_unref(io); tester_print("Listening for connections"); } master_bdaddr = hciemu_get_master_bdaddr(data->hciemu); if (!master_bdaddr) { tester_warn("No master bdaddr"); tester_test_failed(); return; } bthost = hciemu_client_get_host(data->hciemu); bthost_set_connect_cb(bthost, send_req_new_conn, data); if (data->hciemu_type == HCIEMU_TYPE_BREDR) addr_type = BDADDR_BREDR; else addr_type = BDADDR_LE_PUBLIC; bthost_hci_connect(bthost, master_bdaddr, addr_type); }
static void client_l2cap_rsp(uint8_t code, const void *data, uint16_t len, void *user_data) { struct test_data *test_data = user_data; const struct l2cap_data *l2data = test_data->test_data; tester_print("Client received response code 0x%02x", code); if (code != l2data->expect_cmd_code) { tester_warn("Unexpected L2CAP response code (expected 0x%02x)", l2data->expect_cmd_code); goto failed; } if (code == BT_L2CAP_PDU_CONN_RSP) { const struct bt_l2cap_pdu_conn_rsp *rsp = data; if (len == sizeof(rsp) && !rsp->result && !rsp->status) return; test_data->dcid = rsp->dcid; test_data->scid = rsp->scid; if (l2data->data_len) return; } if (!l2data->expect_cmd) { tester_test_passed(); return; } if (l2data->expect_cmd_len != len) { tester_warn("Unexpected L2CAP response length (%u != %u)", len, l2data->expect_cmd_len); goto failed; } if (memcmp(l2data->expect_cmd, data, len) != 0) { tester_warn("Unexpected L2CAP response"); goto failed; } tester_test_passed(); return; failed: tester_test_failed(); }
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; } }
/* Data are taken from RFC 4493 Test Vectors */ static void test_le_encrypt(const void *test_data) { struct user_data *user = tester_get_data(); struct bt_hci_cmd_le_encrypt cmd; uint8_t key[16] = { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c }; uint8_t plaintext[16] = { 0 }; /* Swap bytes since our interface has LE interface, opposed to * common crypto interface */ swap_buf(key, cmd.key, 16); swap_buf(plaintext, cmd.plaintext, 16); util_hexdump('<', cmd.key, 16, test_debug, NULL); util_hexdump('<', cmd.plaintext, 16, test_debug, NULL); if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_LE_ENCRYPT, &cmd, sizeof(cmd), test_le_encrypt_complete, NULL, NULL)) { tester_warn("Failed to send HCI LE Encrypt command"); tester_test_failed(); return; } }
static gboolean l2cap_listen_cb(GIOChannel *io, GIOCondition cond, gpointer user_data) { struct test_data *data = tester_get_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; } tester_print("Successfully connected"); close(new_sk); tester_test_passed(); return FALSE; }
static bool verify_random(const uint8_t rnd[16]) { struct test_data *data = tester_get_data(); uint8_t confirm[16]; if (!bt_crypto_c1(data->crypto, data->tk, data->rrnd, data->prsp, data->preq, data->ia_type, data->ia, data->ra_type, data->ra, confirm)) return false; if (memcmp(data->pcnf, confirm, sizeof(data->pcnf) != 0)) { tester_warn("Confirmation values don't match"); return false; } if (data->out) { struct bthost *bthost = hciemu_client_get_host(data->hciemu); bt_crypto_s1(data->crypto, data->tk, data->rrnd, data->prnd, data->ltk); bthost_le_start_encrypt(bthost, data->handle, data->ltk); } else { bt_crypto_s1(data->crypto, data->tk, data->prnd, data->rrnd, data->ltk); } return true; }
static void setup_le_generate_dhkey(const void *test_data) { struct user_data *user = tester_get_data(); struct bt_hci_cmd_set_event_mask sem; struct bt_hci_cmd_le_set_event_mask lsem; bt_hci_register(user->hci_ut, BT_HCI_EVT_LE_META_EVENT, setup_le_read_local_pk_complete, (void *)test_data, NULL); memset(sem.mask, 0, 8); sem.mask[1] |= 0x20; /* Command Complete */ sem.mask[1] |= 0x40; /* Command Status */ sem.mask[7] |= 0x20; /* LE Meta */ bt_hci_send(user->hci_ut, BT_HCI_CMD_SET_EVENT_MASK, &sem, sizeof(sem), NULL, NULL, NULL); memset(lsem.mask, 0, 8); lsem.mask[0] |= 0x80; /* LE Read Local P-256 Public Key Complete */ lsem.mask[1] |= 0x01; /* LE Generate DHKey Complete */ bt_hci_send(user->hci_ut, BT_HCI_CMD_LE_SET_EVENT_MASK, &lsem, sizeof(lsem), NULL, NULL, NULL); if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_LE_READ_LOCAL_PK256, NULL, 0, setup_le_read_local_pk_status, NULL, NULL)) { tester_warn("Failed to send HCI LE Read Local PK256 command"); tester_setup_failed(); return; } }
static void read_index_list_callback(uint8_t status, uint16_t length, const void *param, void *user_data) { struct test_data *data = tester_get_data(); tester_print("Read Index List callback"); tester_print(" Status: 0x%02x", status); if (status || !param) { tester_pre_setup_failed(); return; } mgmt_register(data->mgmt, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE, index_added_callback, NULL, NULL); mgmt_register(data->mgmt, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE, index_removed_callback, NULL, NULL); data->hciemu = hciemu_new(data->hciemu_type); if (!data->hciemu) { tester_warn("Failed to setup HCI emulation"); tester_pre_setup_failed(); } tester_print("New hciemu instance created"); }
static gboolean sco_connect_cb(GIOChannel *io, GIOCondition cond, gpointer user_data) { struct test_data *data = tester_get_data(); const struct sco_client_data *scodata = 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 (-err != scodata->expect_err) tester_test_failed(); else tester_test_passed(); return FALSE; }
static int connect_l2cap_sock(struct test_data *data, int sk, uint16_t psm, uint16_t cid) { const struct l2cap_data *l2data = data->test_data; const uint8_t *client_bdaddr; uint8_t bdaddr_type; if (l2data->client_bdaddr != NULL) client_bdaddr = l2data->client_bdaddr; else client_bdaddr = hciemu_get_client_bdaddr(data->hciemu); if (!client_bdaddr) { tester_warn("No client bdaddr"); return -ENODEV; } if (l2data && l2data->addr_type_avail) bdaddr_type = l2data->addr_type; else if (data->hciemu_type == HCIEMU_TYPE_LE) bdaddr_type = BDADDR_LE_PUBLIC; else bdaddr_type = BDADDR_BREDR; return connect_l2cap_impl(sk, client_bdaddr, bdaddr_type, psm, cid); }
static void pair_device_complete(uint8_t status, uint16_t length, const void *param, void *user_data) { if (status != MGMT_STATUS_SUCCESS) { tester_warn("Pairing failed: %s", mgmt_errstr(status)); return; } tester_print("Pairing succeedded"); }
static void test_pre_setup_lt_complete(const void *data, uint8_t size, void *user_data) { struct user_data *user = tester_get_data(); uint8_t status = *((uint8_t *) data); if (status) { tester_warn("Reset lower tester failed (0x%02x)", status); tester_pre_setup_failed(); return; } if (!bt_hci_send(user->hci_lt, BT_HCI_CMD_READ_BD_ADDR, NULL, 0, test_pre_setup_lt_address, NULL, NULL)) { tester_warn("Failed to read lower tester address"); tester_pre_setup_failed(); return; } }
static void test_le_read_local_pk_status(const void *data, uint8_t size, void *user_data) { uint8_t status = *((uint8_t *) data); if (status) { tester_warn("Failed to send Read Local PK256 cmd (0x%02x)", status); tester_test_failed(); return; } }
static void setup_le_read_local_pk_status(const void *data, uint8_t size, void *user_data) { uint8_t status = *((uint8_t *) data); if (status) { tester_warn("Failed to send DHKey gen cmd (0x%02x)", status); tester_setup_failed(); return; } }
static void test_le_generate_dhkey_status(const void *data, uint8_t size, void *user_data) { uint8_t status = *((uint8_t *) data); if (status) { tester_warn("Failed to send DHKey gen cmd (0x%02x)", status); tester_test_failed(); return; } }
static void test_inquiry_status(const void *data, uint8_t size, void *user_data) { uint8_t status = *((uint8_t *) data); if (status) { tester_warn("HCI inquiry command failed (0x%02x)", status); tester_test_failed(); return; } }