From 7bc76b3d3a26b562a00a2df62dc492db2b722528 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Fri, 2 Nov 2012 08:39:33 +0100 Subject: [PATCH] monitor: Add more decoding of HCI commands and events --- emulator/btdev.c | 14 +- monitor/bt.h | 92 +++- monitor/packet.c | 1304 +++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 1253 insertions(+), 157 deletions(-) diff --git a/emulator/btdev.c b/emulator/btdev.c index 2cb7cf1a1..e4bcda85c 100644 --- a/emulator/btdev.c +++ b/emulator/btdev.c @@ -506,7 +506,7 @@ static void disconnect_complete(struct btdev *btdev, uint16_t handle, static void name_request_complete(struct btdev *btdev, const uint8_t *bdaddr, uint8_t status) { - struct bt_hci_evt_remote_name_req_complete nc; + struct bt_hci_evt_remote_name_request_complete nc; nc.status = status; memcpy(nc.bdaddr, bdaddr, 6); @@ -626,7 +626,7 @@ static void process_cmd(struct btdev *btdev, const void *data, uint16_t len) const struct bt_hci_cmd_write_voice_setting *wvs; const struct bt_hci_cmd_write_inquiry_mode *wim; const struct bt_hci_cmd_write_afh_assess_mode *waam; - const struct bt_hci_cmd_write_ext_inquiry_rsp *weir; + const struct bt_hci_cmd_write_ext_inquiry_response *weir; const struct bt_hci_cmd_write_simple_pairing_mode *wspm; const struct bt_hci_cmd_write_le_host_supported *wlhs; const struct bt_hci_cmd_le_set_event_mask *lsem; @@ -643,9 +643,9 @@ static void process_cmd(struct btdev *btdev, const void *data, uint16_t len) struct bt_hci_rsp_read_voice_setting rvs; struct bt_hci_rsp_read_inquiry_mode rim; struct bt_hci_rsp_read_afh_assess_mode raam; - struct bt_hci_rsp_read_ext_inquiry_rsp reir; + struct bt_hci_rsp_read_ext_inquiry_response reir; struct bt_hci_rsp_read_simple_pairing_mode rspm; - struct bt_hci_rsp_read_inquiry_rsp_tx_power rirtp; + struct bt_hci_rsp_read_inquiry_resp_tx_power rirtp; struct bt_hci_rsp_read_le_host_supported rlhs; struct bt_hci_rsp_read_local_version rlv; struct bt_hci_rsp_read_local_commands rlc; @@ -910,14 +910,14 @@ static void process_cmd(struct btdev *btdev, const void *data, uint16_t len) cmd_complete(btdev, opcode, &status, sizeof(status)); break; - case BT_HCI_CMD_READ_EXT_INQUIRY_RSP: + case BT_HCI_CMD_READ_EXT_INQUIRY_RESPONSE: reir.status = BT_HCI_ERR_SUCCESS; reir.fec = btdev->ext_inquiry_fec; memcpy(reir.data, btdev->ext_inquiry_rsp, 240); cmd_complete(btdev, opcode, &reir, sizeof(reir)); break; - case BT_HCI_CMD_WRITE_EXT_INQUIRY_RSP: + case BT_HCI_CMD_WRITE_EXT_INQUIRY_RESPONSE: weir = data + sizeof(*hdr); btdev->ext_inquiry_fec = weir->fec; memcpy(btdev->ext_inquiry_rsp, weir->data, 240); @@ -938,7 +938,7 @@ static void process_cmd(struct btdev *btdev, const void *data, uint16_t len) cmd_complete(btdev, opcode, &status, sizeof(status)); break; - case BT_HCI_CMD_READ_INQUIRY_RSP_TX_POWER: + case BT_HCI_CMD_READ_INQUIRY_RESP_TX_POWER: rirtp.status = BT_HCI_ERR_SUCCESS; rirtp.level = 0; cmd_complete(btdev, opcode, &rirtp, sizeof(rirtp)); diff --git a/monitor/bt.h b/monitor/bt.h index 2a68d4cef..214e03582 100644 --- a/monitor/bt.h +++ b/monitor/bt.h @@ -45,11 +45,22 @@ struct bt_hci_evt_hdr { struct bt_hci_cmd_inquiry { uint8_t lap[3]; uint8_t length; - uint8_t num_rsp; + uint8_t num_resp; } __attribute__ ((packed)); #define BT_HCI_CMD_INQUIRY_CANCEL 0x0402 +#define BT_HCI_CMD_PERIODIC_INQUIRY 0x0403 +struct bt_hci_cmd_periodic_inquiry { + uint16_t max_period; + uint16_t min_period; + uint8_t lap[3]; + uint8_t length; + uint8_t num_resp; +} __attribute__ ((packed)); + +#define BT_HCI_CMD_EXIT_PERIODIC_INQUIRY 0x0404 + #define BT_HCI_CMD_CREATE_CONN 0x0405 struct bt_hci_cmd_create_conn { uint8_t bdaddr[6]; @@ -278,15 +289,15 @@ struct bt_hci_cmd_write_afh_assess_mode { uint8_t mode; } __attribute__ ((packed)); -#define BT_HCI_CMD_READ_EXT_INQUIRY_RSP 0x0c51 -struct bt_hci_rsp_read_ext_inquiry_rsp { +#define BT_HCI_CMD_READ_EXT_INQUIRY_RESPONSE 0x0c51 +struct bt_hci_rsp_read_ext_inquiry_response { uint8_t status; uint8_t fec; uint8_t data[240]; } __attribute__ ((packed)); -#define BT_HCI_CMD_WRITE_EXT_INQUIRY_RSP 0x0c52 -struct bt_hci_cmd_write_ext_inquiry_rsp { +#define BT_HCI_CMD_WRITE_EXT_INQUIRY_RESPONSE 0x0c52 +struct bt_hci_cmd_write_ext_inquiry_response { uint8_t fec; uint8_t data[240]; } __attribute__ ((packed)); @@ -302,8 +313,8 @@ struct bt_hci_cmd_write_simple_pairing_mode { uint8_t mode; } __attribute__ ((packed)); -#define BT_HCI_CMD_READ_INQUIRY_RSP_TX_POWER 0x0c58 -struct bt_hci_rsp_read_inquiry_rsp_tx_power { +#define BT_HCI_CMD_READ_INQUIRY_RESP_TX_POWER 0x0c58 +struct bt_hci_rsp_read_inquiry_resp_tx_power { uint8_t status; int8_t level; } __attribute__ ((packed)); @@ -456,7 +467,7 @@ struct bt_hci_evt_inquiry_result { uint8_t pscan_period_mode; uint8_t pscan_mode; uint8_t dev_class[3]; - uint8_t clock_offset; + uint16_t clock_offset; } __attribute__ ((packed)); #define BT_HCI_EVT_CONN_COMPLETE 0x03 @@ -482,13 +493,39 @@ struct bt_hci_evt_disconnect_complete { uint8_t reason; } __attribute__ ((packed)); +#define BT_HCI_EVT_AUTH_COMPLETE 0x06 +struct bt_hci_evt_auth_complete { + uint8_t status; + uint16_t handle; +} __attribute__ ((packed)); + #define BT_HCI_EVT_REMOTE_NAME_REQUEST_COMPLETE 0x07 -struct bt_hci_evt_remote_name_req_complete { +struct bt_hci_evt_remote_name_request_complete { uint8_t status; uint8_t bdaddr[6]; uint8_t name[248]; } __attribute__ ((packed)); +#define BT_HCI_EVT_ENCRYPT_CHANGE 0x08 +struct bt_hci_evt_encrypt_change { + uint8_t status; + uint16_t handle; + uint8_t encr_mode; +} __attribute__ ((packed)); + +#define BT_HCI_EVT_CHANGE_CONN_LINK_KEY_COMPLETE 0x09 +struct bt_hci_evt_change_conn_link_key_complete { + uint8_t status; + uint16_t handle; +} __attribute__ ((packed)); + +#define BT_HCI_EVT_MASTER_LINK_KEY_COMPLETE 0x0a +struct bt_hci_evt_master_link_key_complete { + uint8_t status; + uint16_t handle; + uint8_t key_flag; +} __attribute__ ((packed)); + #define BT_HCI_EVT_REMOTE_FEATURES_COMPLETE 0x0b struct bt_hci_evt_remote_features_complete { uint8_t status; @@ -505,6 +542,8 @@ struct bt_hci_evt_remote_version_complete { uint16_t lmp_subver; } __attribute__ ((packed)); +#define BT_HCI_EVT_QOS_SETUP_COMPLETE 0x0d + #define BT_HCI_EVT_CMD_COMPLETE 0x0e struct bt_hci_evt_cmd_complete { uint8_t ncmd; @@ -518,6 +557,23 @@ struct bt_hci_evt_cmd_status { uint16_t opcode; } __attribute__ ((packed)); +#define BT_HCI_EVT_HARDWARE_ERROR 0x10 +struct bt_hci_evt_hardware_error { + uint8_t code; +} __attribute__ ((packed)); + +#define BT_HCI_EVT_FLUSH_OCCURRED 0x11 +struct bt_hci_evt_flush_occurred { + uint16_t handle; +} __attribute__ ((packed)); + +#define BT_HCI_EVT_ROLE_CHANGE 0x12 +struct bt_hci_evt_role_change { + uint8_t status; + uint8_t bdaddr[6]; + uint8_t role; +} __attribute__ ((packed)); + #define BT_HCI_EVT_NUM_COMPLETED_PACKETS 0x13 struct bt_hci_evt_num_completed_packets { uint8_t num_handles; @@ -525,6 +581,12 @@ struct bt_hci_evt_num_completed_packets { uint16_t count; } __attribute__ ((packed)); +#define BT_HCI_EVT_MAX_SLOTS_CHANGE 0x1b +struct bt_hci_evt_max_slots_change { + uint16_t handle; + uint8_t max_slots; +} __attribute__ ((packed)); + #define BT_HCI_EVT_CONN_PKT_TYPE_CHANGED 0x1d struct bt_hci_evt_conn_pkt_type_changed { uint8_t status; @@ -532,6 +594,12 @@ struct bt_hci_evt_conn_pkt_type_changed { uint16_t pkt_type; } __attribute__ ((packed)); +#define BT_HCI_EVT_PSCAN_REP_MODE_CHANGE 0x20 +struct bt_hci_evt_pscan_rep_mode_change { + uint8_t bdaddr[6]; + uint8_t pscan_rep_mode; +} __attribute__ ((packed)); + #define BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI 0x22 struct bt_hci_evt_inquiry_result_with_rssi { uint8_t num_resp; @@ -564,6 +632,12 @@ struct bt_hci_evt_ext_inquiry_result { uint8_t data[240]; } __attribute__ ((packed)); +#define BT_HCI_EVT_REMOTE_HOST_FEATURES_NOTIFY 0x3d +struct bt_hci_evt_remote_host_features_notify { + uint8_t bdaddr[6]; + uint8_t features[8]; +} __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 f10502e37..4e5e2d898 100644 --- a/monitor/packet.c +++ b/monitor/packet.c @@ -89,9 +89,9 @@ static void print_header(struct timeval *tv, uint16_t index) #define print_field(fmt, args...) printf("%-12c" fmt "\n", ' ', ## args) static const struct { - uint8_t status; + uint8_t error; const char *str; -} status2str_table[] = { +} error2str_table[] = { { 0x00, "Success" }, { 0x01, "Unknown HCI Command" }, { 0x02, "Unknown Connection Identifier" }, @@ -159,30 +159,316 @@ static const struct { { } }; -static void print_status(uint8_t status) +static void print_error(const char *label, uint8_t error) { const char *str = "Unknown"; int i; - for (i = 0; status2str_table[i].str; i++) { - if (status2str_table[i].status == status) { - str = status2str_table[i].str; + for (i = 0; error2str_table[i].str; i++) { + if (error2str_table[i].error == error) { + str = error2str_table[i].str; break; } } - print_field("Status: %s (0x%2.2x)", str, status); + print_field("%s: %s (0x%2.2x)", label, str, error); +} + +static void print_status(uint8_t status) +{ + print_error("Status", status); +} + +static void print_reason(uint8_t reason) +{ + print_error("Reason", reason); +} + +static void print_bdaddr(const uint8_t *bdaddr) +{ + print_field("Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", + bdaddr[5], bdaddr[4], bdaddr[3], + bdaddr[2], bdaddr[1], bdaddr[0]); +} + +static void print_handle(uint16_t handle) +{ + print_field("Handle: %d", btohs(handle)); +} + +static void print_pkt_type(uint16_t pkt_type) +{ + print_field("Packet type: 0x%4.4x", btohs(pkt_type)); +} + +static void print_iac(const uint8_t *lap) +{ + print_field("Access code: 0x%2.2x%2.2x%2.2x", lap[2], lap[1], lap[0]); } -static void print_class(const uint8_t *dev_class) +static void print_dev_class(const uint8_t *dev_class) { print_field("Class: 0x%2.2x%2.2x%2.2x", dev_class[2], dev_class[1], dev_class[0]); } +static void print_voice_setting(uint16_t setting) +{ + print_field("Setting: 0x%4.4x", btohs(setting)); +} + +static void print_link_policy(uint16_t link_policy) +{ + print_field("Link policy: 0x%4.4x", btohs(link_policy)); +} + +static void print_inquiry_mode(uint8_t mode) +{ + const char *str; + + switch (mode) { + case 0x00: + str = "Standard Inquiry Result"; + break; + case 0x01: + str = "Inquiry Result with RSSI"; + break; + case 0x02: + str = "Inquiry Result with RSSI or Extended Inquiry Result"; + break; + default: + str = "Reserved"; + break; + } + + print_field("Mode: %s (0x%2.2x)", str, mode); +} + +static void print_simple_pairing_mode(uint8_t mode) +{ + const char *str; + + switch (mode) { + case 0x00: + str = "Disabled"; + break; + case 0x01: + str = "Enabled"; + break; + default: + str = "Reserved"; + break; + } + + print_field("Mode: %s (0x%2.2x)", str, mode); +} + +static void print_pscan_rep_mode(uint8_t pscan_rep_mode) +{ + const char *str; + + switch (pscan_rep_mode) { + case 0x00: + str = "R0"; + break; + case 0x01: + str = "R1"; + break; + case 0x02: + str = "R3"; + break; + default: + str = "Reserved"; + break; + } + + print_field("Page scan repetition mode: %s (0x%2.2x)", + str, pscan_rep_mode); +} + +static void print_pscan_period_mode(uint8_t pscan_period_mode) +{ + const char *str; + + switch (pscan_period_mode) { + case 0x00: + str = "P0"; + break; + case 0x01: + str = "P1"; + break; + case 0x02: + str = "P3"; + break; + default: + str = "Reserved"; + break; + } + + print_field("Page period mode: %s (0x%2.2x)", str, pscan_period_mode); +} + +static void print_pscan_mode(uint8_t pscan_mode) +{ + const char *str; + + switch (pscan_mode) { + case 0x00: + str = "Mandatory"; + break; + case 0x01: + str = "Optional I"; + break; + case 0x02: + str = "Optional II"; + break; + case 0x03: + str = "Optional III"; + break; + default: + str = "Reserved"; + break; + } + + print_field("Page scan mode: %s (0x%2.2x)", str, pscan_mode); +} + +static void print_clock_offset(uint16_t clock_offset) +{ + print_field("Clock offset: 0x%4.4x", btohs(clock_offset)); +} + +static void print_link_type(uint8_t link_type) +{ + const char *str; + + switch (link_type) { + case 0x00: + str = "SCO"; + break; + case 0x01: + str = "ACL"; + break; + default: + str = "Reserved"; + break; + } + + print_field("Link type: %s (0x%2.2x)", str, link_type); +} + +static void print_encr_mode(uint8_t encr_mode) +{ + const char *str; + + switch (encr_mode) { + case 0x00: + str = "Disabled"; + break; + case 0x01: + str = "Enabled"; + break; + default: + str = "Reserved"; + break; + } + + print_field("Encryption: %s (0x%2.2x)", str, encr_mode); +} + +static void print_key_flag(uint8_t key_flag) +{ + const char *str; + + switch (key_flag) { + case 0x00: + str = "Semi-permanent"; + break; + case 0x01: + str = "Temporary"; + break; + default: + str = "Reserved"; + break; + } + + print_field("Key flag: %s (0x%2.2x)", str, key_flag); +} + +static void print_num_resp(uint8_t num_resp) +{ + print_field("Num responses: %d", num_resp); +} + +static void print_timeout(uint16_t timeout) +{ + print_field("Timeout: %.3f msec (0x%4.4x)", + btohs(timeout) * 0.625, btohs(timeout)); +} + +static void print_role(uint8_t role) +{ + const char *str; + + switch (role) { + case 0x00: + str = "Master"; + break; + case 0x01: + str = "Slave"; + break; + default: + str = "Reserved"; + break; + } + + print_field("Role: %s (0x%2.2x)", str, role); +} + +static void print_name(const uint8_t *name) +{ + char str[249]; + + memcpy(str, name, 248); + str[248] = '\0'; + + print_field("Name: %s", str); +} + +static void print_version(const char *label, uint8_t version, uint16_t revision) +{ + print_field("%s: %d - 0x%4.4x", label, version, revision); +} + +static void print_hci_version(uint8_t hci_ver, uint16_t hci_rev) +{ + print_version("HCI version", hci_ver, hci_rev); +} + +static void print_lmp_version(uint8_t lmp_ver, uint16_t lmp_subver) +{ + print_version("LMP version", lmp_ver, lmp_subver); +} + +static void print_manufacturer(uint16_t manufacturer) +{ + print_field("Manufacturer: %d", manufacturer); +} + +static void print_commands(const uint8_t *commands) +{ + char str[129]; + int i; + + for (i = 0; i < 64; i++) + sprintf(str + (i * 2), "%2.2x", commands[i]); + + print_field("Commands: 0x%s", str); +} + static void print_features(const uint8_t *features) { - char str[41] = ""; + char str[41]; int i; for (i = 0; i < 8; i++) @@ -191,6 +477,41 @@ static void print_features(const uint8_t *features) print_field("Features:%s", str); } +static void print_event_mask(const uint8_t *mask) +{ + char str[17]; + int i; + + for (i = 0; i < 8; i++) + sprintf(str + (i * 2), "%2.2x", mask[i]); + + print_field("Mask: 0x%s", str); +} + +static void print_fec(uint8_t fec) +{ + const char *str; + + switch (fec) { + case 0x00: + str = "Not required"; + break; + case 0x01: + str = "Required"; + break; + default: + str = "Reserved"; + break; + } + + print_field("FEC: %s (0x%02x)", str, fec); +} + +static void print_eir(const uint8_t *eir) +{ + packet_hexdump(eir, 240); +} + void packet_hexdump(const unsigned char *buf, uint16_t len) { static const char hexdigits[] = "0123456789abcdef"; @@ -281,93 +602,418 @@ uint32_t packet_get_flags(uint16_t opcode) break; } - return 0xff; + return 0xff; +} + +uint16_t packet_get_opcode(uint32_t flags) +{ + if (flags & 0x02) { + if (flags & 0x01) + return MONITOR_EVENT_PKT; + else + return MONITOR_COMMAND_PKT; + } else { + if (flags & 0x01) + return MONITOR_ACL_RX_PKT; + else + return MONITOR_ACL_TX_PKT; + } + + return 0xff; +} + +void packet_monitor(struct timeval *tv, uint16_t index, uint16_t opcode, + const void *data, uint16_t size) +{ + const struct monitor_new_index *ni; + char str[18]; + + switch (opcode) { + case MONITOR_NEW_INDEX: + ni = data; + + if (index < MAX_INDEX) + memcpy(&index_list[index], ni, MONITOR_NEW_INDEX_SIZE); + + ba2str(&ni->bdaddr, str); + packet_new_index(tv, index, str, ni->type, ni->bus, ni->name); + break; + case MONITOR_DEL_INDEX: + if (index < MAX_INDEX) + ba2str(&index_list[index].bdaddr, str); + else + ba2str(BDADDR_ANY, str); + + packet_del_index(tv, index, str); + break; + case MONITOR_COMMAND_PKT: + packet_hci_command(tv, index, data, size); + break; + case MONITOR_EVENT_PKT: + packet_hci_event(tv, index, data, size); + break; + case MONITOR_ACL_TX_PKT: + packet_hci_acldata(tv, index, false, data, size); + break; + case MONITOR_ACL_RX_PKT: + packet_hci_acldata(tv, index, true, data, size); + break; + case MONITOR_SCO_TX_PKT: + packet_hci_scodata(tv, index, false, data, size); + break; + case MONITOR_SCO_RX_PKT: + packet_hci_scodata(tv, index, true, data, size); + break; + default: + print_header(tv, index); + printf("* Unknown packet (code %d len %d)\n", opcode, size); + packet_hexdump(data, size); + break; + } +} + +static void null_cmd(const void *data, uint8_t size) +{ +} + +static void status_rsp(const void *data, uint8_t size) +{ + uint8_t status = *((const uint8_t *) data); + + print_status(status); +} + +static void status_bdaddr_rsp(const void *data, uint8_t size) +{ + uint8_t status = *((const uint8_t *) data); + + print_status(status); + print_bdaddr(data + 1); +} + +static void inquiry_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_inquiry *cmd = data; + + print_iac(cmd->lap); + print_field("Length: %.2fs (0x%2.2x)", + cmd->length * 1.28, cmd->length); + print_num_resp(cmd->num_resp); +} + +static void periodic_inquiry_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_periodic_inquiry *cmd = data; + + print_field("Max period: %.2fs (0x%2.2x)", + cmd->max_period * 1.28, cmd->max_period); + print_field("Min period: %.2fs (0x%2.2x)", + cmd->min_period * 1.28, cmd->min_period); + print_iac(cmd->lap); + print_field("Length: %.2fs (0x%2.2x)", + cmd->length * 1.28, cmd->length); + print_num_resp(cmd->num_resp); +} + +static void create_conn_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_create_conn *cmd = data; + const char *str; + + print_bdaddr(cmd->bdaddr); + print_pkt_type(cmd->pkt_type); + print_pscan_rep_mode(cmd->pscan_rep_mode); + print_pscan_mode(cmd->pscan_mode); + print_clock_offset(cmd->clock_offset); + + switch (cmd->role_switch) { + case 0x00: + str = "Stay master"; + break; + case 0x01: + str = "Allow slave"; + break; + default: + str = "Reserved"; + break; + } + + print_field("Role switch: %s (0x%2.2x)", str, cmd->role_switch); +} + +static void disconnect_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_disconnect *cmd = data; + + print_handle(cmd->handle); + print_reason(cmd->reason); +} + +static void add_sco_conn_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_add_sco_conn *cmd = data; + + print_handle(cmd->handle); + print_pkt_type(cmd->pkt_type); +} + +static void create_conn_cancel_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_create_conn_cancel *cmd = data; + + print_bdaddr(cmd->bdaddr); +} + +static void accept_conn_request_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_accept_conn_request *cmd = data; + + print_bdaddr(cmd->bdaddr); + print_role(cmd->role); +} + +static void reject_conn_request_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_reject_conn_request *cmd = data; + + print_bdaddr(cmd->bdaddr); + print_reason(cmd->reason); +} + +static void remote_name_request_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_remote_name_request *cmd = data; + + print_bdaddr(cmd->bdaddr); + print_pscan_rep_mode(cmd->pscan_rep_mode); + print_pscan_mode(cmd->pscan_mode); + print_clock_offset(cmd->clock_offset); +} + +static void remote_name_request_cancel_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_remote_name_request_cancel *cmd = data; + + print_bdaddr(cmd->bdaddr); +} + +static void read_remote_features_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_read_remote_features *cmd = data; + + print_handle(cmd->handle); +} + +static void read_remote_ext_features_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_read_remote_ext_features *cmd = data; + + print_handle(cmd->handle); + print_field("Page: %d", cmd->page); +} + +static void read_remote_version_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_read_remote_version *cmd = data; + + print_handle(cmd->handle); +} + +static void read_default_link_policy_rsp(const void *data, uint8_t size) +{ + const struct bt_hci_rsp_read_default_link_policy *rsp = data; + + print_status(rsp->status); + print_link_policy(rsp->policy); +} + +static void write_default_link_policy_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_write_default_link_policy *cmd = data; + + print_link_policy(cmd->policy); +} + +static void set_event_mask_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_set_event_mask *cmd = data; + + print_event_mask(cmd->mask); +} + +static void set_event_filter_cmd(const void *data, uint8_t size) +{ + uint8_t type = *((const uint8_t *) data); + + print_field("Type: 0x%2.2x", type); + + packet_hexdump(data + 1, size - 1); +} + +static void delete_stored_link_key_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_delete_stored_link_key *cmd = data; + + print_bdaddr(cmd->bdaddr); + print_field("Delete all: 0x%2.2x", cmd->delete_all); +} + +static void delete_stored_link_key_rsp(const void *data, uint8_t size) +{ + const struct bt_hci_rsp_delete_stored_link_key *rsp = data; + + print_status(rsp->status); + print_field("Num keys: %d", btohs(rsp->num_keys)); +} + +static void write_local_name_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_write_local_name *cmd = data; + + print_name(cmd->name); +} + +static void read_local_name_rsp(const void *data, uint8_t size) +{ + const struct bt_hci_rsp_read_local_name *rsp = data; + + print_status(rsp->status); + print_name(rsp->name); +} + +static void read_conn_accept_timeout_rsp(const void *data, uint8_t size) +{ + const struct bt_hci_rsp_read_conn_accept_timeout *rsp = data; + + print_status(rsp->status); + print_timeout(rsp->timeout); +} + +static void write_conn_accept_timeout_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_write_conn_accept_timeout *cmd = data; + + print_timeout(cmd->timeout); +} + +static void read_class_of_dev_rsp(const void *data, uint8_t size) +{ + const struct bt_hci_rsp_read_class_of_dev *rsp = data; + + print_status(rsp->status); + print_dev_class(rsp->dev_class); +} + +static void write_class_of_dev_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_write_class_of_dev *cmd = data; + + print_dev_class(cmd->dev_class); +} + +static void read_voice_setting_rsp(const void *data, uint8_t size) +{ + const struct bt_hci_rsp_read_voice_setting *rsp = data; + + print_status(rsp->status); + print_voice_setting(rsp->setting); +} + +static void write_voice_setting_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_write_voice_setting *cmd = data; + + print_voice_setting(cmd->setting); +} + +static void read_inquiry_mode_rsp(const void *data, uint8_t size) +{ + const struct bt_hci_rsp_read_inquiry_mode *rsp = data; + + print_status(rsp->status); + print_inquiry_mode(rsp->mode); +} + +static void write_inquiry_mode_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_write_inquiry_mode *cmd = data; + + print_inquiry_mode(cmd->mode); +} + +static void read_ext_inquiry_response_rsp(const void *data, uint8_t size) +{ + const struct bt_hci_rsp_read_ext_inquiry_response *rsp = data; + + print_status(rsp->status); + print_fec(rsp->fec); + print_eir(rsp->data); +} + +static void write_ext_inquiry_response_cmd(const void *data, uint8_t size) +{ + const struct bt_hci_cmd_write_ext_inquiry_response *cmd = data; + + print_fec(cmd->fec); + print_eir(cmd->data); } -uint16_t packet_get_opcode(uint32_t flags) +static void read_simple_pairing_mode_rsp(const void *data, uint8_t size) { - if (flags & 0x02) { - if (flags & 0x01) - return MONITOR_EVENT_PKT; - else - return MONITOR_COMMAND_PKT; - } else { - if (flags & 0x01) - return MONITOR_ACL_RX_PKT; - else - return MONITOR_ACL_TX_PKT; - } + const struct bt_hci_rsp_read_simple_pairing_mode *rsp = data; - return 0xff; + print_status(rsp->status); + print_simple_pairing_mode(rsp->mode); } -void packet_monitor(struct timeval *tv, uint16_t index, uint16_t opcode, - const void *data, uint16_t size) +static void write_simple_pairing_mode_cmd(const void *data, uint8_t size) { - const struct monitor_new_index *ni; - char str[18]; + const struct bt_hci_cmd_write_simple_pairing_mode *cmd = data; - switch (opcode) { - case MONITOR_NEW_INDEX: - ni = data; + print_simple_pairing_mode(cmd->mode); +} - if (index < MAX_INDEX) - memcpy(&index_list[index], ni, MONITOR_NEW_INDEX_SIZE); +static void read_inquiry_resp_tx_power_rsp(const void *data, uint8_t size) +{ + const struct bt_hci_rsp_read_inquiry_resp_tx_power *rsp = data; - ba2str(&ni->bdaddr, str); - packet_new_index(tv, index, str, ni->type, ni->bus, ni->name); - break; - case MONITOR_DEL_INDEX: - if (index < MAX_INDEX) - ba2str(&index_list[index].bdaddr, str); - else - ba2str(BDADDR_ANY, str); + print_status(rsp->status); + print_field("TX power: %d dBm", rsp->level); +} - packet_del_index(tv, index, str); - break; - case MONITOR_COMMAND_PKT: - packet_hci_command(tv, index, data, size); - break; - case MONITOR_EVENT_PKT: - packet_hci_event(tv, index, data, size); - break; - case MONITOR_ACL_TX_PKT: - packet_hci_acldata(tv, index, false, data, size); - break; - case MONITOR_ACL_RX_PKT: - packet_hci_acldata(tv, index, true, data, size); - break; - case MONITOR_SCO_TX_PKT: - packet_hci_scodata(tv, index, false, data, size); - break; - case MONITOR_SCO_RX_PKT: - packet_hci_scodata(tv, index, true, data, size); - break; - default: - print_header(tv, index); - printf("* Unknown packet (code %d len %d)\n", opcode, size); - packet_hexdump(data, size); - break; - } +static void read_le_host_supported_rsp(const void *data, uint8_t size) +{ + const struct bt_hci_rsp_read_le_host_supported *rsp = data; + + print_status(rsp->status); + print_field("Supported: 0x%2.2x", rsp->supported); + print_field("Simultaneous: 0x%2.2x", rsp->simultaneous); } -static void null_cmd(const void *data, uint8_t size) +static void write_le_host_supported_cmd(const void *data, uint8_t size) { + const struct bt_hci_cmd_write_le_host_supported *cmd = data; + + print_field("Supported: 0x%2.2x", cmd->supported); + print_field("Simultaneous: 0x%2.2x", cmd->simultaneous); } -static void status_rsp(const void *data, uint8_t size) +static void read_local_version_rsp(const void *data, uint8_t size) { - uint8_t status = *((uint8_t *) data); + const struct bt_hci_rsp_read_local_version *rsp = data; - print_status(status); + print_status(rsp->status); + print_hci_version(rsp->hci_ver, rsp->hci_rev); + print_lmp_version(rsp->lmp_ver, rsp->lmp_subver); + print_manufacturer(rsp->manufacturer); } -static void read_class_of_device_rsp(const void *data, uint8_t size) +static void read_local_commands_rsp(const void *data, uint8_t size) { - const struct bt_hci_rsp_read_class_of_dev *rsp = data; + const struct bt_hci_rsp_read_local_commands *rsp = data; print_status(rsp->status); - print_class(rsp->dev_class); + print_commands(rsp->commands); } static void read_local_features_rsp(const void *data, uint8_t size) @@ -394,6 +1040,66 @@ static void read_local_ext_features_rsp(const void *data, uint8_t size) print_features(rsp->features); } +static void read_buffer_size_rsp(const void *data, uint8_t size) +{ + const struct bt_hci_rsp_read_buffer_size *rsp = data; + + print_status(rsp->status); + print_field("ACL MTU: %-4d ACL max packet: %d", + btohs(rsp->acl_mtu), btohs(rsp->acl_max_pkt)); + print_field("SCO MTU: %-4d SCO max packet: %d", + rsp->sco_mtu, btohs(rsp->sco_max_pkt)); +} + +static void read_country_code_rsp(const void *data, uint8_t size) +{ + const struct bt_hci_rsp_read_country_code *rsp = data; + const char *str; + + print_status(rsp->status); + + switch (rsp->code) { + case 0x00: + str = "North America, Europe*, Japan"; + break; + case 0x01: + str = "France"; + break; + default: + str = "Reserved"; + break; + } + + print_field("Country code: %s (0x%2.2x)", str, rsp->code); +} + +static void read_bd_addr_rsp(const void *data, uint8_t size) +{ + const struct bt_hci_rsp_read_bd_addr *rsp = data; + + print_status(rsp->status); + print_bdaddr(rsp->bdaddr); +} + +static void read_data_block_size_rsp(const void *data, uint8_t size) +{ + const struct bt_hci_rsp_read_data_block_size *rsp = data; + + print_status(rsp->status); + print_field("Max ACL length: %d", btohs(rsp->max_acl_len)); + print_field("Block length: %d", btohs(rsp->block_len)); + print_field("Num blocks: %d", btohs(rsp->num_blocks)); +} + +static void le_read_buffer_size_rsp(const void *data, uint8_t size) +{ + const struct bt_hci_rsp_le_read_buffer_size *rsp = data; + + print_status(rsp->status); + print_field("Data packet length: %d", btohs(rsp->le_mtu)); + print_field("Num data packets: %d", rsp->le_max_pkt); +} + struct opcode_data { uint16_t opcode; const char *str; @@ -406,17 +1112,32 @@ struct opcode_data { }; static const struct opcode_data opcode_table[] = { + { 0x0000, "NOP" }, /* OGF 1 - Link Control */ - { 0x0401, "Inquiry" }, - { 0x0402, "Inquiry Cancel" }, - { 0x0403, "Periodic Inquiry Mode" }, - { 0x0404, "Exit Periodic Inquiry Mode" }, - { 0x0405, "Create Connection" }, - { 0x0406, "Disconnect" }, - { 0x0407, "Add SCO Connection" }, - { 0x0408, "Create Connection Cancel" }, - { 0x0409, "Accept Connection Request" }, - { 0x040a, "Reject Connection Request" }, + { 0x0401, "Inquiry", + inquiry_cmd, 5, true }, + { 0x0402, "Inquiry Cancel", + null_cmd, 0, true, + status_rsp, 1, true }, + { 0x0403, "Periodic Inquiry Mode", + periodic_inquiry_cmd, 9, true, + status_rsp, 1, true }, + { 0x0404, "Exit Periodic Inquiry Mode", + null_cmd, 0, true, + status_rsp, 1, true }, + { 0x0405, "Create Connection", + create_conn_cmd, 13, true }, + { 0x0406, "Disconnect", + disconnect_cmd, 3, true }, + { 0x0407, "Add SCO Connection", + add_sco_conn_cmd, 4, true }, + { 0x0408, "Create Connection Cancel", + create_conn_cancel_cmd, 6, true, + status_bdaddr_rsp, 7, true }, + { 0x0409, "Accept Connection Request", + accept_conn_request_cmd, 7, true }, + { 0x040a, "Reject Connection Request", + reject_conn_request_cmd, 7, true }, { 0x040b, "Link Key Request Reply" }, { 0x040c, "Link Key Request Negative Reply" }, { 0x040d, "PIN Code Request Reply" }, @@ -431,11 +1152,17 @@ static const struct opcode_data opcode_table[] = { /* reserved command */ { 0x0417, "Master Link Key" }, /* reserved command */ - { 0x0419, "Remote Name Request" }, - { 0x041a, "Remote Name Request Cancel" }, - { 0x041b, "Read Remote Supported Features" }, - { 0x041c, "Read Remote Extended Features" }, - { 0x041d, "Read Remote Version Information" }, + { 0x0419, "Remote Name Request", + remote_name_request_cmd, 10, true }, + { 0x041a, "Remote Name Request Cancel", + remote_name_request_cancel_cmd, 6, true, + status_bdaddr_rsp, 7, true }, + { 0x041b, "Read Remote Supported Features", + read_remote_features_cmd, 2, true }, + { 0x041c, "Read Remote Extended Features", + read_remote_ext_features_cmd, 3, true }, + { 0x041d, "Read Remote Version Information", + read_remote_version_cmd, 2, true }, /* reserved command */ { 0x041f, "Read Clock Offset" }, { 0x0420, "Read LMP Handle" }, @@ -475,14 +1202,18 @@ static const struct opcode_data opcode_table[] = { { 0x080b, "Switch Role" }, { 0x080c, "Read Link Policy Settings" }, { 0x080d, "Write Link Policy Settings" }, - { 0x080e, "Read Default Link Policy Settings" }, - { 0x080f, "Write Default Link Policy Settings" }, + { 0x080e, "Read Default Link Policy Settings", + null_cmd, 0, true, + read_default_link_policy_rsp, 3, true }, + { 0x080f, "Write Default Link Policy Settings", + write_default_link_policy_cmd, 2, true, + status_rsp, 1, true }, { 0x0810, "Flow Specification" }, { 0x0811, "Sniff Subrating" }, /* OGF 3 - Host Control */ { 0x0c01, "Set Event Mask", - NULL, 8, true, + set_event_mask_cmd, 8, true, status_rsp, 1, true }, /* reserved command */ { 0x0c03, "Reset", @@ -490,7 +1221,7 @@ static const struct opcode_data opcode_table[] = { status_rsp, 1, true }, /* reserved command */ { 0x0c05, "Set Event Filter", - NULL, 1, false, + set_event_filter_cmd, 1, false, status_rsp, 1, true }, /* reserved commands */ { 0x0c08, "Flush" }, @@ -501,11 +1232,21 @@ static const struct opcode_data opcode_table[] = { { 0x0c0d, "Read Stored Link Key" }, /* reserved commands */ { 0x0c11, "Write Stored Link Key" }, - { 0x0c12, "Delete Stored Link Key" }, - { 0x0c13, "Write Local Name" }, - { 0x0c14, "Read Local Name" }, - { 0x0c15, "Read Connection Accept Timeout" }, - { 0x0c16, "Write Connection Accept Timeout" }, + { 0x0c12, "Delete Stored Link Key", + delete_stored_link_key_cmd, 7, true, + delete_stored_link_key_rsp, 3, true }, + { 0x0c13, "Write Local Name", + write_local_name_cmd, 248, true, + status_rsp, 1, true }, + { 0x0c14, "Read Local Name", + null_cmd, 0, true, + read_local_name_rsp, 249, true }, + { 0x0c15, "Read Connection Accept Timeout", + null_cmd, 0, true, + read_conn_accept_timeout_rsp, 3, true }, + { 0x0c16, "Write Connection Accept Timeout", + write_conn_accept_timeout_cmd, 2, true, + status_rsp, 1, true }, { 0x0c17, "Read Page Timeout" }, { 0x0c18, "Write Page Timeout" }, { 0x0c19, "Read Scan Enable" }, @@ -520,10 +1261,16 @@ static const struct opcode_data opcode_table[] = { { 0x0c22, "Write Encryption Mode" }, { 0x0c23, "Read Class of Device", null_cmd, 0, true, - read_class_of_device_rsp, 4, true }, - { 0x0c24, "Write Class of Device" }, - { 0x0c25, "Read Voice Setting" }, - { 0x0c26, "Write Voice Setting" }, + read_class_of_dev_rsp, 4, true }, + { 0x0c24, "Write Class of Device", + write_class_of_dev_cmd, 3, true, + status_rsp, 1, true }, + { 0x0c25, "Read Voice Setting", + null_cmd, 0, true, + read_voice_setting_rsp, 3, true }, + { 0x0c26, "Write Voice Setting", + write_voice_setting_cmd, 2, true, + status_rsp, 1, true }, { 0x0c27, "Read Automatic Flush Timeout" }, { 0x0c28, "Write Automatic Flush Timeout" }, { 0x0c29, "Read Num Broadcast Retransmissions" }, @@ -552,23 +1299,35 @@ static const struct opcode_data opcode_table[] = { /* reserved commands */ { 0x0c42, "Read Inquiry Scan Type" }, { 0x0c43, "Write Inquiry Scan Type" }, - { 0x0c44, "Read Inquiry Mode" }, - { 0x0c45, "Write Inquiry Mode" }, + { 0x0c44, "Read Inquiry Mode", + null_cmd, 0, true, + read_inquiry_mode_rsp, 2, true }, + { 0x0c45, "Write Inquiry Mode", + write_inquiry_mode_cmd, 1, true, + status_rsp, 1, true }, { 0x0c46, "Read Page Scan Type" }, { 0x0c47, "Write Page Scan Type" }, { 0x0c48, "Read AFH Channel Assessment Mode" }, { 0x0c49, "Write AFH Channel Assessment Mode" }, /* reserved commands */ - { 0x0c51, "Read Extended Inquiry Response" }, + { 0x0c51, "Read Extended Inquiry Response", + null_cmd, 0, true, + read_ext_inquiry_response_rsp, 242, true }, { 0x0c52, "Write Extended Inquiry Response", - NULL, 241, true, + write_ext_inquiry_response_cmd, 241, true, status_rsp, 1, true }, { 0x0c53, "Refresh Encryption Key" }, /* reserved command */ - { 0x0c55, "Read Simple Pairing Mode" }, - { 0x0c56, "Write Simple Pairing Mode" }, + { 0x0c55, "Read Simple Pairing Mode", + null_cmd, 0, true, + read_simple_pairing_mode_rsp, 2, true }, + { 0x0c56, "Write Simple Pairing Mode", + write_simple_pairing_mode_cmd, 1, true, + status_rsp, 1, true }, { 0x0c57, "Read Local OOB Data" }, - { 0x0c58, "Read Inquiry Response TX Power Level"}, + { 0x0c58, "Read Inquiry Response TX Power Level", + null_cmd, 0, true, + read_inquiry_resp_tx_power_rsp, 2, true }, { 0x0c59, "Write Inquiry Transmit Power Level" }, { 0x0c5a, "Read Default Erroneous Reporting" }, { 0x0c5b, "Write Default Erroneous Reporting" }, @@ -586,24 +1345,40 @@ static const struct opcode_data opcode_table[] = { { 0x0c69, "Read Best Effort Flush Timeout" }, { 0x0c6a, "Write Best Effort Flush Timeout" }, { 0x0c6b, "Short Range Mode" }, - { 0x0c6c, "Read LE Host Supported" }, - { 0x0c6d, "Write LE Host Supported" }, + { 0x0c6c, "Read LE Host Supported", + null_cmd, 0, true, + read_le_host_supported_rsp, 3, true }, + { 0x0c6d, "Write LE Host Supported", + write_le_host_supported_cmd, 2, true, + status_rsp, 1, true }, /* OGF 4 - Information Parameter */ - { 0x1001, "Read Local Version Information" }, - { 0x1002, "Read Local Supported Commands" }, + { 0x1001, "Read Local Version Information", + null_cmd, 0, true, + read_local_version_rsp, 9, true }, + { 0x1002, "Read Local Supported Commands", + null_cmd, 0, true, + read_local_commands_rsp, 65, true }, { 0x1003, "Read Local Supported Features", null_cmd, 0, true, read_local_features_rsp, 9, true }, { 0x1004, "Read Local Extended Features", read_local_ext_features_cmd, 1, true, read_local_ext_features_rsp, 11, true }, - { 0x1005, "Read Buffer Size" }, + { 0x1005, "Read Buffer Size", + null_cmd, 0, true, + read_buffer_size_rsp, 8, true }, /* reserved command */ - { 0x1007, "Read Country Code" }, + { 0x1007, "Read Country Code", + null_cmd, 0, true, + read_country_code_rsp, 2, true }, /* reserved command */ - { 0x1009, "Read BD ADDR" }, - { 0x100a, "Read Data Block Size" }, + { 0x1009, "Read BD ADDR", + null_cmd, 0, true, + read_bd_addr_rsp, 7, true }, + { 0x100a, "Read Data Block Size", + null_cmd, 0, true, + read_data_block_size_rsp, 7, true }, /* OGF 5 - Status Parameter */ { 0x1401, "Read Failed Contact Counter" }, @@ -620,7 +1395,9 @@ static const struct opcode_data opcode_table[] = { /* OGF 8 - LE Control */ { 0x2001, "LE Set Event Mask" }, - { 0x2002, "LE Read Buffer Size" }, + { 0x2002, "LE Read Buffer Size", + null_cmd, 0, true, + le_read_buffer_size_rsp, 4, true }, { 0x2003, "LE Read Local Supported Features" }, /* reserved command */ { 0x2005, "LE Set Random Address" }, @@ -653,6 +1430,129 @@ static const struct opcode_data opcode_table[] = { { } }; +static void status_evt(const void *data, uint8_t size) +{ + uint8_t status = *((uint8_t *) data); + + print_status(status); +} + +static void inquiry_result_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_inquiry_result *evt = data; + + print_num_resp(evt->num_resp); + print_bdaddr(evt->bdaddr); + print_pscan_rep_mode(evt->pscan_rep_mode); + print_pscan_period_mode(evt->pscan_period_mode); + print_pscan_mode(evt->pscan_mode); + print_dev_class(evt->dev_class); + print_clock_offset(evt->clock_offset); + + if (size > sizeof(*evt)) + packet_hexdump(data + sizeof(*evt), size - sizeof(*evt)); +} + +static void conn_complete_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_conn_complete *evt = data; + + print_status(evt->status); + print_handle(evt->handle); + print_bdaddr(evt->bdaddr); + print_link_type(evt->link_type); + print_encr_mode(evt->encr_mode); +} + +static void conn_request_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_conn_request *evt = data; + + print_bdaddr(evt->bdaddr); + print_dev_class(evt->dev_class); + print_link_type(evt->link_type); +} + +static void disconnect_complete_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_disconnect_complete *evt = data; + + print_status(evt->status); + print_handle(evt->handle); + print_reason(evt->reason); +} + +static void auth_complete_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_auth_complete *evt = data; + + print_status(evt->status); + print_handle(evt->handle); +} + +static void remote_name_request_complete_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_remote_name_request_complete *evt = data; + + print_status(evt->status); + print_bdaddr(evt->bdaddr); + print_name(evt->name); +} + +static void encrypt_change_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_encrypt_change *evt = data; + + print_status(evt->status); + print_handle(evt->handle); + print_encr_mode(evt->encr_mode); +} + +static void change_conn_link_key_complete_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_change_conn_link_key_complete *evt = data; + + print_status(evt->status); + print_handle(evt->handle); +} + +static void master_link_key_complete_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_master_link_key_complete *evt = data; + + print_status(evt->status); + print_handle(evt->handle); + print_key_flag(evt->key_flag); +} + +static void remote_features_complete_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_remote_features_complete *evt = data; + + print_status(evt->status); + print_handle(evt->handle); + print_features(evt->features); +} + +static void remote_version_complete_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_remote_version_complete *evt = data; + + print_status(evt->status); + print_handle(evt->handle); + print_lmp_version(evt->lmp_ver, evt->lmp_subver); + print_manufacturer(evt->manufacturer); +} + +static void qos_setup_complete_evt(const void *data, uint8_t size) +{ + uint8_t status = *((uint8_t *) data); + + print_status(status); + + packet_hexdump(data + 1, size - 1); +} + static void cmd_complete_evt(const void *data, uint8_t size) { const struct bt_hci_evt_cmd_complete *evt = data; @@ -718,6 +1618,106 @@ static void cmd_status_evt(const void *data, uint8_t size) print_status(evt->status); } +static void hardware_error_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_hardware_error *evt = data; + + print_field("Code: 0x%2.2x", evt->code); +} + +static void flush_occurred_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_flush_occurred *evt = data; + + print_handle(evt->handle); +} + +static void role_change_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_role_change *evt = data; + + print_status(evt->status); + print_bdaddr(evt->bdaddr); + print_role(evt->role); +} + +static void num_completed_packets_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_num_completed_packets *evt = data; + + print_field("Num handles: %d", evt->num_handles); + print_handle(evt->handle); + print_field("Count: %d", btohs(evt->count)); + + if (size > sizeof(*evt)) + packet_hexdump(data + sizeof(*evt), size - sizeof(*evt)); +} + +static void max_slots_change_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_max_slots_change *evt = data; + + print_handle(evt->handle); + print_field("Max slots: %d", evt->max_slots); +} + +static void remote_ext_features_complete_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_remote_ext_features_complete *evt = data; + + print_status(evt->status); + print_handle(evt->handle); + print_field("Page: %d/%d", evt->page, evt->max_page); + print_features(evt->features); +} + +static void pscan_rep_mode_change_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_pscan_rep_mode_change *evt = data; + + print_bdaddr(evt->bdaddr); + print_pscan_rep_mode(evt->pscan_rep_mode); +} + +static void remote_host_features_notify_evt(const void *data, uint8_t size) +{ + const struct bt_hci_evt_remote_host_features_notify *evt = data; + + print_bdaddr(evt->bdaddr); + print_features(evt->features); +} + +struct subevent_data { + uint8_t subevent; + const char *str; +}; + +static const struct subevent_data subevent_table[] = { + { } +}; + +static void le_meta_event_evt(const void *data, uint8_t size) +{ + uint8_t subevent = *((const uint8_t *) data); + const struct subevent_data *subevent_data = NULL; + int i; + + for (i = 0; subevent_table[i].str; i++) { + if (subevent_table[i].subevent == subevent) { + subevent_data = &subevent_table[i]; + break; + } + } + + print_field("Subevent: %s (0x%2.2x)", + subevent_data ? subevent_data->str : "Unknown", subevent); + + if (!subevent_data) { + packet_hexdump(data + 1, size - 1); + return; + } +} + struct event_data { uint8_t event; const char *str; @@ -727,27 +1727,44 @@ struct event_data { }; static const struct event_data event_table[] = { - { 0x01, "Inquiry Complete" }, - { 0x02, "Inquiry Result" }, - { 0x03, "Connect Complete" }, - { 0x04, "Connect Request" }, - { 0x05, "Disconn Complete" }, - { 0x06, "Auth Complete" }, - { 0x07, "Remote Name Req Complete" }, - { 0x08, "Encrypt Change" }, - { 0x09, "Change Connection Link Key Complete" }, - { 0x0a, "Master Link Key Complete" }, - { 0x0b, "Read Remote Supported Features" }, - { 0x0c, "Read Remote Version Complete" }, - { 0x0d, "QoS Setup Complete" }, + { 0x01, "Inquiry Complete", + status_evt, 1, true }, + { 0x02, "Inquiry Result", + inquiry_result_evt, 1, false }, + { 0x03, "Connect Complete", + conn_complete_evt, 11, true }, + { 0x04, "Connect Request", + conn_request_evt, 10, true }, + { 0x05, "Disconnect Complete", + disconnect_complete_evt, 4, true }, + { 0x06, "Auth Complete", + auth_complete_evt, 3, true }, + { 0x07, "Remote Name Req Complete", + remote_name_request_complete_evt, 255, true }, + { 0x08, "Encryption Change", + encrypt_change_evt, 4, true }, + { 0x09, "Change Connection Link Key Complete", + change_conn_link_key_complete_evt, 3, true }, + { 0x0a, "Master Link Key Complete", + master_link_key_complete_evt, 4, true }, + { 0x0b, "Read Remote Supported Features", + remote_features_complete_evt, 11, true }, + { 0x0c, "Read Remote Version Complete", + remote_version_complete_evt, 8, true }, + { 0x0d, "QoS Setup Complete", + qos_setup_complete_evt, 21, true }, { 0x0e, "Command Complete", cmd_complete_evt, 3, false }, { 0x0f, "Command Status", cmd_status_evt, 4, true }, - { 0x10, "Hardware Error" }, - { 0x11, "Flush Occurred" }, - { 0x12, "Role Change" }, - { 0x13, "Number of Completed Packets" }, + { 0x10, "Hardware Error", + hardware_error_evt, 1, true }, + { 0x11, "Flush Occurred", + flush_occurred_evt, 2, true }, + { 0x12, "Role Change", + role_change_evt, 8, true }, + { 0x13, "Number of Completed Packets", + num_completed_packets_evt, 1, false }, { 0x14, "Mode Change" }, { 0x15, "Return Link Keys" }, { 0x16, "PIN Code Request" }, @@ -755,15 +1772,18 @@ static const struct event_data event_table[] = { { 0x18, "Link Key Notification" }, { 0x19, "Loopback Command" }, { 0x1a, "Data Buffer Overflow" }, - { 0x1b, "Max Slots Change" }, + { 0x1b, "Max Slots Change", + max_slots_change_evt, 3, true }, { 0x1c, "Read Clock Offset Complete" }, { 0x1d, "Connection Packet Type Changed" }, { 0x1e, "QoS Violation" }, { 0x1f, "Page Scan Mode Change" }, - { 0x20, "Page Scan Repetition Mode Change" }, + { 0x20, "Page Scan Repetition Mode Change", + pscan_rep_mode_change_evt, 7, true }, { 0x21, "Flow Specification Complete" }, { 0x22, "Inquiry Result with RSSI" }, - { 0x23, "Read Remote Extended Features" }, + { 0x23, "Read Remote Extended Features", + remote_ext_features_complete_evt, 13, true }, /* reserved events */ { 0x2c, "Synchronous Connect Complete" }, { 0x2d, "Synchronous Connect Changed" }, @@ -782,8 +1802,10 @@ static const struct event_data event_table[] = { /* reserved event */ { 0x3b, "User Passkey Notification" }, { 0x3c, "Keypress Notification" }, - { 0x3d, "Remote Host Supported Features" }, - { 0x3e, "LE Meta Event" }, + { 0x3d, "Remote Host Supported Features", + remote_host_features_notify_evt, 14, true }, + { 0x3e, "LE Meta Event", + le_meta_event_evt, 1, false }, /* reserved event */ { 0x40, "Physical Link Complete" }, { 0x41, "Channel Selected" }, @@ -856,7 +1878,7 @@ void packet_hci_command(struct timeval *tv, uint16_t index, opcode_data ? opcode_data->str : "Unknown", ogf, ocf, hdr->plen); - if (!opcode_data->cmd_func) { + if (!opcode_data || !opcode_data->cmd_func) { packet_hexdump(data, size); return; } @@ -911,7 +1933,7 @@ void packet_hci_event(struct timeval *tv, uint16_t index, event_data ? event_data->str : "Unknown", hdr->evt, hdr->plen); - if (!event_data->func) { + if (!event_data || !event_data->func) { packet_hexdump(data, size); return; } -- 2.47.3