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 BLUEKITCHEN 24 * GMBH 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 <stdio.h> 43 #include <string.h> 44 45 #include "bluetooth_company_id.h" 46 #include "bluetooth_data_types.h" 47 #include "bluetooth_gatt.h" 48 #include "btstack_config.h" 49 #include "btstack_crypto.h" 50 #include "btstack_debug.h" 51 #include "btstack_memory.h" 52 #include "btstack_run_loop.h" 53 #include "btstack_util.h" 54 55 #include "mesh/adv_bearer.h" 56 #include "mesh/gatt_bearer.h" 57 #include "mesh/mesh_crypto.h" 58 #include "mesh/mesh_foundation.h" 59 #include "mesh/mesh_iv_index_seq_number.h" 60 #include "mesh/mesh_lower_transport.h" 61 #include "mesh/mesh_network.h" 62 #include "mesh/mesh_node.h" 63 64 static void mesh_proxy_start_advertising_with_node_id_next_subnet(void); 65 static void mesh_proxy_start_advertising_with_node_id_for_subnet(mesh_subnet_t * mesh_subnet); 66 67 #ifdef ENABLE_MESH_PROXY_SERVER 68 69 // we only support a single active node id advertisement. when new one is started, an active one is stopped 70 71 #define MESH_PROXY_NODE_ID_ADVERTISEMENT_TIMEOUT_MS 60000 72 73 static btstack_timer_source_t mesh_proxy_node_id_timer; 74 static btstack_crypto_random_t mesh_proxy_node_id_crypto_request_random; 75 static btstack_crypto_aes128_t mesh_proxy_node_id_crypto_request_aes128; 76 static uint8_t mesh_proxy_node_id_plaintext[16]; 77 static uint8_t mesh_proxy_node_id_hash[16]; 78 static uint8_t mesh_proxy_node_id_random_value[8]; 79 static uint8_t mesh_proxy_node_id_all_subnets; 80 81 static uint16_t primary_element_address; 82 83 // Mesh Proxy, advertise unprovisioned device 84 static adv_bearer_connectable_advertisement_data_item_t connectable_advertisement_unprovisioned_device; 85 86 static const uint8_t adv_data_with_node_id_template[] = { 87 // Flags general discoverable, BR/EDR not supported 88 0x02, BLUETOOTH_DATA_TYPE_FLAGS, 0x06, 89 // 16-bit Service UUIDs 90 0x03, BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS, ORG_BLUETOOTH_SERVICE_MESH_PROXY & 0xff, ORG_BLUETOOTH_SERVICE_MESH_PROXY >> 8, 91 // Service Data 92 0x14, BLUETOOTH_DATA_TYPE_SERVICE_DATA, ORG_BLUETOOTH_SERVICE_MESH_PROXY & 0xff, ORG_BLUETOOTH_SERVICE_MESH_PROXY >> 8, 93 // MESH_IDENTIFICATION_NODE_IDENTIFY_TYPE 94 MESH_IDENTIFICATION_NODE_IDENTIFY_TYPE, 95 // Hash - 8 bytes 96 // Random - 8 bytes 97 }; 98 99 static const uint8_t adv_data_with_network_id_template[] = { 100 // Flags general discoverable, BR/EDR not supported 101 0x02, BLUETOOTH_DATA_TYPE_FLAGS, 0x06, 102 // 16-bit Service UUIDs 103 0x03, BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS, ORG_BLUETOOTH_SERVICE_MESH_PROXY & 0xff, ORG_BLUETOOTH_SERVICE_MESH_PROXY >> 8, 104 // Service Data 105 0x0C, BLUETOOTH_DATA_TYPE_SERVICE_DATA, ORG_BLUETOOTH_SERVICE_MESH_PROXY & 0xff, ORG_BLUETOOTH_SERVICE_MESH_PROXY >> 8, 106 // MESH_IDENTIFICATION_NETWORK_ID_TYPE 107 MESH_IDENTIFICATION_NETWORK_ID_TYPE 108 }; 109 110 #ifdef ENABLE_MESH_PB_GATT 111 112 // Mesh Provisioning 113 static const uint8_t adv_data_unprovisioned_template[] = { 114 // Flags general discoverable, BR/EDR not supported 115 0x02, BLUETOOTH_DATA_TYPE_FLAGS, 0x06, 116 // 16-bit Service UUIDs 117 0x03, BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS, ORG_BLUETOOTH_SERVICE_MESH_PROVISIONING & 0xff, ORG_BLUETOOTH_SERVICE_MESH_PROVISIONING >> 8, 118 // Service Data (22) 119 0x15, BLUETOOTH_DATA_TYPE_SERVICE_DATA, ORG_BLUETOOTH_SERVICE_MESH_PROVISIONING & 0xff, ORG_BLUETOOTH_SERVICE_MESH_PROVISIONING >> 8, 120 // UUID - 16 bytes 121 // OOB information - 2 bytes 122 }; 123 const uint8_t adv_data_unprovisioned_template_len = sizeof(adv_data_unprovisioned_template); 124 125 static void mesh_proxy_setup_advertising_unprovisioned(adv_bearer_connectable_advertisement_data_item_t * advertisement_item, const uint8_t * device_uuid) { 126 // store in advertisement item 127 memset(advertisement_item, 0, sizeof(adv_bearer_connectable_advertisement_data_item_t)); 128 advertisement_item->adv_length = adv_data_unprovisioned_template_len + 18; 129 (void)memcpy(advertisement_item->adv_data, 130 (uint8_t *)adv_data_unprovisioned_template, 131 adv_data_unprovisioned_template_len); 132 // dynamically store device uuid into adv data 133 (void)memcpy(&advertisement_item->adv_data[11], device_uuid, 16); 134 little_endian_store_16(advertisement_item->adv_data, 27, 0); 135 } 136 137 void mesh_proxy_start_advertising_unprovisioned_device(void){ 138 const uint8_t * device_uuid = mesh_node_get_device_uuid(); 139 mesh_proxy_setup_advertising_unprovisioned(&connectable_advertisement_unprovisioned_device, device_uuid); 140 // setup advertisements 141 adv_bearer_advertisements_add_item(&connectable_advertisement_unprovisioned_device); 142 adv_bearer_advertisements_enable(1); 143 } 144 145 /** 146 * @brief Start Advertising Unprovisioned Device with Device ID 147 * @param device_uuid 148 */ 149 void mesh_proxy_stop_advertising_unprovisioned_device(void){ 150 adv_bearer_advertisements_remove_item(&connectable_advertisement_unprovisioned_device); 151 } 152 153 #endif 154 155 static uint8_t mesh_proxy_setup_advertising_with_network_id(uint8_t * buffer, uint8_t * network_id){ 156 (void)memcpy(&buffer[0], adv_data_with_network_id_template, 12); 157 (void)memcpy(&buffer[12], network_id, 8); 158 return 20; 159 } 160 161 static void mesh_proxy_stop_advertising_with_node_id_for_subnet(mesh_subnet_t * mesh_subnet){ 162 if (mesh_subnet->node_id_advertisement_running != 0){ 163 adv_bearer_advertisements_remove_item(&mesh_subnet->advertisement_with_node_id); 164 mesh_subnet->node_id_advertisement_running = 0; 165 } 166 } 167 168 static void mesh_proxy_stop_all_advertising_with_node_id(void){ 169 mesh_subnet_iterator_t it; 170 mesh_subnet_iterator_init(&it); 171 while (mesh_subnet_iterator_has_more(&it)){ 172 mesh_subnet_t * mesh_subnet = mesh_subnet_iterator_get_next(&it); 173 mesh_proxy_stop_advertising_with_node_id_for_subnet(mesh_subnet); 174 } 175 btstack_run_loop_remove_timer(&mesh_proxy_node_id_timer); 176 mesh_proxy_node_id_all_subnets = 0; 177 } 178 179 static void mesh_proxy_node_id_timeout_handler(btstack_timer_source_t * ts){ 180 UNUSED(ts); 181 mesh_proxy_stop_all_advertising_with_node_id(); 182 } 183 184 static void mesh_proxy_node_id_handle_get_aes128(void * arg){ 185 mesh_subnet_t * mesh_subnet = (mesh_subnet_t *) arg; 186 187 (void)memcpy(mesh_subnet->advertisement_with_node_id.adv_data, 188 adv_data_with_node_id_template, 12); 189 (void)memcpy(&mesh_subnet->advertisement_with_node_id.adv_data[12], 190 &mesh_proxy_node_id_hash[8], 8); 191 (void)memcpy(&mesh_subnet->advertisement_with_node_id.adv_data[20], 192 mesh_proxy_node_id_random_value, 8); 193 mesh_subnet->advertisement_with_node_id.adv_length = 28; 194 195 // setup advertisements 196 adv_bearer_advertisements_add_item(&mesh_subnet->advertisement_with_node_id); 197 adv_bearer_advertisements_enable(1); 198 199 // set timer 200 btstack_run_loop_set_timer_handler(&mesh_proxy_node_id_timer, mesh_proxy_node_id_timeout_handler); 201 btstack_run_loop_set_timer(&mesh_proxy_node_id_timer, MESH_PROXY_NODE_ID_ADVERTISEMENT_TIMEOUT_MS); 202 btstack_run_loop_add_timer(&mesh_proxy_node_id_timer); 203 204 // mark as active 205 mesh_subnet->node_id_advertisement_running = 1; 206 207 // next one 208 if (mesh_proxy_node_id_all_subnets == 0) return; 209 mesh_proxy_start_advertising_with_node_id_next_subnet(); 210 } 211 212 static void mesh_proxy_node_id_handle_random(void * arg){ 213 mesh_subnet_t * mesh_subnet = (mesh_subnet_t *) arg; 214 215 // Hash = e(IdentityKey, Padding | Random | Address) mod 2^64 216 memset(mesh_proxy_node_id_plaintext, 0, sizeof(mesh_proxy_node_id_plaintext)); 217 (void)memcpy(&mesh_proxy_node_id_plaintext[6], 218 mesh_proxy_node_id_random_value, 8); 219 big_endian_store_16(mesh_proxy_node_id_plaintext, 14, primary_element_address); 220 // TODO: old vs. new key 221 btstack_crypto_aes128_encrypt(&mesh_proxy_node_id_crypto_request_aes128, mesh_subnet->old_key->identity_key, mesh_proxy_node_id_plaintext, mesh_proxy_node_id_hash, mesh_proxy_node_id_handle_get_aes128, mesh_subnet); 222 } 223 224 static void mesh_proxy_start_advertising_with_node_id_for_subnet(mesh_subnet_t * mesh_subnet){ 225 if (mesh_subnet->node_id_advertisement_running) return; 226 log_info("Proxy start advertising with node id, netkey index %04x", mesh_subnet->netkey_index); 227 // setup node id 228 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, mesh_subnet); 229 } 230 231 // Public API 232 233 uint8_t mesh_proxy_get_advertising_with_node_id_status(uint16_t netkey_index, mesh_node_identity_state_t * out_state ){ 234 mesh_subnet_t * mesh_subnet = mesh_subnet_get_by_netkey_index(netkey_index); 235 if (mesh_subnet == NULL){ 236 *out_state = MESH_NODE_IDENTITY_STATE_ADVERTISING_STOPPED; 237 return MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX; 238 } 239 240 #ifdef ENABLE_MESH_PROXY_SERVER 241 if (mesh_subnet->node_id_advertisement_running == 0){ 242 *out_state = MESH_NODE_IDENTITY_STATE_ADVERTISING_STOPPED; 243 } else { 244 *out_state = MESH_NODE_IDENTITY_STATE_ADVERTISING_RUNNING; 245 } 246 #else 247 *out_state = MESH_NODE_IDENTITY_STATE_ADVERTISING_NOT_SUPPORTED; 248 #endif 249 250 return MESH_FOUNDATION_STATUS_SUCCESS; 251 } 252 253 uint8_t mesh_proxy_set_advertising_with_node_id(uint16_t netkey_index, mesh_node_identity_state_t state){ 254 mesh_subnet_t * mesh_subnet = mesh_subnet_get_by_netkey_index(netkey_index); 255 if (mesh_subnet == NULL){ 256 return MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX; 257 } 258 259 #ifdef ENABLE_MESH_PROXY_SERVER 260 switch (state){ 261 case MESH_NODE_IDENTITY_STATE_ADVERTISING_STOPPED: 262 mesh_proxy_stop_advertising_with_node_id_for_subnet(mesh_subnet); 263 return MESH_FOUNDATION_STATUS_SUCCESS; 264 case MESH_NODE_IDENTITY_STATE_ADVERTISING_RUNNING: 265 mesh_proxy_start_advertising_with_node_id_for_subnet(mesh_subnet); 266 return MESH_FOUNDATION_STATUS_SUCCESS; 267 default: 268 break; 269 } 270 #endif 271 272 return MESH_FOUNDATION_STATUS_FEATURE_NOT_SUPPORTED; 273 } 274 275 static void mesh_proxy_start_advertising_with_node_id_next_subnet(void){ 276 mesh_subnet_iterator_t it; 277 mesh_subnet_iterator_init(&it); 278 while (mesh_subnet_iterator_has_more(&it)){ 279 mesh_subnet_t * subnet = mesh_subnet_iterator_get_next(&it); 280 if (subnet->node_id_advertisement_running != 0) continue; 281 282 mesh_proxy_start_advertising_with_node_id_for_subnet(subnet); 283 return; 284 } 285 } 286 287 void mesh_proxy_start_advertising_with_node_id(void){ 288 mesh_proxy_node_id_all_subnets = 1; 289 adv_bearer_advertisements_enable(1); 290 291 // start advertising on first subnet that is not already advertising with node id 292 mesh_proxy_start_advertising_with_node_id_next_subnet(); 293 } 294 295 void mesh_proxy_stop_advertising_with_node_id(void){ 296 mesh_proxy_stop_all_advertising_with_node_id(); 297 } 298 299 void mesh_proxy_start_advertising_with_network_id(void){ 300 mesh_subnet_iterator_t it; 301 mesh_subnet_iterator_init(&it); 302 while (mesh_subnet_iterator_has_more(&it)){ 303 mesh_subnet_t * subnet = mesh_subnet_iterator_get_next(&it); 304 log_info("Proxy start advertising with network id, netkey index %04x", subnet->netkey_index); 305 // setup advertisement with network id (used by proxy) 306 mesh_network_key_t * network_key = mesh_subnet_get_outgoing_network_key(subnet); 307 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); 308 adv_bearer_advertisements_add_item(&subnet->advertisement_with_network_id); 309 } 310 adv_bearer_advertisements_enable(1); 311 } 312 313 void mesh_proxy_stop_advertising_with_network_id(void){ 314 mesh_subnet_iterator_t it; 315 mesh_subnet_iterator_init(&it); 316 while (mesh_subnet_iterator_has_more(&it)){ 317 mesh_subnet_t * network_key = mesh_subnet_iterator_get_next(&it); 318 log_info("Proxy stop advertising with network id, netkey index %04x", network_key->netkey_index); 319 adv_bearer_advertisements_remove_item(&network_key->advertisement_with_network_id); 320 } 321 } 322 323 // Mesh Proxy Configuration 324 325 typedef enum { 326 MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_SET_FILTER_TYPE = 0, 327 MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_ADD_ADDRESSES, 328 MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_REMOVE_ADDRESSES, 329 MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_FILTER_STATUS 330 } mesh_proxy_configuration_message_opcode_t; 331 332 typedef enum { 333 MESH_PROXY_CONFIGURATION_FILTER_TYPE_SET_WHITE_LIST = 0, 334 MESH_PROXY_CONFIGURATION_FILTER_TYPE_BLACK_LIST 335 } mesh_proxy_configuration_filter_type_t; 336 337 static mesh_network_pdu_t * encrypted_proxy_configuration_ready_to_send; 338 339 // Used to answer configuration request 340 static uint16_t proxy_configuration_filter_list_len; 341 static mesh_proxy_configuration_filter_type_t proxy_configuration_filter_type; 342 343 static void request_can_send_now_proxy_configuration_callback_handler(mesh_network_pdu_t * network_pdu){ 344 encrypted_proxy_configuration_ready_to_send = network_pdu; 345 gatt_bearer_request_can_send_now_for_mesh_proxy_configuration(); 346 } 347 348 static void proxy_configuration_message_handler(mesh_network_callback_type_t callback_type, mesh_network_pdu_t * received_network_pdu){ 349 mesh_proxy_configuration_message_opcode_t opcode; 350 uint8_t data[4]; 351 mesh_network_pdu_t * network_pdu; 352 uint8_t * network_pdu_data; 353 354 switch (callback_type){ 355 case MESH_NETWORK_PDU_RECEIVED: 356 printf("proxy_configuration_message_handler: MESH_PROXY_PDU_RECEIVED\n"); 357 network_pdu_data = mesh_network_pdu_data(received_network_pdu); 358 opcode = network_pdu_data[0]; 359 switch (opcode){ 360 case MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_SET_FILTER_TYPE:{ 361 switch ((mesh_proxy_configuration_filter_type_t) network_pdu_data[1]){ 362 case MESH_PROXY_CONFIGURATION_FILTER_TYPE_SET_WHITE_LIST: 363 case MESH_PROXY_CONFIGURATION_FILTER_TYPE_BLACK_LIST: 364 proxy_configuration_filter_type = network_pdu_data[1]; 365 break; 366 default: 367 // invalid filter type, ignore 368 btstack_memory_mesh_network_pdu_free(received_network_pdu); 369 return; 370 } 371 372 uint8_t ctl = 1; 373 uint8_t ttl = 0; 374 uint16_t src = primary_element_address; 375 uint16_t dest = 0; // unassigned address 376 uint32_t seq = mesh_sequence_number_next(); 377 uint8_t nid = mesh_network_nid(received_network_pdu); 378 uint16_t netkey_index = received_network_pdu->netkey_index; 379 printf("netkey index 0x%02x\n", netkey_index); 380 381 network_pdu = btstack_memory_mesh_network_pdu_get(); 382 int pos = 0; 383 data[pos++] = MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_FILTER_STATUS; 384 data[pos++] = proxy_configuration_filter_type; 385 big_endian_store_16(data, pos, proxy_configuration_filter_list_len); 386 387 mesh_network_setup_pdu(network_pdu, netkey_index, nid, ctl, ttl, seq, src, dest, data, sizeof(data)); 388 mesh_network_encrypt_proxy_configuration_message(network_pdu); 389 390 // received_network_pdu is processed 391 btstack_memory_mesh_network_pdu_free(received_network_pdu); 392 break; 393 } 394 default: 395 printf("proxy config not implemented, opcode %d\n", opcode); 396 btstack_memory_mesh_network_pdu_free(received_network_pdu); 397 break; 398 } 399 break; 400 case MESH_NETWORK_CAN_SEND_NOW: 401 printf("MESH_SUBEVENT_CAN_SEND_NOW mesh_netework_gatt_bearer_handle_proxy_configuration len %d\n", encrypted_proxy_configuration_ready_to_send->len); 402 printf_hexdump(encrypted_proxy_configuration_ready_to_send->data, encrypted_proxy_configuration_ready_to_send->len); 403 gatt_bearer_send_mesh_proxy_configuration(encrypted_proxy_configuration_ready_to_send->data, encrypted_proxy_configuration_ready_to_send->len); 404 break; 405 case MESH_NETWORK_PDU_SENT: 406 // printf("test MESH_PROXY_PDU_SENT\n"); 407 // mesh_lower_transport_received_mesage(MESH_NETWORK_PDU_SENT, network_pdu); 408 break; 409 case MESH_NETWORK_PDU_ENCRYPTED: 410 request_can_send_now_proxy_configuration_callback_handler(received_network_pdu); 411 break; 412 default: 413 break; 414 } 415 } 416 417 void mesh_proxy_init(uint16_t primary_unicast_address){ 418 primary_element_address = primary_unicast_address; 419 420 // mesh proxy configuration 421 mesh_network_set_proxy_message_handler(proxy_configuration_message_handler); 422 } 423 #endif 424 425