From 82180fcac7efc09e4e33b3f5c10b9bf4b6f30069 Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Mon, 7 Nov 2016 15:15:48 +0100 Subject: [PATCH] add le commands for reading and generating diffie-hellman keys via hci commands --- src/bluetooth.h | 94 ++++++++- src/btstack_event.h | 341 ++++++++++++++++++++++++++++++++ src/hci_cmd.c | 24 +++ src/hci_cmd.h | 3 +- tool/btstack_event_generator.py | 6 +- 5 files changed, 461 insertions(+), 7 deletions(-) diff --git a/src/bluetooth.h b/src/bluetooth.h index 8f7423e2c..e40acffc4 100644 --- a/src/bluetooth.h +++ b/src/bluetooth.h @@ -520,6 +520,9 @@ typedef enum { #define HCI_EVENT_LE_META 0x3E +// last used HCI_EVENT in 2.1 is 0x3d +// last used HCI_EVENT in 4.1 is 0x57 + #define HCI_EVENT_VENDOR_SPECIFIC 0xFF /** @@ -536,13 +539,96 @@ typedef enum { * @param master_clock_accuracy */ #define HCI_SUBEVENT_LE_CONNECTION_COMPLETE 0x01 + +// array of advertisements, not handled by event accessor generator #define HCI_SUBEVENT_LE_ADVERTISING_REPORT 0x02 -#define HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE 0x03 + +/** + * @format 11H222 + * @param subevent_code + * @param status + * @param connection_handle + * @param conn_interval + * @param conn_latency + */ + #define HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE 0x03 + +/** + * @format 1HD2 + * @param subevent_code + * @param connection_handle + * @param random_number + * @param encryption_diversifier + */ #define HCI_SUBEVENT_LE_READ_REMOTE_USED_FEATURES_COMPLETE 0x04 + +/** + * @format 1HD2 + * @param subevent_code + * @param connection_handle + * @param random_number + * @param encryption_diversifier + */ #define HCI_SUBEVENT_LE_LONG_TERM_KEY_REQUEST 0x05 - -// last used HCI_EVENT in 2.1 is 0x3d -// last used HCI_EVENT in 4.1 is 0x57 + +/** + * @format 1H2222 + * @param subevent_code + * @param connection_handle + * @param interval_min + * @param interval_max + * @param latency + * @param timeout + */ +#define HCI_SUBEVENT_LE_REMOTE_CONNECTION_PARAMETER_REQUEST 0x06 + +/** + * @format 1H2222 + * @param subevent_code + * @param connection_handle + * @param max_tx_octets + * @param max_tx_time + * @param max_rx_octets + * @param max_rx_time + */ +#define HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE 0x07 + +/** + * @format 11QQ + * @param subevent_code + * @param status + * @param dhkey_x x coordinate of P256 public key + * @param dhkey_y y coordinate of P256 public key + */ +#define HCI_SUBEVENT_LE_READ_LOCAL_P256_PUBLIC_KEY_COMPLETE 0x08 + /** + * @format 11QQ + * @param subevent_code + * @param status + * @param dhkey_x x coordinate of Diffie-Hellman key + * @param dhkey_y y coordinate of Diffie-Hellman key + */ +#define HCI_SUBEVENT_LE_GENERATE_DHKEY_COMPLETE 0x09 + +/** + * @format 11H11BBB2221 + * @param subevent_code + * @param status + * @param connection_handle + * @param role + * @param peer_address_type + * @param perr_addresss + * @param local_resolvable_private_addres + * @param peer_resolvable_private_addres + * @param conn_interval + * @param conn_latency + * @param supervision_timeout + * @param master_clock_accuracy + */ +#define HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE 0x0A + +// array of advertisements, not handled by event accessor generator +#define HCI_SUBEVENT_LE_DIRECT_ADVERTISING_REPORT 0x0B /** * L2CAP Layer diff --git a/src/btstack_event.h b/src/btstack_event.h index f18adc207..8d86e204c 100644 --- a/src/btstack_event.h +++ b/src/btstack_event.h @@ -2931,6 +2931,347 @@ static inline uint8_t hci_subevent_le_connection_complete_get_master_clock_accur return event[20]; } +/** + * @brief Get field status from event HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ +static inline uint8_t hci_subevent_le_connection_update_complete_get_status(const uint8_t * event){ + return event[3]; +} +/** + * @brief Get field connection_handle from event HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE + * @param event packet + * @return connection_handle + * @note: btstack_type H + */ +static inline hci_con_handle_t hci_subevent_le_connection_update_complete_get_connection_handle(const uint8_t * event){ + return little_endian_read_16(event, 4); +} +/** + * @brief Get field conn_interval from event HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE + * @param event packet + * @return conn_interval + * @note: btstack_type 2 + */ +static inline uint16_t hci_subevent_le_connection_update_complete_get_conn_interval(const uint8_t * event){ + return little_endian_read_16(event, 6); +} +/** + * @brief Get field conn_latency from event HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE + * @param event packet + * @return conn_latency + * @note: btstack_type 2 + */ +static inline uint16_t hci_subevent_le_connection_update_complete_get_conn_latency(const uint8_t * event){ + return little_endian_read_16(event, 8); +} + +/** + * @brief Get field connection_handle from event HCI_SUBEVENT_LE_READ_REMOTE_USED_FEATURES_COMPLETE + * @param event packet + * @return connection_handle + * @note: btstack_type H + */ +// static inline hci_con_handle_t hci_subevent_le_read_remote_used_features_complete_get_connection_handle(const uint8_t * event){ +// not implemented yet +// } +/** + * @brief Get field random_number from event HCI_SUBEVENT_LE_READ_REMOTE_USED_FEATURES_COMPLETE + * @param event packet + * @return random_number + * @note: btstack_type D + */ +// static inline const uint8_t * hci_subevent_le_read_remote_used_features_complete_get_random_number(const uint8_t * event){ +// not implemented yet +// } +/** + * @brief Get field encryption_diversifier from event HCI_SUBEVENT_LE_READ_REMOTE_USED_FEATURES_COMPLETE + * @param event packet + * @return encryption_diversifier + * @note: btstack_type 2 + */ +// static inline uint16_t hci_subevent_le_read_remote_used_features_complete_get_encryption_diversifier(const uint8_t * event){ +// not implemented yet +// } + +/** + * @brief Get field connection_handle from event HCI_SUBEVENT_LE_LONG_TERM_KEY_REQUEST + * @param event packet + * @return connection_handle + * @note: btstack_type H + */ +// static inline hci_con_handle_t hci_subevent_le_long_term_key_request_get_connection_handle(const uint8_t * event){ +// not implemented yet +// } +/** + * @brief Get field random_number from event HCI_SUBEVENT_LE_LONG_TERM_KEY_REQUEST + * @param event packet + * @return random_number + * @note: btstack_type D + */ +// static inline const uint8_t * hci_subevent_le_long_term_key_request_get_random_number(const uint8_t * event){ +// not implemented yet +// } +/** + * @brief Get field encryption_diversifier from event HCI_SUBEVENT_LE_LONG_TERM_KEY_REQUEST + * @param event packet + * @return encryption_diversifier + * @note: btstack_type 2 + */ +// static inline uint16_t hci_subevent_le_long_term_key_request_get_encryption_diversifier(const uint8_t * event){ +// not implemented yet +// } + +/** + * @brief Get field connection_handle from event HCI_SUBEVENT_LE_REMOTE_CONNECTION_PARAMETER_REQUEST + * @param event packet + * @return connection_handle + * @note: btstack_type H + */ +static inline hci_con_handle_t hci_subevent_le_remote_connection_parameter_request_get_connection_handle(const uint8_t * event){ + return little_endian_read_16(event, 3); +} +/** + * @brief Get field interval_min from event HCI_SUBEVENT_LE_REMOTE_CONNECTION_PARAMETER_REQUEST + * @param event packet + * @return interval_min + * @note: btstack_type 2 + */ +static inline uint16_t hci_subevent_le_remote_connection_parameter_request_get_interval_min(const uint8_t * event){ + return little_endian_read_16(event, 5); +} +/** + * @brief Get field interval_max from event HCI_SUBEVENT_LE_REMOTE_CONNECTION_PARAMETER_REQUEST + * @param event packet + * @return interval_max + * @note: btstack_type 2 + */ +static inline uint16_t hci_subevent_le_remote_connection_parameter_request_get_interval_max(const uint8_t * event){ + return little_endian_read_16(event, 7); +} +/** + * @brief Get field latency from event HCI_SUBEVENT_LE_REMOTE_CONNECTION_PARAMETER_REQUEST + * @param event packet + * @return latency + * @note: btstack_type 2 + */ +static inline uint16_t hci_subevent_le_remote_connection_parameter_request_get_latency(const uint8_t * event){ + return little_endian_read_16(event, 9); +} +/** + * @brief Get field timeout from event HCI_SUBEVENT_LE_REMOTE_CONNECTION_PARAMETER_REQUEST + * @param event packet + * @return timeout + * @note: btstack_type 2 + */ +static inline uint16_t hci_subevent_le_remote_connection_parameter_request_get_timeout(const uint8_t * event){ + return little_endian_read_16(event, 11); +} + +/** + * @brief Get field connection_handle from event HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE + * @param event packet + * @return connection_handle + * @note: btstack_type H + */ +static inline hci_con_handle_t hci_subevent_le_data_length_change_get_connection_handle(const uint8_t * event){ + return little_endian_read_16(event, 3); +} +/** + * @brief Get field max_tx_octets from event HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE + * @param event packet + * @return max_tx_octets + * @note: btstack_type 2 + */ +static inline uint16_t hci_subevent_le_data_length_change_get_max_tx_octets(const uint8_t * event){ + return little_endian_read_16(event, 5); +} +/** + * @brief Get field max_tx_time from event HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE + * @param event packet + * @return max_tx_time + * @note: btstack_type 2 + */ +static inline uint16_t hci_subevent_le_data_length_change_get_max_tx_time(const uint8_t * event){ + return little_endian_read_16(event, 7); +} +/** + * @brief Get field max_rx_octets from event HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE + * @param event packet + * @return max_rx_octets + * @note: btstack_type 2 + */ +static inline uint16_t hci_subevent_le_data_length_change_get_max_rx_octets(const uint8_t * event){ + return little_endian_read_16(event, 9); +} +/** + * @brief Get field max_rx_time from event HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE + * @param event packet + * @return max_rx_time + * @note: btstack_type 2 + */ +static inline uint16_t hci_subevent_le_data_length_change_get_max_rx_time(const uint8_t * event){ + return little_endian_read_16(event, 11); +} + +/** + * @brief Get field status from event HCI_SUBEVENT_LE_READ_LOCAL_P256_PUBLIC_KEY_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ +static inline uint8_t hci_subevent_le_read_local_p256_public_key_complete_get_status(const uint8_t * event){ + return event[3]; +} +/** + * @brief Get field dhkey_x from event HCI_SUBEVENT_LE_READ_LOCAL_P256_PUBLIC_KEY_COMPLETE + * @param event packet + * @param Pointer to storage for dhkey_x + * @note: btstack_type Q + */ +static inline void hci_subevent_le_read_local_p256_public_key_complete_get_dhkey_x(const uint8_t * event, uint8_t * dhkey_x){ + reverse_bytes(&event[4], dhkey_x, 32); +} +/** + * @brief Get field dhkey_y from event HCI_SUBEVENT_LE_READ_LOCAL_P256_PUBLIC_KEY_COMPLETE + * @param event packet + * @param Pointer to storage for dhkey_y + * @note: btstack_type Q + */ +static inline void hci_subevent_le_read_local_p256_public_key_complete_get_dhkey_y(const uint8_t * event, uint8_t * dhkey_y){ + reverse_bytes(&event[36], dhkey_y, 32); +} + +/** + * @brief Get field status from event HCI_SUBEVENT_LE_GENERATE_DHKEY_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ +static inline uint8_t hci_subevent_le_generate_dhkey_complete_get_status(const uint8_t * event){ + return event[3]; +} +/** + * @brief Get field dhkey_x from event HCI_SUBEVENT_LE_GENERATE_DHKEY_COMPLETE + * @param event packet + * @param Pointer to storage for dhkey_x + * @note: btstack_type Q + */ +static inline void hci_subevent_le_generate_dhkey_complete_get_dhkey_x(const uint8_t * event, uint8_t * dhkey_x){ + reverse_bytes(&event[4], dhkey_x, 32); +} +/** + * @brief Get field dhkey_y from event HCI_SUBEVENT_LE_GENERATE_DHKEY_COMPLETE + * @param event packet + * @param Pointer to storage for dhkey_y + * @note: btstack_type Q + */ +static inline void hci_subevent_le_generate_dhkey_complete_get_dhkey_y(const uint8_t * event, uint8_t * dhkey_y){ + reverse_bytes(&event[36], dhkey_y, 32); +} + +/** + * @brief Get field status from event HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE + * @param event packet + * @return status + * @note: btstack_type 1 + */ +static inline uint8_t hci_subevent_le_enhanced_connection_complete_get_status(const uint8_t * event){ + return event[3]; +} +/** + * @brief Get field connection_handle from event HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE + * @param event packet + * @return connection_handle + * @note: btstack_type H + */ +static inline hci_con_handle_t hci_subevent_le_enhanced_connection_complete_get_connection_handle(const uint8_t * event){ + return little_endian_read_16(event, 4); +} +/** + * @brief Get field role from event HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE + * @param event packet + * @return role + * @note: btstack_type 1 + */ +static inline uint8_t hci_subevent_le_enhanced_connection_complete_get_role(const uint8_t * event){ + return event[6]; +} +/** + * @brief Get field peer_address_type from event HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE + * @param event packet + * @return peer_address_type + * @note: btstack_type 1 + */ +static inline uint8_t hci_subevent_le_enhanced_connection_complete_get_peer_address_type(const uint8_t * event){ + return event[7]; +} +/** + * @brief Get field perr_addresss from event HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE + * @param event packet + * @param Pointer to storage for perr_addresss + * @note: btstack_type B + */ +static inline void hci_subevent_le_enhanced_connection_complete_get_perr_addresss(const uint8_t * event, bd_addr_t perr_addresss){ + reverse_bd_addr(&event[8], perr_addresss); +} +/** + * @brief Get field local_resolvable_private_addres from event HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE + * @param event packet + * @param Pointer to storage for local_resolvable_private_addres + * @note: btstack_type B + */ +static inline void hci_subevent_le_enhanced_connection_complete_get_local_resolvable_private_addres(const uint8_t * event, bd_addr_t local_resolvable_private_addres){ + reverse_bd_addr(&event[14], local_resolvable_private_addres); +} +/** + * @brief Get field peer_resolvable_private_addres from event HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE + * @param event packet + * @param Pointer to storage for peer_resolvable_private_addres + * @note: btstack_type B + */ +static inline void hci_subevent_le_enhanced_connection_complete_get_peer_resolvable_private_addres(const uint8_t * event, bd_addr_t peer_resolvable_private_addres){ + reverse_bd_addr(&event[20], peer_resolvable_private_addres); +} +/** + * @brief Get field conn_interval from event HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE + * @param event packet + * @return conn_interval + * @note: btstack_type 2 + */ +static inline uint16_t hci_subevent_le_enhanced_connection_complete_get_conn_interval(const uint8_t * event){ + return little_endian_read_16(event, 26); +} +/** + * @brief Get field conn_latency from event HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE + * @param event packet + * @return conn_latency + * @note: btstack_type 2 + */ +static inline uint16_t hci_subevent_le_enhanced_connection_complete_get_conn_latency(const uint8_t * event){ + return little_endian_read_16(event, 28); +} +/** + * @brief Get field supervision_timeout from event HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE + * @param event packet + * @return supervision_timeout + * @note: btstack_type 2 + */ +static inline uint16_t hci_subevent_le_enhanced_connection_complete_get_supervision_timeout(const uint8_t * event){ + return little_endian_read_16(event, 30); +} +/** + * @brief Get field master_clock_accuracy from event HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE + * @param event packet + * @return master_clock_accuracy + * @note: btstack_type 1 + */ +static inline uint8_t hci_subevent_le_enhanced_connection_complete_get_master_clock_accuracy(const uint8_t * event){ + return event[32]; +} + /** * @brief Get field status from event HSP_SUBEVENT_RFCOMM_CONNECTION_COMPLETE * @param event packet diff --git a/src/hci_cmd.c b/src/hci_cmd.c index 247cbb675..f7985120e 100644 --- a/src/hci_cmd.c +++ b/src/hci_cmd.c @@ -65,6 +65,7 @@ * P: 16 byte Pairing code * A: 31 bytes advertising data * S: Service Record (Data Element Sequence) + * Q: 32 byte data block, e.g. for X and Y coordinates of P-256 public key */ uint16_t hci_cmd_create_from_template(uint8_t *hci_cmd_buffer, const hci_cmd_t *cmd, va_list argptr){ @@ -155,6 +156,13 @@ uint16_t hci_cmd_create_from_template(uint8_t *hci_cmd_buffer, const hci_cmd_t * pos += len; break; } +#endif +#ifdef ENABLE_LE_SECURE_CONNECTIONS + case 'Q': + ptr = va_arg(argptr, uint8_t *); + reverse_bytes(ptr, &hci_cmd_buffer[pos], 32); + pos += 32; + break; #endif default: break; @@ -1000,4 +1008,20 @@ const hci_cmd_t hci_le_test_end = { OPCODE(OGF_LE_CONTROLLER, 0x1f), "1" // return: status, number of packets (8) }; + +/** + */ +const hci_cmd_t hci_le_read_local_p256_public_key = { +OPCODE(OGF_LE_CONTROLLER, 0x25), "" +// LE Read Local P-256 Public Key Complete is generated on completion +}; + +/** + * @param end_test_cmd + */ +const hci_cmd_t hci_le_generate_dhkey = { +OPCODE(OGF_LE_CONTROLLER, 0x26), "QQ" +// LE Generate DHKey Complete is generated on completion +}; + #endif diff --git a/src/hci_cmd.h b/src/hci_cmd.h index 28ac366b7..b3e2f8c8c 100644 --- a/src/hci_cmd.h +++ b/src/hci_cmd.h @@ -155,12 +155,14 @@ extern const hci_cmd_t hci_le_connection_update; extern const hci_cmd_t hci_le_create_connection; extern const hci_cmd_t hci_le_create_connection_cancel; extern const hci_cmd_t hci_le_encrypt; +extern const hci_cmd_t hci_le_generate_dhkey; extern const hci_cmd_t hci_le_long_term_key_negative_reply; extern const hci_cmd_t hci_le_long_term_key_request_reply; extern const hci_cmd_t hci_le_rand; extern const hci_cmd_t hci_le_read_advertising_channel_tx_power; extern const hci_cmd_t hci_le_read_buffer_size ; extern const hci_cmd_t hci_le_read_channel_map; +extern const hci_cmd_t hci_le_read_local_p256_public_key; extern const hci_cmd_t hci_le_read_remote_used_features; extern const hci_cmd_t hci_le_read_supported_features; extern const hci_cmd_t hci_le_read_supported_states; @@ -180,7 +182,6 @@ extern const hci_cmd_t hci_le_start_encryption; extern const hci_cmd_t hci_le_test_end; extern const hci_cmd_t hci_le_transmitter_test; - /** * construct HCI Command based on template * diff --git a/tool/btstack_event_generator.py b/tool/btstack_event_generator.py index dfd42acd9..6beebd7ca 100755 --- a/tool/btstack_event_generator.py +++ b/tool/btstack_event_generator.py @@ -159,6 +159,7 @@ param_read = { 'B' : 'reverse_bd_addr(&event[{offset}], {result_name});', 'R' : 'return &event[{offset}];', 'T' : 'return (const char *) &event[{offset}];', + 'Q' : 'reverse_bytes(&event[{offset}], {result_name}, 32);', 'V' : 'return &event[{offset}];', 'X' : 'gatt_client_deserialize_service(event, {offset}, {result_name});', 'Y' : 'gatt_client_deserialize_characteristic(event, {offset}, {result_name});', @@ -170,12 +171,13 @@ def c_type_for_btstack_type(type): 'D' : 'const uint8_t *', 'E' : 'const uint8_t * ', 'N' : 'String' , 'P' : 'const uint8_t *', 'A' : 'const uint8_t *', 'R' : 'const uint8_t *', 'S' : 'const uint8_t *', 'J' : 'int', 'L' : 'int', 'V' : 'const uint8_t *', 'U' : 'BT_UUID', + 'Q' : 'uint8_t *', 'X' : 'gatt_client_service_t *', 'Y' : 'gatt_client_characteristic_t *', 'Z' : 'gatt_client_characteristic_descriptor_t *', 'T' : 'const char *'} return param_types[type] def size_for_type(type): - param_sizes = { '1' : 1, '2' : 2, '3' : 3, '4' : 4, 'H' : 2, 'B' : 6, 'D' : 8, 'E' : 240, 'N' : 248, 'P' : 16, + param_sizes = { '1' : 1, '2' : 2, '3' : 3, '4' : 4, 'H' : 2, 'B' : 6, 'D' : 8, 'E' : 240, 'N' : 248, 'P' : 16, 'Q':32, 'A' : 31, 'S' : -1, 'V': -1, 'J' : 1, 'L' : 2, 'U' : 16, 'X' : 20, 'Y' : 24, 'Z' : 18, 'T':-1} return param_sizes[type] @@ -188,7 +190,7 @@ def format_function_name(event_name): def template_for_type(field_type): global c_prototoype_simple_return global c_prototoype_struct_return - types_with_struct_return = "BXYZ" + types_with_struct_return = "BQXYZ" if field_type in types_with_struct_return: return c_prototoype_struct_return else: