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 void adv_le_evtmask_callback(const void *data, uint8_t size, void *user_data) { struct bt_hci_cmd_le_set_resolv_timeout cmd0; struct bt_hci_cmd_le_add_to_resolv_list cmd1; struct bt_hci_cmd_le_set_resolv_enable cmd2; struct bt_hci_cmd_le_set_random_address cmd3; struct bt_hci_cmd_le_set_adv_parameters cmd4; struct bt_hci_cmd_le_set_adv_enable cmd5; cmd0.timeout = cpu_to_le16(0x0384); bt_hci_send(adv_dev, BT_HCI_CMD_LE_SET_RESOLV_TIMEOUT, &cmd0, sizeof(cmd0), NULL, NULL, NULL); cmd1.addr_type = PEER_ADDR_TYPE; memcpy(cmd1.addr, PEER_ADDR, 6); memset(cmd1.peer_irk, 0, 16); memcpy(cmd1.local_irk, ADV_IRK, 16); bt_hci_send(adv_dev, BT_HCI_CMD_LE_ADD_TO_RESOLV_LIST, &cmd1, sizeof(cmd1), NULL, NULL, NULL); cmd2.enable = 0x01; bt_hci_send(adv_dev, BT_HCI_CMD_LE_SET_RESOLV_ENABLE, &cmd2, sizeof(cmd2), NULL, NULL, NULL); bt_crypto_random_bytes(crypto, cmd3.addr + 3, 3); cmd3.addr[5] &= 0x3f; /* Clear two most significant bits */ cmd3.addr[5] |= 0x40; /* Set second most significant bit */ bt_crypto_ah(crypto, cmd1.local_irk, cmd3.addr + 3, cmd3.addr); bt_hci_send(adv_dev, BT_HCI_CMD_LE_SET_RANDOM_ADDRESS, &cmd3, sizeof(cmd3), NULL, NULL, NULL); printf("Setting advertising address\n"); print_rpa(cmd3.addr); cmd4.min_interval = cpu_to_le16(0x0800); cmd4.max_interval = cpu_to_le16(0x0800); cmd4.type = 0x03; /* Non-connectable advertising */ cmd4.own_addr_type = 0x03; /* Local IRK, random address fallback */ cmd4.direct_addr_type = PEER_ADDR_TYPE; memcpy(cmd4.direct_addr, PEER_ADDR, 6); cmd4.channel_map = 0x07; cmd4.filter_policy = 0x00; bt_hci_send(adv_dev, BT_HCI_CMD_LE_SET_ADV_PARAMETERS, &cmd4, sizeof(cmd4), NULL, NULL, NULL); cmd5.enable = 0x01; bt_hci_send(adv_dev, BT_HCI_CMD_LE_SET_ADV_ENABLE, &cmd5, sizeof(cmd5), adv_enable_callback, NULL, NULL); }
static void scan_le_features_callback(const void *data, uint8_t size, void *user_data) { const struct bt_hci_rsp_le_read_local_features *rsp = data; uint8_t evtmask[] = { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00 }; if (rsp->status) { fprintf(stderr, "Failed to read local LE features\n"); mainloop_exit_failure(); return; } bt_hci_send(adv_dev, BT_HCI_CMD_LE_SET_EVENT_MASK, evtmask, 8, scan_le_evtmask_callback, NULL, NULL); }
static void ext_inquiry_result(const void *data, uint8_t size, void *user_data) { const struct bt_hci_evt_ext_inquiry_result *evt = data; if (evt->dev_class[0] != 0x3c || evt->dev_class[1] != 0x04 || evt->dev_class[2] != 0x08) return; if (evt->data[0]) { struct bt_hci_cmd_truncated_page cmd; printf("Found 3D display\n"); bt_hci_send(hci_dev, BT_HCI_CMD_INQUIRY_CANCEL, NULL, 0, NULL, NULL, NULL); memcpy(cmd.bdaddr, evt->bdaddr, 6); cmd.pscan_rep_mode = evt->pscan_rep_mode; cmd.clock_offset = evt->clock_offset; bt_hci_send(hci_dev, BT_HCI_CMD_TRUNCATED_PAGE, &cmd, sizeof(cmd), NULL, NULL, NULL); } }
static void scan_features_callback(const void *data, uint8_t size, void *user_data) { const struct bt_hci_rsp_read_local_features *rsp = data; uint8_t evtmask[] = { 0x90, 0xe8, 0x04, 0x02, 0x00, 0x80, 0x00, 0x20 }; if (rsp->status) { fprintf(stderr, "Failed to read local features\n"); mainloop_exit_failure(); return; } if (!(rsp->features[4] & 0x40)) { fprintf(stderr, "Controller without Low Energy support\n"); mainloop_exit_failure(); return; } bt_hci_send(scan_dev, BT_HCI_CMD_SET_EVENT_MASK, evtmask, 8, NULL, NULL, NULL); bt_hci_send(scan_dev, BT_HCI_CMD_LE_READ_LOCAL_FEATURES, NULL, 0, scan_le_features_callback, NULL, NULL); }
static void conn_request(const void *data, uint8_t size, void *user_data) { const struct bt_hci_evt_conn_request *evt = data; struct bt_hci_cmd_accept_conn_request cmd; printf("Incoming connection from 3D glasses\n"); memcpy(cmd.bdaddr, evt->bdaddr, 6); cmd.role = 0x00; bt_hci_send(hci_dev, BT_HCI_CMD_ACCEPT_CONN_REQUEST, &cmd, sizeof(cmd), NULL, NULL, NULL); start_sync_train(); }
static void test_read_local_extended_features(const void *test_data) { struct user_data *user = tester_get_data(); struct bt_hci_cmd_read_local_ext_features cmd; cmd.page = 0x00; if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_READ_LOCAL_EXT_FEATURES, &cmd, sizeof(cmd), test_local_extended_features_complete, NULL, NULL)) { tester_warn("Failed to send HCI extended features command"); tester_test_failed(); return; } }
static void set_adv_parameters(void) { struct bt_hci_cmd_le_set_adv_parameters cmd; cmd.min_interval = cpu_to_le16(0x0800); cmd.max_interval = cpu_to_le16(0x0800); cmd.type = 0x03; /* Non-connectable advertising */ cmd.own_addr_type = 0x01; /* Use random address */ cmd.direct_addr_type = 0x00; memset(cmd.direct_addr, 0, 6); cmd.channel_map = 0x07; cmd.filter_policy = 0x00; bt_hci_send(hci_dev, BT_HCI_CMD_LE_SET_ADV_PARAMETERS, &cmd, sizeof(cmd), NULL, NULL, NULL); }
static void slave_broadcast_timeout(const void *data, uint8_t size, void *user_data) { const struct bt_hci_evt_slave_broadcast_timeout *evt = data; struct bt_hci_cmd_receive_sync_train cmd; printf("Re-synchronizing with 3D display\n"); memcpy(cmd.bdaddr, evt->bdaddr, 6); cmd.timeout = cpu_to_le16(0x4000); cmd.window = cpu_to_le16(0x0100); cmd.interval = cpu_to_le16(0x0080); bt_hci_send(hci_dev, BT_HCI_CMD_RECEIVE_SYNC_TRAIN, &cmd, sizeof(cmd), NULL, NULL, NULL); }
static void setup_le_generate_dhkey(const void *test_data) { struct user_data *user = tester_get_data(); bt_hci_register(user->hci_ut, BT_HCI_EVT_LE_META_EVENT, setup_le_read_local_pk_complete, (void *)test_data, 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 setup_lt_connect_request_accept(const void *data, uint8_t size, void *user_data) { struct user_data *user = tester_get_data(); const struct bt_hci_evt_conn_request *evt = data; struct bt_hci_cmd_accept_conn_request cmd; memcpy(cmd.bdaddr, evt->bdaddr, 6); cmd.role = 0x01; if (!bt_hci_send(user->hci_lt, BT_HCI_CMD_ACCEPT_CONN_REQUEST, &cmd, sizeof(cmd), NULL, NULL, NULL)) { tester_warn("Failed to send HCI accept connection command"); return; } }
static void set_random_address(void) { struct bt_hci_cmd_le_set_random_address cmd; ssize_t len; len = read(urandom_fd, cmd.addr, sizeof(cmd.addr)); if (len < 0 || len != sizeof(cmd.addr)) { fprintf(stderr, "Failed to read random data\n"); return; } /* Clear top most significant bits */ cmd.addr[5] &= 0x3f; bt_hci_send(hci_dev, BT_HCI_CMD_LE_SET_RANDOM_ADDRESS, &cmd, sizeof(cmd), NULL, NULL, NULL); }
static void read_bd_data_complete(const void *data, uint8_t size, void *user_data) { const struct rsp_read_bd_data *rsp = data; if (rsp->status) { fprintf(stderr, "Failed to read data (0x%02x)\n", rsp->status); shutdown_device(); return; } printf("Controller Data\n"); printf("\tBD_ADDR: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", rsp->bdaddr[5], rsp->bdaddr[4], rsp->bdaddr[3], rsp->bdaddr[2], rsp->bdaddr[1], rsp->bdaddr[0]); printf("\tLMP Version: %u\n", rsp->lmp_version); printf("\tLMP Features: 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x" " 0x%2.2x 0x%2.2x 0x%2.2x 0x%2.2x\n", rsp->features[0], rsp->features[1], rsp->features[2], rsp->features[3], rsp->features[4], rsp->features[5], rsp->features[6], rsp->features[7]); printf("\tLE Features: 0x%2.2x\n", rsp->le_features); if (set_bdaddr) { struct cmd_write_bd_data cmd; memcpy(cmd.bdaddr, rsp->bdaddr, 6); cmd.bdaddr[0] = (hci_index & 0xff); cmd.lmp_version = 0x07; memcpy(cmd.features, rsp->features, 8); cmd.le_features = rsp->le_features; cmd.le_features |= 0x1e; memcpy(cmd.reserved1, rsp->reserved1, sizeof(cmd.reserved1)); memcpy(cmd.reserved2, rsp->reserved2, sizeof(cmd.reserved2)); memcpy(cmd.reserved3, rsp->reserved3, sizeof(cmd.reserved3)); bt_hci_send(hci_dev, CMD_WRITE_BD_DATA, &cmd, sizeof(cmd), write_bd_data_complete, NULL, NULL); return; } shutdown_device(); }
static void set_slave_broadcast(const void *data, uint8_t size, void *user_data) { const struct bt_hci_rsp_set_slave_broadcast *rsp = data; struct bt_hci_cmd_read_clock cmd; if (rsp->status) { printf("Failed to set slave broadcast transmission\n"); shutdown_device(); return; } cmd.handle = cpu_to_le16(0x0000); cmd.type = 0x00; bt_hci_send(hci_dev, BT_HCI_CMD_READ_CLOCK, &cmd, sizeof(cmd), read_clock, NULL, NULL); }
static void teardown_connection(const void *test_data) { struct user_data *user = tester_get_data(); struct bt_hci_cmd_disconnect cmd; cmd.handle = cpu_to_le16(user->handle_ut); cmd.reason = 0x13; if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_DISCONNECT, &cmd, sizeof(cmd), teardown_disconnect_status, NULL, NULL)) { tester_warn("Failed to send HCI disconnect command"); tester_test_failed(); return; } }
static void slave_broadcast_receive(const void *data, uint8_t size, void *user_data) { const struct bt_hci_evt_slave_broadcast_receive *evt = data; struct bt_hci_cmd_read_clock cmd; if (evt->status != 0x00) return; if (le32_to_cpu(evt->clock) != 0x00000000) return; cmd.handle = cpu_to_le16(0x0000); cmd.type = 0x00; bt_hci_send(hci_dev, BT_HCI_CMD_READ_CLOCK, &cmd, sizeof(cmd), NULL, NULL, NULL); }
static void setup_lt_connectable(const void *test_data) { struct user_data *user = tester_get_data(); struct bt_hci_cmd_write_scan_enable cmd; bt_hci_register(user->hci_lt, BT_HCI_EVT_CONN_REQUEST, setup_lt_connect_request_accept, NULL, NULL); cmd.enable = 0x02; if (!bt_hci_send(user->hci_lt, BT_HCI_CMD_WRITE_SCAN_ENABLE, &cmd, sizeof(cmd), setup_lt_connectable_complete, NULL, NULL)) { tester_warn("Failed to send HCI scan enable command"); tester_setup_failed(); return; } }
static void firmware_command_complete(const void *data, uint8_t size, void *user_data) { uint8_t status = *((uint8_t *) data); if (status) { fprintf(stderr, "Failed to load firmware (0x%02x)\n", status); manufacturer_mode_reset = 0x01; shutdown_device(); return; } if (firmware_offset >= firmware_size) { printf("Activating firmware\n"); manufacturer_mode_reset = 0x02; shutdown_device(); return; } if (firmware_data[firmware_offset] == 0x01) { uint16_t opcode; uint8_t dlen; opcode = firmware_data[firmware_offset + 2] << 8 | firmware_data[firmware_offset + 1]; dlen = firmware_data[firmware_offset + 3]; bt_hci_send(hci_dev, opcode, firmware_data + firmware_offset + 4, dlen, firmware_command_complete, NULL, NULL); firmware_offset += dlen + 4; if (firmware_data[firmware_offset] == 0x02) { dlen = firmware_data[firmware_offset + 2]; firmware_offset += dlen + 3; } } else { fprintf(stderr, "Invalid packet in firmware\n"); manufacturer_mode_reset = 0x01; shutdown_device(); } }
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; } }
bool bt_hci_crypto_prand(struct bt_hci *hci, bt_hci_crypto_func_t callback, void *user_data) { struct crypto_data *data; if (!callback) return false; data = new0(struct crypto_data, 1); data->callback = callback; data->user_data = user_data; if (!bt_hci_send(hci, BT_HCI_CMD_LE_RAND, NULL, 0, prand_callback, data, free)) { free(data); return false; } return true; }
static void leave_manufacturer_mode_complete(const void *data, uint8_t size, void *user_data) { uint8_t status = *((uint8_t *) data); if (status) { fprintf(stderr, "Failed to leave manufacturer mode (0x%02x)\n", status); mainloop_quit(); return; } if (reset_on_exit) { bt_hci_send(hci_dev, BT_HCI_CMD_RESET, NULL, 0, reset_complete, NULL, NULL); return; } mainloop_quit(); }
static void local_features_callback(const void *data, uint8_t size, void *user_data) { const struct bt_hci_rsp_read_local_features *rsp = data; if (rsp->status) { fprintf(stderr, "Failed to read local features\n"); shutdown_device(); return; } if (!(rsp->features[4] & 0x40)) { fprintf(stderr, "Controller without Low Energy support\n"); shutdown_device(); return; } bt_hci_send(hci_dev, BT_HCI_CMD_LE_READ_ADV_TX_POWER, NULL, 0, adv_tx_power_callback, NULL, NULL); }
static void test_inquiry_liac(const void *test_data) { struct user_data *user = tester_get_data(); struct bt_hci_cmd_inquiry cmd; bt_hci_register(user->hci_ut, BT_HCI_EVT_INQUIRY_COMPLETE, test_inquiry_complete, NULL, NULL); cmd.lap[0] = 0x00; cmd.lap[1] = 0x8b; cmd.lap[2] = 0x9e; cmd.length = 0x08; cmd.num_resp = 0x00; if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_INQUIRY, &cmd, sizeof(cmd), test_inquiry_status, NULL, NULL)) { tester_warn("Failed to send HCI inquiry command"); tester_test_failed(); return; } }
static void truncated_page_complete(const void *data, uint8_t size, void *user_data) { const struct bt_hci_evt_truncated_page_complete *evt = data; struct bt_hci_cmd_receive_sync_train cmd; if (evt->status) { printf("Failed to contact 3D display\n"); shutdown_device(); return; } printf("Attempt to synchronize with 3D display\n"); memcpy(cmd.bdaddr, evt->bdaddr, 6); cmd.timeout = cpu_to_le16(0x4000); cmd.window = cpu_to_le16(0x0100); cmd.interval = cpu_to_le16(0x0080); bt_hci_send(hci_dev, BT_HCI_CMD_RECEIVE_SYNC_TRAIN, &cmd, sizeof(cmd), NULL, NULL, NULL); }
static void read_bd_addr_complete(const void *data, uint8_t size, void *user_data) { const struct bt_hci_rsp_read_bd_addr *rsp = data; struct cmd_write_bd_address cmd; if (rsp->status) { fprintf(stderr, "Failed to read address (0x%02x)\n", rsp->status); mainloop_quit(); shutdown_device(); return; } if (set_bdaddr_value) { fprintf(stderr, "Setting address is not supported\n"); mainloop_quit(); return; } printf("Controller Address\n"); printf("\tOld BD_ADDR: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", rsp->bdaddr[5], rsp->bdaddr[4], rsp->bdaddr[3], rsp->bdaddr[2], rsp->bdaddr[1], rsp->bdaddr[0]); memcpy(cmd.bdaddr, rsp->bdaddr, 6); cmd.bdaddr[0] = (hci_index & 0xff); printf("\tNew BD_ADDR: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n", cmd.bdaddr[5], cmd.bdaddr[4], cmd.bdaddr[3], cmd.bdaddr[2], cmd.bdaddr[1], cmd.bdaddr[0]); bt_hci_send(hci_dev, CMD_WRITE_BD_ADDRESS, &cmd, sizeof(cmd), write_bd_address_complete, NULL, NULL); }
static void adv_tx_power_callback(const void *data, uint8_t size, void *user_data) { const struct bt_hci_rsp_le_read_adv_tx_power *rsp = data; struct bt_hci_cmd_le_set_adv_data cmd; if (rsp->status) { fprintf(stderr, "Failed to read advertising TX power\n"); shutdown_device(); return; } cmd.data[0] = 0x02; /* Field length */ cmd.data[1] = 0x01; /* Flags */ cmd.data[2] = 0x02; /* LE General Discoverable Mode */ cmd.data[2] |= 0x04; /* BR/EDR Not Supported */ cmd.data[3] = 0x1a; /* Field length */ cmd.data[4] = 0xff; /* Vendor field */ cmd.data[5] = 0x4c; /* Apple (76) - LSB */ cmd.data[6] = 0x00; /* Apple (76) - MSB */ cmd.data[7] = 0x02; /* iBeacon type */ cmd.data[8] = 0x15; /* Length */ memset(cmd.data + 9, 0, 16); /* UUID */ cmd.data[25] = 0x00; /* Major - LSB */ cmd.data[26] = 0x00; /* Major - MSB */ cmd.data[27] = 0x00; /* Minor - LSB */ cmd.data[28] = 0x00; /* Minor - MSB */ cmd.data[29] = 0xc5; /* TX power level */ cmd.data[30] = 0x00; /* Field terminator */ cmd.len = 1 + cmd.data[0] + 1 + cmd.data[3]; bt_hci_send(hci_dev, BT_HCI_CMD_LE_SET_ADV_DATA, &cmd, sizeof(cmd), adv_data_callback, NULL, NULL); }
static void test_create_connection(const void *test_data) { struct user_data *user = tester_get_data(); struct bt_hci_cmd_create_conn cmd; bt_hci_register(user->hci_ut, BT_HCI_EVT_CONN_COMPLETE, test_create_connection_complete, NULL, NULL); memcpy(cmd.bdaddr, user->bdaddr_lt, 6); cmd.pkt_type = cpu_to_le16(0x0008); cmd.pscan_rep_mode = 0x02; cmd.pscan_mode = 0x00; cmd.clock_offset = cpu_to_le16(0x0000); cmd.role_switch = 0x01; if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_CREATE_CONN, &cmd, sizeof(cmd), test_create_connection_status, NULL, NULL)) { tester_warn("Failed to send HCI create connection command"); tester_test_failed(); return; } }
static void test_le_generate_dhkey(const void *test_data) { struct user_data *user = tester_get_data(); struct bt_hci_cmd_le_generate_dhkey cmd; struct le_keys *keys = (void *)test_data; ecc_make_key(cmd.remote_pk256, keys->remote_sk); /* Unregister handler for META event */ bt_hci_unregister(user->hci_ut, 1); bt_hci_register(user->hci_ut, BT_HCI_EVT_LE_META_EVENT, test_le_generate_dhkey_complete, keys, NULL); if (!bt_hci_send(user->hci_ut, BT_HCI_CMD_LE_GENERATE_DHKEY, &cmd, sizeof(cmd), test_le_generate_dhkey_status, NULL, NULL)) { tester_warn("Failed to send HCI LE Encrypt command"); tester_test_failed(); return; } }
static void read_index_list(uint8_t status, uint16_t len, const void *param, void *user_data) { const struct mgmt_rp_read_index_list *rp = param; uint16_t count; int i; if (status) { fprintf(stderr, "Reading index list failed: %s\n", mgmt_errstr(status)); mainloop_exit_failure(); return; } count = le16_to_cpu(rp->num_controllers); if (count < 2) { fprintf(stderr, "At least 2 controllers are required\n"); mainloop_exit_failure(); return; } for (i = 0; i < count; i++) { uint16_t index = cpu_to_le16(rp->index[i]); if (index < index1) index1 = index; } for (i = 0; i < count; i++) { uint16_t index = cpu_to_le16(rp->index[i]); if (index < index2 && index > index1) index2 = index; } printf("Selecting index %u for advertiser\n", index1); printf("Selecting index %u for scanner\n", index2); crypto = bt_crypto_new(); if (!crypto) { fprintf(stderr, "Failed to open crypto interface\n"); mainloop_exit_failure(); return; } adv_dev = bt_hci_new_user_channel(index1); if (!adv_dev) { fprintf(stderr, "Failed to open HCI for advertiser\n"); mainloop_exit_failure(); return; } scan_dev = bt_hci_new_user_channel(index2); if (!scan_dev) { fprintf(stderr, "Failed to open HCI for scanner\n"); mainloop_exit_failure(); return; } bt_hci_register(scan_dev, BT_HCI_EVT_LE_META_EVENT, scan_le_meta_event, NULL, NULL); bt_hci_send(scan_dev, BT_HCI_CMD_RESET, NULL, 0, NULL, NULL, NULL); bt_hci_send(scan_dev, BT_HCI_CMD_READ_LOCAL_FEATURES, NULL, 0, scan_features_callback, NULL, NULL); }
static void local_features_callback(const void *data, uint8_t size, void *user_data) { bt_hci_send(hci_dev, BT_HCI_CMD_READ_LOCAL_COMMANDS, NULL, 0, local_commands_callback, NULL, NULL); }