Return-Path: From: =?UTF-8?q?Micha=C5=82=20Narajowski?= To: linux-bluetooth@vger.kernel.org Cc: =?UTF-8?q?Micha=C5=82=20Narajowski?= Subject: [PATCH BlueZ v2 2/7] monitor: Add LE Extended Advertising commands decoding Date: Tue, 13 Jun 2017 15:18:12 +0200 Message-Id: <20170613131817.18516-3-michal.narajowski@codecoup.pl> In-Reply-To: <20170613131817.18516-1-michal.narajowski@codecoup.pl> References: <20170613131817.18516-1-michal.narajowski@codecoup.pl> Sender: linux-bluetooth-owner@vger.kernel.org List-ID: monitor: Add LE Set Advertising Set Random Address decoding < HCI Command: LE Set Advertising Set Random Address (0x08|0x0035) plen 7 Advertising handle: 0x01 Advertising random address: FF:EE:DD:CC:BB:AA (OUI FF-EE-DD) monitor: Add LE Set Extended Advertising Parameters decoding < HCI Command: LE Set Extended Advertising Parameters (0x08|0x0036) plen 25 Handle: 0x01 Properties: 0x001d Connectable Directed High Duty Cycle Directed Connectable Use legacy advertising PDUs: ADV_DIRECT_IND (high duty cycle) Min advertising interval: 0.000 msec (0x0000) Max advertising interval: 40960.000 msec (0x10000) Channel map: 38 (0x02) Own address type: Random (0x03) Peer address type: Reserved (0x0a) Peer address: 01-0A-0A-0A-0A-0A Filter policy: Allow Scan Request from Any, Allow Connect Request from White List Only (0x02) Tx power: 0x03 Primary PHY: Reserved (0x04) Secondary max skip: 0x05 Secondary PHY: Reserved (0x06) SID: 0x00 Scan request notifications: Disabled monitor: Add LE Set Extended Advertising Data decoding < HCI Command: LE Set Extended Advertising Data (0x08|0x0037) plen 9 Handle: 0x01 Operation: Complete extended advertising data Fragment preference: Fragment all Data length: 0x05 a0 a1 a2 a3 a4 ..... monitor: Add LE Set Extended Scan Response Data decoding < HCI Command: LE Set Extended Scan Response Data (0x08|0x0038) plen 9 Handle: 0x01 Operation: Complete scan response data Fragment preference: Fragment all Data length: 0x05 b0 b1 b2 b3 b4 ..... monitor: Add LE Set Extended Advertising Enable decoding < HCI Command: LE Set Extended Advertising Enable (0x08|0x0039) plen 24 Ext adv: Enabled Number of sets: 2 Entry 0 Handle: 0xff Duration: 0 ms (0x00) Max ext adv events: 0 Entry 1 Handle: 0x00 Duration: 0 ms (0x00) Max ext adv events: 1 monitor: Add LE Read Maximum Advertising Data Length decoding monitor: Add LE Read Number of Supported Advertising Sets decoding monitor: Add LE Remove Advertising Set decoding < HCI Command: LE Remove Advertising Set (0x08|0x003c) plen 1 Handle: 1 monitor: Add LE Clear Advertising Sets decoding monitor: Add LE Advertising Set Terminated Event decoding monitor: Add LE Scan Request Received Event decoding --- monitor/bt.h | 92 +++++++++++++ monitor/packet.c | 411 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 492 insertions(+), 11 deletions(-) diff --git a/monitor/bt.h b/monitor/bt.h index a877b2c..aa55579 100644 --- a/monitor/bt.h +++ b/monitor/bt.h @@ -2176,6 +2176,83 @@ struct bt_hci_cmd_le_enhanced_transmitter_test { uint8_t phy; } __attribute__((packed)); +#define BT_HCI_CMD_LE_SET_ADV_SET_RAND_ADDR 0x2035 +struct bt_hci_cmd_le_set_adv_set_rand_addr { + uint8_t handle; + uint8_t bdaddr[6]; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_SET_EXT_ADV_PARAMS 0x2036 +struct bt_hci_cmd_le_set_ext_adv_params { + uint8_t handle; + uint16_t evt_properties; + uint8_t min_interval[3]; + uint8_t max_interval[3]; + uint8_t channel_map; + uint8_t own_addr_type; + uint8_t peer_addr_type; + uint8_t peer_addr[6]; + uint8_t filter_policy; + uint8_t tx_power; + uint8_t primary_phy; + uint8_t secondary_max_skip; + uint8_t secondary_phy; + uint8_t sid; + uint8_t notif_enable; +} __attribute__ ((packed)); +struct bt_hci_rsp_le_set_ext_adv_params { + uint8_t status; + uint8_t tx_power; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_SET_EXT_ADV_DATA 0x2037 +struct bt_hci_cmd_le_set_ext_adv_data { + uint8_t handle; + uint8_t operation; + uint8_t fragment_preference; + uint8_t data_len; + uint8_t data[0]; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_SET_EXT_SCAN_RSP_DATA 0x2038 +struct bt_hci_cmd_le_set_ext_scan_rsp_data { + uint8_t handle; + uint8_t operation; + uint8_t fragment_preference; + uint8_t data_len; + uint8_t data[0]; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_SET_EXT_ADV_ENABLE 0x2039 +struct bt_hci_cmd_le_set_ext_adv_enable { + uint8_t enable; + uint8_t num_of_sets; +} __attribute__ ((packed)); +struct bt_hci_cmd_ext_adv_set { + uint8_t handle; + uint16_t duration; + uint8_t max_events; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_READ_MAX_ADV_DATA_LEN 0x203a +struct bt_hci_rsp_le_read_max_adv_data_len { + uint8_t status; + uint16_t max_len; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_READ_NUM_SUPPORTED_ADV_SETS 0x203b +struct bt_hci_rsp_le_read_num_supported_adv_sets { + uint8_t status; + uint8_t num_of_sets; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_REMOVE_ADV_SET 0x203c +struct bt_hci_cmd_le_remove_adv_set { + uint8_t handle; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_LE_CLEAR_ADV_SETS 0x203d + #define BT_HCI_EVT_INQUIRY_COMPLETE 0x01 struct bt_hci_evt_inquiry_complete { uint8_t status; @@ -2786,6 +2863,21 @@ struct bt_hci_evt_le_phy_update_complete { uint8_t rx_phy; } __attribute__ ((packed)); +#define BT_HCI_EVT_LE_ADV_SET_TERM 0x12 +struct bt_hci_evt_le_adv_set_term { + uint8_t status; + uint8_t handle; + uint16_t conn_handle; + uint8_t num_evts; +} __attribute__ ((packed)); + +#define BT_HCI_EVT_LE_SCAN_REQ_RECEIVED 0x13 +struct bt_hci_evt_le_scan_req_received { + uint8_t handle; + uint8_t scanner_addr_type; + uint8_t scanner_addr[6]; +} __attribute__ ((packed)); + #define BT_HCI_EVT_LE_CHAN_SELECT_ALG 0x14 struct bt_hci_evt_le_chan_select_alg { uint16_t handle; diff --git a/monitor/packet.c b/monitor/packet.c index f2ea610..8827f5e 100644 --- a/monitor/packet.c +++ b/monitor/packet.c @@ -6932,6 +6932,354 @@ static void le_enhanced_transmitter_test_cmd(const void *data, uint8_t size) print_field("PHY: %s (0x%2.2x)", str, cmd->phy); } +static void le_set_adv_set_rand_addr(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_le_set_adv_set_rand_addr *cmd = data; + + print_field("Advertising handle: 0x%2.2x", cmd->handle); + print_addr("Advertising random address", cmd->bdaddr, 0x00); +} + +static const struct { + uint8_t bit; + const char *str; +} ext_adv_properties_table[] = { + { 0, "Connectable" }, + { 1, "Scannable" }, + { 2, "Directed" }, + { 3, "High Duty Cycle Directed Connectable" }, + { 4, "Use legacy advertising PDUs" }, + { 5, "Anonymous advertising" }, + { 6, "Include TxPower" }, + { } +}; + +static const char *get_adv_pdu_desc(uint16_t flags) +{ + const char *str; + + switch (flags) { + case 0x10: + str = "ADV_NONCONN_IND"; + break; + case 0x12: + str = "ADV_SCAN_IND"; + break; + case 0x13: + str = "ADV_IND"; + break; + case 0x15: + str = "ADV_DIRECT_IND (low duty cycle)"; + break; + case 0x1d: + str = "ADV_DIRECT_IND (high duty cycle)"; + break; + default: + str = "Reserved"; + break; + } + + return str; +} + +static void print_ext_adv_properties(uint16_t flags) +{ + uint16_t mask = flags; + const char *property; + int i; + + print_field("Properties: 0x%4.4x", flags); + + for (i = 0; ext_adv_properties_table[i].str; i++) { + if (flags & (1 << ext_adv_properties_table[i].bit)) { + property = ext_adv_properties_table[i].str; + + if (ext_adv_properties_table[i].bit == 4) { + print_field(" %s: %s", property, + get_adv_pdu_desc(flags)); + } else { + print_field(" %s", property); + } + mask &= ~(1 << ext_adv_properties_table[i].bit); + } + } + + if (mask) + print_text(COLOR_UNKNOWN_ADV_FLAG, + " Unknown advertising properties (0x%4.4x)", + mask); +} + +static void print_ext_slot_625(const char *label, const uint8_t value[3]) +{ + uint32_t value_cpu = value[0]; + + value_cpu |= value[1] << 8; + value_cpu |= value[2] << 16; + + print_field("%s: %.3f msec (0x%4.4x)", label, + value_cpu * 0.625, value_cpu); +} + +static void le_set_ext_adv_params_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_le_set_ext_adv_params *cmd = data; + const char *str; + + print_field("Handle: 0x%2.2x", cmd->handle); + print_ext_adv_properties(le16_to_cpu(cmd->evt_properties)); + + print_ext_slot_625("Min advertising interval", cmd->min_interval); + print_ext_slot_625("Max advertising interval", cmd->max_interval); + + switch (cmd->channel_map) { + case 0x01: + str = "37"; + break; + case 0x02: + str = "38"; + break; + case 0x03: + str = "37, 38"; + break; + case 0x04: + str = "39"; + break; + case 0x05: + str = "37, 39"; + break; + case 0x06: + str = "38, 39"; + break; + case 0x07: + str = "37, 38, 39"; + break; + default: + str = "Reserved"; + break; + } + + print_field("Channel map: %s (0x%2.2x)", str, cmd->channel_map); + + print_own_addr_type(cmd->own_addr_type); + print_peer_addr_type("Peer address type", cmd->peer_addr_type); + print_addr("Peer address", cmd->peer_addr, cmd->peer_addr_type); + + switch (cmd->filter_policy) { + case 0x00: + str = "Allow Scan Request from Any, " + "Allow Connect Request from Any"; + break; + case 0x01: + str = "Allow Scan Request from White List Only, " + "Allow Connect Request from Any"; + break; + case 0x02: + str = "Allow Scan Request from Any, " + "Allow Connect Request from White List Only"; + break; + case 0x03: + str = "Allow Scan Request from White List Only, " + "Allow Connect Request from White List Only"; + break; + default: + str = "Reserved"; + break; + } + + print_field("Filter policy: %s (0x%2.2x)", str, cmd->filter_policy); + print_field("Tx power: 0x%2.2x", cmd->tx_power); + + switch (cmd->primary_phy) { + case 0x01: + str = "LE 1M"; + break; + case 0x03: + str = "LE Coded"; + break; + default: + str = "Reserved"; + break; + } + + print_field("Primary PHY: %s (0x%2.2x)", str, cmd->primary_phy); + print_field("Secondary max skip: 0x%2.2x", cmd->secondary_max_skip); + print_le_phy("Secondary PHY", cmd->secondary_phy); + print_field("SID: 0x%2.2x", cmd->sid); + + switch (cmd->notif_enable) { + case 0x00: + str = "Disabled"; + break; + case 0x01: + str = "Enabled"; + break; + default: + str = "Reserved"; + break; + } + print_field("Scan request notifications: %s", str); +} + +static void le_set_ext_adv_params_rsp(const void *data, uint8_t size) +{ + const struct bt_hci_rsp_le_set_ext_adv_params *rsp = data; + + print_status(rsp->status); + print_field("Selected Tx power: 0x%2.2x", rsp->tx_power); +} + +static void le_set_ext_adv_data_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_le_set_ext_adv_data *cmd = data; + const char *str; + + print_field("Handle: 0x%2.2x", cmd->handle); + + switch (cmd->operation) { + case 0x00: + str = "Immediate fragment"; + break; + case 0x01: + str = "First fragment"; + break; + case 0x02: + str = "Last fragment"; + break; + case 0x03: + str = "Complete extended advertising data"; + break; + case 0x04: + str = "Unchanged data"; + break; + default: + str = "Reserved"; + break; + } + print_field("Operation: %s", str); + + switch (cmd->fragment_preference) { + case 0x00: + str = "Fragment all"; + break; + case 0x01: + str = "Minimize fragmentation"; + break; + default: + str = "Reserved"; + break; + } + print_field("Fragment preference: %s", str); + print_field("Data length: 0x%2.2x", cmd->data_len); + packet_print_ad(cmd->data, size - sizeof(*cmd)); +} + +static void le_set_ext_scan_rsp_data_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_le_set_ext_scan_rsp_data *cmd = data; + const char *str; + + print_field("Handle: 0x%2.2x", cmd->handle); + + switch (cmd->operation) { + case 0x00: + str = "Immediate fragment"; + break; + case 0x01: + str = "First fragment"; + break; + case 0x02: + str = "Last fragment"; + break; + case 0x03: + str = "Complete scan response data"; + break; + case 0x04: + str = "Unchanged data"; + break; + default: + str = "Reserved"; + break; + } + print_field("Operation: %s", str); + + switch (cmd->fragment_preference) { + case 0x00: + str = "Fragment all"; + break; + case 0x01: + str = "Minimize fragmentation"; + break; + default: + str = "Reserved"; + break; + } + print_field("Fragment preference: %s", str); + print_field("Data length: 0x%2.2x", cmd->data_len); + packet_print_ad(cmd->data, size - sizeof(*cmd)); +} + +static void le_set_ext_adv_enable_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_le_set_ext_adv_enable *cmd = data; + const struct bt_hci_cmd_ext_adv_set *adv_set; + const char *str; + int i; + + switch (cmd->enable) { + case 0x00: + str = "Disable"; + break; + case 0x01: + str = "Enabled"; + break; + default: + str = "Reserved"; + break; + } + + print_field("Ext adv: %s", str); + + if (cmd->num_of_sets == 0) + print_field("Number of sets: Disable all advertising sets"); + else if (cmd->num_of_sets > 0x3f) + print_field("Number of sets: Reserved"); + else + print_field("Number of sets: %u", cmd->num_of_sets); + + for (i = 0; i < cmd->num_of_sets; ++i) { + adv_set = data + 2 + i * sizeof(struct bt_hci_cmd_ext_adv_set); + print_field("Entry %d", i); + print_field(" Handle: 0x%2.2x", adv_set->handle); + print_field(" Duration: %d ms (0x%2.2x)", + adv_set->duration * 10, adv_set->duration); + print_field(" Max ext adv events: %d", adv_set->max_events); + } +} + +static void le_read_max_adv_data_len_rsp(const void *data, uint8_t size) +{ + const struct bt_hci_rsp_le_read_max_adv_data_len *rsp = data; + + print_status(rsp->status); + print_field("Max length: %d", rsp->max_len); +} + +static void le_read_num_supported_adv_sets_rsp(const void *data, uint8_t size) +{ + const struct bt_hci_rsp_le_read_num_supported_adv_sets *rsp = data; + + print_status(rsp->status); + print_field("Num supported adv sets: %d", rsp->num_of_sets); +} + +static void le_remove_adv_set_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_le_remove_adv_set *cmd = data; + + print_handle(cmd->handle); +} + struct opcode_data { uint16_t opcode; int bit; @@ -7641,15 +7989,33 @@ static const struct opcode_data opcode_table[] = { { 0x2034, 288, "LE Enhanced Transmitter Test", le_enhanced_transmitter_test_cmd, 4, true, status_rsp, 1, true }, - { 0x2035, 289, "LE Set Advertising Set Random Address" }, - { 0x2036, 290, "LE Set Extended Advertising Parameters" }, - { 0x2037, 291, "LE Set Extended Advertising Data" }, - { 0x2038, 292, "LE Set Extended Scan Response Data" }, - { 0x2039, 293, "LE Set Extended Advertising Enable" }, - { 0x203a, 294, "LE Read Maximum Advertising Data Length" }, - { 0x203b, 295, "LE Read Number of Supported Advertising Sets" }, - { 0x203c, 296, "LE Remove Advertising Set" }, - { 0x203d, 297, "LE Clear Advertising Sets" }, + { 0x2035, 289, "LE Set Advertising Set Random Address", + le_set_adv_set_rand_addr, 7, true, + status_rsp, 1, true }, + { 0x2036, 290, "LE Set Extended Advertising Parameters", + le_set_ext_adv_params_cmd, 25, true, + le_set_ext_adv_params_rsp, 2, true }, + { 0x2037, 291, "LE Set Extended Advertising Data", + le_set_ext_adv_data_cmd, 4, false, + status_rsp, 1, true }, + { 0x2038, 292, "LE Set Extended Scan Response Data", + le_set_ext_scan_rsp_data_cmd, 4, false, + status_rsp, 1, true }, + { 0x2039, 293, "LE Set Extended Advertising Enable", + le_set_ext_adv_enable_cmd, 2, false, + status_rsp, 1, true }, + { 0x203a, 294, "LE Read Maximum Advertising Data Length", + null_cmd, 0, true, + le_read_max_adv_data_len_rsp, 3, true }, + { 0x203b, 295, "LE Read Number of Supported Advertising Sets", + null_cmd, 0, true, + le_read_num_supported_adv_sets_rsp, 2, true }, + { 0x203c, 296, "LE Remove Advertising Set", + le_remove_adv_set_cmd, 1, true, + status_rsp, 1, true }, + { 0x203d, 297, "LE Clear Advertising Sets", + null_cmd, 0, true, + status_rsp, 1, true }, { 0x203e, 298, "LE Set Periodic Advertising Parameters" }, { 0x203f, 299, "LE Set Periodic Advertising Data" }, { 0x2040, 300, "LE Set Periodic Advertising Enable" }, @@ -8770,6 +9136,27 @@ static void le_phy_update_complete_evt(const void *data, uint8_t size) print_le_phy("RX PHY", evt->rx_phy); } +static void le_adv_set_term_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_le_adv_set_term *evt = data; + + print_status(evt->status); + print_field("Handle: %d", evt->handle); + print_field("Connection handle: %d", evt->conn_handle); + print_field("Number of completed extended advertising events: %d", + evt->num_evts); +} + +static void le_scan_req_received_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_le_scan_req_received *evt = data; + + print_field("Handle: %d", evt->handle); + print_peer_addr_type("Scanner ddress type", evt->scanner_addr_type); + print_addr("Scanner address", evt->scanner_addr, + evt->scanner_addr_type); +} + static void le_chan_select_alg_evt(const void *data, uint8_t size) { const struct bt_hci_evt_le_chan_select_alg *evt = data; @@ -8865,8 +9252,10 @@ static const struct subevent_data le_meta_event_table[] = { { 0x0f, "LE Periodic Advertising Report" }, { 0x10, "LE Periodic Advertising Sync Lost" }, { 0x11, "LE Scan Timeout" }, - { 0x12, "LE Advertising Set Terminated" }, - { 0x13, "LE Scan Request Received" }, + { 0x12, "LE Advertising Set Terminated", + le_adv_set_term_evt, 5, true}, + { 0x13, "LE Scan Request Received", + le_scan_req_received_evt, 8, true}, { 0x14, "LE Channel Selection Algorithm", le_chan_select_alg_evt, 3, true}, { } -- 2.9.3