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