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