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 memcpy(advertisement_item->adv_data, (uint8_t*) adv_data_unprovisioned_template, adv_data_unprovisioned_template_len); 129 // dynamically store device uuid into adv data 130 memcpy(&advertisement_item->adv_data[11], device_uuid, 16); 131 little_endian_store_16(advertisement_item->adv_data, 27, 0); 132 } 133 134 void mesh_proxy_start_advertising_unprovisioned_device(void){ 135 const uint8_t * device_uuid = mesh_node_get_device_uuid(); 136 mesh_proxy_setup_advertising_unprovisioned(&connectable_advertisement_unprovisioned_device, device_uuid); 137 // setup advertisements 138 adv_bearer_advertisements_add_item(&connectable_advertisement_unprovisioned_device); 139 adv_bearer_advertisements_enable(1); 140 } 141 142 /** 143 * @brief Start Advertising Unprovisioned Device with Device ID 144 * @param device_uuid 145 */ 146 void mesh_proxy_stop_advertising_unprovisioned_device(void){ 147 adv_bearer_advertisements_remove_item(&connectable_advertisement_unprovisioned_device); 148 } 149 150 #endif 151 152 static uint8_t mesh_proxy_setup_advertising_with_network_id(uint8_t * buffer, uint8_t * network_id){ 153 memcpy(&buffer[0], adv_data_with_network_id_template, 12); 154 memcpy(&buffer[12], network_id, 8); 155 return 20; 156 } 157 158 static void mesh_proxy_stop_advertising_with_node_id_for_subnet(mesh_subnet_t * mesh_subnet){ 159 if (mesh_subnet->node_id_advertisement_running != 0){ 160 adv_bearer_advertisements_remove_item(&mesh_subnet->advertisement_with_node_id); 161 mesh_subnet->node_id_advertisement_running = 0; 162 } 163 } 164 165 static void mesh_proxy_stop_all_advertising_with_node_id(void){ 166 mesh_subnet_iterator_t it; 167 mesh_subnet_iterator_init(&it); 168 while (mesh_subnet_iterator_has_more(&it)){ 169 mesh_subnet_t * mesh_subnet = mesh_subnet_iterator_get_next(&it); 170 mesh_proxy_stop_advertising_with_node_id_for_subnet(mesh_subnet); 171 } 172 btstack_run_loop_remove_timer(&mesh_proxy_node_id_timer); 173 mesh_proxy_node_id_all_subnets = 0; 174 } 175 176 static void mesh_proxy_node_id_timeout_handler(btstack_timer_source_t * ts){ 177 UNUSED(ts); 178 mesh_proxy_stop_all_advertising_with_node_id(); 179 } 180 181 static void mesh_proxy_node_id_handle_get_aes128(void * arg){ 182 mesh_subnet_t * mesh_subnet = (mesh_subnet_t *) arg; 183 184 memcpy(mesh_subnet->advertisement_with_node_id.adv_data, adv_data_with_node_id_template, 12); 185 memcpy(&mesh_subnet->advertisement_with_node_id.adv_data[12], &mesh_proxy_node_id_hash[8], 8); 186 memcpy(&mesh_subnet->advertisement_with_node_id.adv_data[20], mesh_proxy_node_id_random_value, 8); 187 mesh_subnet->advertisement_with_node_id.adv_length = 28; 188 189 // setup advertisements 190 adv_bearer_advertisements_add_item(&mesh_subnet->advertisement_with_node_id); 191 adv_bearer_advertisements_enable(1); 192 193 // set timer 194 btstack_run_loop_set_timer_handler(&mesh_proxy_node_id_timer, mesh_proxy_node_id_timeout_handler); 195 btstack_run_loop_set_timer(&mesh_proxy_node_id_timer, MESH_PROXY_NODE_ID_ADVERTISEMENT_TIMEOUT_MS); 196 btstack_run_loop_add_timer(&mesh_proxy_node_id_timer); 197 198 // mark as active 199 mesh_subnet->node_id_advertisement_running = 1; 200 201 // next one 202 if (mesh_proxy_node_id_all_subnets == 0) return; 203 mesh_proxy_start_advertising_with_node_id_next_subnet(); 204 } 205 206 static void mesh_proxy_node_id_handle_random(void * arg){ 207 mesh_subnet_t * mesh_subnet = (mesh_subnet_t *) arg; 208 209 // Hash = e(IdentityKey, Padding | Random | Address) mod 2^64 210 memset(mesh_proxy_node_id_plaintext, 0, sizeof(mesh_proxy_node_id_plaintext)); 211 memcpy(&mesh_proxy_node_id_plaintext[6] , mesh_proxy_node_id_random_value, 8); 212 big_endian_store_16(mesh_proxy_node_id_plaintext, 14, primary_element_address); 213 // TODO: old vs. new key 214 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); 215 } 216 217 static void mesh_proxy_start_advertising_with_node_id_for_subnet(mesh_subnet_t * mesh_subnet){ 218 if (mesh_subnet->node_id_advertisement_running) return; 219 log_info("Proxy start advertising with node id, netkey index %04x", mesh_subnet->netkey_index); 220 // setup node id 221 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); 222 } 223 224 // Public API 225 226 uint8_t mesh_proxy_get_advertising_with_node_id_status(uint16_t netkey_index, mesh_node_identity_state_t * out_state ){ 227 mesh_subnet_t * mesh_subnet = mesh_subnet_get_by_netkey_index(netkey_index); 228 if (mesh_subnet == NULL){ 229 *out_state = MESH_NODE_IDENTITY_STATE_ADVERTISING_STOPPED; 230 return MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX; 231 } 232 233 #ifdef ENABLE_MESH_PROXY_SERVER 234 if (mesh_subnet->node_id_advertisement_running == 0){ 235 *out_state = MESH_NODE_IDENTITY_STATE_ADVERTISING_STOPPED; 236 } else { 237 *out_state = MESH_NODE_IDENTITY_STATE_ADVERTISING_RUNNING; 238 } 239 #else 240 *out_state = MESH_NODE_IDENTITY_STATE_ADVERTISING_NOT_SUPPORTED; 241 #endif 242 243 return MESH_FOUNDATION_STATUS_SUCCESS; 244 } 245 246 uint8_t mesh_proxy_set_advertising_with_node_id(uint16_t netkey_index, mesh_node_identity_state_t state){ 247 mesh_subnet_t * mesh_subnet = mesh_subnet_get_by_netkey_index(netkey_index); 248 if (mesh_subnet == NULL){ 249 return MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX; 250 } 251 252 #ifdef ENABLE_MESH_PROXY_SERVER 253 switch (state){ 254 case MESH_NODE_IDENTITY_STATE_ADVERTISING_STOPPED: 255 mesh_proxy_stop_advertising_with_node_id_for_subnet(mesh_subnet); 256 return MESH_FOUNDATION_STATUS_SUCCESS; 257 case MESH_NODE_IDENTITY_STATE_ADVERTISING_RUNNING: 258 mesh_proxy_start_advertising_with_node_id_for_subnet(mesh_subnet); 259 return MESH_FOUNDATION_STATUS_SUCCESS; 260 default: 261 break; 262 } 263 #endif 264 265 return MESH_FOUNDATION_STATUS_FEATURE_NOT_SUPPORTED; 266 } 267 268 static void mesh_proxy_start_advertising_with_node_id_next_subnet(void){ 269 mesh_subnet_iterator_t it; 270 mesh_subnet_iterator_init(&it); 271 while (mesh_subnet_iterator_has_more(&it)){ 272 mesh_subnet_t * subnet = mesh_subnet_iterator_get_next(&it); 273 if (subnet->node_id_advertisement_running != 0) continue; 274 275 mesh_proxy_start_advertising_with_node_id_for_subnet(subnet); 276 return; 277 } 278 } 279 280 void mesh_proxy_start_advertising_with_node_id(void){ 281 mesh_proxy_node_id_all_subnets = 1; 282 adv_bearer_advertisements_enable(1); 283 284 // start advertising on first subnet that is not already advertising with node id 285 mesh_proxy_start_advertising_with_node_id_next_subnet(); 286 } 287 288 void mesh_proxy_stop_advertising_with_node_id(void){ 289 mesh_proxy_stop_all_advertising_with_node_id(); 290 } 291 292 void mesh_proxy_start_advertising_with_network_id(void){ 293 mesh_subnet_iterator_t it; 294 mesh_subnet_iterator_init(&it); 295 while (mesh_subnet_iterator_has_more(&it)){ 296 mesh_subnet_t * subnet = mesh_subnet_iterator_get_next(&it); 297 log_info("Proxy start advertising with network id, netkey index %04x", subnet->netkey_index); 298 // setup advertisement with network id (used by proxy) 299 mesh_network_key_t * network_key = mesh_subnet_get_outgoing_network_key(subnet); 300 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); 301 adv_bearer_advertisements_add_item(&subnet->advertisement_with_network_id); 302 } 303 adv_bearer_advertisements_enable(1); 304 } 305 306 void mesh_proxy_stop_advertising_with_network_id(void){ 307 mesh_subnet_iterator_t it; 308 mesh_subnet_iterator_init(&it); 309 while (mesh_subnet_iterator_has_more(&it)){ 310 mesh_subnet_t * network_key = mesh_subnet_iterator_get_next(&it); 311 log_info("Proxy stop advertising with network id, netkey index %04x", network_key->netkey_index); 312 adv_bearer_advertisements_remove_item(&network_key->advertisement_with_network_id); 313 } 314 } 315 316 // Mesh Proxy Configuration 317 318 typedef enum { 319 MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_SET_FILTER_TYPE = 0, 320 MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_ADD_ADDRESSES, 321 MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_REMOVE_ADDRESSES, 322 MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_FILTER_STATUS 323 } mesh_proxy_configuration_message_opcode_t; 324 325 typedef enum { 326 MESH_PROXY_CONFIGURATION_FILTER_TYPE_SET_WHITE_LIST = 0, 327 MESH_PROXY_CONFIGURATION_FILTER_TYPE_BLACK_LIST 328 } mesh_proxy_configuration_filter_type_t; 329 330 static mesh_network_pdu_t * encrypted_proxy_configuration_ready_to_send; 331 332 // Used to answer configuration request 333 static uint16_t proxy_configuration_filter_list_len; 334 static mesh_proxy_configuration_filter_type_t proxy_configuration_filter_type; 335 static uint16_t primary_element_address; 336 337 static void request_can_send_now_proxy_configuration_callback_handler(mesh_network_pdu_t * network_pdu){ 338 encrypted_proxy_configuration_ready_to_send = network_pdu; 339 gatt_bearer_request_can_send_now_for_mesh_proxy_configuration(); 340 } 341 342 static void proxy_configuration_message_handler(mesh_network_callback_type_t callback_type, mesh_network_pdu_t * received_network_pdu){ 343 mesh_proxy_configuration_message_opcode_t opcode; 344 uint8_t data[4]; 345 mesh_network_pdu_t * network_pdu; 346 uint8_t * network_pdu_data; 347 348 switch (callback_type){ 349 case MESH_NETWORK_PDU_RECEIVED: 350 printf("proxy_configuration_message_handler: MESH_PROXY_PDU_RECEIVED\n"); 351 network_pdu_data = mesh_network_pdu_data(received_network_pdu); 352 opcode = network_pdu_data[0]; 353 switch (opcode){ 354 case MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_SET_FILTER_TYPE:{ 355 switch (network_pdu_data[1]){ 356 case MESH_PROXY_CONFIGURATION_FILTER_TYPE_SET_WHITE_LIST: 357 case MESH_PROXY_CONFIGURATION_FILTER_TYPE_BLACK_LIST: 358 proxy_configuration_filter_type = network_pdu_data[1]; 359 break; 360 } 361 362 uint8_t ctl = 1; 363 uint8_t ttl = 0; 364 uint16_t src = primary_element_address; 365 uint16_t dest = 0; // unassigned address 366 uint32_t seq = mesh_sequence_number_next(); 367 uint8_t nid = mesh_network_nid(received_network_pdu); 368 uint16_t netkey_index = received_network_pdu->netkey_index; 369 printf("netkey index 0x%02x\n", netkey_index); 370 371 network_pdu = btstack_memory_mesh_network_pdu_get(); 372 int pos = 0; 373 data[pos++] = MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_FILTER_STATUS; 374 data[pos++] = proxy_configuration_filter_type; 375 big_endian_store_16(data, pos, proxy_configuration_filter_list_len); 376 377 mesh_network_setup_pdu(network_pdu, netkey_index, nid, ctl, ttl, seq, src, dest, data, sizeof(data)); 378 mesh_network_encrypt_proxy_configuration_message(network_pdu, &request_can_send_now_proxy_configuration_callback_handler); 379 380 // received_network_pdu is processed 381 btstack_memory_mesh_network_pdu_free(received_network_pdu); 382 break; 383 } 384 default: 385 printf("proxy config not implemented, opcode %d\n", opcode); 386 break; 387 } 388 break; 389 case MESH_NETWORK_CAN_SEND_NOW: 390 printf("MESH_SUBEVENT_CAN_SEND_NOW mesh_netework_gatt_bearer_handle_proxy_configuration len %d\n", encrypted_proxy_configuration_ready_to_send->len); 391 printf_hexdump(encrypted_proxy_configuration_ready_to_send->data, encrypted_proxy_configuration_ready_to_send->len); 392 gatt_bearer_send_mesh_proxy_configuration(encrypted_proxy_configuration_ready_to_send->data, encrypted_proxy_configuration_ready_to_send->len); 393 break; 394 case MESH_NETWORK_PDU_SENT: 395 // printf("test MESH_PROXY_PDU_SENT\n"); 396 // mesh_lower_transport_received_mesage(MESH_NETWORK_PDU_SENT, network_pdu); 397 break; 398 default: 399 break; 400 } 401 } 402 403 void mesh_proxy_init(uint16_t primary_unicast_address){ 404 primary_element_address = primary_unicast_address; 405 406 // mesh proxy configuration 407 mesh_network_set_proxy_message_handler(proxy_configuration_message_handler); 408 } 409 #endif 410 411