xref: /btstack/src/mesh/mesh_proxy.c (revision 2fca4dad957cd7b88f4657ed51e89c12615dda72)
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 
mesh_proxy_setup_advertising_unprovisioned(adv_bearer_connectable_advertisement_data_item_t * advertisement_item,const uint8_t * device_uuid)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 
mesh_proxy_start_advertising_unprovisioned_device(void)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  */
mesh_proxy_stop_advertising_unprovisioned_device(void)149 void mesh_proxy_stop_advertising_unprovisioned_device(void){
150     adv_bearer_advertisements_remove_item(&connectable_advertisement_unprovisioned_device);
151 }
152 
153 #endif
154 
mesh_proxy_setup_advertising_with_network_id(uint8_t * buffer,uint8_t * network_id)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 
mesh_proxy_stop_advertising_with_node_id_for_subnet(mesh_subnet_t * mesh_subnet)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 
mesh_proxy_stop_all_advertising_with_node_id(void)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 
mesh_proxy_node_id_timeout_handler(btstack_timer_source_t * ts)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 
mesh_proxy_node_id_handle_get_aes128(void * arg)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 
mesh_proxy_node_id_handle_random(void * arg)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 
mesh_proxy_start_advertising_with_node_id_for_subnet(mesh_subnet_t * mesh_subnet)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 
mesh_proxy_get_advertising_with_node_id_status(uint16_t netkey_index,mesh_node_identity_state_t * out_state)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 
mesh_proxy_set_advertising_with_node_id(uint16_t netkey_index,mesh_node_identity_state_t state)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 
mesh_proxy_start_advertising_with_node_id_next_subnet(void)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 
mesh_proxy_start_advertising_with_node_id(void)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 
mesh_proxy_stop_advertising_with_node_id(void)295 void mesh_proxy_stop_advertising_with_node_id(void){
296     mesh_proxy_stop_all_advertising_with_node_id();
297 }
298 
mesh_proxy_start_advertising_with_network_id(void)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 
mesh_proxy_stop_advertising_with_network_id(void)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 
request_can_send_now_proxy_configuration_callback_handler(mesh_network_pdu_t * network_pdu)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 
proxy_configuration_message_handler(mesh_network_callback_type_t callback_type,mesh_network_pdu_t * received_network_pdu)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 
mesh_proxy_init(uint16_t primary_unicast_address)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