1 /* 2 * Copyright (C) 2019 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 24 * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 #define __BTSTACK_FILE__ "mesh_proxy.c" 39 40 #include "mesh/mesh_proxy.h" 41 42 #include <string.h> 43 44 #include "bluetooth_company_id.h" 45 #include "bluetooth_data_types.h" 46 #include "bluetooth_gatt.h" 47 #include "btstack_config.h" 48 #include "btstack_crypto.h" 49 #include "btstack_debug.h" 50 #include "btstack_memory.h" 51 #include "btstack_run_loop.h" 52 #include "btstack_util.h" 53 54 #include "mesh/adv_bearer.h" 55 #include "mesh/gatt_bearer.h" 56 #include "mesh/mesh_crypto.h" 57 #include "mesh/mesh_foundation.h" 58 #include "mesh/mesh_iv_index_seq_number.h" 59 #include "mesh/mesh_lower_transport.h" 60 #include "mesh/mesh_network.h" 61 #include "mesh/mesh_node.h" 62 63 #ifdef ENABLE_MESH_PROXY_SERVER 64 65 // we only support a single active node id advertisement. when new one is started, an active one is stopped 66 67 #define MESH_PROXY_NODE_ID_ADVERTISEMENT_TIMEOUT_MS 60000 68 69 static btstack_timer_source_t mesh_proxy_node_id_timer; 70 static btstack_crypto_random_t mesh_proxy_node_id_crypto_request_random; 71 static btstack_crypto_aes128_t mesh_proxy_node_id_crypto_request_aes128; 72 static uint8_t mesh_proxy_node_id_plaintext[16]; 73 static uint8_t mesh_proxy_node_id_hash[16]; 74 static uint8_t mesh_proxy_node_id_random_value[8]; 75 76 static uint16_t primary_element_address; 77 78 // Mesh Proxy, advertise with node id 79 static adv_bearer_connectable_advertisement_data_item_t connectable_advertisement; 80 81 static const uint8_t adv_data_with_node_identity_template[] = { 82 // Flags general discoverable, BR/EDR not supported 83 0x02, BLUETOOTH_DATA_TYPE_FLAGS, 0x06, 84 // 16-bit Service UUIDs 85 0x03, BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS, ORG_BLUETOOTH_SERVICE_MESH_PROXY & 0xff, ORG_BLUETOOTH_SERVICE_MESH_PROXY >> 8, 86 // Service Data 87 0x14, BLUETOOTH_DATA_TYPE_SERVICE_DATA, ORG_BLUETOOTH_SERVICE_MESH_PROXY & 0xff, ORG_BLUETOOTH_SERVICE_MESH_PROXY >> 8, 88 // MESH_IDENTIFICATION_NODE_IDENTIFY_TYPE 89 MESH_IDENTIFICATION_NODE_IDENTIFY_TYPE, 90 // Hash - 8 bytes 91 // Random - 8 bytes 92 }; 93 94 static const uint8_t adv_data_with_network_id_template[] = { 95 // Flags general discoverable, BR/EDR not supported 96 0x02, BLUETOOTH_DATA_TYPE_FLAGS, 0x06, 97 // 16-bit Service UUIDs 98 0x03, BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS, ORG_BLUETOOTH_SERVICE_MESH_PROXY & 0xff, ORG_BLUETOOTH_SERVICE_MESH_PROXY >> 8, 99 // Service Data 100 0x0C, BLUETOOTH_DATA_TYPE_SERVICE_DATA, ORG_BLUETOOTH_SERVICE_MESH_PROXY & 0xff, ORG_BLUETOOTH_SERVICE_MESH_PROXY >> 8, 101 // MESH_IDENTIFICATION_NETWORK_ID_TYPE 102 MESH_IDENTIFICATION_NETWORK_ID_TYPE 103 }; 104 105 #ifdef ENABLE_MESH_PB_GATT 106 107 // Mesh Provisioning 108 static const uint8_t adv_data_unprovisioned_template[] = { 109 // Flags general discoverable, BR/EDR not supported 110 0x02, BLUETOOTH_DATA_TYPE_FLAGS, 0x06, 111 // 16-bit Service UUIDs 112 0x03, BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS, ORG_BLUETOOTH_SERVICE_MESH_PROVISIONING & 0xff, ORG_BLUETOOTH_SERVICE_MESH_PROVISIONING >> 8, 113 // Service Data (22) 114 0x15, BLUETOOTH_DATA_TYPE_SERVICE_DATA, ORG_BLUETOOTH_SERVICE_MESH_PROVISIONING & 0xff, ORG_BLUETOOTH_SERVICE_MESH_PROVISIONING >> 8, 115 // UUID - 16 bytes 116 // OOB information - 2 bytes 117 }; 118 const uint8_t adv_data_unprovisioned_template_len = sizeof(adv_data_unprovisioned_template); 119 120 static void mesh_proxy_setup_advertising_unprovisioned(adv_bearer_connectable_advertisement_data_item_t * advertisement_item, const uint8_t * device_uuid) { 121 // store in advertisement item 122 memset(advertisement_item, 0, sizeof(adv_bearer_connectable_advertisement_data_item_t)); 123 advertisement_item->adv_length = adv_data_unprovisioned_template_len + 18; 124 memcpy(advertisement_item->adv_data, (uint8_t*) adv_data_unprovisioned_template, adv_data_unprovisioned_template_len); 125 // dynamically store device uuid into adv data 126 memcpy(&advertisement_item->adv_data[11], device_uuid, 16); 127 little_endian_store_16(advertisement_item->adv_data, 27, 0); 128 } 129 130 void mesh_proxy_start_advertising_unprovisioned_device(void){ 131 const uint8_t * device_uuid = mesh_node_get_device_uuid(); 132 mesh_proxy_setup_advertising_unprovisioned(&connectable_advertisement, device_uuid); 133 // setup advertisements 134 adv_bearer_advertisements_add_item(&connectable_advertisement); 135 adv_bearer_advertisements_enable(1); 136 } 137 138 /** 139 * @brief Start Advertising Unprovisioned Device with Device ID 140 * @param device_uuid 141 */ 142 void mesh_proxy_stop_advertising_unprovisioned_device(void){ 143 adv_bearer_advertisements_remove_item(&connectable_advertisement); 144 } 145 146 #endif 147 148 static uint8_t mesh_proxy_setup_advertising_with_network_id(uint8_t * buffer, uint8_t * network_id){ 149 memcpy(&buffer[0], adv_data_with_network_id_template, 12); 150 memcpy(&buffer[12], network_id, 8); 151 return 20; 152 } 153 154 static void mesh_proxy_stop_all_advertising_with_node_id(void){ 155 adv_bearer_advertisements_remove_item(&connectable_advertisement); 156 mesh_subnet_iterator_t it; 157 mesh_subnet_iterator_init(&it); 158 while (mesh_subnet_iterator_has_more(&it)){ 159 mesh_subnet_t * network_key = mesh_subnet_iterator_get_next(&it); 160 if (network_key->node_id_advertisement_running != 0){ 161 btstack_run_loop_remove_timer(&mesh_proxy_node_id_timer); 162 network_key->node_id_advertisement_running = 0; 163 } 164 } 165 } 166 167 static void mesh_proxy_node_id_timeout_handler(btstack_timer_source_t * ts){ 168 UNUSED(ts); 169 mesh_proxy_stop_all_advertising_with_node_id(); 170 } 171 172 static void mesh_proxy_node_id_handle_get_aes128(void * arg){ 173 mesh_subnet_t * network_key = (mesh_subnet_t *) arg; 174 175 memcpy(connectable_advertisement.adv_data, adv_data_with_node_identity_template, 12); 176 memcpy(&connectable_advertisement.adv_data[12], &mesh_proxy_node_id_hash[8], 8); 177 memcpy(&connectable_advertisement.adv_data[20], mesh_proxy_node_id_random_value, 8); 178 connectable_advertisement.adv_length = 28; 179 180 // setup advertisements 181 adv_bearer_advertisements_add_item(&connectable_advertisement); 182 adv_bearer_advertisements_enable(1); 183 184 // set timer 185 btstack_run_loop_set_timer_handler(&mesh_proxy_node_id_timer, mesh_proxy_node_id_timeout_handler); 186 btstack_run_loop_set_timer(&mesh_proxy_node_id_timer, MESH_PROXY_NODE_ID_ADVERTISEMENT_TIMEOUT_MS); 187 btstack_run_loop_add_timer(&mesh_proxy_node_id_timer); 188 189 // mark as active 190 network_key->node_id_advertisement_running = 1; 191 } 192 193 static void mesh_proxy_node_id_handle_random(void * arg){ 194 mesh_subnet_t * network_key = (mesh_subnet_t *) arg; 195 196 // Hash = e(IdentityKey, Padding | Random | Address) mod 2^64 197 memset(mesh_proxy_node_id_plaintext, 0, sizeof(mesh_proxy_node_id_plaintext)); 198 memcpy(&mesh_proxy_node_id_plaintext[6] , mesh_proxy_node_id_random_value, 8); 199 big_endian_store_16(mesh_proxy_node_id_plaintext, 14, primary_element_address); 200 // TODO: old vs. new key 201 btstack_crypto_aes128_encrypt(&mesh_proxy_node_id_crypto_request_aes128, network_key->old_key->identity_key, mesh_proxy_node_id_plaintext, mesh_proxy_node_id_hash, mesh_proxy_node_id_handle_get_aes128, network_key); 202 } 203 204 static void mesh_proxy_start_advertising_with_node_id(uint16_t netkey_index){ 205 mesh_proxy_stop_all_advertising_with_node_id(); 206 // get network key 207 mesh_subnet_t * network_key = mesh_subnet_get_by_netkey_index(netkey_index); 208 if (network_key == NULL) return; 209 log_info("Proxy start advertising with node id, netkey index %04x", netkey_index); 210 // setup node id 211 btstack_crypto_random_generate(&mesh_proxy_node_id_crypto_request_random, mesh_proxy_node_id_random_value, sizeof(mesh_proxy_node_id_random_value), mesh_proxy_node_id_handle_random, network_key); 212 } 213 214 static void mesh_proxy_stop_advertising_with_node_id(uint16_t netkey_index){ 215 UNUSED(netkey_index); 216 log_info("Proxy stop advertising with node id, netkey index %04x", netkey_index); 217 mesh_proxy_stop_all_advertising_with_node_id(); 218 } 219 220 // Public API 221 222 uint8_t mesh_proxy_get_advertising_with_node_id_status(uint16_t netkey_index, mesh_node_identity_state_t * out_state ){ 223 mesh_subnet_t * network_key = mesh_subnet_get_by_netkey_index(netkey_index); 224 if (network_key == NULL){ 225 *out_state = MESH_NODE_IDENTITY_STATE_ADVERTISING_NOT_SUPPORTED; 226 return MESH_FOUNDATION_STATUS_SUCCESS; 227 } 228 229 #ifdef ENABLE_MESH_PROXY_SERVER 230 if (network_key->node_id_advertisement_running == 0){ 231 *out_state = MESH_NODE_IDENTITY_STATE_ADVERTISING_STOPPED; 232 } else { 233 *out_state = MESH_NODE_IDENTITY_STATE_ADVERTISING_RUNNING; 234 } 235 #else 236 *out_state = MESH_NODE_IDENTITY_STATE_ADVERTISING_NOT_SUPPORTED; 237 #endif 238 239 return MESH_FOUNDATION_STATUS_SUCCESS; 240 } 241 242 uint8_t mesh_proxy_set_advertising_with_node_id(uint16_t netkey_index, mesh_node_identity_state_t state){ 243 mesh_subnet_t * network_key = mesh_subnet_get_by_netkey_index(netkey_index); 244 if (network_key == NULL){ 245 return MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX; 246 } 247 248 #ifdef ENABLE_MESH_PROXY_SERVER 249 switch (state){ 250 case MESH_NODE_IDENTITY_STATE_ADVERTISING_STOPPED: 251 mesh_proxy_stop_advertising_with_node_id(netkey_index); 252 return MESH_FOUNDATION_STATUS_SUCCESS; 253 case MESH_NODE_IDENTITY_STATE_ADVERTISING_RUNNING: 254 mesh_proxy_start_advertising_with_node_id(netkey_index); 255 return MESH_FOUNDATION_STATUS_SUCCESS; 256 default: 257 break; 258 } 259 #endif 260 261 return MESH_FOUNDATION_STATUS_FEATURE_NOT_SUPPORTED; 262 } 263 264 265 void mesh_proxy_start_advertising_with_network_id(void){ 266 mesh_subnet_iterator_t it; 267 mesh_subnet_iterator_init(&it); 268 while (mesh_subnet_iterator_has_more(&it)){ 269 mesh_subnet_t * subnet = mesh_subnet_iterator_get_next(&it); 270 log_info("Proxy start advertising with network id, netkey index %04x", subnet->netkey_index); 271 // setup advertisement with network id (used by proxy) 272 mesh_network_key_t * network_key = mesh_subnet_get_outgoing_network_key(subnet); 273 subnet->advertisement_with_network_id.adv_length = mesh_proxy_setup_advertising_with_network_id(subnet->advertisement_with_network_id.adv_data, network_key->network_id); 274 adv_bearer_advertisements_add_item(&subnet->advertisement_with_network_id); 275 } 276 adv_bearer_advertisements_enable(1); 277 } 278 279 void mesh_proxy_stop_advertising_with_network_id(void){ 280 mesh_subnet_iterator_t it; 281 mesh_subnet_iterator_init(&it); 282 while (mesh_subnet_iterator_has_more(&it)){ 283 mesh_subnet_t * network_key = mesh_subnet_iterator_get_next(&it); 284 log_info("Proxy stop advertising with network id, netkey index %04x", network_key->netkey_index); 285 adv_bearer_advertisements_remove_item(&network_key->advertisement_with_network_id); 286 } 287 } 288 289 // Mesh Proxy Configuration 290 291 typedef enum { 292 MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_SET_FILTER_TYPE = 0, 293 MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_ADD_ADDRESSES, 294 MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_REMOVE_ADDRESSES, 295 MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_FILTER_STATUS 296 } mesh_proxy_configuration_message_opcode_t; 297 298 typedef enum { 299 MESH_PROXY_CONFIGURATION_FILTER_TYPE_SET_WHITE_LIST = 0, 300 MESH_PROXY_CONFIGURATION_FILTER_TYPE_BLACK_LIST 301 } mesh_proxy_configuration_filter_type_t; 302 303 static mesh_network_pdu_t * encrypted_proxy_configuration_ready_to_send; 304 305 // Used to answer configuration request 306 static uint16_t proxy_configuration_filter_list_len; 307 static mesh_proxy_configuration_filter_type_t proxy_configuration_filter_type; 308 static uint16_t primary_element_address; 309 310 static void request_can_send_now_proxy_configuration_callback_handler(mesh_network_pdu_t * network_pdu){ 311 encrypted_proxy_configuration_ready_to_send = network_pdu; 312 gatt_bearer_request_can_send_now_for_mesh_proxy_configuration(); 313 } 314 315 static void proxy_configuration_message_handler(mesh_network_callback_type_t callback_type, mesh_network_pdu_t * received_network_pdu){ 316 mesh_proxy_configuration_message_opcode_t opcode; 317 uint8_t data[4]; 318 mesh_network_pdu_t * network_pdu; 319 uint8_t * network_pdu_data; 320 321 switch (callback_type){ 322 case MESH_NETWORK_PDU_RECEIVED: 323 printf("proxy_configuration_message_handler: MESH_PROXY_PDU_RECEIVED\n"); 324 network_pdu_data = mesh_network_pdu_data(received_network_pdu); 325 opcode = network_pdu_data[0]; 326 switch (opcode){ 327 case MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_SET_FILTER_TYPE:{ 328 switch (network_pdu_data[1]){ 329 case MESH_PROXY_CONFIGURATION_FILTER_TYPE_SET_WHITE_LIST: 330 case MESH_PROXY_CONFIGURATION_FILTER_TYPE_BLACK_LIST: 331 proxy_configuration_filter_type = network_pdu_data[1]; 332 break; 333 } 334 335 uint8_t ctl = 1; 336 uint8_t ttl = 0; 337 uint16_t src = primary_element_address; 338 uint16_t dest = 0; // unassigned address 339 uint32_t seq = mesh_sequence_number_next(); 340 uint8_t nid = mesh_network_nid(received_network_pdu); 341 uint16_t netkey_index = received_network_pdu->netkey_index; 342 printf("netkey index 0x%02x\n", netkey_index); 343 344 network_pdu = btstack_memory_mesh_network_pdu_get(); 345 int pos = 0; 346 data[pos++] = MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_FILTER_STATUS; 347 data[pos++] = proxy_configuration_filter_type; 348 big_endian_store_16(data, pos, proxy_configuration_filter_list_len); 349 350 mesh_network_setup_pdu(network_pdu, netkey_index, nid, ctl, ttl, seq, src, dest, data, sizeof(data)); 351 mesh_network_encrypt_proxy_configuration_message(network_pdu, &request_can_send_now_proxy_configuration_callback_handler); 352 353 // received_network_pdu is processed 354 btstack_memory_mesh_network_pdu_free(received_network_pdu); 355 break; 356 } 357 default: 358 printf("proxy config not implemented, opcode %d\n", opcode); 359 break; 360 } 361 break; 362 case MESH_NETWORK_CAN_SEND_NOW: 363 printf("MESH_SUBEVENT_CAN_SEND_NOW mesh_netework_gatt_bearer_handle_proxy_configuration len %d\n", encrypted_proxy_configuration_ready_to_send->len); 364 printf_hexdump(encrypted_proxy_configuration_ready_to_send->data, encrypted_proxy_configuration_ready_to_send->len); 365 gatt_bearer_send_mesh_proxy_configuration(encrypted_proxy_configuration_ready_to_send->data, encrypted_proxy_configuration_ready_to_send->len); 366 break; 367 case MESH_NETWORK_PDU_SENT: 368 // printf("test MESH_PROXY_PDU_SENT\n"); 369 // mesh_lower_transport_received_mesage(MESH_NETWORK_PDU_SENT, network_pdu); 370 break; 371 default: 372 break; 373 } 374 } 375 376 void mesh_proxy_init(uint16_t primary_unicast_address){ 377 primary_element_address = primary_unicast_address; 378 379 // mesh proxy configuration 380 mesh_network_set_proxy_message_handler(proxy_configuration_message_handler); 381 } 382 #endif 383 384