From patchwork Tue Jan 28 20:13:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luiz Augusto von Dentz X-Patchwork-Id: 197403 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.6 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2C7BEC2D0DB for ; Tue, 28 Jan 2020 20:13:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D4F8620708 for ; Tue, 28 Jan 2020 20:13:39 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="koJW2hXT" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726257AbgA1UNj (ORCPT ); Tue, 28 Jan 2020 15:13:39 -0500 Received: from mail-pf1-f194.google.com ([209.85.210.194]:39190 "EHLO mail-pf1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726141AbgA1UNj (ORCPT ); Tue, 28 Jan 2020 15:13:39 -0500 Received: by mail-pf1-f194.google.com with SMTP id 84so1123063pfy.6 for ; Tue, 28 Jan 2020 12:13:38 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=6pG4fhtZNdH5sppIl2RsLlh09z9a/k6G9gWcBW1wFUQ=; b=koJW2hXTU2NDRUDz7rbKkHK0vurEB6jIt1hyVUtQzlM8ELqxNP+IyvjrMHOjio+kyc hsypp7rDEC3g9Q4UUYQqcUWB4smXbXNJe3I/W9avM9PW5ZmoVnTUNIOHcT1pco2dseJO C6Xa4f+DBr3tnZkksW/kZ24H5X65bG4H8k+ulBkU4v8VrbBVmuLyACWU2W6tNVDVIVAR 0Nb9W/fwYB3dTrOprFQm52oh8vBvGm08kuAVdWufsl6Z3L3EMrpS25noeJf3Zi7gqJPQ AqBFPDyT9ddCtKPPqG7PJhApzqkA9T3AtdjMf9GhZZRc889/ER6+aGbW9vrkqQNQOUuB MRLA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:mime-version :content-transfer-encoding; bh=6pG4fhtZNdH5sppIl2RsLlh09z9a/k6G9gWcBW1wFUQ=; b=WlKR6ChKchcIxN6dcBqw1eqHpZPdPNNPwOHeiqq+AK/wSpJPEsn+fyVukKl24aQ3X2 Pqo7YsNEzo5c7MpNg4hAYT0y0KrqBEE8EC+Wq/GtyclB9R2xretXlvKkqpH7hJxPoXuI 4OPQzL+TYU5g0AGTH+ne3+msSAGcDQJAd0ivssLy5XCMPCwnE/pSP+yhoYoMSLLxecXj 1hhIV1PMlhXHHh4qgRpplGT1h+iGB4XUtUCauFSYJC8iJilvYGxOLxGKUvYMmyYJCQIP F9bgG6gjs15XykPWOBRgTReJCvgEFsQlf7Qr8LGWT30fQ7ll4vmDAaq+ho/p9DQCQ5aG gi+w== X-Gm-Message-State: APjAAAUAZf6YaC9hpD4jv69fe6UU/QIk5uxnJYRV2CH5ijjdPbvxYdXt YXdvm/iiRtrvNRdhiCUFSUZjJzFmb4o= X-Google-Smtp-Source: APXvYqwzqEtrQAQP2e7KZsvC2pphenXTQfouTYLqFZUwj4l0YRx48qhfgVc3olKbn8DAcYjp0lzihA== X-Received: by 2002:a65:42ca:: with SMTP id l10mr27101670pgp.121.1580242417677; Tue, 28 Jan 2020 12:13:37 -0800 (PST) Received: from localhost.localdomain ([192.102.209.38]) by smtp.gmail.com with ESMTPSA id x8sm3367504pfr.104.2020.01.28.12.13.36 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 28 Jan 2020 12:13:36 -0800 (PST) From: Luiz Augusto von Dentz To: linux-bluetooth@vger.kernel.org Subject: [PATCH BlueZ 1/6] monitor: Add support for decoding ISO related commands Date: Tue, 28 Jan 2020 12:13:30 -0800 Message-Id: <20200128201335.6165-1-luiz.dentz@gmail.com> X-Mailer: git-send-email 2.21.0 MIME-Version: 1.0 Sender: linux-bluetooth-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Luiz Augusto von Dentz This adds parsing of ISO related commands. --- monitor/bt.h | 307 ++++++++++++++++++++++ monitor/packet.c | 661 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 968 insertions(+) diff --git a/monitor/bt.h b/monitor/bt.h index b31e6c5c5..48901d7cd 100644 --- a/monitor/bt.h +++ b/monitor/bt.h @@ -24,6 +24,10 @@ #include +#define BT_HCI_CMD_5_2 0x2060 +#define BT_HCI_BIT_5_2 (8 * 41) + 5 +#define BT_HCI_SUBEVT_5_2 0x19 + struct bt_ll_hdr { uint8_t preamble; uint32_t access_addr; @@ -443,6 +447,7 @@ struct bt_lmp_power_control_res { #define BT_H4_ACL_PKT 0x02 #define BT_H4_SCO_PKT 0x03 #define BT_H4_EVT_PKT 0x04 +#define BT_H4_ISO_PKT 0x05 struct bt_hci_cmd_hdr { uint16_t opcode; @@ -459,6 +464,16 @@ struct bt_hci_sco_hdr { uint8_t dlen; } __attribute__ ((packed)); +struct bt_hci_iso_hdr { + uint16_t handle; + uint8_t dlen; +} __attribute__ ((packed)); + +struct bt_hci_iso_data_start { + uint16_t sn; + uint16_t slen; +} __attribute__ ((packed)); + struct bt_hci_evt_hdr { uint8_t evt; uint8_t plen; @@ -2498,6 +2513,231 @@ struct bt_hci_cmd_default_periodic_adv_sync_trans_params { uint8_t cte_type; } __attribute__ ((packed)); +#define BT_HCI_CMD_LE_READ_BUFFER_SIZE_V2 BT_HCI_CMD_5_2 +#define BT_HCI_BIT_LE_READ_BUFFER_SIZE_V2 BT_HCI_BIT_5_2 +struct bt_hci_rsp_le_read_buffer_size_v2 { + uint8_t status; + uint16_t acl_mtu; + uint8_t acl_max_pkt; + uint16_t iso_mtu; + uint8_t iso_max_pkt; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_READ_ISO_TX_SYNC BT_HCI_CMD_5_2 + 1 +#define BT_HCI_BIT_LE_READ_ISO_TX_SYNC BT_HCI_BIT_5_2 + 1 +struct bt_hci_cmd_le_read_iso_tx_sync { + uint16_t handle; +} __attribute__ ((packed)); + +struct bt_hci_rsp_le_read_iso_tx_sync { + uint8_t status; + uint16_t handle; + uint16_t seq; + uint32_t timestamp; + uint8_t offset[3]; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_SET_CIG_PARAMS BT_HCI_CMD_5_2 + 2 +#define BT_HCI_BIT_LE_SET_CIG_PARAMS BT_HCI_BIT_5_2 + 2 +struct bt_hci_cis_params { + uint8_t cis_id; + uint16_t m_sdu; + uint16_t s_sdu; + uint8_t m_phy; + uint8_t s_phy; + uint8_t m_rtn; + uint8_t s_rtn; +} __attribute__ ((packed)); + +struct bt_hci_cmd_le_set_cig_params { + uint8_t cig_id; + uint8_t m_interval[3]; + uint8_t s_interval[3]; + uint8_t sca; + uint8_t packing; + uint8_t framing; + uint16_t m_latency; + uint16_t s_latency; + uint8_t num_cis; + struct bt_hci_cis_params cis[0]; +} __attribute__ ((packed)); + +struct bt_hci_rsp_le_set_cig_params { + uint8_t status; + uint8_t cig_id; + uint8_t num_handles; + uint16_t handle[0]; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_SET_CIG_PARAMS_TEST BT_HCI_CMD_5_2 + 3 +#define BT_HCI_BIT_LE_SET_CIG_PARAMS_TEST BT_HCI_BIT_5_2 + 3 +struct bt_hci_cis_params_test { + uint8_t cis_id; + uint8_t nse; + uint16_t m_sdu; + uint16_t s_sdu; + uint8_t m_pdu; + uint8_t s_pdu; + uint8_t m_phy; + uint8_t s_phy; + uint8_t m_bn; + uint8_t s_bn; +} __attribute__ ((packed)); + +struct bt_hci_cmd_le_set_cig_params_test { + uint8_t cig_id; + uint8_t m_interval[3]; + uint8_t s_interval[3]; + uint8_t m_ft; + uint8_t s_ft; + uint16_t iso_interval; + uint8_t sca; + uint8_t packing; + uint8_t framing; + uint8_t num_cis; + struct bt_hci_cis_params_test cis[0]; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_CREATE_CIS BT_HCI_CMD_5_2 + 4 +#define BT_HCI_BIT_LE_CREATE_CIS BT_HCI_BIT_5_2 + 4 +struct bt_hci_cis { + uint16_t cis_handle; + uint16_t acl_handle; +} __attribute__ ((packed)); + +struct bt_hci_cmd_le_create_cis { + uint8_t num_cis; + struct bt_hci_cis cis[0]; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_REMOVE_CIG BT_HCI_CMD_5_2 + 5 +#define BT_HCI_BIT_LE_REMOVE_CIG BT_HCI_BIT_5_2 + 5 +struct bt_hci_cmd_le_remove_cig { + uint8_t cig_id; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_ACCEPT_CIS BT_HCI_CMD_5_2 + 6 +#define BT_HCI_BIT_LE_ACCEPT_CIS BT_HCI_BIT_5_2 + 6 +struct bt_hci_cmd_le_accept_cis { + uint16_t handle; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_REJECT_CIS BT_HCI_CMD_5_2 + 7 +#define BT_HCI_BIT_LE_REJECT_CIS BT_HCI_BIT_5_2 + 7 +struct bt_hci_cmd_le_reject_cis { + uint16_t handle; + uint8_t reason; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_CREATE_BIG BT_HCI_CMD_5_2 + 8 +#define BT_HCI_BIT_LE_CREATE_BIG BT_HCI_BIT_5_2 + 8 +struct bt_hci_bis { + uint8_t sdu_interval[3]; + uint16_t sdu; + uint16_t latency; + uint8_t rtn; + uint8_t phy; + uint8_t packing; + uint8_t framing; + uint8_t encryption; + uint8_t bcode[16]; +} __attribute__ ((packed)); + +struct bt_hci_cmd_le_create_big { + uint8_t big_id; + uint8_t adv_handle; + uint8_t num_bis; + struct bt_hci_bis bis[0]; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_CREATE_BIG_TEST BT_HCI_CMD_5_2 + 9 +#define BT_HCI_BIT_LE_CREATE_BIG_TEST BT_HCI_BIT_5_2 + 9 +struct bt_hci_bis_test { + uint8_t sdu_interval[3]; + uint16_t iso_interval; + uint8_t nse; + uint16_t sdu; + uint8_t pdu; + uint8_t phy; + uint8_t packing; + uint8_t framing; + uint8_t bn; + uint8_t irc; + uint8_t pto; + uint8_t adv_handle; + uint8_t encryption; + uint8_t bcode[16]; +} __attribute__ ((packed)); + +struct bt_hci_cmd_le_create_big_test { + uint8_t big_id; + uint8_t adv_handle; + uint8_t num_bis; + struct bt_hci_bis_test bis[0]; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_TERM_BIG BT_HCI_CMD_5_2 + 10 +#define BT_HCI_BIT_LE_TERM_BIG BT_HCI_BIT_5_2 + 10 +struct bt_hci_cmd_le_term_big { + uint8_t big_id; + uint8_t reason; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_BIG_CREATE_SYNC BT_HCI_CMD_5_2 + 11 +#define BT_HCI_BIT_LE_BIG_CREATE_SYNC BT_HCI_BIT_5_2 + 11 +struct bt_hci_bis_sync { +} __attribute__ ((packed)); + +struct bt_hci_cmd_le_big_create_sync { + uint8_t big_id; + uint16_t sync_handle; + uint8_t num_bis; + uint8_t encryption; + uint8_t bcode[16]; + uint8_t mse; + uint16_t timeout; + struct bt_hci_bis_sync bis[0]; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_BIG_TERM_SYNC BT_HCI_CMD_5_2 + 12 +#define BT_HCI_BIT_LE_BIG_TERM_SYNC BT_HCI_BIT_5_2 + 12 +struct bt_hci_cmd_le_big_term_sync { + uint8_t big_id; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_REQ_PEER_SCA BT_HCI_CMD_5_2 + 13 +#define BT_HCI_BIT_LE_REQ_PEER_SCA BT_HCI_BIT_5_2 + 13 +struct bt_hci_cmd_le_req_peer_sca { + uint16_t handle; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_SETUP_ISO_PATH BT_HCI_CMD_5_2 + 14 +#define BT_HCI_BIT_LE_SETUP_ISO_PATH BT_HCI_BIT_5_2 + 14 +struct bt_hci_cmd_le_setup_iso_path { + uint16_t handle; + uint8_t input_path; + uint8_t output_path; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_REMOVE_ISO_PATH BT_HCI_CMD_5_2 + 15 +#define BT_HCI_BIT_LE_REMOVE_ISO_PATH BT_HCI_BIT_5_2 + 15 +struct bt_hci_cmd_le_remove_iso_path { + uint16_t handle; + uint8_t path_dir; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_ISO_TX_TEST BT_HCI_CMD_5_2 + 16 +#define BT_HCI_BIT_LE_ISO_TX_TEST BT_HCI_BIT_5_2 + 16 + +#define BT_HCI_CMD_LE_ISO_RX_TEST BT_HCI_CMD_5_2 + 17 +#define BT_HCI_BIT_LE_ISO_RX_TEST BT_HCI_BIT_5_2 + 17 + +#define BT_HCI_CMD_LE_ISO_READ_TEST_COUNTER BT_HCI_CMD_5_2 + 18 +#define BT_HCI_BIT_LE_ISO_READ_TEST_COUNTER BT_HCI_BIT_5_2 + 18 + +#define BT_HCI_CMD_LE_ISO_TEST_END BT_HCI_CMD_5_2 + 19 +#define BT_HCI_BIT_LE_ISO_TEST_END BT_HCI_BIT_5_2 + 19 + #define BT_HCI_EVT_INQUIRY_COMPLETE 0x01 struct bt_hci_evt_inquiry_complete { uint8_t status; @@ -3197,6 +3437,73 @@ struct bt_hci_evt_le_per_adv_sync_trans_rec { uint8_t clock_accuracy; } __attribute__ ((packed)); +#define BT_HCI_EVT_LE_CIS_ESTABLISHED BT_HCI_SUBEVT_5_2 +struct bt_hci_evt_le_cis_established { + uint8_t status; + uint16_t conn_handle; + uint8_t cig_sync_delay[3]; + uint8_t cis_sync_delay[3]; + uint8_t m_latency[3]; + uint8_t s_latency[3]; + uint8_t m_phy; + uint8_t s_phy; + uint8_t nse; + uint8_t m_bn; + uint8_t s_bn; + uint8_t m_ft; + uint8_t s_ft; + uint16_t m_mtu; + uint16_t s_mtu; + uint16_t interval; +} __attribute__ ((packed)); + +#define BT_HCI_EVT_LE_CIS_REQ BT_HCI_SUBEVT_5_2 + 1 +struct bt_hci_evt_le_cis_req { + uint16_t acl_handle; + uint16_t cis_handle; + uint8_t cig_id; + uint8_t cis_id; +} __attribute__ ((packed)); + +#define BT_HCI_EVT_LE_BIG_COMPLETE BT_HCI_SUBEVT_5_2 + 2 +struct bt_hci_evt_le_big_complete { + uint8_t status; + uint8_t big_id; + uint8_t sync_delay[3]; + uint8_t latency[3]; + uint8_t phy; + uint8_t num_bis; + uint16_t handle[0]; +} __attribute__ ((packed)); + +#define BT_HCI_EVT_LE_BIG_TERMINATE BT_HCI_SUBEVT_5_2 + 3 +struct bt_hci_evt_le_big_terminate { + uint8_t reason; + uint8_t big_id; +} __attribute__ ((packed)); + +#define BT_HCI_EVT_LE_BIG_SYNC_ESTABILISHED BT_HCI_SUBEVT_5_2 + 4 +struct bt_hci_evt_le_big_sync_estabilished { + uint8_t status; + uint8_t big_id; + uint8_t latency[3]; + uint8_t num_bis; + uint16_t handle[0]; +} __attribute__ ((packed)); + +#define BT_HCI_EVT_LE_BIG_SYNC_LOST BT_HCI_SUBEVT_5_2 + 5 +struct bt_hci_evt_le_big_sync_lost { + uint8_t big_id; + uint8_t reason; +} __attribute__ ((packed)); + +#define BT_HCI_EVT_LE_REQ_PEER_SCA_COMPLETE BT_HCI_SUBEVT_5_2 + 6 +struct bt_hci_evt_le_req_peer_sca_complete { + uint8_t status; + uint16_t handle; + uint8_t sca; +} __attribute__ ((packed)); + #define BT_HCI_ERR_SUCCESS 0x00 #define BT_HCI_ERR_UNKNOWN_COMMAND 0x01 #define BT_HCI_ERR_UNKNOWN_CONN_ID 0x02 diff --git a/monitor/packet.c b/monitor/packet.c index 6e7cc5e85..007887181 100644 --- a/monitor/packet.c +++ b/monitor/packet.c @@ -2617,6 +2617,11 @@ static const struct bitfield_data features_le[] = { { 25, "Periodic Advertising Sync Transfer - Recipient" }, { 26, "Sleep Clock Accuracy Updates" }, { 27, "Remote Public Key Validation" }, + { 28, "Connected Isochronous Stream - Master" }, + { 29, "Connected Isochronous Stream - Slave" }, + { 30, "Isochronous Broadcaster" }, + { 31, "Synchronized Receiver" }, + { 32, "Isochronous Channels (Host Support)" }, { } }; @@ -2977,6 +2982,12 @@ static const struct bitfield_data events_le_table[] = { { 17, "LE Extended Advertising Set Terminated" }, { 18, "LE Scan Request Received" }, { 19, "LE Channel Selection Algorithm" }, + { 24, "LE CIS Established" }, + { 25, "LE CIS Request" }, + { 26, "LE Create BIG Complete" }, + { 27, "LE Terminate BIG Complete" }, + { 28, "LE BIG Sync Estabilished Complete" }, + { 29, "LE BIG Sync Lost" }, { } }; @@ -7666,6 +7677,437 @@ static void le_set_default_periodic_adv_sync_trans_params(const void *data, print_create_sync_cte_type(cmd->cte_type); } +static void print_sca(uint8_t sca) +{ + switch (sca) { + case 0x00: + print_field("SCA: 201 - 500 ppm (0x%2.2x)", sca); + return; + case 0x01: + print_field("SCA: 151 - 200 ppm (0x%2.2x)", sca); + return; + case 0x02: + print_field("SCA: 101 - 150 ppm (0x%2.2x)", sca); + return; + case 0x03: + print_field("SCA: 76 - 100 ppm (0x%2.2x)", sca); + return; + case 0x04: + print_field("SCA: 51 - 75 ppm (0x%2.2x)", sca); + return; + case 0x05: + print_field("SCA: 31 - 50 ppm (0x%2.2x)", sca); + return; + case 0x06: + print_field("SCA: 21 - 30 ppm (0x%2.2x)", sca); + return; + case 0x07: + print_field("SCA: 0 - 20 ppm (0x%2.2x)", sca); + return; + default: + print_field("SCA: Reserved (0x%2.2x)", sca); + } +} + +static void print_packing(uint8_t value) +{ + switch (value) { + case 0x00: + print_field("Packing: Sequential (0x%2.2x)", value); + return; + case 0x01: + print_field("Packing: Interleaved (0x%2.2x)", value); + return; + default: + print_field("Packing: Reserved (0x%2.2x)", value); + } +} + +static void print_framing(uint8_t value) +{ + switch (value) { + case 0x00: + print_field("Framing: Unframed (0x%2.2x)", value); + return; + case 0x01: + print_field("Framing: Framed (0x%2.2x)", value); + return; + default: + print_field("Packing: Reserved (0x%2.2x)", value); + } +} + +static void le_read_buffer_size_v2_rsp(const void *data, uint8_t size) +{ + const struct bt_hci_rsp_le_read_buffer_size_v2 *rsp = data; + + print_status(rsp->status); + + if (size == 1) + return; + + print_field("ACL MTU: %d", le16_to_cpu(rsp->acl_mtu)); + print_field("ACL max packet: %d", rsp->acl_max_pkt); + print_field("ISO MTU: %d", le16_to_cpu(rsp->iso_mtu)); + print_field("ISO max packet: %d", rsp->iso_max_pkt); +} + +static void le_read_iso_tx_sync_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_le_read_iso_tx_sync *cmd = data; + + print_field("Handle: %d", le16_to_cpu(cmd->handle)); +} + +static void le_read_iso_tx_sync_rsp(const void *data, uint8_t size) +{ + const struct bt_hci_rsp_le_read_iso_tx_sync *rsp = data; + uint32_t offset = 0; + + print_status(rsp->status); + + if (size == 1) + return; + + print_field("Handle: %d", le16_to_cpu(rsp->handle)); + print_field("Sequence Number: %d", le16_to_cpu(rsp->seq)); + print_field("Timestamp: %d", le32_to_cpu(rsp->timestamp)); + + memcpy(&offset, rsp->offset, sizeof(rsp->offset)); + + print_field("Offset: %d", le32_to_cpu(offset)); +} + +static void print_cis_params(const void *data) +{ + const struct bt_hci_cis_params *cis = data; + + print_field("CIS ID: 0x%2.2x", cis->cis_id); + print_field("Master to Slave Maximum SDU Size: %u", + le16_to_cpu(cis->m_sdu)); + print_field("Slave to Master Maximum SDU Size: %u", + le16_to_cpu(cis->s_sdu)); + print_le_phy("Master to Slave PHY", cis->m_phy); + print_le_phy("Slave to Master PHY", cis->s_phy); + print_field("Master to Slave Retransmission attempts: 0x%2.2x", + cis->m_rtn); + print_field("Slave to Master Retransmission attempts: 0x%2.2x", + cis->s_rtn); +} + +static void print_list(const void *data, uint8_t size, int num_items, + size_t item_size, void (*callback)(const void *data)) +{ + while (size >= item_size && num_items) { + callback(data); + data += item_size; + size -= item_size; + num_items--; + } + + if (num_items) + print_hex_field("", data, size); +} + +static void print_usec_interval(const char *prefix, const uint8_t interval[3]) +{ + uint32_t u24 = 0; + + memcpy(&u24, interval, 3); + print_field("%s: %u us (0x%6.6x)", prefix, le32_to_cpu(u24), + le32_to_cpu(u24)); +} + +static void le_set_cig_params_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_le_set_cig_params *cmd = data; + + print_field("CIG ID: 0x%2.2x", cmd->cig_id); + print_usec_interval("Master to Slave SDU Interval", cmd->m_interval); + print_usec_interval("Slave to Master SDU Interval", cmd->s_interval); + print_sca(cmd->sca); + print_packing(cmd->packing); + print_framing(cmd->framing); + print_field("Master to Slave Maximum Latency: %d ms (0x%4.4x)", + le16_to_cpu(cmd->m_latency), le16_to_cpu(cmd->m_latency)); + print_field("Slave to Master Maximum Latency: %d ms (0x%4.4x)", + le16_to_cpu(cmd->s_latency), le16_to_cpu(cmd->s_latency)); + print_field("Number of CIS: %u", cmd->num_cis); + + size -= sizeof(*cmd); + + print_list(cmd->cis, size, cmd->num_cis, sizeof(*cmd->cis), + print_cis_params); +} + +static void print_cis_params_test(const void *data) +{ + const struct bt_hci_cis_params_test *cis = data; + + print_field("CIS ID: 0x%2.2x", cis->cis_id); + print_field("NSE: 0x%2.2x", cis->nse); + print_field("Master to Slave Maximum SDU: 0x%4.4x", cis->m_sdu); + print_field("Slave to Master Maximum SDU: 0x%4.4x", + le16_to_cpu(cis->s_sdu)); + print_field("Master to Slave Maximum PDU: 0x%2.2x", + le16_to_cpu(cis->m_pdu)); + print_field("Slave to Master Maximum PDU: 0x%2.2x", cis->s_pdu); + print_le_phy("Master to Slave PHY", cis->m_phy); + print_le_phy("Slave to Master PHY", cis->s_phy); + print_field("Master to Slave Burst Number: 0x%2.2x", cis->m_bn); + print_field("Slave to Master Burst Number: 0x%2.2x", cis->s_bn); +} + +static void le_set_cig_params_test_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_le_set_cig_params_test *cmd = data; + + print_field("CIG ID: 0x%2.2x", cmd->cig_id); + print_usec_interval("Master to Slave SDU Interval", cmd->m_interval); + print_usec_interval("Master to Slave SDU Interval", cmd->s_interval); + print_field("Master to Slave Flush Timeout: 0x%2.2x", cmd->m_ft); + print_field("Slave to Master Flush Timeout: 0x%2.2x", cmd->s_ft); + print_field("ISO Interval: %.2f ms (0x%4.4x)", + le16_to_cpu(cmd->iso_interval) * 1.25, + le16_to_cpu(cmd->iso_interval)); + print_sca(cmd->sca); + print_packing(cmd->packing); + print_framing(cmd->framing); + print_field("Number of CIS: %u", cmd->num_cis); + + size -= sizeof(*cmd); + + print_list(cmd->cis, size, cmd->num_cis, sizeof(*cmd->cis), + print_cis_params_test); +} + +static void print_cig_handle(const void *data) +{ + const uint16_t *handle = data; + + print_field("Connection Handle: %d", le16_to_cpu(*handle)); +} + +static void le_set_cig_params_rsp(const void *data, uint8_t size) +{ + const struct bt_hci_rsp_le_set_cig_params *rsp = data; + + print_status(rsp->status); + + if (size == 1) + return; + + print_field("CIG ID: 0x%2.2x", rsp->cig_id); + print_field("Number of Handles: %u", rsp->num_handles); + + size -= sizeof(*rsp); + + print_list(rsp->handle, size, rsp->num_handles, sizeof(*rsp->handle), + print_cig_handle); +} + +static void print_cis(const void *data) +{ + const struct bt_hci_cis *cis = data; + + print_field("CIS Handle: %d", cis->cis_handle); + print_field("ACL Handle: %d", cis->acl_handle); +} + +static void le_create_cis_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_le_create_cis *cmd = data; + + print_field("Number of CIS: %u", cmd->num_cis); + + size -= sizeof(*cmd); + + print_list(cmd->cis, size, cmd->num_cis, sizeof(*cmd->cis), print_cis); +} + +static void le_remove_cig_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_le_remove_cig *cmd = data; + + print_field("CIG ID: 0x%02x", cmd->cig_id); +} + +static void le_accept_cis_req_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_le_accept_cis *cmd = data; + + print_field("CIS Handle: %d", le16_to_cpu(cmd->handle)); +} + +static void le_reject_cis_req_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_le_reject_cis *cmd = data; + + print_field("CIS Handle: %d", le16_to_cpu(cmd->handle)); + print_reason(cmd->reason); +} + +static void print_bis(const void *data) +{ + const struct bt_hci_bis *bis = data; + + print_usec_interval("SDU Interval", bis->sdu_interval); + print_field("Maximum SDU size: %u", le16_to_cpu(bis->sdu)); + print_field("Maximum Latency: %u ms (0x%4.4x)", + le16_to_cpu(bis->latency), le16_to_cpu(bis->latency)); + print_field("RTN: 0x%2.2x", bis->rtn); + print_le_phy("PHY", bis->phy); + print_packing(bis->packing); + print_framing(bis->framing); + print_field("Encryption: 0x%2.2x", bis->encryption); + print_hex_field("Broadcast Code", bis->bcode, 16); +} + +static void le_create_big_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_le_create_big *cmd = data; + + print_field("BIG ID: 0x%2.2x", cmd->big_id); + print_field("Advertising Handle: 0x%2.2x", cmd->adv_handle); + print_field("Number of BIS: %u", cmd->num_bis); + + size -= sizeof(*cmd); + + print_list(cmd->bis, size, cmd->num_bis, sizeof(*cmd->bis), print_bis); +} + +static void print_bis_test(const void *data) +{ + const struct bt_hci_bis_test *bis = data; + + print_usec_interval("SDU Interval", bis->sdu_interval); + print_field("ISO Interval: %.2f ms (0x%4.4x)", + le16_to_cpu(bis->iso_interval) * 1.25, + le16_to_cpu(bis->iso_interval)); + print_field("Number of Subevents: %u", bis->nse); + print_field("Maximum SDU: %u", bis->sdu); + print_field("Maximum PDU: %u", bis->pdu); + print_packing(bis->packing); + print_framing(bis->framing); + print_le_phy("PHY", bis->phy); + print_field("Burst Number: %u", bis->bn); + print_field("Immediate Repetition Count: %u", bis->irc); + print_field("Pre Transmission Offset: 0x%2.2x", bis->pto); + print_field("Encryption: 0x%2.2x", bis->encryption); + print_hex_field("Broadcast Code", bis->bcode, 16); +} + +static void le_create_big_cmd_test_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_le_create_big_test *cmd = data; + + print_field("BIG ID: 0x%2.2x", cmd->big_id); + print_field("Advertising Handle: 0x%2.2x", cmd->adv_handle); + print_field("Number of BIS: %u", cmd->num_bis); + + size -= sizeof(*cmd); + + print_list(cmd->bis, size, cmd->num_bis, sizeof(*cmd->bis), + print_bis_test); +} + +static void le_terminate_big_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_le_term_big *cmd = data; + + print_field("BIG ID: 0x%2.2x", cmd->big_id); + print_reason(cmd->reason); +} + +static void print_bis_sync(const void *data) +{ + const uint8_t *bis_id = data; + + print_field("BIS ID: 0x%2.2x", *bis_id); +} + +static void le_big_create_sync_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_le_big_create_sync *cmd = data; + + print_field("BIG ID: 0x%2.2x", cmd->big_id); + print_field("Number of BIS: %u", cmd->num_bis); + print_field("Encryption: 0x%2.2x", cmd->encryption); + print_hex_field("Broadcast Code", cmd->bcode, 16); + print_field("Number Subevents: 0x%2.2x", cmd->mse); + print_field("Timeout: %d ms (0x%4.4x)", le16_to_cpu(cmd->timeout) * 10, + le16_to_cpu(cmd->timeout)); + + size -= sizeof(*cmd); + + print_list(cmd->bis, size, cmd->num_bis, sizeof(*cmd->bis), + print_bis_sync); +} + +static void le_big_term_sync_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_le_big_term_sync *cmd = data; + + print_field("BIG ID: 0x%2.2x", cmd->big_id); +} + +static void print_iso_path(const char *prefix, uint8_t path) +{ + switch (path) { + case 0x00: + print_field("%s Data Path: Disabled (0x%2.2x)", prefix, path); + return; + case 0x01: + print_field("%s Data Path: HCI (0x%2.2x)", prefix, path); + return; + case 0xff: + print_field("%s Data Path: Test Mode (0x%2.2x)", prefix, path); + return; + default: + print_field("%s Data Path: Logical Channel Number (0x%2.2x)", + prefix, path); + } +} + +static void le_setup_iso_path_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_le_setup_iso_path *cmd = data; + + print_field("Handle: %d", le16_to_cpu(cmd->handle)); + print_iso_path("Input", cmd->input_path); + print_iso_path("Output", cmd->output_path); +} + +static void print_iso_dir(uint8_t path_dir) +{ + switch (path_dir) { + case 0x00: + print_field("Data Path Direction: Input (0x%2.2x)", path_dir); + return; + case 0x01: + print_field("Data Path Direction: Output (0x%2.2x)", path_dir); + return; + default: + print_field("Data Path Direction: Reserved (0x%2.2x)", + path_dir); + } +} + +static void le_remove_iso_path_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_le_remove_iso_path *cmd = data; + + print_field("Connection Handle: %d", le16_to_cpu(cmd->handle)); + print_iso_dir(cmd->path_dir); +} + +static void le_req_peer_sca_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_le_req_peer_sca *cmd = data; + + print_field("Connection Handle: %d", le16_to_cpu(cmd->handle)); +} + struct opcode_data { uint16_t opcode; int bit; @@ -8475,6 +8917,107 @@ static const struct opcode_data opcode_table[] = { "Parameters", le_set_default_periodic_adv_sync_trans_params, 6, true, status_rsp, 1, true}, + { BT_HCI_CMD_LE_READ_BUFFER_SIZE_V2, + BT_HCI_BIT_LE_READ_BUFFER_SIZE_V2, + "LE Read Buffer v2", + null_cmd, 0, true, + le_read_buffer_size_v2_rsp, + sizeof( + struct bt_hci_rsp_le_read_buffer_size_v2), + true }, + { BT_HCI_CMD_LE_READ_ISO_TX_SYNC, + BT_HCI_BIT_LE_READ_ISO_TX_SYNC, + "LE Read ISO TX Sync", + le_read_iso_tx_sync_cmd, + sizeof(struct bt_hci_cmd_le_read_iso_tx_sync), + true, + le_read_iso_tx_sync_rsp, + sizeof(struct bt_hci_rsp_le_read_iso_tx_sync), + true }, + { BT_HCI_CMD_LE_SET_CIG_PARAMS, BT_HCI_BIT_LE_SET_CIG_PARAMS, + "LE Set Connected Isochronous Group Parameters", + le_set_cig_params_cmd, + sizeof(struct bt_hci_cmd_le_set_cig_params), + false, + le_set_cig_params_rsp, + sizeof(struct bt_hci_rsp_le_set_cig_params), + false }, + { BT_HCI_CMD_LE_SET_CIG_PARAMS_TEST, BT_HCI_BIT_LE_SET_CIG_PARAMS_TEST, + "LE Set Connected Isochronous Group Parameters" + " Test", le_set_cig_params_test_cmd, + sizeof( + struct bt_hci_cmd_le_set_cig_params_test), + false, + le_set_cig_params_rsp, + sizeof(struct bt_hci_rsp_le_set_cig_params), + false }, + { BT_HCI_CMD_LE_CREATE_CIS, BT_HCI_BIT_LE_CREATE_CIS, + "LE Create Connected Isochronous Stream", + le_create_cis_cmd, + sizeof(struct bt_hci_cmd_le_create_cis), + false }, + { BT_HCI_CMD_LE_REMOVE_CIG, BT_HCI_BIT_LE_REMOVE_CIG, + "LE Remove Connected Isochronous Group", + le_remove_cig_cmd, + sizeof(struct bt_hci_cmd_le_remove_cig), false, + status_rsp, 1, true }, + { BT_HCI_CMD_LE_ACCEPT_CIS, BT_HCI_BIT_LE_ACCEPT_CIS, + "LE Accept Connected Isochronous Stream Request", + le_accept_cis_req_cmd, + sizeof(struct bt_hci_cmd_le_accept_cis), true }, + { BT_HCI_CMD_LE_REJECT_CIS, BT_HCI_BIT_LE_REJECT_CIS, + "LE Reject Connected Isochronous Stream Request", + le_reject_cis_req_cmd, + sizeof(struct bt_hci_cmd_le_reject_cis), true, + status_rsp, 1, true }, + { BT_HCI_CMD_LE_CREATE_BIG, BT_HCI_BIT_LE_CREATE_BIG, + "LE Create Broadcast Isochronous Group", + le_create_big_cmd }, + { BT_HCI_CMD_LE_CREATE_BIG_TEST, BT_HCI_BIT_LE_CREATE_BIG_TEST, + "LE Create Broadcast Isochronous Group Test", + le_create_big_cmd_test_cmd }, + { BT_HCI_CMD_LE_TERM_BIG, BT_HCI_BIT_LE_TERM_BIG, + "LE Terminate Broadcast Isochronous Group", + le_terminate_big_cmd, + sizeof(struct bt_hci_cmd_le_term_big), true, + status_rsp, 1, true}, + { BT_HCI_CMD_LE_BIG_CREATE_SYNC, BT_HCI_BIT_LE_BIG_CREATE_SYNC, + "LE Broadcast Isochronous Group Create Sync", + le_big_create_sync_cmd, + sizeof(struct bt_hci_cmd_le_big_create_sync), + true }, + { BT_HCI_CMD_LE_BIG_TERM_SYNC, BT_HCI_BIT_LE_BIG_TERM_SYNC, + "LE Broadcast Isochronous Group Terminate Sync", + le_big_term_sync_cmd, + sizeof(struct bt_hci_cmd_le_big_term_sync), + true }, + { BT_HCI_CMD_LE_REQ_PEER_SCA, BT_HCI_BIT_LE_REQ_PEER_SCA, + "LE Request Peer SCA", le_req_peer_sca_cmd, + sizeof(struct bt_hci_cmd_le_req_peer_sca), + true }, + { BT_HCI_CMD_LE_SETUP_ISO_PATH, BT_HCI_BIT_LE_SETUP_ISO_PATH, + "LE Setup Isochronous Data Path", + le_setup_iso_path_cmd, + sizeof(struct bt_hci_cmd_le_setup_iso_path), + true, status_rsp, 1, true }, + { BT_HCI_CMD_LE_REMOVE_ISO_PATH, BT_HCI_BIT_LE_REMOVE_ISO_PATH, + "LE Remove Isochronous Data Path", + le_remove_iso_path_cmd, + sizeof(struct bt_hci_cmd_le_remove_iso_path), + true, status_rsp, 1, true }, + { BT_HCI_CMD_LE_ISO_TX_TEST, BT_HCI_BIT_LE_ISO_TX_TEST, + "LE Isochronous Transmit Test", NULL, 0, + false }, + { BT_HCI_CMD_LE_ISO_RX_TEST, BT_HCI_BIT_LE_ISO_RX_TEST, + "LE Isochronous Receive Test", NULL, 0, + false }, + { BT_HCI_CMD_LE_ISO_READ_TEST_COUNTER, + BT_HCI_BIT_LE_ISO_READ_TEST_COUNTER, + "LE Isochronous Read Test Counters", NULL, 0, + false }, + { BT_HCI_CMD_LE_ISO_TEST_END, BT_HCI_BIT_LE_ISO_TEST_END, + "LE Isochronous Read Test Counters", NULL, 0, + false }, { } }; @@ -9912,6 +10455,94 @@ static void le_per_adv_sync_trans_rec_evt(const void *data, uint8_t size) print_clock_accuracy(evt->clock_accuracy); } +static void le_cis_established_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_le_cis_established *evt = data; + + print_status(evt->status); + print_field("Connection Handle: %d", le16_to_cpu(evt->conn_handle)); + print_usec_interval("CIG Synchronization Delay", evt->cig_sync_delay); + print_usec_interval("CIS Synchronization Delay", evt->cis_sync_delay); + print_usec_interval("Master to Slave Latency", evt->m_latency); + print_usec_interval("Slave to Master Latency", evt->s_latency); + print_le_phy("Master to Slave PHY", evt->m_phy); + print_le_phy("Slave to Master PHY", evt->s_phy); + print_field("Number of Subevents: %u", evt->nse); + print_field("Master to Slave Burst Number: %u", evt->m_bn); + print_field("Slave to Master Burst Number: %u", evt->s_bn); + print_field("Master to Slave Flush Timeout: %u", evt->m_ft); + print_field("Slave to Master Flush Timeout: %u", evt->s_ft); + print_field("Master to Slave MTU: %u", le16_to_cpu(evt->m_mtu)); + print_field("Slave to Master MTU: %u", le16_to_cpu(evt->s_mtu)); + print_field("ISO Interval: %u", le16_to_cpu(evt->interval)); +} + +static void le_req_cis_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_le_cis_req *evt = data; + + print_field("ACL Handle: %d", le16_to_cpu(evt->acl_handle)); + print_field("CIS Handle: %d", le16_to_cpu(evt->cis_handle)); + print_field("CIG ID: 0x%2.2x", evt->cig_id); + print_field("CIS ID: 0x%2.2x", evt->cis_id); +} + +static void print_bis_handle(const void *data) +{ + const uint16_t *handle = data; + + print_field("Connection Handle: %d", le16_to_cpu(*handle)); +} + +static void le_big_complete_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_le_big_complete *evt = data; + + print_status(evt->status); + print_field("BIG ID: 0x%2.2x", evt->big_id); + print_usec_interval("BIG Synchronization Delay", evt->sync_delay); + print_usec_interval("Transport Latency", evt->latency); + print_le_phy("PHY", evt->phy); + print_list(evt->handle, size, evt->num_bis, sizeof(*evt->handle), + print_bis_handle); +} + +static void le_big_terminate_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_le_big_terminate *evt = data; + + print_reason(evt->reason); + print_field("BIG ID: 0x%2.2x", evt->big_id); +} + +static void le_big_sync_estabilished_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_le_big_sync_estabilished *evt = data; + + print_status(evt->status); + print_field("BIG ID: 0x%2.2x", evt->big_id); + print_usec_interval("Transport Latency", evt->latency); + print_list(evt->handle, size, evt->num_bis, sizeof(*evt->handle), + print_bis_handle); +} + +static void le_big_sync_lost_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_le_big_sync_lost *evt = data; + + print_field("BIG ID: 0x%2.2x", evt->big_id); + print_reason(evt->reason); +} + +static void le_req_sca_complete_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_le_req_peer_sca_complete *evt = data; + + print_status(evt->status); + print_field("Connection Handle: %d", le16_to_cpu(evt->handle)); + print_sca(evt->sca); +} + struct subevent_data { uint8_t subevent; const char *str; @@ -10000,6 +10631,36 @@ static const struct subevent_data le_meta_event_table[] = { { 0x18, "LE Periodic Advertising Sync Transfer Received", le_per_adv_sync_trans_rec_evt, 19, true}, + { BT_HCI_EVT_LE_CIS_ESTABLISHED, + "LE Connected Isochronous Stream Established", + le_cis_established_evt, + sizeof(struct bt_hci_evt_le_cis_established), + true }, + { BT_HCI_EVT_LE_CIS_REQ, "LE Connected Isochronous Stream Request", + le_req_cis_evt, + sizeof(struct bt_hci_evt_le_cis_req), + true }, + { BT_HCI_EVT_LE_BIG_COMPLETE, + "LE Broadcast Isochronous Group Complete", + le_big_complete_evt, + sizeof(struct bt_hci_evt_le_big_complete) }, + { BT_HCI_EVT_LE_BIG_TERMINATE, + "LE Broadcast Isochronous Group Terminate", + le_big_terminate_evt, + sizeof(struct bt_hci_evt_le_big_terminate) }, + { BT_HCI_EVT_LE_BIG_SYNC_ESTABILISHED, + "LE Broadcast Isochronous Group Sync " + "Estabilished", le_big_sync_estabilished_evt, + sizeof(struct bt_hci_evt_le_big_sync_lost) }, + { BT_HCI_EVT_LE_BIG_SYNC_LOST, + "LE Broadcast Isochronous Group Sync Lost", + le_big_sync_lost_evt, + sizeof(struct bt_hci_evt_le_big_sync_lost) }, + { BT_HCI_EVT_LE_REQ_PEER_SCA_COMPLETE, + "LE Request Peer SCA Complete", + le_req_sca_complete_evt, + sizeof( + struct bt_hci_evt_le_req_peer_sca_complete)}, { } }; From patchwork Tue Jan 28 20:13:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Luiz Augusto von Dentz X-Patchwork-Id: 197402 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.6 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B4EC8C35240 for ; Tue, 28 Jan 2020 20:13:42 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 808A620708 for ; Tue, 28 Jan 2020 20:13:42 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="llT86hx+" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726299AbgA1UNm (ORCPT ); Tue, 28 Jan 2020 15:13:42 -0500 Received: from mail-pf1-f174.google.com ([209.85.210.174]:38416 "EHLO mail-pf1-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726234AbgA1UNl (ORCPT ); Tue, 28 Jan 2020 15:13:41 -0500 Received: by mail-pf1-f174.google.com with SMTP id x185so7233809pfc.5 for ; Tue, 28 Jan 2020 12:13:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=0gQt3GtwJe66EQRGNjJ06N/zsaxGo0nIdnz5kJuLxd0=; b=llT86hx++9JlcslKDIjW0P+D9JaNQU0lrAihFS5DhXxcWlQixdv4yUt7luOQyyGUBs aPJjP0Xg3JTlr18oLQg++BARxGfFCe99BfIZPMY6JTmrF5xISPlCatAErcGsS/QJ/w4/ IicX0VXCyXGEzQ8EsDrNea7RLnnmGKl1f3Ac5P+C4GpM2FXc33pzZBWeI3Q0zXzDf/OO fWWmTCIKn0O30FYO6ZSRi8SUxn2Qudq2K+qUjOcTu7JRfSBjb3Gjh3AAW+OPxwVTJ0mf qOMMmFQMcCeiZjFKEiEatB0QjGOO/orjkM6f9yzHl3uqR8w2foe+neqWZz99F1Z7wE/5 pySg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=0gQt3GtwJe66EQRGNjJ06N/zsaxGo0nIdnz5kJuLxd0=; b=bGc6BGfbx8ZKRdK3VjEmkiRPdQd0+jm5T5pNrChH9NPlQIsxz8O6WWbtCNiLbTuXcY ssmanY3g17TIGChjUWbO51fiKwpp4i/1/yB5cqVbLQaEN9zdmmV3c7J6mf1kknxQXJVh M7mZqXGid2dtFL8Bg+OiCWJrCZcB29xyPEyKKILHY7u19KBefJyXrMzONO/FzGGZRd8M fkgWFCP/XvPtyErsw6fL5WtmxKVqjxqS5w2Kv0NO3Z9LC1Idn7iTOpF3Sl4EbKdB9mSM pMsYFTXqqxr36PHS0NNiwlLY9sBxvkVKZsi6/cKi9PGsg+JwIoZyzYn9LNxdUNLex7it mCnA== X-Gm-Message-State: APjAAAWvBUDdGX61HoF5dTIB1I5hEUoJ/+Ul0J9OrUfLbeLx/cpnz3w7 lep9iB9UZGndXZSfj5t7oXadoWREyy8= X-Google-Smtp-Source: APXvYqy9T/m478dM5T6HIGdrb7kHrtweXl4LIpj67f6O/QHdQl8N13bZAHEWWRMkKUH5U/z/srUjeA== X-Received: by 2002:a65:5608:: with SMTP id l8mr27389695pgs.210.1580242420718; Tue, 28 Jan 2020 12:13:40 -0800 (PST) Received: from localhost.localdomain ([192.102.209.38]) by smtp.gmail.com with ESMTPSA id x8sm3367504pfr.104.2020.01.28.12.13.39 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 28 Jan 2020 12:13:39 -0800 (PST) From: Luiz Augusto von Dentz To: linux-bluetooth@vger.kernel.org Subject: [PATCH BlueZ 4/6] monitor: Add decoding for L2CAP Enhanced Credit Based PDUs Date: Tue, 28 Jan 2020 12:13:33 -0800 Message-Id: <20200128201335.6165-4-luiz.dentz@gmail.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20200128201335.6165-1-luiz.dentz@gmail.com> References: <20200128201335.6165-1-luiz.dentz@gmail.com> MIME-Version: 1.0 Sender: linux-bluetooth-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Luiz Augusto von Dentz Enhanced Credit Based Flow Control Mode is used for L2CAP connection-oriented channels on LE and BR/EDR with flow control using a credit-based scheme for L2CAP data. --- monitor/bt.h | 30 ++++++++++ monitor/l2cap.c | 153 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 183 insertions(+) diff --git a/monitor/bt.h b/monitor/bt.h index c2e6964ff..d989f5b94 100644 --- a/monitor/bt.h +++ b/monitor/bt.h @@ -3712,6 +3712,36 @@ struct bt_l2cap_pdu_le_flowctl_creds { uint16_t credits; } __attribute__ ((packed)); +#define BT_L2CAP_PDU_ECRED_CONN_REQ 0x17 +struct bt_l2cap_pdu_ecred_conn_req { + uint16_t psm; + uint16_t mtu; + uint16_t mps; + uint16_t credits; + uint16_t scid[0]; +} __attribute__ ((packed)); + +#define BT_L2CAP_PDU_ECRED_CONN_RSP 0x18 +struct bt_l2cap_pdu_ecred_conn_rsp { + uint16_t mtu; + uint16_t mps; + uint16_t credits; + uint16_t result; + uint16_t dcid[0]; +} __attribute__ ((packed)); + +#define BT_L2CAP_PDU_ECRED_RECONF_REQ 0x19 +struct bt_l2cap_pdu_ecred_reconf_req { + uint16_t mtu; + uint16_t mps; + uint16_t scid[0]; +} __attribute__ ((packed)); + +#define BT_L2CAP_PDU_ECRED_RECONF_RSP 0x1a +struct bt_l2cap_pdu_ecred_reconf_rsp { + uint16_t result; +} __attribute__ ((packed)); + struct bt_l2cap_hdr_connless { uint16_t psm; } __attribute__ ((packed)); diff --git a/monitor/l2cap.c b/monitor/l2cap.c index d4feca451..3b2b25f24 100644 --- a/monitor/l2cap.c +++ b/monitor/l2cap.c @@ -54,6 +54,7 @@ #define L2CAP_MODE_ERTM 0x03 #define L2CAP_MODE_STREAMING 0x04 #define L2CAP_MODE_LE_FLOWCTL 0x80 +#define L2CAP_MODE_ECRED 0x81 /* L2CAP Control Field bit masks */ #define L2CAP_CTRL_SAR_MASK 0xC000 @@ -121,6 +122,9 @@ static void assign_scid(const struct l2cap_frame *frame, uint16_t scid, int i, n = -1; uint8_t seq_num = 1; + if (!scid) + return; + for (i = 0; i < MAX_CHAN; i++) { if (n < 0 && chan_list[i].handle == 0x0000) { n = i; @@ -417,6 +421,8 @@ static char *mode2str(uint8_t mode) return "Streaming"; case L2CAP_MODE_LE_FLOWCTL: return "LE Flow Control"; + case L2CAP_MODE_ECRED: + return "Enhanced Credit"; default: return "Unknown"; } @@ -1333,6 +1339,132 @@ static void sig_le_flowctl_creds(const struct l2cap_frame *frame) print_field("Credits: %u", le16_to_cpu(pdu->credits)); } +static void sig_ecred_conn_req(const struct l2cap_frame *frame) +{ + const struct bt_l2cap_pdu_ecred_conn_req *pdu = frame->data; + uint16_t scid; + + l2cap_frame_pull((void *)frame, frame, sizeof(pdu)); + + print_psm(pdu->psm); + print_field("MTU: %u", le16_to_cpu(pdu->mtu)); + print_field("MPS: %u", le16_to_cpu(pdu->mps)); + print_field("Credits: %u", le16_to_cpu(pdu->credits)); + + while (l2cap_frame_get_le16((void *)frame, &scid)) { + print_cid("Source", scid); + assign_scid(frame, scid, le16_to_cpu(pdu->psm), + L2CAP_MODE_ECRED, 0); + } +} + +static void print_ecred_conn_result(uint16_t result) +{ + const char *str; + + switch (le16_to_cpu(result)) { + case 0x0000: + str = "Connection successful"; + break; + case 0x0002: + str = "Connection refused - PSM not supported"; + break; + case 0x0004: + str = "Some connections refused – not enough resources " + "available"; + break; + case 0x0005: + str = "All Connections refused - insufficient authentication"; + break; + case 0x0006: + str = "All Connections refused - insufficient authorization"; + break; + case 0x0007: + str = "All Connection refused - insufficient encryption key " + "size"; + break; + case 0x0008: + str = "All Connections refused - insufficient encryption"; + break; + case 0x0009: + str = "Some Connections refused - Invalid Source CID"; + break; + case 0x000a: + str = "Some Connections refused - Source CID already allocated"; + break; + case 0x000b: + str = "All Connections refused - unacceptable parameters"; + break; + default: + str = "Reserved"; + break; + } + + print_field("Result: %s (0x%4.4x)", str, le16_to_cpu(result)); +} + +static void sig_ecred_conn_rsp(const struct l2cap_frame *frame) +{ + const struct bt_l2cap_pdu_ecred_conn_rsp *pdu = frame->data; + uint16_t dcid; + + l2cap_frame_pull((void *)frame, frame, sizeof(pdu)); + + print_field("MTU: %u", le16_to_cpu(pdu->mtu)); + print_field("MPS: %u", le16_to_cpu(pdu->mps)); + print_field("Credits: %u", le16_to_cpu(pdu->credits)); + print_ecred_conn_result(pdu->result); + + while (l2cap_frame_get_le16((void *)frame, &dcid)) { + print_cid("Destination", dcid); + assign_dcid(frame, dcid, 0); + } +} + +static void sig_ecred_reconf_req(const struct l2cap_frame *frame) +{ + const struct bt_l2cap_pdu_ecred_reconf_req *pdu = frame->data; + uint16_t scid; + + l2cap_frame_pull((void *)frame, frame, sizeof(pdu)); + + print_field("MTU: %u", le16_to_cpu(pdu->mtu)); + print_field("MPS: %u", le16_to_cpu(pdu->mps)); + + while (l2cap_frame_get_le16((void *)frame, &scid)) + print_cid("Source", scid); +} + +static void print_ecred_reconf_result(uint16_t result) +{ + const char *str; + + switch (le16_to_cpu(result)) { + case 0x0000: + str = "Reconfiguration successful"; + break; + case 0x0001: + str = "Reconfiguration failed - reduction in size of MTU not " + "allowed"; + break; + case 0x0002: + str = "Reconfiguration failed - reduction in size of MPS not " + "allowed for more than one channel at a time"; + break; + default: + str = "Reserved"; + } + + print_field("Result: %s (0x%4.4x)", str, le16_to_cpu(result)); +} + +static void sig_ecred_reconf_rsp(const struct l2cap_frame *frame) +{ + const struct bt_l2cap_pdu_ecred_reconf_rsp *pdu = frame->data; + + print_ecred_reconf_result(pdu->result); +} + struct sig_opcode_data { uint8_t opcode; const char *str; @@ -1341,6 +1473,24 @@ struct sig_opcode_data { bool fixed; }; +#define SIG_ECRED \ + { BT_L2CAP_PDU_ECRED_CONN_REQ, \ + "Enhanced Credit Connection Request", \ + sig_ecred_conn_req, sizeof(struct bt_l2cap_pdu_ecred_conn_req), \ + false }, \ + { BT_L2CAP_PDU_ECRED_CONN_RSP, \ + "Enhanced Credit Connection Response", \ + sig_ecred_conn_rsp, sizeof(struct bt_l2cap_pdu_ecred_conn_rsp), \ + false }, \ + { BT_L2CAP_PDU_ECRED_RECONF_REQ, \ + "Enhanced Credit Reconfigure Request", \ + sig_ecred_reconf_req, sizeof(struct bt_l2cap_pdu_ecred_reconf_req), \ + false }, \ + { BT_L2CAP_PDU_ECRED_RECONF_RSP, \ + "Enhanced Credit Reconfigure Respond", \ + sig_ecred_reconf_rsp, sizeof(struct bt_l2cap_pdu_ecred_reconf_rsp), \ + true }, + static const struct sig_opcode_data bredr_sig_opcode_table[] = { { 0x01, "Command Reject", sig_cmd_reject, 2, false }, @@ -1376,6 +1526,7 @@ static const struct sig_opcode_data bredr_sig_opcode_table[] = { sig_move_chan_cfm, 4, true }, { 0x11, "Move Channel Confirmation Response", sig_move_chan_cfm_rsp, 2, true }, + SIG_ECRED { }, }; @@ -1396,6 +1547,7 @@ static const struct sig_opcode_data le_sig_opcode_table[] = { sig_le_conn_rsp, 10, true }, { 0x16, "LE Flow Control Credit", sig_le_flowctl_creds, 4, true }, + SIG_ECRED { }, }; @@ -3066,6 +3218,7 @@ void l2cap_frame(uint16_t index, bool in, uint16_t handle, uint16_t cid, switch (frame.mode) { case L2CAP_MODE_LE_FLOWCTL: + case L2CAP_MODE_ECRED: chan = get_chan(&frame); if (!chan->sdu) { if (!l2cap_frame_get_le16(&frame, &chan->sdu)) From patchwork Tue Jan 28 20:13:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Luiz Augusto von Dentz X-Patchwork-Id: 197401 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.6 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B66FBC2D0DB for ; Tue, 28 Jan 2020 20:13:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 6AA5220708 for ; Tue, 28 Jan 2020 20:13:44 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ViBdZhT1" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726320AbgA1UNo (ORCPT ); Tue, 28 Jan 2020 15:13:44 -0500 Received: from mail-pl1-f179.google.com ([209.85.214.179]:34823 "EHLO mail-pl1-f179.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726234AbgA1UNn (ORCPT ); Tue, 28 Jan 2020 15:13:43 -0500 Received: by mail-pl1-f179.google.com with SMTP id g6so5554590plt.2 for ; Tue, 28 Jan 2020 12:13:42 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references:mime-version :content-transfer-encoding; bh=7PNitGNBLMTj2k5raXkxTT5DtOuf0T55XL9mvcTlHnc=; b=ViBdZhT1skKrZcktXhK6P66AaLBDOkFW2dGPaarOaOuhpeRTapYHA0/3lel9RHOkRh oj0vAmchpSoJsk0cRMoM0iRhEbsUNkA+fNYKnYAAQLeZeKr2gRN2kD3CxaQVhZDowong 5807CYnyXFcWH/V1XEeJn8yAbNJpBaVlqpzMu75oUx0Rx1CBkn0at7dhknd7aFdc0LP2 f2hQrjFzh8zh7KZLyeZh5O9URP+mD4Wu1m18wJHJxYuoQHo+wJemFJGE1xCYzziAGZe1 kRGdUYTIAHHVZMzTiwfM42h44+bktMNvxzDdKCv+pEtliV9sO7kJ6ufBFNE1yWnVINBi nV/Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=7PNitGNBLMTj2k5raXkxTT5DtOuf0T55XL9mvcTlHnc=; b=AkRfom3nOLj3ZlaGCRs6FvzQs1K4NG4jYtLwjFzOX/UN1MxxDvnSIKG8ymYy1k2+1u sMMJAcyokMtLnnztGKYR7Sjq1aQvT7hhIJBfhgGc2oM1aQRaUKrOZIaGpiNuLmSK639m JVBVGSy49rXkqnRZhwBhwWft4Z+d6mn8hxGujv8KMmnpAuJeBfFUm1przdOuZE9W+4IM ZExrbH0JhrNxkxdHigqPlHsupE3ZNVnfDNHgC3CxrfllIUhRoU7PH1yzIuqwnnE0J//S 9NtHBTzkRcoDd6ZyOuqyRf9EqBSxM9/Z07jIuAfukYY2EW4MrJVCh4Y08eDn2QhfKVKk 9YTA== X-Gm-Message-State: APjAAAV+9JVueYAG/dueOp++nP0fUbtjQyxf34WRejqd6YNWwSkIDd3Q QYV3tch0c9W3O/QEuybO8wkiVk0KGwk= X-Google-Smtp-Source: APXvYqzTNf8QL4xbZz2u30Rpz4Yp0s2vnRHT4xinRfQkXgKxQqnXXnDo1QAQi/2uhX/qarV28d1+wA== X-Received: by 2002:a17:902:900c:: with SMTP id a12mr24702870plp.87.1580242421861; Tue, 28 Jan 2020 12:13:41 -0800 (PST) Received: from localhost.localdomain ([192.102.209.38]) by smtp.gmail.com with ESMTPSA id x8sm3367504pfr.104.2020.01.28.12.13.40 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 28 Jan 2020 12:13:41 -0800 (PST) From: Luiz Augusto von Dentz To: linux-bluetooth@vger.kernel.org Subject: [PATCH BlueZ 5/6] emulator: Add initial support for BT 5.2 Date: Tue, 28 Jan 2020 12:13:34 -0800 Message-Id: <20200128201335.6165-5-luiz.dentz@gmail.com> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20200128201335.6165-1-luiz.dentz@gmail.com> References: <20200128201335.6165-1-luiz.dentz@gmail.com> MIME-Version: 1.0 Sender: linux-bluetooth-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-bluetooth@vger.kernel.org From: Luiz Augusto von Dentz This adds the initial command/event decoding for 5.2. --- emulator/btdev.c | 293 +++++++++++++++++++++++++++++++++++++++------- emulator/btdev.h | 1 + emulator/hciemu.c | 3 + emulator/hciemu.h | 1 + emulator/vhci.c | 3 +- 5 files changed, 258 insertions(+), 43 deletions(-) diff --git a/emulator/btdev.c b/emulator/btdev.c index 38d5b3b1f..0de273e53 100644 --- a/emulator/btdev.c +++ b/emulator/btdev.c @@ -47,6 +47,9 @@ #define has_bredr(btdev) (!((btdev)->features[4] & 0x20)) #define has_le(btdev) (!!((btdev)->features[4] & 0x40)) +#define ACL_HANDLE 42 +#define ISO_HANDLE 44 + struct hook { btdev_hook_func handler; void *user_data; @@ -92,6 +95,8 @@ struct btdev { uint8_t feat_page_2[8]; uint16_t acl_mtu; uint16_t acl_max_pkt; + uint16_t iso_mtu; + uint16_t iso_max_pkt; uint8_t country_code; uint8_t bdaddr[6]; uint8_t random_addr[6]; @@ -139,6 +144,10 @@ struct btdev { uint8_t le_filter_dup; uint8_t le_adv_enable; uint8_t le_ltk[16]; + struct { + struct bt_hci_cmd_le_set_cig_params params; + struct bt_hci_cis_params cis; + } __attribute__ ((packed)) le_cig; uint8_t le_local_sk256[32]; @@ -438,6 +447,30 @@ static void set_le_50_commands(struct btdev *btdev) btdev->commands[38] |= 0x40; /* LE Read Periodic Adv List Size */ } +static void set_le_60_commands(struct btdev *btdev) +{ + btdev->commands[41] |= 0x20; /* LE Read Buffer Size v2 */ + btdev->commands[41] |= 0x40; /* LE Read ISO TX Sync */ + btdev->commands[41] |= 0x80; /* LE Set CIG Parameters */ + btdev->commands[42] |= 0x01; /* LE Set CIG Parameters Test */ + btdev->commands[42] |= 0x02; /* LE Create CIS */ + btdev->commands[42] |= 0x04; /* LE Remove CIG */ + btdev->commands[42] |= 0x08; /* LE Accept CIS */ + btdev->commands[42] |= 0x10; /* LE Reject CIS */ + btdev->commands[42] |= 0x20; /* LE Create BIG */ + btdev->commands[42] |= 0x40; /* LE Create BIG Test */ + btdev->commands[42] |= 0x80; /* LE Terminate BIG */ + btdev->commands[43] |= 0x01; /* LE BIG Create Sync */ + btdev->commands[43] |= 0x02; /* LE BIG Terminate Sync */ + btdev->commands[43] |= 0x04; /* LE Request Peer SCA */ + btdev->commands[43] |= 0x08; /* LE Setup ISO Path */ + btdev->commands[43] |= 0x10; /* LE Remove ISO Path */ + btdev->commands[43] |= 0x20; /* LE ISO TX Test */ + btdev->commands[43] |= 0x40; /* LE ISO RX Test */ + btdev->commands[43] |= 0x80; /* LE ISO Read Test Counter */ + btdev->commands[44] |= 0x01; /* LE ISO Test End */ +} + static void set_le_commands(struct btdev *btdev) { set_common_commands_all(btdev); @@ -482,6 +515,10 @@ static void set_le_commands(struct btdev *btdev) /* Extra LE commands for >= 5.0 adapters */ if (btdev->type >= BTDEV_TYPE_BREDRLE50) set_le_50_commands(btdev); + + /* Extra LE commands for >= 6.0 adapters */ + if (btdev->type >= BTDEV_TYPE_BREDRLE60) + set_le_60_commands(btdev); } static void set_bredrle_commands(struct btdev *btdev) @@ -550,6 +587,14 @@ static void set_bredrle_features(struct btdev *btdev) btdev->le_features[1] |= 0x10; /* LE EXT ADV */ } + if (btdev->type >= BTDEV_TYPE_BREDRLE60) { + btdev->le_features[3] |= 0x10; /* LE CIS Master */ + btdev->le_features[3] |= 0x20; /* LE CIS Slave */ + btdev->le_features[3] |= 0x40; /* LE ISO Broadcaster */ + btdev->le_features[3] |= 0x80; /* LE Synchronized Receiver */ + btdev->le_features[4] |= 0x01; /* LE ISO channels */ + } + btdev->feat_page_2[0] |= 0x01; /* CSB - Master Operation */ btdev->feat_page_2[0] |= 0x02; /* CSB - Slave Operation */ btdev->feat_page_2[0] |= 0x04; /* Synchronization Train */ @@ -644,8 +689,9 @@ 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 - || type == BTDEV_TYPE_BREDRLE50) { + if (type == BTDEV_TYPE_BREDRLE || type == BTDEV_TYPE_LE || + type == BTDEV_TYPE_BREDRLE50 || + type == BTDEV_TYPE_BREDRLE60) { btdev->crypto = bt_crypto_new(); if (!btdev->crypto) { free(btdev); @@ -661,6 +707,7 @@ struct btdev *btdev_create(enum btdev_type type, uint16_t id) switch (btdev->type) { case BTDEV_TYPE_BREDRLE: case BTDEV_TYPE_BREDRLE50: + case BTDEV_TYPE_BREDRLE60: btdev->version = 0x09; set_bredrle_features(btdev); set_bredrle_commands(btdev); @@ -700,6 +747,9 @@ struct btdev *btdev_create(enum btdev_type type, uint16_t id) btdev->acl_mtu = 192; btdev->acl_max_pkt = 1; + btdev->iso_mtu = 251; + btdev->iso_max_pkt = 1; + btdev->country_code = 0x00; index = add_btdev(btdev); @@ -893,13 +943,13 @@ static void le_meta_event(struct btdev *btdev, uint8_t event, send_event(btdev, BT_HCI_EVT_LE_META_EVENT, pkt_data, 1 + len); } -static void num_completed_packets(struct btdev *btdev) +static void num_completed_packets(struct btdev *btdev, uint16_t handle) { if (btdev->conn) { struct bt_hci_evt_num_completed_packets ncp; ncp.num_handles = 1; - ncp.handle = cpu_to_le16(42); + ncp.handle = cpu_to_le16(handle); ncp.count = cpu_to_le16(1); send_event(btdev, BT_HCI_EVT_NUM_COMPLETED_PACKETS, @@ -1106,12 +1156,12 @@ static void conn_complete(struct btdev *btdev, memcpy(cc.bdaddr, btdev->bdaddr, 6); cc.encr_mode = 0x00; - cc.handle = cpu_to_le16(42); + cc.handle = cpu_to_le16(ACL_HANDLE); cc.link_type = 0x01; send_event(remote, BT_HCI_EVT_CONN_COMPLETE, &cc, sizeof(cc)); - cc.handle = cpu_to_le16(42); + cc.handle = cpu_to_le16(ACL_HANDLE); cc.link_type = 0x01; } else { cc.handle = cpu_to_le16(0x0000); @@ -1208,7 +1258,7 @@ static void le_conn_complete(struct btdev *btdev, memcpy(cc->peer_addr, btdev->bdaddr, 6); cc->role = 0x01; - cc->handle = cpu_to_le16(42); + cc->handle = cpu_to_le16(ACL_HANDLE); cc->interval = lecc->max_interval; cc->latency = lecc->latency; cc->supv_timeout = lecc->supv_timeout; @@ -1255,7 +1305,7 @@ static void le_ext_conn_complete(struct btdev *btdev, memcpy(cc->peer_addr, btdev->bdaddr, 6); cc->role = 0x01; - cc->handle = cpu_to_le16(42); + cc->handle = cpu_to_le16(ACL_HANDLE); cc->interval = lecc->max_interval; cc->latency = lecc->latency; cc->supv_timeout = lecc->supv_timeout; @@ -1356,6 +1406,63 @@ static void le_ext_conn_request(struct btdev *btdev, BT_HCI_ERR_CONN_FAILED_TO_ESTABLISH); } +static void le_cis_estabilished(struct btdev *dev, uint8_t status) +{ + struct bt_hci_evt_le_cis_established evt; + + memset(&evt, 0, sizeof(evt)); + + evt.status = status; + + if (!evt.status) { + evt.conn_handle = cpu_to_le16(ISO_HANDLE); + /* TODO: Figure out if these values makes sense */ + memcpy(evt.cig_sync_delay, dev->le_cig.params.m_interval, + sizeof(dev->le_cig.params.m_interval)); + memcpy(evt.cis_sync_delay, dev->le_cig.params.s_interval, + sizeof(dev->le_cig.params.s_interval)); + memcpy(evt.m_latency, &dev->le_cig.params.m_latency, + sizeof(dev->le_cig.params.m_latency)); + memcpy(evt.s_latency, &dev->le_cig.params.s_latency, + sizeof(dev->le_cig.params.s_latency)); + evt.m_phy = dev->le_cig.cis.m_phy; + evt.s_phy = dev->le_cig.cis.s_phy; + evt.nse = 0x01; + evt.m_bn = 0x01; + evt.s_bn = 0x01; + evt.m_ft = 0x01; + evt.s_ft = 0x01; + evt.m_mtu = dev->iso_mtu; + evt.s_mtu = dev->iso_mtu; + evt.interval = dev->le_cig.params.m_latency; + } + + le_meta_event(dev, BT_HCI_EVT_LE_CIS_ESTABLISHED, &evt, sizeof(evt)); + + if (dev->conn) + le_meta_event(dev->conn, BT_HCI_EVT_LE_CIS_ESTABLISHED, &evt, + sizeof(evt)); +} + +static void le_cis_request(struct btdev *dev, + const struct bt_hci_cmd_le_create_cis *leccis) +{ + struct btdev *remote = dev->conn; + + if (remote) { + struct bt_hci_evt_le_cis_req evt; + + evt.acl_handle = cpu_to_le16(ACL_HANDLE); + evt.cis_handle = cpu_to_le16(ISO_HANDLE); + evt.cis_id = 0x00; + evt.cis_id = 0x00; + + le_meta_event(remote, BT_HCI_EVT_LE_CIS_REQ, &evt, sizeof(evt)); + } else { + le_cis_estabilished(dev, BT_HCI_ERR_UNKNOWN_CONN_ID); + } +} + static void conn_request(struct btdev *btdev, const uint8_t *bdaddr) { struct btdev *remote = find_btdev_by_bdaddr(bdaddr); @@ -1464,8 +1571,10 @@ static void disconnect_complete(struct btdev *btdev, uint16_t handle, dc.handle = cpu_to_le16(handle); dc.reason = reason; - btdev->conn = NULL; - remote->conn = NULL; + if (dc.handle == ACL_HANDLE) { + btdev->conn = NULL; + remote->conn = NULL; + } send_event(btdev, BT_HCI_EVT_DISCONNECT_COMPLETE, &dc, sizeof(dc)); send_event(remote, BT_HCI_EVT_DISCONNECT_COMPLETE, &dc, sizeof(dc)); @@ -1492,7 +1601,7 @@ static void link_key_req_reply_complete(struct btdev *btdev, return; } - ev.handle = cpu_to_le16(42); + ev.handle = cpu_to_le16(ACL_HANDLE); if (!memcmp(btdev->link_key, remote->link_key, 16)) ev.status = BT_HCI_ERR_SUCCESS; @@ -1587,7 +1696,7 @@ static void encrypt_change(struct btdev *btdev, uint8_t mode, uint8_t status) struct bt_hci_evt_encrypt_change ev; ev.status = status; - ev.handle = cpu_to_le16(42); + ev.handle = cpu_to_le16(ACL_HANDLE); ev.encr_mode = mode; send_event(btdev, BT_HCI_EVT_ENCRYPT_CHANGE, &ev, sizeof(ev)); @@ -1628,7 +1737,7 @@ static void pin_code_req_reply_complete(struct btdev *btdev, } if (remote->conn) { - ev.handle = cpu_to_le16(42); + ev.handle = cpu_to_le16(ACL_HANDLE); send_event(remote, BT_HCI_EVT_AUTH_COMPLETE, &ev, sizeof(ev)); } else { conn_complete(remote, btdev->bdaddr, ev.status); @@ -1651,7 +1760,7 @@ static void pin_code_req_neg_reply_complete(struct btdev *btdev, } ev.status = BT_HCI_ERR_PIN_OR_KEY_MISSING; - ev.handle = cpu_to_le16(42); + ev.handle = cpu_to_le16(ACL_HANDLE); if (btdev->conn) send_event(btdev, BT_HCI_EVT_AUTH_COMPLETE, &ev, sizeof(ev)); @@ -1944,7 +2053,7 @@ static void ssp_complete(struct btdev *btdev, const uint8_t *bdaddr, } auth.status = status; - auth.handle = cpu_to_le16(42); + auth.handle = cpu_to_le16(ACL_HANDLE); send_event(init, BT_HCI_EVT_AUTH_COMPLETE, &auth, sizeof(auth)); } @@ -2207,7 +2316,7 @@ static void le_read_remote_features_complete(struct btdev *btdev) memset(buf, 0, sizeof(buf)); buf[0] = BT_HCI_EVT_LE_REMOTE_FEATURES_COMPLETE; ev->status = BT_HCI_ERR_SUCCESS; - ev->handle = cpu_to_le16(42); + ev->handle = cpu_to_le16(ACL_HANDLE); memcpy(ev->features, remote->le_features, 8); send_event(btdev, BT_HCI_EVT_LE_META_EVENT, buf, sizeof(buf)); @@ -2230,7 +2339,7 @@ static void le_start_encrypt_complete(struct btdev *btdev, uint16_t ediv, memset(buf, 0, sizeof(buf)); buf[0] = BT_HCI_EVT_LE_LONG_TERM_KEY_REQUEST; - ev->handle = cpu_to_le16(42); + ev->handle = cpu_to_le16(ACL_HANDLE); ev->ediv = ediv; ev->rand = rand; @@ -2244,7 +2353,7 @@ static void le_encrypt_complete(struct btdev *btdev) struct btdev *remote = btdev->conn; memset(&rp, 0, sizeof(rp)); - rp.handle = cpu_to_le16(42); + rp.handle = cpu_to_le16(ACL_HANDLE); if (!remote) { rp.status = BT_HCI_ERR_UNKNOWN_CONN_ID; @@ -2266,7 +2375,7 @@ static void le_encrypt_complete(struct btdev *btdev) ev.encr_mode = 0x01; } - ev.handle = cpu_to_le16(42); + ev.handle = cpu_to_le16(ACL_HANDLE); send_event(btdev, BT_HCI_EVT_ENCRYPT_CHANGE, &ev, sizeof(ev)); send_event(remote, BT_HCI_EVT_ENCRYPT_CHANGE, &ev, sizeof(ev)); @@ -2279,7 +2388,7 @@ static void ltk_neg_reply_complete(struct btdev *btdev) struct btdev *remote = btdev->conn; memset(&rp, 0, sizeof(rp)); - rp.handle = cpu_to_le16(42); + rp.handle = cpu_to_le16(ACL_HANDLE); if (!remote) { rp.status = BT_HCI_ERR_UNKNOWN_CONN_ID; @@ -2293,7 +2402,7 @@ static void ltk_neg_reply_complete(struct btdev *btdev) memset(&ev, 0, sizeof(ev)); ev.status = BT_HCI_ERR_PIN_OR_KEY_MISSING; - ev.handle = cpu_to_le16(42); + ev.handle = cpu_to_le16(ACL_HANDLE); send_event(remote, BT_HCI_EVT_ENCRYPT_CHANGE, &ev, sizeof(ev)); } @@ -2364,6 +2473,7 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, 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; + const struct bt_hci_cmd_le_reject_cis *lrcis; 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; @@ -2425,6 +2535,11 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, 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; + struct bt_hci_rsp_le_read_buffer_size_v2 lrbsv2; + struct lescp { + struct bt_hci_rsp_le_set_cig_params params; + uint16_t handle; + } __attribute__ ((packed)) lscp; uint8_t status, page; switch (opcode) { @@ -2960,7 +3075,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, case BT_HCI_CMD_READ_LE_HOST_SUPPORTED: if (btdev->type != BTDEV_TYPE_BREDRLE && - btdev->type != BTDEV_TYPE_BREDRLE50) + btdev->type != BTDEV_TYPE_BREDRLE50 && + btdev->type != BTDEV_TYPE_BREDRLE60) goto unsupported; rlhs.status = BT_HCI_ERR_SUCCESS; rlhs.supported = btdev->le_supported; @@ -2971,7 +3087,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, case BT_HCI_CMD_WRITE_LE_HOST_SUPPORTED: if (btdev->type != BTDEV_TYPE_BREDRLE && btdev->type != BTDEV_TYPE_LE && - btdev->type != BTDEV_TYPE_BREDRLE50) + btdev->type != BTDEV_TYPE_BREDRLE50 && + btdev->type != BTDEV_TYPE_BREDRLE60) goto unsupported; wlhs = data; btdev->le_supported = wlhs->supported; @@ -2982,7 +3099,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, case BT_HCI_CMD_READ_SECURE_CONN_SUPPORT: if (btdev->type != BTDEV_TYPE_BREDRLE && - btdev->type != BTDEV_TYPE_BREDRLE50) + btdev->type != BTDEV_TYPE_BREDRLE50 && + btdev->type != BTDEV_TYPE_BREDRLE60) goto unsupported; rscs.status = BT_HCI_ERR_SUCCESS; rscs.support = btdev->secure_conn_support; @@ -2991,7 +3109,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, case BT_HCI_CMD_WRITE_SECURE_CONN_SUPPORT: if (btdev->type != BTDEV_TYPE_BREDRLE && - btdev->type != BTDEV_TYPE_BREDRLE50) + btdev->type != BTDEV_TYPE_BREDRLE50 && + btdev->type != BTDEV_TYPE_BREDRLE60) goto unsupported; wscs = data; btdev->secure_conn_support = wscs->support; @@ -3001,7 +3120,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, case BT_HCI_CMD_READ_LOCAL_OOB_EXT_DATA: if (btdev->type != BTDEV_TYPE_BREDRLE && - btdev->type != BTDEV_TYPE_BREDRLE50) + btdev->type != BTDEV_TYPE_BREDRLE50 && + btdev->type != BTDEV_TYPE_BREDRLE60) goto unsupported; rloed.status = BT_HCI_ERR_SUCCESS; cmd_complete(btdev, opcode, &rloed, sizeof(rloed)); @@ -3009,7 +3129,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, case BT_HCI_CMD_READ_SYNC_TRAIN_PARAMS: if (btdev->type != BTDEV_TYPE_BREDRLE && - btdev->type != BTDEV_TYPE_BREDRLE50) + btdev->type != BTDEV_TYPE_BREDRLE50 && + btdev->type != BTDEV_TYPE_BREDRLE60) goto unsupported; rstp.status = BT_HCI_ERR_SUCCESS; rstp.interval = cpu_to_le16(btdev->sync_train_interval); @@ -3160,7 +3281,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_BREDRLE50) + btdev->type != BTDEV_TYPE_BREDRLE50 && + btdev->type != BTDEV_TYPE_BREDRLE60) goto unsupported; reks = data; read_enc_key_size_complete(btdev, le16_to_cpu(reks->handle)); @@ -3535,7 +3657,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, 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) + if (btdev->type != BTDEV_TYPE_BREDRLE50 && + btdev->type != BTDEV_TYPE_BREDRLE60) goto unsupported; rlrnsas.status = BT_HCI_ERR_SUCCESS; @@ -3544,7 +3667,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, cmd_complete(btdev, opcode, &rlrnsas, sizeof(rlrnsas)); break; case BT_HCI_CMD_LE_SET_ADV_SET_RAND_ADDR: - if (btdev->type != BTDEV_TYPE_BREDRLE50) + if (btdev->type != BTDEV_TYPE_BREDRLE50 && + btdev->type != BTDEV_TYPE_BREDRLE60) goto unsupported; lsasra = data; @@ -3553,7 +3677,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_LE_SET_EXT_ADV_PARAMS: - if (btdev->type != BTDEV_TYPE_BREDRLE50) + if (btdev->type != BTDEV_TYPE_BREDRLE50 && + btdev->type != BTDEV_TYPE_BREDRLE60) goto unsupported; if (btdev->le_adv_enable) { @@ -3573,7 +3698,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, cmd_complete(btdev, opcode, &rlseap, sizeof(rlseap)); break; case BT_HCI_CMD_LE_SET_EXT_ADV_ENABLE: - if (btdev->type != BTDEV_TYPE_BREDRLE50) + if (btdev->type != BTDEV_TYPE_BREDRLE50 && + btdev->type != BTDEV_TYPE_BREDRLE60) goto unsupported; lseae = data; @@ -3588,7 +3714,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, le_set_ext_adv_enable_complete(btdev); break; case BT_HCI_CMD_LE_SET_EXT_ADV_DATA: - if (btdev->type != BTDEV_TYPE_BREDRLE50) + if (btdev->type != BTDEV_TYPE_BREDRLE50 && + btdev->type != BTDEV_TYPE_BREDRLE60) goto unsupported; lsead = data; @@ -3598,7 +3725,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_LE_SET_EXT_SCAN_RSP_DATA: - if (btdev->type != BTDEV_TYPE_BREDRLE50) + if (btdev->type != BTDEV_TYPE_BREDRLE50 && + btdev->type != BTDEV_TYPE_BREDRLE60) goto unsupported; lsesrd = data; @@ -3608,14 +3736,16 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_LE_REMOVE_ADV_SET: - if (btdev->type != BTDEV_TYPE_BREDRLE50) + if (btdev->type != BTDEV_TYPE_BREDRLE50 && + btdev->type != BTDEV_TYPE_BREDRLE60) 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) + if (btdev->type != BTDEV_TYPE_BREDRLE50 && + btdev->type != BTDEV_TYPE_BREDRLE60) goto unsupported; status = BT_HCI_ERR_SUCCESS; @@ -3636,7 +3766,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_LE_SET_EXT_SCAN_PARAMS: - if (btdev->type != BTDEV_TYPE_BREDRLE50) + if (btdev->type != BTDEV_TYPE_BREDRLE50 && + btdev->type != BTDEV_TYPE_BREDRLE60) goto unsupported; lsesp = data; @@ -3658,7 +3789,8 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_LE_SET_EXT_SCAN_ENABLE: - if (btdev->type != BTDEV_TYPE_BREDRLE50) + if (btdev->type != BTDEV_TYPE_BREDRLE50 && + btdev->type != BTDEV_TYPE_BREDRLE60) goto unsupported; lsese = data; @@ -3672,11 +3804,63 @@ static void default_cmd(struct btdev *btdev, uint16_t opcode, cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_LE_EXT_CREATE_CONN: - if (btdev->type != BTDEV_TYPE_BREDRLE50) + if (btdev->type != BTDEV_TYPE_BREDRLE50 && + btdev->type != BTDEV_TYPE_BREDRLE60) goto unsupported; cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode); break; + + case BT_HCI_CMD_LE_READ_BUFFER_SIZE_V2: + if (btdev->type != BTDEV_TYPE_BREDRLE60) + goto unsupported; + lrbsv2.status = BT_HCI_ERR_SUCCESS; + lrbsv2.acl_mtu = cpu_to_le16(btdev->acl_mtu); + lrbsv2.acl_max_pkt = btdev->acl_max_pkt; + lrbsv2.iso_mtu = cpu_to_le16(btdev->iso_mtu); + lrbsv2.iso_max_pkt = btdev->iso_max_pkt; + cmd_complete(btdev, opcode, &lrbsv2, sizeof(lrbsv2)); + break; + + case BT_HCI_CMD_LE_SET_CIG_PARAMS: + if (btdev->type != BTDEV_TYPE_BREDRLE60) + goto unsupported; + memcpy(&btdev->le_cig, data, len); + lscp.params.status = BT_HCI_ERR_SUCCESS; + lscp.params.cig_id = 0x00; + lscp.params.num_handles = 1; + lscp.handle = cpu_to_le16(ISO_HANDLE); + cmd_complete(btdev, opcode, &lscp, sizeof(lscp)); + break; + + case BT_HCI_CMD_LE_CREATE_CIS: + if (btdev->type != BTDEV_TYPE_BREDRLE60) + goto unsupported; + + cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode); + + break; + + case BT_HCI_CMD_LE_ACCEPT_CIS: + if (btdev->type != BTDEV_TYPE_BREDRLE60) + goto unsupported; + + cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode); + le_cis_estabilished(btdev, BT_HCI_ERR_SUCCESS); + + break; + + case BT_HCI_CMD_LE_REJECT_CIS: + if (btdev->type != BTDEV_TYPE_BREDRLE60) + goto unsupported; + + cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode); + + lrcis = data; + le_cis_estabilished(btdev, lrcis->reason); + + break; + default: goto unsupported; } @@ -3716,6 +3900,7 @@ static void default_cmd_completion(struct btdev *btdev, uint16_t opcode, 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; + const struct bt_hci_cmd_le_create_cis *leccis; switch (opcode) { case BT_HCI_CMD_INQUIRY: @@ -3912,19 +4097,28 @@ static void default_cmd_completion(struct btdev *btdev, uint16_t opcode, le_set_scan_enable_complete(btdev); break; case BT_HCI_CMD_LE_SET_EXT_SCAN_ENABLE: - if (btdev->type != BTDEV_TYPE_BREDRLE50) + if (btdev->type != BTDEV_TYPE_BREDRLE50 && + btdev->type != BTDEV_TYPE_BREDRLE60) 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) + if (btdev->type != BTDEV_TYPE_BREDRLE50 && + btdev->type != BTDEV_TYPE_BREDRLE60) return; leecc = data; btdev->le_scan_own_addr_type = leecc->own_addr_type; le_ext_conn_request(btdev, leecc); break; + case BT_HCI_CMD_LE_CREATE_CIS: + if (btdev->type != BTDEV_TYPE_BREDRLE50 && + btdev->type != BTDEV_TYPE_BREDRLE60) + return; + leccis = data; + le_cis_request(btdev, leccis); + break; } } @@ -4033,6 +4227,16 @@ static void send_acl(struct btdev *conn, const void *data, uint16_t len) send_packet(conn, iov, 3); } +static void send_iso(struct btdev *conn, const void *data, uint16_t len) +{ + struct iovec iov; + + iov.iov_base = (void *) (data); + iov.iov_len = len; + + send_packet(conn, &iov, 1); +} + void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len) { uint8_t pkt_type; @@ -4052,7 +4256,12 @@ void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len) case BT_H4_ACL_PKT: if (btdev->conn) send_acl(btdev->conn, data, len); - num_completed_packets(btdev); + num_completed_packets(btdev, ACL_HANDLE); + break; + case BT_H4_ISO_PKT: + num_completed_packets(btdev, ISO_HANDLE); + if (btdev->conn) + send_iso(btdev->conn, data, len); break; default: printf("Unsupported packet 0x%2.2x\n", pkt_type); diff --git a/emulator/btdev.h b/emulator/btdev.h index 362d1e7a2..b535930de 100644 --- a/emulator/btdev.h +++ b/emulator/btdev.h @@ -64,6 +64,7 @@ enum btdev_type { BTDEV_TYPE_AMP, BTDEV_TYPE_BREDR20, BTDEV_TYPE_BREDRLE50, + BTDEV_TYPE_BREDRLE60, }; enum btdev_hook_type { diff --git a/emulator/hciemu.c b/emulator/hciemu.c index 1045043f1..23891a2ee 100644 --- a/emulator/hciemu.c +++ b/emulator/hciemu.c @@ -335,6 +335,9 @@ struct hciemu *hciemu_new(enum hciemu_type type) case HCIEMU_TYPE_BREDRLE50: hciemu->btdev_type = BTDEV_TYPE_BREDRLE50; break; + case HCIEMU_TYPE_BREDRLE60: + hciemu->btdev_type = BTDEV_TYPE_BREDRLE60; + break; default: return NULL; } diff --git a/emulator/hciemu.h b/emulator/hciemu.h index e37c069e1..6f651cb98 100644 --- a/emulator/hciemu.h +++ b/emulator/hciemu.h @@ -32,6 +32,7 @@ enum hciemu_type { HCIEMU_TYPE_LE, HCIEMU_TYPE_LEGACY, HCIEMU_TYPE_BREDRLE50, + HCIEMU_TYPE_BREDRLE60, }; enum hciemu_hook_type { diff --git a/emulator/vhci.c b/emulator/vhci.c index 8dec20a08..7a69b484e 100644 --- a/emulator/vhci.c +++ b/emulator/vhci.c @@ -89,6 +89,7 @@ static void vhci_read_callback(int fd, uint32_t events, void *user_data) case BT_H4_CMD_PKT: case BT_H4_ACL_PKT: case BT_H4_SCO_PKT: + case BT_H4_ISO_PKT: btdev_receive_h4(vhci->btdev, buf, len); break; } @@ -104,7 +105,7 @@ struct vhci *vhci_open(enum vhci_type type) switch (type) { case VHCI_TYPE_BREDRLE: - btdev_type = BTDEV_TYPE_BREDRLE; + btdev_type = BTDEV_TYPE_BREDRLE60; ctrl_type = HCI_PRIMARY; break; case VHCI_TYPE_BREDR: