Return-Path: MIME-Version: 1.0 In-Reply-To: <1524578447-17347-8-git-send-email-jaganathx.kanakkassery@intel.com> References: <1524578447-17347-1-git-send-email-jaganathx.kanakkassery@intel.com> <1524578447-17347-8-git-send-email-jaganathx.kanakkassery@intel.com> From: Luiz Augusto von Dentz Date: Wed, 13 Jun 2018 11:19:36 +0300 Message-ID: Subject: Re: [PATCH BlueZ v2 07/11] emulator: Add 5.0 feature support To: Jaganath Kanakkassery Cc: "linux-bluetooth@vger.kernel.org" , Jaganath Kanakkassery Content-Type: text/plain; charset="UTF-8" Sender: linux-bluetooth-owner@vger.kernel.org List-ID: Hi Jaganath, On Tue, Apr 24, 2018 at 5:00 PM, Jaganath Kanakkassery wrote: > This adds new hciemu for BT 5.0. Also adds extended advertising, > scanning and connection support in btdev and bthost > --- > emulator/btdev.c | 458 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- > emulator/btdev.h | 1 + > emulator/bthost.c | 99 ++++++++++++ > emulator/bthost.h | 7 + > emulator/hciemu.c | 3 + > emulator/hciemu.h | 1 + > monitor/bt.h | 1 + > 7 files changed, 560 insertions(+), 10 deletions(-) > > diff --git a/emulator/btdev.c b/emulator/btdev.c > index 69d84a5..c2859a6 100644 > --- a/emulator/btdev.c > +++ b/emulator/btdev.c > @@ -145,6 +145,8 @@ struct btdev { > uint16_t sync_train_interval; > uint32_t sync_train_timeout; > uint8_t sync_train_service_data; > + > + uint16_t le_ext_adv_type; > }; > > struct inquiry_data { > @@ -469,6 +471,34 @@ static void set_bredrle_commands(struct btdev *btdev) > btdev->commands[32] |= 0x40; /* Read Local OOB Extended Data */ > } > > +static void set_bredrle50_commands(struct btdev *btdev) > +{ > + set_bredrle_commands(btdev); > + > + btdev->commands[36] |= 0x02; /* LE Set Advertising Set Random Address */ > + btdev->commands[36] |= 0x04; /* LE Set Extended Advertising Parameters */ > + btdev->commands[36] |= 0x08; /* LE Set Extended Advertising Data */ > + btdev->commands[36] |= 0x10; /* LE Set Extended Scan Response Data */ > + btdev->commands[36] |= 0x20; /* LE Set Extended Advertising Enable */ > + btdev->commands[36] |= 0x40; /* LE Read Maximum Advertising Data Length */ > + btdev->commands[36] |= 0x80; /* LE Read Number of Supported Advertising Sets */ > + btdev->commands[37] |= 0x01; /* LE Remove Advertising Set */ > + btdev->commands[37] |= 0x02; /* LE Clear Advertising Sets */ > + btdev->commands[37] |= 0x04; /* LE Set Periodic Advertising Parameters */ > + btdev->commands[37] |= 0x08; /* LE Set Periodic Advertising Data */ > + btdev->commands[37] |= 0x10; /* LE Set Periodic Advertising Enable */ > + btdev->commands[37] |= 0x20; /* LE Set Extended Scan Parameters */ > + btdev->commands[37] |= 0x40; /* LE Set Extended Scan Enable */ > + btdev->commands[37] |= 0x80; /* LE Extended Create Connection */ > + btdev->commands[38] |= 0x01; /* LE Periodic Advertising Create Sync */ > + btdev->commands[38] |= 0x02; /* LE Periodic Advertising Create Sync Cancel */ > + btdev->commands[38] |= 0x04; /* LE Periodic Advertising Terminate Sync */ > + btdev->commands[38] |= 0x08; /* LE Add Device To Periodic Advertiser List */ > + btdev->commands[38] |= 0x10; /* LE Remove Device From Periodic Advertiser List */ > + btdev->commands[38] |= 0x20; /* LE Clear Periodic Advertiser List */ > + btdev->commands[38] |= 0x40; /* LE Read Periodic Advertiser List Size */ > +} > + > static void set_amp_commands(struct btdev *btdev) > { > set_common_commands_all(btdev); > @@ -570,6 +600,15 @@ static void set_le_features(struct btdev *btdev) > btdev->le_features[0] |= 0x08; /* Slave-initiated Features Exchange */ > } > > +static void set_bredrle50_features(struct btdev *btdev) > +{ > + set_bredrle_features(btdev); > + > + btdev->le_features[1] |= 0x01; /* LE 2M PHY */ > + btdev->le_features[1] |= 0x08; /* LE Coded PHY */ > + btdev->le_features[1] |= 0x10; /* LE EXT ADV */ I wouldn't add a different type for these features, at least not 2M and EXT Adv which Id expect to be common. > +} > + > static void set_le_states(struct btdev *btdev) > { > /* Set all 41 bits as per Bluetooth 5.0 specification */ > @@ -596,7 +635,8 @@ struct btdev *btdev_create(enum btdev_type type, uint16_t id) > > memset(btdev, 0, sizeof(*btdev)); > > - if (type == BTDEV_TYPE_BREDRLE || type == BTDEV_TYPE_LE) { > + if (type == BTDEV_TYPE_BREDRLE || type == BTDEV_TYPE_LE > + || BTDEV_TYPE_BREDRLE50) { > btdev->crypto = bt_crypto_new(); > if (!btdev->crypto) { > free(btdev); > @@ -637,6 +677,12 @@ struct btdev *btdev_create(enum btdev_type type, uint16_t id) > set_bredr20_features(btdev); > set_bredr20_commands(btdev); > break; > + case BTDEV_TYPE_BREDRLE50: > + btdev->version = 0x05; > + set_bredrle50_features(btdev); > + set_bredrle50_commands(btdev); > + set_le_states(btdev); > + break; > } > > btdev->page_scan_interval = 0x0800; > @@ -1174,6 +1220,53 @@ static void le_conn_complete(struct btdev *btdev, > send_event(btdev, BT_HCI_EVT_LE_META_EVENT, buf, sizeof(buf)); > } > > +static void le_ext_conn_complete(struct btdev *btdev, > + const struct bt_hci_cmd_le_ext_create_conn *leecc, > + uint8_t status) > +{ > + char buf[1 + sizeof(struct bt_hci_evt_le_enhanced_conn_complete)]; > + struct bt_hci_evt_le_enhanced_conn_complete *cc = (void *) &buf[1]; > + struct bt_hci_le_ext_create_conn *lecc = (void *)leecc->data; > + > + memset(buf, 0, sizeof(buf)); > + > + buf[0] = BT_HCI_EVT_LE_ENHANCED_CONN_COMPLETE; > + > + if (!status) { > + struct btdev *remote; > + > + remote = find_btdev_by_bdaddr_type(leecc->peer_addr, > + leecc->peer_addr_type); > + > + btdev->conn = remote; > + btdev->le_adv_enable = 0; > + remote->conn = btdev; > + remote->le_adv_enable = 0; > + > + cc->status = status; > + cc->peer_addr_type = btdev->le_scan_own_addr_type; > + if (cc->peer_addr_type == 0x01) > + memcpy(cc->peer_addr, btdev->random_addr, 6); > + else > + memcpy(cc->peer_addr, btdev->bdaddr, 6); > + > + cc->role = 0x01; > + cc->handle = cpu_to_le16(42); > + cc->interval = lecc->max_interval; > + cc->latency = lecc->latency; > + cc->supv_timeout = lecc->supv_timeout; > + > + send_event(remote, BT_HCI_EVT_LE_META_EVENT, buf, sizeof(buf)); > + } > + > + cc->status = status; > + cc->peer_addr_type = leecc->peer_addr_type; > + memcpy(cc->peer_addr, leecc->peer_addr, 6); > + cc->role = 0x00; > + > + send_event(btdev, BT_HCI_EVT_LE_META_EVENT, buf, sizeof(buf)); > +} > + > static const uint8_t *scan_addr(const struct btdev *btdev) > { > if (btdev->le_scan_own_addr_type == 0x01) > @@ -1202,6 +1295,18 @@ static bool adv_match(struct btdev *scan, struct btdev *adv) > return !memcmp(scan_addr(scan), adv->le_adv_direct_addr, 6); > } > > +static bool ext_adv_match(struct btdev *scan, struct btdev *adv) > +{ > + /* Match everything if this is not directed advertising */ > + if (!(adv->le_ext_adv_type & 0x04)) > + return true; > + > + if (scan->le_scan_own_addr_type != adv->le_adv_direct_addr_type) > + return false; > + > + return !memcmp(scan_addr(scan), adv->le_adv_direct_addr, 6); > +} > + > static bool adv_connectable(struct btdev *btdev) > { > if (!btdev->le_adv_enable) > @@ -1210,6 +1315,14 @@ static bool adv_connectable(struct btdev *btdev) > return btdev->le_adv_type != 0x03; > } > > +static bool ext_adv_connectable(struct btdev *btdev) > +{ > + if (!btdev->le_adv_enable) > + return false; > + > + return btdev->le_ext_adv_type & 0x01; > +} > + > static void le_conn_request(struct btdev *btdev, > const struct bt_hci_cmd_le_create_conn *lecc) > { > @@ -1224,6 +1337,20 @@ static void le_conn_request(struct btdev *btdev, > BT_HCI_ERR_CONN_FAILED_TO_ESTABLISH); > } > > +static void le_ext_conn_request(struct btdev *btdev, > + const struct bt_hci_cmd_le_ext_create_conn *leecc) > +{ > + struct btdev *remote = find_btdev_by_bdaddr_type(leecc->peer_addr, > + leecc->peer_addr_type); > + > + if (remote && ext_adv_connectable(remote) && ext_adv_match(btdev, remote) && > + remote->le_adv_own_addr == leecc->peer_addr_type) > + le_ext_conn_complete(btdev, leecc, 0); > + else > + le_ext_conn_complete(btdev, leecc, > + BT_HCI_ERR_CONN_FAILED_TO_ESTABLISH); > +} > + > static void conn_request(struct btdev *btdev, const uint8_t *bdaddr) > { > struct btdev *remote = find_btdev_by_bdaddr(bdaddr); > @@ -1851,6 +1978,47 @@ static void le_send_adv_report(struct btdev *btdev, const struct btdev *remote, > 1 + 10 + meta_event.lar.data_len + 1); > } > > +static void le_send_ext_adv_report(struct btdev *btdev, > + const struct btdev *remote, > + uint16_t type, bool is_scan_rsp) > +{ > + struct __packed { > + uint8_t subevent; > + uint8_t num_reports; > + union { > + struct bt_hci_le_ext_adv_report lear; > + uint8_t raw[24 + 31]; > + }; > + } meta_event; > + > + meta_event.subevent = BT_HCI_EVT_LE_EXT_ADV_REPORT; > + > + memset(&meta_event.lear, 0, sizeof(meta_event.lear)); > + meta_event.num_reports = 1; > + meta_event.lear.event_type = cpu_to_le16(type); > + meta_event.lear.addr_type = remote->le_adv_own_addr; > + memcpy(meta_event.lear.addr, adv_addr(remote), 6); > + meta_event.lear.rssi = 127; > + meta_event.lear.tx_power = 127; > + /* Right now we dont care about phy in adv report */ > + meta_event.lear.primary_phy = 0x01; > + meta_event.lear.secondary_phy = 0x01; > + > + /* Scan or advertising response */ > + if (is_scan_rsp) { > + meta_event.lear.data_len = remote->le_scan_data_len; > + memcpy(meta_event.lear.data, remote->le_scan_data, > + meta_event.lear.data_len); > + } else { > + meta_event.lear.data_len = remote->le_adv_data_len; > + memcpy(meta_event.lear.data, remote->le_adv_data, > + meta_event.lear.data_len); > + } > + > + send_event(btdev, BT_HCI_EVT_LE_META_EVENT, &meta_event, > + 1 + 1 + 24 + meta_event.lear.data_len); > +} > + > static uint8_t get_adv_report_type(uint8_t adv_type) > { > /* > @@ -1863,6 +2031,22 @@ static uint8_t get_adv_report_type(uint8_t adv_type) > return adv_type; > } > > +static uint8_t get_ext_adv_report_type(uint8_t ext_adv_type) > +{ > + /* If legacy bit is not set then just reset high duty cycle directed bit */ > + if (!(ext_adv_type & 0x10)) > + return (ext_adv_type & 0xf7); > + > + /* > + * Connectable low duty cycle directed advertising creates a > + * connectable directed advertising report type. > + */ > + if (ext_adv_type == 0x001d) > + return 0x0015; > + > + return ext_adv_type; > +} > + > static void le_set_adv_enable_complete(struct btdev *btdev) > { > uint8_t report_type; > @@ -1891,6 +2075,44 @@ static void le_set_adv_enable_complete(struct btdev *btdev) > } > } > > +static void le_set_ext_adv_enable_complete(struct btdev *btdev) > +{ > + uint16_t report_type; > + int i; > + > + report_type = get_ext_adv_report_type(btdev->le_ext_adv_type); > + > + for (i = 0; i < MAX_BTDEV_ENTRIES; i++) { > + if (!btdev_list[i] || btdev_list[i] == btdev) > + continue; > + > + if (!btdev_list[i]->le_scan_enable) > + continue; > + > + if (!ext_adv_match(btdev_list[i], btdev)) > + continue; > + > + le_send_ext_adv_report(btdev_list[i], btdev, report_type, false); > + > + if (btdev_list[i]->le_scan_type != 0x01) > + continue; > + > + /* if scannable bit is set the send scan response */ > + if (btdev->le_ext_adv_type & 0x02) { > + if (btdev->le_ext_adv_type == 0x13) > + report_type = 0x1b; > + else if (btdev->le_ext_adv_type == 0x12) > + report_type = 0x1a; > + else if (!(btdev->le_ext_adv_type & 0x10)) > + report_type &= 0x08; > + else > + continue; > + > + le_send_ext_adv_report(btdev_list[i], btdev, report_type, true); > + } > + } > +} > + > static void le_set_scan_enable_complete(struct btdev *btdev) > { > int i; > @@ -1920,6 +2142,44 @@ static void le_set_scan_enable_complete(struct btdev *btdev) > } > } > > +static void le_set_ext_scan_enable_complete(struct btdev *btdev) > +{ > + int i; > + > + for (i = 0; i < MAX_BTDEV_ENTRIES; i++) { > + uint16_t report_type; > + > + if (!btdev_list[i] || btdev_list[i] == btdev) > + continue; > + > + if (!btdev_list[i]->le_adv_enable) > + continue; > + > + if (!ext_adv_match(btdev, btdev_list[i])) > + continue; > + > + report_type = get_ext_adv_report_type(btdev_list[i]->le_ext_adv_type); > + le_send_ext_adv_report(btdev, btdev_list[i], report_type, false); > + > + if (btdev->le_scan_type != 0x01) > + continue; > + > + /* if scannable bit is set the send scan response */ > + if (btdev_list[i]->le_ext_adv_type & 0x02) { > + if (btdev_list[i]->le_ext_adv_type == 0x13) > + report_type = 0x1b; > + else if (btdev_list[i]->le_ext_adv_type == 0x12) > + report_type = 0x1a; > + else if (!(btdev_list[i]->le_ext_adv_type & 0x10)) > + report_type &= 0x08; > + else > + continue; > + > + le_send_ext_adv_report(btdev, btdev_list[i], report_type, true); > + } > + } > +} > + > static void le_read_remote_features_complete(struct btdev *btdev) > { > char buf[1 + sizeof(struct bt_hci_evt_le_remote_features_complete)]; > @@ -2086,6 +2346,15 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, > const struct bt_hci_cmd_read_local_amp_assoc *rlaa_cmd; > const struct bt_hci_cmd_read_rssi *rrssi; > const struct bt_hci_cmd_read_tx_power *rtxp; > + const struct bt_hci_cmd_le_set_adv_set_rand_addr *lsasra; > + const struct bt_hci_cmd_le_set_ext_adv_params *lseap; > + const struct bt_hci_cmd_le_set_ext_adv_enable *lseae; > + const struct bt_hci_cmd_le_set_ext_adv_data *lsead; > + const struct bt_hci_cmd_le_set_ext_scan_rsp_data *lsesrd; > + const struct bt_hci_cmd_le_set_default_phy *phys; > + const struct bt_hci_cmd_le_set_ext_scan_params *lsesp; > + const struct bt_hci_le_scan_phy *lsp; > + const struct bt_hci_cmd_le_set_ext_scan_enable *lsese; > struct bt_hci_rsp_read_default_link_policy rdlp; > struct bt_hci_rsp_read_stored_link_key rslk; > struct bt_hci_rsp_write_stored_link_key wslk; > @@ -2145,6 +2414,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, > struct bt_hci_rsp_read_tx_power rtxp_rsp; > struct bt_hci_evt_le_read_local_pk256_complete pk_evt; > struct bt_hci_evt_le_generate_dhkey_complete dh_evt; > + struct bt_hci_rsp_le_read_num_supported_adv_sets rlrnsas; > + struct bt_hci_rsp_le_set_ext_adv_params rlseap; > uint8_t status, page; > > switch (opcode) { > @@ -2679,7 +2950,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, > break; > > case BT_HCI_CMD_READ_LE_HOST_SUPPORTED: > - if (btdev->type != BTDEV_TYPE_BREDRLE) > + if (btdev->type != BTDEV_TYPE_BREDRLE && > + btdev->type != BTDEV_TYPE_BREDRLE50) > goto unsupported; > rlhs.status = BT_HCI_ERR_SUCCESS; > rlhs.supported = btdev->le_supported; > @@ -2688,7 +2960,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, > break; > > case BT_HCI_CMD_WRITE_LE_HOST_SUPPORTED: > - if (btdev->type != BTDEV_TYPE_BREDRLE) > + if (btdev->type != BTDEV_TYPE_BREDRLE && > + btdev->type != BTDEV_TYPE_BREDRLE50) > goto unsupported; > wlhs = data; > btdev->le_supported = wlhs->supported; > @@ -2698,7 +2971,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, > break; > > case BT_HCI_CMD_READ_SECURE_CONN_SUPPORT: > - if (btdev->type != BTDEV_TYPE_BREDRLE) > + if (btdev->type != BTDEV_TYPE_BREDRLE && > + btdev->type != BTDEV_TYPE_BREDRLE50) > goto unsupported; > rscs.status = BT_HCI_ERR_SUCCESS; > rscs.support = btdev->secure_conn_support; > @@ -2706,7 +2980,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, > break; > > case BT_HCI_CMD_WRITE_SECURE_CONN_SUPPORT: > - if (btdev->type != BTDEV_TYPE_BREDRLE) > + if (btdev->type != BTDEV_TYPE_BREDRLE && > + btdev->type != BTDEV_TYPE_BREDRLE50) > goto unsupported; > wscs = data; > btdev->secure_conn_support = wscs->support; > @@ -2715,14 +2990,16 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, > break; > > case BT_HCI_CMD_READ_LOCAL_OOB_EXT_DATA: > - if (btdev->type != BTDEV_TYPE_BREDRLE) > + if (btdev->type != BTDEV_TYPE_BREDRLE && > + btdev->type != BTDEV_TYPE_BREDRLE50) > goto unsupported; > rloed.status = BT_HCI_ERR_SUCCESS; > cmd_complete(btdev, opcode, &rloed, sizeof(rloed)); > break; > > case BT_HCI_CMD_READ_SYNC_TRAIN_PARAMS: > - if (btdev->type != BTDEV_TYPE_BREDRLE) > + if (btdev->type != BTDEV_TYPE_BREDRLE && > + btdev->type != BTDEV_TYPE_BREDRLE50) > goto unsupported; > rstp.status = BT_HCI_ERR_SUCCESS; > rstp.interval = cpu_to_le16(btdev->sync_train_interval); > @@ -2872,7 +3149,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, > > case BT_HCI_CMD_READ_ENCRYPT_KEY_SIZE: > if (btdev->type != BTDEV_TYPE_BREDRLE && > - btdev->type != BTDEV_TYPE_BREDR) > + btdev->type != BTDEV_TYPE_BREDR && > + btdev->type != BTDEV_TYPE_BREDRLE50) > goto unsupported; > reks = data; > read_enc_key_size_complete(btdev, le16_to_cpu(reks->handle)); > @@ -2918,7 +3196,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, > break; > > case BT_HCI_CMD_SET_EVENT_MASK_PAGE2: > - if (btdev->type != BTDEV_TYPE_BREDRLE) > + if (btdev->type != BTDEV_TYPE_BREDRLE && > + btdev->type != BTDEV_TYPE_BREDRLE50) > goto unsupported; > semp2 = data; > memcpy(btdev->event_mask_page2, semp2->mask, 8); > @@ -3245,6 +3524,149 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, > lcprnr_rsp.status = BT_HCI_ERR_SUCCESS; > cmd_complete(btdev, opcode, &lcprnr_rsp, sizeof(lcprnr_rsp)); > break; > + case BT_HCI_CMD_LE_READ_NUM_SUPPORTED_ADV_SETS: > + if (btdev->type != BTDEV_TYPE_BREDRLE50) > + goto unsupported; > + > + rlrnsas.status = BT_HCI_ERR_SUCCESS; > + /* Support one set as of now */ > + rlrnsas.num_of_sets = 1; > + cmd_complete(btdev, opcode, &rlrnsas, sizeof(rlrnsas)); > + break; > + case BT_HCI_CMD_LE_SET_ADV_SET_RAND_ADDR: > + if (btdev->type != BTDEV_TYPE_BREDRLE50) > + goto unsupported; > + > + lsasra = data; > + memcpy(btdev->random_addr, lsasra->bdaddr, 6); > + status = BT_HCI_ERR_SUCCESS; > + cmd_complete(btdev, opcode, &status, sizeof(status)); > + break; > + case BT_HCI_CMD_LE_SET_EXT_ADV_PARAMS: > + if (btdev->type != BTDEV_TYPE_BREDRLE50) > + goto unsupported; > + > + if (btdev->le_adv_enable) { > + status = BT_HCI_ERR_COMMAND_DISALLOWED; > + cmd_complete(btdev, opcode, &status, sizeof(status)); > + break; > + } > + > + lseap = data; > + btdev->le_ext_adv_type = le16_to_cpu(lseap->evt_properties); > + btdev->le_adv_own_addr = lseap->own_addr_type; > + btdev->le_adv_direct_addr_type = lseap->peer_addr_type; > + memcpy(btdev->le_adv_direct_addr, lseap->peer_addr, 6); > + > + rlseap.status = BT_HCI_ERR_SUCCESS; > + rlseap.tx_power = 0; > + cmd_complete(btdev, opcode, &rlseap, sizeof(rlseap)); > + break; > + case BT_HCI_CMD_LE_SET_EXT_ADV_ENABLE: > + if (btdev->type != BTDEV_TYPE_BREDRLE50) > + goto unsupported; > + > + lseae = data; > + if (btdev->le_adv_enable == lseae->enable) > + status = BT_HCI_ERR_COMMAND_DISALLOWED; > + else { > + btdev->le_adv_enable = lseae->enable; > + status = BT_HCI_ERR_SUCCESS; > + } > + cmd_complete(btdev, opcode, &status, sizeof(status)); > + if (status == BT_HCI_ERR_SUCCESS && btdev->le_adv_enable) > + le_set_ext_adv_enable_complete(btdev); > + break; > + case BT_HCI_CMD_LE_SET_EXT_ADV_DATA: > + if (btdev->type != BTDEV_TYPE_BREDRLE50) > + goto unsupported; > + > + lsead = data; > + btdev->le_adv_data_len = lsead->data_len; > + memcpy(btdev->le_adv_data, lsead->data, 31); > + status = BT_HCI_ERR_SUCCESS; > + cmd_complete(btdev, opcode, &status, sizeof(status)); > + break; > + case BT_HCI_CMD_LE_SET_EXT_SCAN_RSP_DATA: > + if (btdev->type != BTDEV_TYPE_BREDRLE50) > + goto unsupported; > + > + lsesrd = data; > + btdev->le_scan_data_len = lsesrd->data_len; > + memcpy(btdev->le_scan_data, lsesrd->data, 31); > + status = BT_HCI_ERR_SUCCESS; > + cmd_complete(btdev, opcode, &status, sizeof(status)); > + break; > + case BT_HCI_CMD_LE_REMOVE_ADV_SET: > + if (btdev->type != BTDEV_TYPE_BREDRLE50) > + goto unsupported; > + > + status = BT_HCI_ERR_SUCCESS; > + cmd_complete(btdev, opcode, &status, sizeof(status)); > + break; > + case BT_HCI_CMD_LE_CLEAR_ADV_SETS: > + if (btdev->type != BTDEV_TYPE_BREDRLE50) > + goto unsupported; > + > + status = BT_HCI_ERR_SUCCESS; > + cmd_complete(btdev, opcode, &status, sizeof(status)); > + break; > + case BT_HCI_CMD_LE_SET_DEFAULT_PHY: > + if (btdev->type == BTDEV_TYPE_BREDR) > + goto unsupported; > + phys = data; > + if (phys->all_phys > 0x03 || > + (!(phys->all_phys & 0x01) && > + (!phys->tx_phys || phys->tx_phys > 0x07)) || > + (!(phys->all_phys & 0x02) && > + (!phys->rx_phys || phys->rx_phys > 0x07))) > + status = BT_HCI_ERR_INVALID_PARAMETERS; > + else > + status = BT_HCI_ERR_SUCCESS; > + cmd_complete(btdev, opcode, &status, sizeof(status)); > + break; > + case BT_HCI_CMD_LE_SET_EXT_SCAN_PARAMS: > + if (btdev->type != BTDEV_TYPE_BREDRLE50) > + goto unsupported; > + > + lsesp = data; > + lsp = (void *)lsesp->data; > + > + if (btdev->le_scan_enable) > + status = BT_HCI_ERR_COMMAND_DISALLOWED; > + else if (lsesp->num_phys == 0) > + status = BT_HCI_ERR_INVALID_PARAMETERS; > + else { > + status = BT_HCI_ERR_SUCCESS; > + /* Currently we dont support multiple types in single command > + * So just take the first one will do. > + */ > + btdev->le_scan_type = lsp->type; > + btdev->le_scan_own_addr_type = lsesp->own_addr_type; > + } > + > + cmd_complete(btdev, opcode, &status, sizeof(status)); > + break; > + case BT_HCI_CMD_LE_SET_EXT_SCAN_ENABLE: > + if (btdev->type != BTDEV_TYPE_BREDRLE50) > + goto unsupported; > + > + lsese = data; > + if (btdev->le_scan_enable == lsese->enable) > + status = BT_HCI_ERR_COMMAND_DISALLOWED; > + else { > + btdev->le_scan_enable = lsese->enable; > + btdev->le_filter_dup = lsese->filter_dup; > + status = BT_HCI_ERR_SUCCESS; > + } > + cmd_complete(btdev, opcode, &status, sizeof(status)); > + break; > + case BT_HCI_CMD_LE_EXT_CREATE_CONN: > + if (btdev->type != BTDEV_TYPE_BREDRLE50) > + goto unsupported; > + > + cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode); > + break; > default: > goto unsupported; > } > @@ -3282,6 +3704,8 @@ static void default_cmd_completion(struct btdev *btdev, uint16_t opcode, > const struct bt_hci_cmd_le_conn_param_req_reply *lcprr; > const struct bt_hci_cmd_le_conn_param_req_neg_reply *lcprnr; > const struct bt_hci_cmd_le_set_scan_enable *lsse; > + const struct bt_hci_cmd_le_set_ext_scan_enable *lsese; > + const struct bt_hci_cmd_le_ext_create_conn *leecc; > > switch (opcode) { > case BT_HCI_CMD_INQUIRY: > @@ -3476,7 +3900,21 @@ static void default_cmd_completion(struct btdev *btdev, uint16_t opcode, > lsse = data; > if (btdev->le_scan_enable && lsse->enable) > le_set_scan_enable_complete(btdev); > - > + break; > + case BT_HCI_CMD_LE_SET_EXT_SCAN_ENABLE: > + if (btdev->type != BTDEV_TYPE_BREDRLE50) > + return; > + lsese = data; > + if (btdev->le_scan_enable && lsese->enable) > + le_set_ext_scan_enable_complete(btdev); > + break; > + case BT_HCI_CMD_LE_EXT_CREATE_CONN: > + if (btdev->type != BTDEV_TYPE_BREDRLE50) > + return; > + leecc = data; > + btdev->le_scan_own_addr_type = leecc->own_addr_type; > + le_ext_conn_request(btdev, leecc); > + break; > } > } > > diff --git a/emulator/btdev.h b/emulator/btdev.h > index ba06a10..362d1e7 100644 > --- a/emulator/btdev.h > +++ b/emulator/btdev.h > @@ -63,6 +63,7 @@ enum btdev_type { > BTDEV_TYPE_LE, > BTDEV_TYPE_AMP, > BTDEV_TYPE_BREDR20, > + BTDEV_TYPE_BREDRLE50, > }; > > enum btdev_hook_type { > diff --git a/emulator/bthost.c b/emulator/bthost.c > index 2bcdc31..d37957f 100644 > --- a/emulator/bthost.c > +++ b/emulator/bthost.c > @@ -839,6 +839,12 @@ static void evt_cmd_complete(struct bthost *bthost, const void *data, > break; > case BT_HCI_CMD_LE_SET_ADV_DATA: > break; > + case BT_HCI_CMD_LE_SET_EXT_ADV_PARAMS: > + break; > + case BT_HCI_CMD_LE_SET_EXT_ADV_DATA: > + break; > + case BT_HCI_CMD_LE_SET_EXT_ADV_ENABLE: > + break; > default: > printf("Unhandled cmd_complete opcode 0x%04x\n", opcode); > break; > @@ -1161,6 +1167,26 @@ static void evt_le_conn_complete(struct bthost *bthost, const void *data, > init_conn(bthost, le16_to_cpu(ev->handle), ev->peer_addr, addr_type); > } > > +static void evt_le_ext_conn_complete(struct bthost *bthost, const void *data, > + uint8_t len) > +{ > + const struct bt_hci_evt_le_enhanced_conn_complete *ev = data; > + uint8_t addr_type; > + > + if (len < sizeof(*ev)) > + return; > + > + if (ev->status) > + return; > + > + if (ev->peer_addr_type == 0x00) > + addr_type = BDADDR_LE_PUBLIC; > + else > + addr_type = BDADDR_LE_RANDOM; > + > + init_conn(bthost, le16_to_cpu(ev->handle), ev->peer_addr, addr_type); > +} > + > static void evt_le_conn_update_complete(struct bthost *bthost, const void *data, > uint8_t len) > { > @@ -1240,6 +1266,9 @@ static void evt_le_meta_event(struct bthost *bthost, const void *data, > case BT_HCI_EVT_LE_LONG_TERM_KEY_REQUEST: > evt_le_ltk_request(bthost, evt_data, len - 1); > break; > + case BT_HCI_EVT_LE_ENHANCED_CONN_COMPLETE: > + evt_le_ext_conn_complete(bthost, evt_data, len - 1); > + break; > default: > printf("Unsupported LE Meta event 0x%2.2x\n", *event); > break; > @@ -2269,6 +2298,38 @@ void bthost_hci_connect(struct bthost *bthost, const uint8_t *bdaddr, > } > } > > +void bthost_hci_ext_connect(struct bthost *bthost, const uint8_t *bdaddr, > + uint8_t addr_type) > +{ > + struct bt_hci_cmd_le_ext_create_conn *cc; > + struct bt_hci_le_ext_create_conn *cp; > + uint8_t buf[sizeof(*cc) + sizeof(*cp)]; > + > + cc = (void *)buf; > + cp = (void *)cc->data; > + > + bthost->conn_init = true; > + > + memset(cc, 0, sizeof(*cc)); > + memset(cp, 0, sizeof(*cp)); > + > + memcpy(cc->peer_addr, bdaddr, sizeof(cc->peer_addr)); > + > + if (addr_type == BDADDR_LE_RANDOM) > + cc->peer_addr_type = 0x01; > + > + cc->phys = 0x01; > + > + cp->scan_interval = cpu_to_le16(0x0060); > + cp->scan_window = cpu_to_le16(0x0030); > + cp->min_interval = cpu_to_le16(0x0028); > + cp->max_interval = cpu_to_le16(0x0038); > + cp->supv_timeout = cpu_to_le16(0x002a); > + > + send_command(bthost, BT_HCI_CMD_LE_EXT_CREATE_CONN, > + buf, sizeof(buf)); > +} > + > void bthost_hci_disconnect(struct bthost *bthost, uint16_t handle, > uint8_t reason) > { > @@ -2301,6 +2362,29 @@ void bthost_set_adv_data(struct bthost *bthost, const uint8_t *data, > sizeof(adv_cp)); > } > > +void bthost_set_ext_adv_data(struct bthost *bthost, const uint8_t *data, > + uint8_t len) > +{ > + struct bt_hci_cmd_le_set_ext_adv_data *adv_cp; > + uint8_t buf[sizeof(*adv_cp) + 31]; > + > + adv_cp = (void *)buf; > + > + memset(adv_cp, 0, sizeof(*adv_cp)); > + memset(adv_cp->data, 0, 31); > + > + adv_cp->operation = 0x03; > + adv_cp->fragment_preference = 0x01; > + > + if (len) { > + adv_cp->data_len = len; > + memcpy(adv_cp->data, data, len); > + } > + > + send_command(bthost, BT_HCI_CMD_LE_SET_EXT_ADV_DATA, buf, > + sizeof(buf)); > +} > + > void bthost_set_adv_enable(struct bthost *bthost, uint8_t enable) > { > struct bt_hci_cmd_le_set_adv_parameters cp; > @@ -2312,6 +2396,21 @@ void bthost_set_adv_enable(struct bthost *bthost, uint8_t enable) > send_command(bthost, BT_HCI_CMD_LE_SET_ADV_ENABLE, &enable, 1); > } > > +void bthost_set_ext_adv_enable(struct bthost *bthost, uint8_t enable) > +{ > + struct bt_hci_cmd_le_set_ext_adv_params cp; > + struct bt_hci_cmd_le_set_ext_adv_enable cp_enable; > + > + memset(&cp, 0, sizeof(cp)); > + cp.evt_properties = cpu_to_le16(0x0013); > + send_command(bthost, BT_HCI_CMD_LE_SET_EXT_ADV_PARAMS, > + &cp, sizeof(cp)); > + > + cp_enable.enable = enable; > + send_command(bthost, BT_HCI_CMD_LE_SET_EXT_ADV_ENABLE, &cp_enable, > + sizeof(cp_enable)); > +} > + > void bthost_write_ssp_mode(struct bthost *bthost, uint8_t mode) > { > send_command(bthost, BT_HCI_CMD_WRITE_SIMPLE_PAIRING_MODE, &mode, 1); > diff --git a/emulator/bthost.h b/emulator/bthost.h > index 553865a..b5f3696 100644 > --- a/emulator/bthost.h > +++ b/emulator/bthost.h > @@ -56,6 +56,9 @@ void bthost_set_connect_cb(struct bthost *bthost, bthost_new_conn_cb cb, > void bthost_hci_connect(struct bthost *bthost, const uint8_t *bdaddr, > uint8_t addr_type); > > +void bthost_hci_ext_connect(struct bthost *bthost, const uint8_t *bdaddr, > + uint8_t addr_type); > + > void bthost_hci_disconnect(struct bthost *bthost, uint16_t handle, > uint8_t reason); > > @@ -83,6 +86,10 @@ void bthost_set_adv_data(struct bthost *bthost, const uint8_t *data, > uint8_t len); > void bthost_set_adv_enable(struct bthost *bthost, uint8_t enable); > > +void bthost_set_ext_adv_data(struct bthost *bthost, const uint8_t *data, > + uint8_t len); > +void bthost_set_ext_adv_enable(struct bthost *bthost, uint8_t enable); > + > void bthost_write_ssp_mode(struct bthost *bthost, uint8_t mode); > > void bthost_write_le_host_supported(struct bthost *bthost, uint8_t mode); > diff --git a/emulator/hciemu.c b/emulator/hciemu.c > index 1787a6c..bc36773 100644 > --- a/emulator/hciemu.c > +++ b/emulator/hciemu.c > @@ -331,6 +331,9 @@ struct hciemu *hciemu_new(enum hciemu_type type) > case HCIEMU_TYPE_LEGACY: > hciemu->btdev_type = BTDEV_TYPE_BREDR20; > break; > + case HCIEMU_TYPE_BREDRLE50: > + hciemu->btdev_type = BTDEV_TYPE_BREDRLE50; > + break; > default: > return NULL; > } > diff --git a/emulator/hciemu.h b/emulator/hciemu.h > index 5c0c4c3..e37c069 100644 > --- a/emulator/hciemu.h > +++ b/emulator/hciemu.h > @@ -31,6 +31,7 @@ enum hciemu_type { > HCIEMU_TYPE_BREDR, > HCIEMU_TYPE_LE, > HCIEMU_TYPE_LEGACY, > + HCIEMU_TYPE_BREDRLE50, > }; > > enum hciemu_hook_type { > diff --git a/monitor/bt.h b/monitor/bt.h > index 595b6a7..ec62864 100644 > --- a/monitor/bt.h > +++ b/monitor/bt.h > @@ -3010,6 +3010,7 @@ struct bt_hci_le_ext_adv_report { > uint8_t direct_addr_type; > uint8_t direct_addr[6]; > uint8_t data_len; > + uint8_t data[0]; > } __attribute__ ((packed)); > > #define BT_HCI_EVT_LE_ADV_SET_TERM 0x12 > -- > 2.7.4 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- Luiz Augusto von Dentz