xref: /btstack/src/mesh/mesh_proxy.c (revision b6fc147f78a37f3479b846963ca40c9b931f6e2f)
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