static void setup_powered_client(const void *test_data) { struct test_data *data = tester_get_data(); unsigned char param[] = { 0x01 }; tester_print("Powering on controller"); mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index, sizeof(param), param, NULL, NULL, NULL); mgmt_send(data->mgmt, MGMT_OP_SET_PAIRABLE, data->mgmt_index, sizeof(param), param, NULL, NULL, NULL); mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index, sizeof(param), param, setup_powered_client_callback, NULL, NULL); }
static void test_client(const void *test_data) { struct test_data *data = tester_get_data(); const struct smp_data *smp = data->test_data; struct mgmt_cp_pair_device cp; struct bthost *bthost; init_bdaddr(data); bthost = hciemu_client_get_host(data->hciemu); bthost_set_connect_cb(bthost, smp_new_conn, data); test_add_condition(data); if (smp->expect_hci_command) { tester_print("Registering HCI command callback"); hciemu_add_master_post_command_hook(data->hciemu, command_hci_callback, data); test_add_condition(data); } memcpy(&cp.addr.bdaddr, data->ra, sizeof(data->ra)); cp.addr.type = BDADDR_LE_PUBLIC; if (smp->mitm) cp.io_cap = 0x04; /* KeyboardDisplay */ else cp.io_cap = 0x03; /* NoInputNoOutput */ mgmt_send(data->mgmt, MGMT_OP_PAIR_DEVICE, data->mgmt_index, sizeof(cp), &cp, pair_device_complete, NULL, NULL); tester_print("Pairing in progress"); }
struct bt_gap *bt_gap_new(void) { struct bt_gap *gap; gap = new0(struct bt_gap, 1); if (!gap) return NULL; gap->mgmt = mgmt_new_default(); if (!gap->mgmt) { free(gap); return NULL; } gap->mgmt_ready = false; if (!mgmt_send(gap->mgmt, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE, 0, NULL, read_version_complete, gap, NULL)) { mgmt_unref(gap->mgmt); return NULL; } return bt_gap_ref(gap); }
static struct btd_advertising * advertising_manager_create(struct btd_adapter *adapter) { struct btd_advertising *manager; manager = new0(struct btd_advertising, 1); if (!manager) return NULL; manager->adapter = adapter; manager->mgmt = mgmt_new_default(); if (!manager->mgmt) { error("Failed to access management interface"); free(manager); return NULL; } manager->mgmt_index = btd_adapter_get_index(adapter); if (!mgmt_send(manager->mgmt, MGMT_OP_READ_ADV_FEATURES, manager->mgmt_index, 0, NULL, read_adv_features_callback, manager, NULL)) { error("Failed to read advertising features"); advertising_manager_destroy(manager); return NULL; } manager->ads = queue_new(); return manager; }
static void cmd_discoverable(int argcp, char **argvp) { struct mgmt_cp_set_discoverable cp = {0, 0}; uint16_t opcode = MGMT_OP_SET_DISCOVERABLE; if (argcp < 2) { resp_mgmt(err_BAD_PARAM); return; } if (!on_or_off(argvp[1], &cp.val)) { resp_mgmt(err_BAD_PARAM); return; } if (!mgmt_master) { resp_error(err_NO_MGMT); return; } if (mgmt_send(mgmt_master, opcode, opt_src_idx, sizeof(cp), &cp, set_mode_complete, NULL, NULL) == 0) { DBG("mgmt_send(MGMT_OP_SET_DISCOVERABLE) failed"); resp_mgmt(err_PROTO_ERR); return; } }
struct bt_gap *bt_gap_new_index(uint16_t index) { struct bt_gap *gap; if (index == MGMT_INDEX_NONE) return NULL; gap = new0(struct bt_gap, 1); gap->index = index; gap->mgmt = mgmt_new_default(); if (!gap->mgmt) { free(gap); return NULL; } gap->irk_list = queue_new(); gap->mgmt_ready = false; if (!mgmt_send(gap->mgmt, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE, 0, NULL, read_version_complete, gap, NULL)) { mgmt_unref(gap->mgmt); return NULL; } return bt_gap_ref(gap); }
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 bool set_mode_with_cb(uint16_t opcode, char *p_mode, mgmt_request_func_t callback) { struct mgmt_mode cp; uintptr_t user_data; memset(&cp, 0, sizeof(cp)); if (!on_or_off(p_mode, &cp.val)) return false; /* Save the configured value in the user_data */ if (cp.val) user_data = 1; else user_data = 0; if (!mgmt_master) { resp_error(err_NO_MGMT); return true; } if (mgmt_send(mgmt_master, opcode, opt_src_idx, sizeof(cp), &cp, callback, (void *)user_data, NULL) == 0) { resp_mgmt(err_SUCCESS); } return true; }
static void read_version_complete(uint8_t status, uint16_t length, const void *param, void *user_data) { struct bt_gap *gap = user_data; const struct mgmt_rp_read_version *rp = param; if (status != MGMT_STATUS_SUCCESS) { ready_status(gap, false); return; } if (length < sizeof(*rp)) { ready_status(gap, false); return; } gap->mgmt_version = rp->version; gap->mgmt_revision = le16_to_cpu(rp->revision); if (!mgmt_send(gap->mgmt, MGMT_OP_READ_COMMANDS, MGMT_INDEX_NONE, 0, NULL, read_commands_complete, gap, NULL)) { ready_status(gap, false); return; } }
static DBusMessage *refresh_advertisement(struct advertisement *ad) { struct mgmt_cp_add_advertising *cp; uint8_t param_len; uint8_t *adv_data; size_t adv_data_len; uint32_t flags = 0; DBG("Refreshing advertisement: %s", ad->path); if (ad->type == AD_TYPE_PERIPHERAL) flags = MGMT_ADV_FLAG_CONNECTABLE | MGMT_ADV_FLAG_DISCOV; if (ad->include_tx_power) flags |= MGMT_ADV_FLAG_TX_POWER; adv_data = bt_ad_generate(ad->data, &adv_data_len); if (!adv_data || (adv_data_len > calc_max_adv_len(ad, flags))) { error("Advertising data too long or couldn't be generated."); return g_dbus_create_error(ad->reg, ERROR_INTERFACE ".InvalidLength", "Advertising data too long."); } param_len = sizeof(struct mgmt_cp_add_advertising) + adv_data_len; cp = malloc0(param_len); if (!cp) { error("Couldn't allocate for MGMT!"); free(adv_data); return btd_error_failed(ad->reg, "Failed"); } cp->flags = flags; cp->instance = ad->instance; cp->adv_data_len = adv_data_len; memcpy(cp->data, adv_data, adv_data_len); free(adv_data); if (!mgmt_send(ad->manager->mgmt, MGMT_OP_ADD_ADVERTISING, ad->manager->mgmt_index, param_len, cp, add_advertising_callback, ad, NULL)) { error("Failed to add Advertising Data"); free(cp); return btd_error_failed(ad->reg, "Failed"); } free(cp); return NULL; }
static void setup_powered_client(const void *test_data) { struct test_data *data = tester_get_data(); unsigned char param[] = { 0x01 }; tester_print("Powering on controller"); if (data->hciemu_type == HCIEMU_TYPE_BREDR) mgmt_send(data->mgmt, MGMT_OP_SET_SSP, data->mgmt_index, sizeof(param), param, NULL, NULL, NULL); else mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index, sizeof(param), param, NULL, NULL, NULL); mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index, sizeof(param), param, setup_powered_client_callback, NULL, NULL); }
int main(int argc ,char *argv[]) { int exit_status; for (;;) { int opt; opt = getopt_long(argc, argv, "vh", main_options, NULL); if (opt < 0) break; switch (opt) { case 'v': printf("%s\n", VERSION); return EXIT_SUCCESS; case 'h': usage(); return EXIT_SUCCESS; default: return EXIT_FAILURE; } } if (argc - optind > 0) { fprintf(stderr, "Invalid command line parameters\n"); return EXIT_FAILURE; } mainloop_init(); mgmt = mgmt_new_default(); if (!mgmt) { fprintf(stderr, "Failed to open management socket\n"); return EXIT_FAILURE; } if (!mgmt_send(mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL, read_index_list, NULL, NULL)) { fprintf(stderr, "Failed to read index list\n"); exit_status = EXIT_FAILURE; goto done; } exit_status = mainloop_run_with_signal(signal_callback, NULL); bt_hci_unref(adv_dev); bt_hci_unref(scan_dev); bt_crypto_unref(crypto); done: mgmt_unref(mgmt); return exit_status; }
static void setup_powered_server(const void *test_data) { struct test_data *data = tester_get_data(); unsigned char param[] = { 0x01 }; setup_powered_common(); tester_print("Powering on controller"); mgmt_send(data->mgmt, MGMT_OP_SET_CONNECTABLE, data->mgmt_index, sizeof(param), param, NULL, NULL, NULL); if (data->hciemu_type != HCIEMU_TYPE_BREDR) mgmt_send(data->mgmt, MGMT_OP_SET_ADVERTISING, data->mgmt_index, sizeof(param), param, NULL, NULL, NULL); mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index, sizeof(param), param, setup_powered_server_callback, NULL, NULL); }
static void setup_powered_server(const void *test_data) { struct test_data *data = tester_get_data(); const struct smp_data *smp = data->test_data; unsigned char param[] = { 0x01 }; mgmt_register(data->mgmt, MGMT_EV_USER_CONFIRM_REQUEST, data->mgmt_index, user_confirm_request_callback, data, NULL); tester_print("Powering on controller"); mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index, sizeof(param), param, NULL, NULL, NULL); mgmt_send(data->mgmt, MGMT_OP_SET_BONDABLE, data->mgmt_index, sizeof(param), param, NULL, NULL, NULL); mgmt_send(data->mgmt, MGMT_OP_SET_CONNECTABLE, data->mgmt_index, sizeof(param), param, NULL, NULL, NULL); mgmt_send(data->mgmt, MGMT_OP_SET_ADVERTISING, data->mgmt_index, sizeof(param), param, NULL, NULL, NULL); if (smp->sc) { mgmt_send(data->mgmt, MGMT_OP_SET_SECURE_CONN, data->mgmt_index, sizeof(param), param, NULL, NULL, NULL); make_pk(data); } mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index, sizeof(param), param, setup_powered_server_callback, NULL, NULL); }
static void index_added_callback(uint16_t index, uint16_t length, const void *param, void *user_data) { struct test_data *data = tester_get_data(); tester_print("Index Added callback"); tester_print(" Index: 0x%04x", index); data->mgmt_index = index; mgmt_send(data->mgmt, MGMT_OP_READ_INFO, data->mgmt_index, 0, NULL, read_info_callback, NULL, NULL); }
static void toggle_powered(const void *test_data) { struct test_data *data = tester_get_data(); bool power = PTR_TO_INT(test_data); unsigned char param[1]; param[0] = power ? 0x01 : 0x00; tester_print("Powering %s controller", power ? "on" : "off"); mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index, sizeof(param), param, toggle_powered_client_callback, INT_TO_PTR(power), NULL); }
static void setup_powered_common(void) { struct test_data *data = tester_get_data(); const struct l2cap_data *test = data->test_data; struct bthost *bthost = hciemu_client_get_host(data->hciemu); unsigned char param[] = { 0x01 }; mgmt_register(data->mgmt, MGMT_EV_USER_CONFIRM_REQUEST, data->mgmt_index, user_confirm_request_callback, NULL, NULL); if (test && (test->pin || test->expect_pin)) mgmt_register(data->mgmt, MGMT_EV_PIN_CODE_REQUEST, data->mgmt_index, pin_code_request_callback, data, NULL); if (test && test->client_io_cap) bthost_set_io_capability(bthost, test->client_io_cap); if (test && test->client_pin) bthost_set_pin_code(bthost, test->client_pin, test->client_pin_len); if (test && test->reject_ssp) bthost_set_reject_user_confirm(bthost, true); if (data->hciemu_type == HCIEMU_TYPE_LE) mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index, sizeof(param), param, NULL, NULL, NULL); if (test && test->enable_ssp) mgmt_send(data->mgmt, MGMT_OP_SET_SSP, data->mgmt_index, sizeof(param), param, NULL, NULL, NULL); mgmt_send(data->mgmt, MGMT_OP_SET_BONDABLE, data->mgmt_index, sizeof(param), param, NULL, NULL, NULL); }
static void setup_powered_client(const void *test_data) { struct test_data *data = tester_get_data(); const struct l2cap_data *test = data->test_data; unsigned char param[] = { 0x01 }; setup_powered_common(); tester_print("Powering on controller"); if (test && (test->expect_cmd || test->send_cmd)) { struct bthost *bthost = hciemu_client_get_host(data->hciemu); bthost_set_connect_cb(bthost, send_rsp_new_conn, data); } if (test && test->direct_advertising) mgmt_send(data->mgmt, MGMT_OP_SET_ADVERTISING, data->mgmt_index, sizeof(param), param, NULL, NULL, NULL); mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index, sizeof(param), param, setup_powered_client_callback, NULL, NULL); }
static void test_pre_setup(const void *data) { struct test_data *test_data = tester_get_data(); if (!tester_use_debug()) fclose(stderr); test_data->mgmt = mgmt_new_default(); if (!test_data->mgmt) { tester_warn("Failed to setup management interface"); tester_pre_setup_failed(); return; } mgmt_send(test_data->mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL, read_index_list_callback, NULL, NULL); }
static void cmd_settings(int argcp, char **argvp) { if (1 < argcp) { resp_mgmt(err_BAD_PARAM); } if (!mgmt_master) { resp_error(err_NO_MGMT); return; } if (mgmt_send(mgmt_master, MGMT_OP_READ_INFO, opt_src_idx, 0, NULL, read_info_complete, NULL, NULL) == 0) { DBG("mgmt_send(MGMT_OP_READ_INFO) failed"); resp_mgmt(err_PROTO_ERR); } }
static void advertisement_remove(void *data) { struct advertisement *ad = data; struct mgmt_cp_remove_advertising cp; g_dbus_client_set_disconnect_watch(ad->client, NULL, NULL); cp.instance = ad->instance; mgmt_send(ad->manager->mgmt, MGMT_OP_REMOVE_ADVERTISING, ad->manager->mgmt_index, sizeof(cp), &cp, NULL, NULL, NULL); queue_remove(ad->manager->ads, ad); util_clear_uid(&ad->manager->instance_bitmap, ad->instance); g_idle_add(advertisement_free_idle_cb, ad); }
// Unlike Bluez, we follow BT 4.0 spec which renammed Device Discovery by Scan static void scan(bool start) { // mgmt_cp_start_discovery and mgmt_cp_stop_discovery are the same struct mgmt_cp_start_discovery cp = { (1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM) }; uint16_t opcode = start? MGMT_OP_START_DISCOVERY : MGMT_OP_STOP_DISCOVERY; DBG("Scan %s", start? "start" : "stop"); if (!mgmt_master) { resp_error(err_NO_MGMT); return; } if (mgmt_send(mgmt_master, opcode, opt_src_idx, sizeof(cp), &cp, scan_cb, NULL, NULL) == 0) { DBG("mgmt_send(MGMT_OP_%s_DISCOVERY) failed", start? "START" : "STOP"); resp_mgmt(err_PROTO_ERR); return; } }
static void cmd_pair(int argcp, char **argvp) { struct mgmt_cp_pair_device cp; bdaddr_t bdaddr; uint8_t io_cap = IO_CAPABILITY_NOINPUTNOOUTPUT; uint8_t addr_type = BDADDR_LE_RANDOM; if (conn_state != STATE_CONNECTED) { resp_mgmt(err_BAD_STATE); return; } if (str2ba(opt_dst, &bdaddr)) { resp_mgmt(err_NOT_FOUND); return; } if (!memcmp(opt_dst_type, "public", 6)) { addr_type = BDADDR_LE_PUBLIC; } memset(&cp, 0, sizeof(cp)); bacpy(&cp.addr.bdaddr, &bdaddr); cp.addr.type = addr_type; cp.io_cap = io_cap; if (!mgmt_master) { resp_error(err_NO_MGMT); return; } if (mgmt_send(mgmt_master, MGMT_OP_PAIR_DEVICE, opt_src_idx, sizeof(cp), &cp, pair_device_complete, NULL, NULL) == 0) { DBG("mgmt_send(MGMT_OP_PAIR_DEVICE) failed for %s for hci%u", opt_dst, MGMT_INDEX_NONE); resp_mgmt(err_PROTO_ERR); return; } }
static void cmd_unpair(int argcp, char **argvp) { struct mgmt_cp_unpair_device cp; bdaddr_t bdaddr; uint8_t addr_type = BDADDR_LE_RANDOM; if (argcp != 3) { resp_mgmt(err_BAD_PARAM); return; } if (str2ba(argvp[1], &bdaddr)) { DBG("str2ba failed"); resp_mgmt(err_NOT_FOUND); return; } if (!memcmp(argvp[2], "public", 6)) { addr_type = BDADDR_LE_PUBLIC; } memset(&cp, 0, sizeof(cp)); bacpy(&cp.addr.bdaddr, &bdaddr); cp.addr.type = addr_type; cp.disconnect = 1; if (!mgmt_master) { resp_error(err_NO_MGMT); return; } if (mgmt_send(mgmt_master, MGMT_OP_UNPAIR_DEVICE, opt_src_idx, sizeof(cp), &cp, unpair_device_complete, NULL, NULL) == 0) { DBG("mgmt_send(MGMT_OP_UNPAIR_DEVICE) failed for %s for hci%u", opt_dst, MGMT_INDEX_NONE); resp_mgmt(err_PROTO_ERR); return; } }
static void mgmt_setup(void) { mgmt_master = mgmt_new_default(); if (!mgmt_master) { DBG("Could not connect to the BT management interface, try with su rights"); } else { mgmt_set_debug(mgmt_master, mgmt_debug, "mgmt: ", NULL); /* For READ_VERSION, it is mandatory to use INDEX_NONE */ if (!mgmt_send(mgmt_master, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE, 0, NULL, read_version_complete, NULL, NULL)) { DBG("mgmt_send(MGMT_OP_READ_VERSION) failed"); } if (!mgmt_register(mgmt_master, MGMT_EV_DEVICE_CONNECTED, opt_src_idx, mgmt_device_connected, NULL, NULL)) { DBG("mgmt_register(MGMT_EV_DEVICE_CONNECTED) failed"); } if (!mgmt_register(mgmt_master, MGMT_EV_DEVICE_DISCONNECTED, opt_src_idx, mgmt_device_disconnected, NULL, NULL)) { DBG("mgmt_register(MGMT_EV_DEVICE_DISCONNECTED) failed"); } if (!mgmt_register(mgmt_master, MGMT_EV_DISCOVERING, opt_src_idx, mgmt_scanning, NULL, NULL)) { DBG("mgmt_register(MGMT_EV_DISCOVERING) failed"); } if (!mgmt_register(mgmt_master, MGMT_EV_DEVICE_FOUND, opt_src_idx, mgmt_device_found, NULL, NULL)) { DBG("mgmt_register(MGMT_EV_DEVICE_FOUND) failed"); } } }