xref: /btstack/src/mesh/mesh_configuration_server.c (revision 9d29a5e25270abdb085922d5b22f9ff526880c34)
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_configuration_server.c"
39 
40 #include <string.h>
41 #include <stdio.h>
42 
43 #include "mesh/mesh_configuration_server.h"
44 
45 #include "bluetooth_company_id.h"
46 #include "btstack_debug.h"
47 #include "btstack_memory.h"
48 #include "btstack_tlv.h"
49 #include "btstack_util.h"
50 
51 #include "mesh/beacon.h"
52 #include "mesh/gatt_bearer.h"
53 #include "mesh/mesh.h"
54 #include "mesh/mesh_access.h"
55 #include "mesh/mesh_crypto.h"
56 #include "mesh/mesh_foundation.h"
57 #include "mesh/mesh_iv_index_seq_number.h"
58 #include "mesh/mesh_keys.h"
59 #include "mesh/mesh_network.h"
60 #include "mesh/mesh_node.h"
61 #include "mesh/mesh_proxy.h"
62 #include "mesh/mesh_upper_transport.h"
63 #include "mesh/mesh_virtual_addresses.h"
64 
65 #define MESH_HEARTBEAT_FEATURES_SUPPORTED_MASK 0x000f
66 
67 typedef struct {
68     uint16_t  hash;
69     uint8_t   label_uuid[16];
70 } mesh_persistent_virtual_address_t;
71 
72 
73 // current access pdu
74 static mesh_pdu_t * access_pdu_in_process;
75 
76 // data from current pdu
77 static uint16_t                     configuration_server_element_address;
78 static uint32_t                     configuration_server_model_identifier;
79 static mesh_model_t               * configuration_server_target_model;
80 static mesh_publication_model_t     configuration_server_publication_model;
81 
82 // cmac for virtual address hash and netkey derive
83 static btstack_crypto_aes128_cmac_t configuration_server_cmac_request;
84 
85 // used to setup virtual addresses
86 static uint8_t                      configuration_server_label_uuid[16];
87 static uint16_t                     configuration_server_hash;
88 
89 // heartbeat publication and subscription state for all Configuration Server models - there is only one
90 // static mesh_heartbeat_subscription_t mesh_heartbeat_subscription;
91 
92 // for PTS testing
93 static int config_netkey_list_max = 0;
94 
95 
96 // Heartbeat (helper)
97 static uint16_t heartbeat_pwr2(uint8_t value){
98     if (!value)                         return 0x0000;
99     if (value == 0xff || value == 0x11) return 0xffff;
100     return 1 << (value-1);
101 }
102 
103 static uint8_t heartbeat_count_log(uint16_t value){
104     if (!value)          return 0x00;
105     if (value == 0x01)   return 0x01;
106     if (value == 0xffff) return 0xff;
107     // count leading zeros, supported by clang and gcc
108     return 32 - __builtin_clz(value - 1) + 1;
109 }
110 
111 // TLV
112 
113 static const btstack_tlv_t * btstack_tlv_singleton_impl;
114 static void *                btstack_tlv_singleton_context;
115 
116 static uint32_t mesh_virtual_address_tag_for_pseudo_dst(uint16_t pseudo_dst){
117     return ((uint32_t) 'M' << 24) | ((uint32_t) 'V' << 16) | ((uint32_t) pseudo_dst);
118 }
119 
120 static void mesh_configuration_server_setup_tlv(void){
121     if (btstack_tlv_singleton_impl) return;
122     btstack_tlv_get_instance(&btstack_tlv_singleton_impl, &btstack_tlv_singleton_context);
123 }
124 
125 static void mesh_store_virtual_address(uint16_t pseudo_dest, uint16_t hash, const uint8_t * label_uuid){
126     mesh_configuration_server_setup_tlv();
127 
128     mesh_persistent_virtual_address_t data;
129     uint32_t tag = mesh_virtual_address_tag_for_pseudo_dst(pseudo_dest);
130     data.hash = hash;
131     memcpy(data.label_uuid, label_uuid, 16);
132     btstack_tlv_singleton_impl->store_tag(btstack_tlv_singleton_context, tag, (uint8_t *) &data, sizeof(data));
133 }
134 
135 static void mesh_delete_virtual_address(uint16_t pseudo_dest){
136     mesh_configuration_server_setup_tlv();
137 
138     uint32_t tag = mesh_virtual_address_tag_for_pseudo_dst(pseudo_dest);
139     btstack_tlv_singleton_impl->delete_tag(btstack_tlv_singleton_context, tag);
140 }
141 
142 void mesh_load_virtual_addresses(void){
143     mesh_configuration_server_setup_tlv();
144     uint16_t pseudo_dst;
145     for (pseudo_dst = 0x8000; pseudo_dst < (0x8000 + MAX_NR_MESH_VIRTUAL_ADDRESSES); pseudo_dst++){
146         mesh_virtual_address_tag_for_pseudo_dst(pseudo_dst);
147         mesh_persistent_virtual_address_t data;
148         uint32_t tag = mesh_virtual_address_tag_for_pseudo_dst(pseudo_dst);
149         int virtual_address_len = btstack_tlv_singleton_impl->get_tag(btstack_tlv_singleton_context, tag, (uint8_t *) &data, sizeof(data));
150         if (virtual_address_len == 0) return;
151 
152         mesh_virtual_address_t * virtual_address = btstack_memory_mesh_virtual_address_get();
153         if (virtual_address == NULL) return;
154 
155         virtual_address->pseudo_dst = pseudo_dst;
156         virtual_address->hash = data.hash;
157         memcpy(virtual_address->label_uuid, data.label_uuid, 16);
158         mesh_virtual_address_add(virtual_address);
159     }
160 }
161 
162 void mesh_delete_virtual_addresses(void){
163     uint16_t pseudo_dest;
164     for (pseudo_dest = 0x8000; pseudo_dest < (0x8000 + MAX_NR_MESH_VIRTUAL_ADDRESSES); pseudo_dest++){
165         mesh_delete_virtual_address(pseudo_dest);
166     }
167 }
168 
169 static void mesh_virtual_address_decrease_refcount(mesh_virtual_address_t * virtual_address){
170     if (virtual_address == NULL){
171         log_error("virtual_address == NULL");
172     }
173     // decrease refcount
174     virtual_address->ref_count--;
175     // Free virtual address if ref count reaches zero
176     if (virtual_address->ref_count > 0) return;
177     // delete from TLV
178     mesh_delete_virtual_address(virtual_address->pseudo_dst);
179     // remove from list
180     mesh_virtual_address_remove(virtual_address);
181     // free memory
182     btstack_memory_mesh_virtual_address_free(virtual_address);
183 }
184 
185 static void mesh_virtual_address_increase_refcount(mesh_virtual_address_t * virtual_address){
186     if (virtual_address == NULL){
187         log_error("virtual_address == NULL");
188     }
189     virtual_address->ref_count++;
190     if (virtual_address->ref_count > 1) return;
191     // store in TLV
192     mesh_store_virtual_address(virtual_address->pseudo_dst, virtual_address->hash, virtual_address->label_uuid);
193 }
194 
195 static int mesh_model_is_configuration_server(uint32_t model_identifier){
196     return mesh_model_is_bluetooth_sig(model_identifier) && (mesh_model_get_model_id(model_identifier) == MESH_SIG_MODEL_ID_CONFIGURATION_SERVER);
197 }
198 
199 // Configuration Model Subscriptions (helper)
200 
201 // Model to Appkey List
202 
203 static uint32_t mesh_model_subscription_tag_for_index(uint16_t internal_model_id){
204     return ((uint32_t) 'M' << 24) | ((uint32_t) 'S' << 16) | ((uint32_t) internal_model_id);
205 }
206 
207 static void mesh_model_load_subscriptions(mesh_model_t * mesh_model){
208     mesh_configuration_server_setup_tlv();
209     uint32_t tag = mesh_model_subscription_tag_for_index(mesh_model->mid);
210     btstack_tlv_singleton_impl->get_tag(btstack_tlv_singleton_context, tag, (uint8_t *) &mesh_model->subscriptions, sizeof(mesh_model->subscriptions));
211     // update ref count
212 
213     // increase ref counts for virtual subscriptions
214     uint16_t i;
215     for (i = 0; i<MAX_NR_MESH_SUBSCRIPTION_PER_MODEL ; i++){
216         uint16_t src = mesh_model->subscriptions[i];
217         if (mesh_network_address_virtual(src)){
218             mesh_virtual_address_t * virtual_address = mesh_virtual_address_for_pseudo_dst(src);
219             mesh_virtual_address_increase_refcount(virtual_address);
220         }
221     }
222 }
223 
224 static void mesh_model_store_subscriptions(mesh_model_t * model){
225     mesh_configuration_server_setup_tlv();
226     uint32_t tag = mesh_model_subscription_tag_for_index(model->mid);
227     btstack_tlv_singleton_impl->store_tag(btstack_tlv_singleton_context, tag, (uint8_t *) &model->subscriptions, sizeof(model->subscriptions));
228 }
229 
230 static void mesh_model_delete_subscriptions(mesh_model_t * model){
231     mesh_configuration_server_setup_tlv();
232     uint32_t tag = mesh_model_subscription_tag_for_index(model->mid);
233     btstack_tlv_singleton_impl->delete_tag(btstack_tlv_singleton_context, tag);
234 }
235 
236 void mesh_load_subscriptions(void){
237     printf("Load Model Subscription Lists\n");
238     // iterate over elements and models
239     mesh_element_iterator_t element_it;
240     mesh_element_iterator_init(&element_it);
241     while (mesh_element_iterator_has_next(&element_it)){
242         mesh_element_t * element = mesh_element_iterator_next(&element_it);
243         mesh_model_iterator_t model_it;
244         mesh_model_iterator_init(&model_it, element);
245         while (mesh_model_iterator_has_next(&model_it)){
246             mesh_model_t * model = mesh_model_iterator_next(&model_it);
247             mesh_model_load_subscriptions(model);
248         }
249     }
250 }
251 
252 void mesh_delete_subscriptions(void){
253     printf("Delete Model Subscription Lists\n");
254     mesh_configuration_server_setup_tlv();
255     // iterate over elements and models
256     mesh_element_iterator_t element_it;
257     mesh_element_iterator_init(&element_it);
258     while (mesh_element_iterator_has_next(&element_it)){
259         mesh_element_t * element = mesh_element_iterator_next(&element_it);
260         mesh_model_iterator_t model_it;
261         mesh_model_iterator_init(&model_it, element);
262         while (mesh_model_iterator_has_next(&model_it)){
263             mesh_model_t * model = mesh_model_iterator_next(&model_it);
264             mesh_model_delete_subscriptions(model);
265         }
266     }
267 }
268 
269 static uint8_t mesh_model_add_subscription(mesh_model_t * mesh_model, uint16_t address){
270     uint16_t i;
271     for (i=0;i<MAX_NR_MESH_SUBSCRIPTION_PER_MODEL;i++){
272         if (mesh_model->subscriptions[i] == address) return MESH_FOUNDATION_STATUS_SUCCESS;
273     }
274     for (i=0;i<MAX_NR_MESH_SUBSCRIPTION_PER_MODEL;i++){
275         if (mesh_model->subscriptions[i] == MESH_ADDRESS_UNSASSIGNED) {
276             mesh_model->subscriptions[i] = address;
277             return MESH_FOUNDATION_STATUS_SUCCESS;
278         }
279     }
280     return MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES;
281 }
282 
283 static void mesh_model_delete_subscription(mesh_model_t * mesh_model, uint16_t address){
284     uint16_t i;
285     for (i=0;i<MAX_NR_MESH_SUBSCRIPTION_PER_MODEL;i++){
286         if (mesh_model->subscriptions[i] == address) {
287             mesh_model->subscriptions[i] = MESH_ADDRESS_UNSASSIGNED;
288         }
289     }
290 }
291 
292 static void mesh_model_delete_all_subscriptions(mesh_model_t * mesh_model){
293     uint16_t i;
294     for (i=0;i<MAX_NR_MESH_SUBSCRIPTION_PER_MODEL;i++){
295         mesh_model->subscriptions[i] = MESH_ADDRESS_UNSASSIGNED;
296     }
297 }
298 
299 static void mesh_subcription_decrease_virtual_address_ref_count(mesh_model_t *mesh_model){
300     // decrease ref counts for current virtual subscriptions
301     uint16_t i;
302     for (i = 0; i<MAX_NR_MESH_SUBSCRIPTION_PER_MODEL ; i++){
303         uint16_t src = mesh_model->subscriptions[i];
304         if (mesh_network_address_virtual(src)){
305             mesh_virtual_address_t * virtual_address = mesh_virtual_address_for_pseudo_dst(src);
306             mesh_virtual_address_decrease_refcount(virtual_address);
307         }
308     }
309 }
310 
311 // Model Publication
312 
313 static uint32_t mesh_model_publication_tag_for_index(uint16_t internal_model_id){
314     return ((uint32_t) 'M' << 24) | ((uint32_t) 'P' << 16) | ((uint32_t) internal_model_id);
315 }
316 
317 static void mesh_model_load_publication(mesh_model_t * mesh_model){
318     mesh_configuration_server_setup_tlv();
319     if (mesh_model->publication_model == NULL) return;
320 
321     uint32_t tag = mesh_model_publication_tag_for_index(mesh_model->mid);
322     btstack_tlv_singleton_impl->get_tag(btstack_tlv_singleton_context, tag, (uint8_t *) &mesh_model->publication_model, sizeof(mesh_publication_model_t));
323 
324     // increase ref counts for current virtual publicataion address
325     uint16_t src = mesh_model->publication_model->address;
326     if (mesh_network_address_virtual(src)){
327         mesh_virtual_address_t * virtual_address = mesh_virtual_address_for_pseudo_dst(src);
328         mesh_virtual_address_increase_refcount(virtual_address);
329     }
330 
331     mesh_model_publication_start(mesh_model);
332 }
333 
334 static void mesh_model_store_publication(mesh_model_t * mesh_model){
335     mesh_configuration_server_setup_tlv();
336     if (mesh_model->publication_model == NULL) return;
337     uint32_t tag = mesh_model_publication_tag_for_index(mesh_model->mid);
338     btstack_tlv_singleton_impl->store_tag(btstack_tlv_singleton_context, tag, (uint8_t *) &mesh_model->subscriptions, sizeof(mesh_publication_model_t));
339 }
340 
341 static void mesh_model_delete_publication(mesh_model_t * mesh_model){
342     mesh_configuration_server_setup_tlv();
343     if (mesh_model->publication_model == NULL) return;
344     uint32_t tag = mesh_model_publication_tag_for_index(mesh_model->mid);
345     btstack_tlv_singleton_impl->delete_tag(btstack_tlv_singleton_context, tag);
346 }
347 
348 void mesh_load_publications(void){
349     printf("Load Model Publications\n");
350     // iterate over elements and models
351     mesh_element_iterator_t element_it;
352     mesh_element_iterator_init(&element_it);
353     while (mesh_element_iterator_has_next(&element_it)){
354         mesh_element_t * element = mesh_element_iterator_next(&element_it);
355         mesh_model_iterator_t model_it;
356         mesh_model_iterator_init(&model_it, element);
357         while (mesh_model_iterator_has_next(&model_it)){
358             mesh_model_t * model = mesh_model_iterator_next(&model_it);
359             mesh_model_load_publication(model);
360         }
361     }
362 }
363 
364 void mesh_delete_publications(void){
365     printf("Delete Model Publications\n");
366     mesh_configuration_server_setup_tlv();
367     // iterate over elements and models
368     mesh_element_iterator_t element_it;
369     mesh_element_iterator_init(&element_it);
370     while (mesh_element_iterator_has_next(&element_it)){
371         mesh_element_t * element = mesh_element_iterator_next(&element_it);
372         mesh_model_iterator_t model_it;
373         mesh_model_iterator_init(&model_it, element);
374         while (mesh_model_iterator_has_next(&model_it)){
375             mesh_model_t * model = mesh_model_iterator_next(&model_it);
376             mesh_model_delete_publication(model);
377         }
378     }
379 }
380 
381 // AppKeys Helper
382 static void mesh_configuration_server_delete_appkey(mesh_transport_key_t * transport_key){
383     uint16_t appkey_index = transport_key->appkey_index;
384 
385     // iterate over elements and models
386     mesh_element_iterator_t element_it;
387     mesh_element_iterator_init(&element_it);
388     while (mesh_element_iterator_has_next(&element_it)){
389         mesh_element_t * element = mesh_element_iterator_next(&element_it);
390         mesh_model_iterator_t model_it;
391         mesh_model_iterator_init(&model_it, element);
392         while (mesh_model_iterator_has_next(&model_it)){
393             mesh_model_t * mesh_model = mesh_model_iterator_next(&model_it);
394 
395             // remove from Model to AppKey List
396             mesh_model_unbind_appkey(mesh_model, appkey_index);
397 
398             // stop publishing if this AppKey was used
399             if (mesh_model->publication_model != NULL){
400                 mesh_publication_model_t * publication_model = mesh_model->publication_model;
401                 if (publication_model->appkey_index == appkey_index){
402                     publication_model->address = MESH_ADDRESS_UNSASSIGNED;
403                     publication_model->appkey_index = MESH_APPKEY_INVALID;
404                     mesh_model_store_publication(mesh_model);
405                 }
406             }
407         }
408     }
409 
410     mesh_access_appkey_finalize(transport_key);
411 }
412 
413 // Foundatiopn Message
414 
415 const mesh_access_message_t mesh_foundation_config_beacon_status = {
416         MESH_FOUNDATION_OPERATION_BEACON_STATUS, "1"
417 };
418 const mesh_access_message_t mesh_foundation_config_default_ttl_status = {
419         MESH_FOUNDATION_OPERATION_DEFAULT_TTL_STATUS, "1"
420 };
421 const mesh_access_message_t mesh_foundation_config_friend_status = {
422         MESH_FOUNDATION_OPERATION_FRIEND_STATUS, "1"
423 };
424 const mesh_access_message_t mesh_foundation_config_gatt_proxy_status = {
425         MESH_FOUNDATION_OPERATION_GATT_PROXY_STATUS, "1"
426 };
427 const mesh_access_message_t mesh_foundation_config_relay_status = {
428         MESH_FOUNDATION_OPERATION_RELAY_STATUS, "11"
429 };
430 const mesh_access_message_t mesh_foundation_config_model_publication_status = {
431         MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_STATUS, "1222111m"
432 };
433 const mesh_access_message_t mesh_foundation_config_model_subscription_status = {
434         MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_STATUS, "122m"
435 };
436 const mesh_access_message_t mesh_foundation_config_netkey_status = {
437         MESH_FOUNDATION_OPERATION_NETKEY_STATUS, "12"
438 };
439 const mesh_access_message_t mesh_foundation_config_appkey_status = {
440         MESH_FOUNDATION_OPERATION_APPKEY_STATUS, "13"
441 };
442 const mesh_access_message_t mesh_foundation_config_model_app_status = {
443         MESH_FOUNDATION_OPERATION_MODEL_APP_STATUS, "122m"
444 };
445 const mesh_access_message_t mesh_foundation_node_reset_status = {
446         MESH_FOUNDATION_OPERATION_NODE_RESET_STATUS, ""
447 };
448 const mesh_access_message_t mesh_foundation_config_heartbeat_publication_status = {
449         MESH_FOUNDATION_OPERATION_HEARTBEAT_PUBLICATION_STATUS, "1211122"
450 };
451 const mesh_access_message_t mesh_foundation_config_network_transmit_status = {
452         MESH_FOUNDATION_OPERATION_NETWORK_TRANSMIT_STATUS, "11"
453 };
454 const mesh_access_message_t mesh_foundation_node_identity_status = {
455         MESH_FOUNDATION_OPERATION_NODE_IDENTITY_STATUS, "121"
456 };
457 const mesh_access_message_t mesh_key_refresh_phase_status = {
458         MESH_FOUNDATION_OPERATION_KEY_REFRESH_PHASE_STATUS, "121"
459 };
460 const mesh_access_message_t mesh_foundation_low_power_node_poll_timeout_status = {
461         MESH_FOUNDATION_OPERATION_LOW_POWER_NODE_POLL_TIMEOUT_STATUS, "23"
462 };
463 const mesh_access_message_t mesh_foundation_config_heartbeat_subscription_status = {
464         MESH_FOUNDATION_OPERATION_HEARTBEAT_SUBSCRIPTION_STATUS, "1221111"
465 };
466 
467 static void config_server_send_message(uint16_t netkey_index, uint16_t dest, mesh_pdu_t *pdu){
468     // Configuration Server is on primary element and can only use DeviceKey
469     uint16_t appkey_index = MESH_DEVICE_KEY_INDEX;
470     uint16_t src          = mesh_node_get_primary_element_address();
471     uint8_t  ttl          = mesh_foundation_default_ttl_get();
472     mesh_upper_transport_setup_access_pdu_header(pdu, netkey_index, appkey_index, ttl, src, dest, 0);
473     mesh_access_send_unacknowledged_pdu(pdu);
474 }
475 
476 static void config_composition_data_status(uint16_t netkey_index, uint16_t dest){
477 
478     printf("Received Config Composition Data Get -> send Config Composition Data Status\n");
479 
480     mesh_transport_pdu_t * transport_pdu = mesh_access_transport_init(MESH_FOUNDATION_OPERATION_COMPOSITION_DATA_STATUS);
481     if (!transport_pdu) return;
482 
483     // page 0
484     mesh_access_transport_add_uint8(transport_pdu, 0);
485 
486     // CID
487     mesh_access_transport_add_uint16(transport_pdu, BLUETOOTH_COMPANY_ID_BLUEKITCHEN_GMBH);
488     // PID
489     mesh_access_transport_add_uint16(transport_pdu, 0);
490     // VID
491     mesh_access_transport_add_uint16(transport_pdu, 0);
492     // CRPL - number of protection list entries
493     mesh_access_transport_add_uint16(transport_pdu, 1);
494     // Features - Relay, Proxy, Friend, Lower Power, ...
495     mesh_access_transport_add_uint16(transport_pdu, 0);
496 
497     mesh_element_iterator_t element_it;
498     mesh_element_iterator_init(&element_it);
499     while (mesh_element_iterator_has_next(&element_it)){
500         mesh_element_t * element = mesh_element_iterator_next(&element_it);
501 
502         // Loc
503         mesh_access_transport_add_uint16(transport_pdu, element->loc);
504         // NumS
505         mesh_access_transport_add_uint8( transport_pdu, element->models_count_sig);
506         // NumV
507         mesh_access_transport_add_uint8( transport_pdu, element->models_count_vendor);
508 
509         mesh_model_iterator_t model_it;
510 
511         // SIG Models
512         mesh_model_iterator_init(&model_it, element);
513         while (mesh_model_iterator_has_next(&model_it)){
514             mesh_model_t * model = mesh_model_iterator_next(&model_it);
515             if (!mesh_model_is_bluetooth_sig(model->model_identifier)) continue;
516             mesh_access_transport_add_uint16(transport_pdu, model->model_identifier);
517         }
518         // Vendor Models
519         mesh_model_iterator_init(&model_it, element);
520         while (mesh_model_iterator_has_next(&model_it)){
521             mesh_model_t * model = mesh_model_iterator_next(&model_it);
522             if (mesh_model_is_bluetooth_sig(model->model_identifier)) continue;
523             mesh_access_transport_add_uint32(transport_pdu, model->model_identifier);
524         }
525     }
526 
527     // send as segmented access pdu
528     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
529 }
530 
531 static void config_composition_data_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
532     UNUSED(mesh_model);
533     config_composition_data_status(mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
534 
535     mesh_access_message_processed(pdu);
536 }
537 
538 static void config_model_beacon_status(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest){
539     UNUSED(mesh_model);
540     // setup message
541     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_foundation_config_beacon_status,
542                                                                                mesh_foundation_beacon_get());
543     if (!transport_pdu) return;
544 
545     // send as segmented access pdu
546     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
547 }
548 
549 static void config_beacon_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
550     config_model_beacon_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
551 
552     mesh_access_message_processed(pdu);
553 }
554 
555 static void config_beacon_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
556     mesh_access_parser_state_t parser;
557     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
558 
559     uint8_t beacon_enabled = mesh_access_parser_get_u8(&parser);
560 
561     // beacon valid
562     if (beacon_enabled >= MESH_FOUNDATION_STATE_NOT_SUPPORTED) return;
563 
564     // store
565     mesh_foundation_beacon_set(beacon_enabled);
566     mesh_foundation_state_store();
567 
568     //
569     config_model_beacon_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
570 
571     mesh_access_message_processed(pdu);
572 }
573 
574 static void config_model_default_ttl_status(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest){
575     UNUSED(mesh_model);
576     // setup message
577     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(
578             &mesh_foundation_config_default_ttl_status, mesh_foundation_default_ttl_get());
579     if (!transport_pdu) return;
580 
581     // send as segmented access pdu
582     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
583 }
584 
585 static void config_default_ttl_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
586     config_model_default_ttl_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
587 
588     mesh_access_message_processed(pdu);
589 }
590 
591 static void config_default_ttl_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
592     mesh_access_parser_state_t parser;
593     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
594 
595     uint8_t new_ttl = mesh_access_parser_get_u8(&parser);
596 
597     // ttl valid
598     if (new_ttl > 0x7f || new_ttl == 0x01) return;
599     // store
600     mesh_foundation_default_ttl_set(new_ttl);
601     mesh_foundation_state_store();
602 
603     //
604     config_model_default_ttl_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
605 
606     mesh_access_message_processed(pdu);
607 }
608 
609 static void config_friend_status(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest){
610     UNUSED(mesh_model);
611 
612     // setup message
613     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(
614             &mesh_foundation_config_friend_status, mesh_foundation_friend_get());
615     if (!transport_pdu) return;
616 
617     // send as segmented access pdu
618     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
619 }
620 
621 static void config_friend_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
622     config_friend_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
623 
624     mesh_access_message_processed(pdu);
625 }
626 
627 static void config_friend_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
628     mesh_access_parser_state_t parser;
629     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
630 
631     uint8_t new_friend_state = mesh_access_parser_get_u8(&parser);
632 
633     // validate
634     if (new_friend_state >= MESH_FOUNDATION_STATE_NOT_SUPPORTED) return;
635 
636     // store if supported
637     if (mesh_foundation_friend_get() != MESH_FOUNDATION_STATE_NOT_SUPPORTED){
638         mesh_foundation_friend_set(new_friend_state);
639         mesh_foundation_state_store();
640     }
641 
642     //
643     config_friend_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
644 
645     mesh_access_message_processed(pdu);
646 }
647 
648 static void config_model_gatt_proxy_status(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest){
649     UNUSED(mesh_model);
650     // setup message
651     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(
652             &mesh_foundation_config_gatt_proxy_status, mesh_foundation_gatt_proxy_get());
653     if (!transport_pdu) return;
654 
655     // send as segmented access pdu
656     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
657 }
658 
659 static void config_gatt_proxy_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
660     config_model_gatt_proxy_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
661 
662     mesh_access_message_processed(pdu);
663 }
664 
665 static void config_gatt_proxy_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
666     mesh_access_parser_state_t parser;
667     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
668 
669     uint8_t enabled = mesh_access_parser_get_u8(&parser);
670 
671     // ttl valid
672     if (enabled > 1) return;
673     // store
674     mesh_foundation_gatt_proxy_set(enabled);
675     mesh_foundation_state_store();
676 
677     //
678     config_model_gatt_proxy_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
679 
680     mesh_access_message_processed(pdu);
681 
682     // trigger heartbeat emit on change
683     mesh_configuration_server_feature_changed();
684 }
685 
686 static void config_model_relay_status(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest){
687     UNUSED(mesh_model);
688 
689     // setup message
690     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_foundation_config_relay_status,
691                                                                                mesh_foundation_relay_get(),
692                                                                                mesh_foundation_relay_retransmit_get());
693     if (!transport_pdu) return;
694 
695     // send as segmented access pdu
696     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
697 }
698 
699 static void config_relay_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
700     config_model_relay_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
701 
702     mesh_access_message_processed(pdu);
703 }
704 
705 static void config_relay_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
706 
707     mesh_access_parser_state_t parser;
708     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
709 
710     // check if valid
711     uint8_t relay            = mesh_access_parser_get_u8(&parser);
712     uint8_t relay_retransmit = mesh_access_parser_get_u8(&parser);
713 
714     // check if valid
715     if (relay > 1) return;
716 
717     // only update if supported
718     if (mesh_foundation_relay_get() != MESH_FOUNDATION_STATE_NOT_SUPPORTED){
719         mesh_foundation_relay_set(relay);
720         mesh_foundation_relay_retransmit_set(relay_retransmit);
721         mesh_foundation_state_store();
722     }
723 
724     //
725     config_model_relay_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
726 
727     mesh_access_message_processed(pdu);
728 
729     // trigger heartbeat emit on change
730     mesh_configuration_server_feature_changed();
731 }
732 
733 static void config_model_network_transmit_status(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest){
734     UNUSED(mesh_model);
735 
736     // setup message
737     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(
738             &mesh_foundation_config_network_transmit_status, mesh_foundation_network_transmit_get());
739     if (!transport_pdu) return;
740 
741     // send as segmented access pdu
742     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
743 }
744 
745 static void config_model_network_transmit_get_handler(mesh_model_t * mesh_model, mesh_pdu_t * pdu){
746     config_model_network_transmit_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
747 
748     mesh_access_message_processed(pdu);
749 }
750 
751 static void config_model_network_transmit_set_handler(mesh_model_t * mesh_model, mesh_pdu_t * pdu){
752     mesh_access_parser_state_t parser;
753     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
754 
755     uint8_t new_ttl = mesh_access_parser_get_u8(&parser);
756 
757     // store
758     mesh_foundation_network_transmit_set(new_ttl);
759     mesh_foundation_state_store();
760 
761     //
762     config_model_network_transmit_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
763 
764     mesh_access_message_processed(pdu);
765 }
766 
767 // NetKey List
768 
769 void config_nekey_list_set_max(uint16_t max){
770     config_netkey_list_max = max;
771 }
772 
773 static void config_netkey_status(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest, uint8_t status, uint16_t new_netkey_index){
774     UNUSED(mesh_model);
775 
776     // setup message
777     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(
778             &mesh_foundation_config_netkey_status, status, new_netkey_index);
779     if (!transport_pdu) return;
780 
781     // send as segmented access pdu
782     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
783 }
784 
785 static void config_netkey_list(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest) {
786     UNUSED(mesh_model);
787 
788     mesh_transport_pdu_t * transport_pdu = mesh_access_transport_init(MESH_FOUNDATION_OPERATION_NETKEY_LIST);
789     if (!transport_pdu) return;
790 
791     // add list of netkey indexes
792     mesh_network_key_iterator_t it;
793     mesh_network_key_iterator_init(&it);
794     while (mesh_network_key_iterator_has_more(&it)){
795         mesh_network_key_t * network_key = mesh_network_key_iterator_get_next(&it);
796         mesh_access_transport_add_uint16(transport_pdu, network_key->netkey_index);
797     }
798 
799     // send as segmented access pdu
800     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
801 }
802 
803 static void config_netkey_add_derived(void * arg){
804     mesh_subnet_t * subnet = (mesh_subnet_t *) arg;
805 
806     // store network key
807     mesh_store_network_key(subnet->old_key);
808 
809     // add key to NetKey List
810     mesh_network_key_add(subnet->old_key);
811 
812     // add subnet
813     mesh_subnet_add(subnet);
814 
815 #ifdef ENABLE_MESH_PROXY_SERVER
816     mesh_proxy_start_advertising_with_network_id();
817 #endif
818 
819     config_netkey_status(mesh_model_get_configuration_server(), mesh_pdu_netkey_index(access_pdu_in_process), mesh_pdu_src(access_pdu_in_process), MESH_FOUNDATION_STATUS_SUCCESS, subnet->netkey_index);
820     mesh_access_message_processed(access_pdu_in_process);
821 }
822 
823 static void config_netkey_add_handler(mesh_model_t * mesh_model, mesh_pdu_t * pdu){
824     mesh_access_parser_state_t parser;
825     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
826 
827     // get params
828     uint8_t new_netkey[16];
829     uint16_t new_netkey_index = mesh_access_parser_get_u16(&parser);
830     mesh_access_parser_get_key(&parser, new_netkey);
831 
832     uint8_t status;
833 
834     const mesh_subnet_t * existing_subnet = mesh_subnet_get_by_netkey_index(new_netkey_index);
835     if (existing_subnet == NULL){
836 
837         // check limit for pts
838         uint16_t internal_index = mesh_network_key_get_free_index();
839         if (internal_index == 0 || (config_netkey_list_max && mesh_network_key_list_count() >= config_netkey_list_max)){
840             status = MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES;
841         } else {
842 
843             // allocate new key and subnet
844             mesh_network_key_t * new_network_key = btstack_memory_mesh_network_key_get();
845             mesh_subnet_t * new_subnet = btstack_memory_mesh_subnet_get();
846 
847             if (new_network_key == NULL || new_subnet == NULL){
848                 if (new_network_key != NULL){
849                     btstack_memory_mesh_network_key_free(new_network_key);
850                 }
851                 if (new_subnet != NULL){
852                     btstack_memory_mesh_subnet_free(new_subnet);
853                 }
854                 status = MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES;
855 
856             } else {
857 
858                 // setup key
859                 new_network_key->internal_index = internal_index;
860                 new_network_key->netkey_index   = new_netkey_index;
861                 memcpy(new_network_key->net_key, new_netkey, 16);
862 
863                 // setup subnet
864                 new_subnet->old_key = new_network_key;
865                 new_subnet->netkey_index = new_netkey_index;
866                 new_subnet->key_refresh = MESH_KEY_REFRESH_NOT_ACTIVE;
867 
868                 // derive other keys
869                 access_pdu_in_process = pdu;
870                 mesh_network_key_derive(&configuration_server_cmac_request, new_network_key, config_netkey_add_derived, new_network_key);
871                 return;
872             }
873         }
874 
875     } else {
876         // network key for netkey index already exists
877         if (memcmp(existing_subnet->old_key->net_key, new_netkey, 16) == 0){
878             // same netkey
879             status = MESH_FOUNDATION_STATUS_SUCCESS;
880         } else {
881             // different netkey
882             status = MESH_FOUNDATION_STATUS_KEY_INDEX_ALREADY_STORED;
883         }
884     }
885 
886     // report status
887     config_netkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, new_netkey_index);
888     mesh_access_message_processed(access_pdu_in_process);
889 }
890 
891 static void config_netkey_update_derived(void * arg){
892     mesh_subnet_t * subnet = (mesh_subnet_t *) arg;
893 
894     // store network key
895     mesh_store_network_key(subnet->new_key);
896 
897     // add key to NetKey List
898     mesh_network_key_add(subnet->new_key);
899 
900     // update subnet - Key Refresh Phase 1
901     subnet->key_refresh = MESH_KEY_REFRESH_FIRST_PHASE;
902 
903     // report status
904     config_netkey_status(mesh_model_get_configuration_server(), mesh_pdu_netkey_index(access_pdu_in_process), mesh_pdu_src(access_pdu_in_process), MESH_FOUNDATION_STATUS_SUCCESS, subnet->netkey_index);
905     mesh_access_message_processed(access_pdu_in_process);
906 }
907 
908 static void config_netkey_update_handler(mesh_model_t * mesh_model, mesh_pdu_t * pdu) {
909     mesh_access_parser_state_t parser;
910     mesh_access_parser_init(&parser, (mesh_pdu_t *) pdu);
911 
912     // get params
913     uint8_t new_netkey[16];
914     uint16_t netkey_index = mesh_access_parser_get_u16(&parser);
915     mesh_access_parser_get_key(&parser, new_netkey);
916 
917     // get existing subnet
918     mesh_subnet_t * subnet = mesh_subnet_get_by_netkey_index(netkey_index);
919     if (subnet == NULL){
920         config_netkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX, netkey_index);
921         mesh_access_message_processed(access_pdu_in_process);
922         return;
923     }
924 
925     // setup new key
926     uint16_t internal_index = mesh_network_key_get_free_index();
927     mesh_network_key_t * new_network_key = btstack_memory_mesh_network_key_get();
928     if (internal_index == 0 || new_network_key == NULL){
929         config_netkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES, netkey_index);
930         mesh_access_message_processed(access_pdu_in_process);
931         return;
932     }
933 
934     // setup new key
935     new_network_key->internal_index = internal_index;
936     new_network_key->netkey_index   = netkey_index;
937     new_network_key->version        = (uint8_t)(subnet->old_key->version + 1);
938     memcpy(new_network_key->net_key, new_netkey, 16);
939 
940     // store in subnet (not active yet)
941     subnet->new_key = new_network_key;
942 
943     // derive other keys
944     access_pdu_in_process = pdu;
945     mesh_network_key_derive(&configuration_server_cmac_request, new_network_key, config_netkey_update_derived, subnet);
946 }
947 
948 static void config_netkey_delete_handler(mesh_model_t * mesh_model, mesh_pdu_t * pdu) {
949     mesh_access_parser_state_t parser;
950     mesh_access_parser_init(&parser, (mesh_pdu_t *) pdu);
951 
952     // get params
953     uint16_t netkey_index = mesh_access_parser_get_u16(&parser);
954 
955     // get existing network_key
956     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
957 
958     // remove subnet
959     mesh_subnet_t * subnet = mesh_subnet_get_by_netkey_index(netkey_index);
960     if (subnet != NULL){
961         // A NetKey shall not be deleted from the NetKey List using a message secured with this NetKey.
962         if (mesh_subnet_list_count() > 1 && subnet->netkey_index != netkey_index){
963 
964             // remove all appkeys for this netkey
965             mesh_transport_key_iterator_t it;
966             mesh_transport_key_iterator_init(&it, netkey_index);
967             while (mesh_transport_key_iterator_has_more(&it)){
968                 mesh_transport_key_t * transport_key = mesh_transport_key_iterator_get_next(&it);
969                 mesh_configuration_server_delete_appkey(transport_key);
970             }
971 
972             // delete old/current key
973             mesh_access_netkey_finalize(subnet->old_key);
974             subnet->old_key = NULL;
975 
976             // delete new key
977             if (subnet->new_key != NULL){
978                 mesh_access_netkey_finalize(subnet->new_key);
979                 subnet->new_key = NULL;
980             }
981 
982             // remove subnet
983             mesh_subnet_remove(subnet);
984             btstack_memory_mesh_subnet_free(subnet);
985 
986         } else {
987             // we cannot remove the last network key
988             status = MESH_FOUNDATION_STATUS_CANNOT_REMOVE;
989         }
990     }
991     config_netkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, netkey_index);
992 }
993 
994 static void config_netkey_get_handler(mesh_model_t * mesh_model, mesh_pdu_t * pdu){
995     config_netkey_list(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
996     mesh_access_message_processed(pdu);
997 }
998 
999 // AppKey List
1000 
1001 static void config_appkey_status(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest, uint32_t netkey_and_appkey_index, uint8_t status){
1002     UNUSED(mesh_model);
1003 
1004     // setup message
1005     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_foundation_config_appkey_status,
1006                                                                                status, netkey_and_appkey_index);
1007     if (!transport_pdu) return;
1008 
1009     // send as segmented access pdu
1010     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
1011 }
1012 
1013 static void config_appkey_list(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest, uint32_t netkey_index_of_list){
1014     UNUSED(mesh_model);
1015 
1016     mesh_transport_pdu_t * transport_pdu = mesh_access_transport_init(MESH_FOUNDATION_OPERATION_APPKEY_LIST);
1017     if (!transport_pdu) return;
1018 
1019     // check netkey_index is valid
1020     mesh_network_key_t * network_key = mesh_network_key_list_get(netkey_index_of_list);
1021     uint8_t status;
1022     if (network_key == NULL){
1023         status = MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX;
1024     } else {
1025         status = MESH_FOUNDATION_STATUS_SUCCESS;
1026     }
1027     mesh_access_transport_add_uint8(transport_pdu, status);
1028     mesh_access_transport_add_uint16(transport_pdu, netkey_index_of_list);
1029 
1030     // add list of appkey indexes
1031     mesh_transport_key_iterator_t it;
1032     mesh_transport_key_iterator_init(&it, netkey_index_of_list);
1033     while (mesh_transport_key_iterator_has_more(&it)){
1034         mesh_transport_key_t * transport_key = mesh_transport_key_iterator_get_next(&it);
1035         mesh_access_transport_add_uint16(transport_pdu, transport_key->appkey_index);
1036     }
1037 
1038     // send as segmented access pdu
1039     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
1040 }
1041 
1042 static void config_appkey_add_or_update_aid(void *arg){
1043     mesh_transport_key_t * transport_key = (mesh_transport_key_t *) arg;
1044 
1045     printf("Config Appkey Add/Update: NetKey Index 0x%04x, AppKey Index 0x%04x, AID %02x: ", transport_key->netkey_index, transport_key->appkey_index, transport_key->aid);
1046     printf_hexdump(transport_key->key, 16);
1047 
1048     // store in TLV
1049     mesh_store_app_key(transport_key);
1050 
1051     // add app key
1052     mesh_transport_key_add(transport_key);
1053 
1054     uint32_t netkey_and_appkey_index = (transport_key->appkey_index << 12) | transport_key->netkey_index;
1055     config_appkey_status(mesh_model_get_configuration_server(),  mesh_pdu_netkey_index(access_pdu_in_process), mesh_pdu_src(access_pdu_in_process), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_SUCCESS);
1056 
1057     mesh_access_message_processed(access_pdu_in_process);
1058 }
1059 
1060 static void config_appkey_add_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1061 
1062     mesh_access_parser_state_t parser;
1063     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1064 
1065     // netkey and appkey index
1066     uint32_t netkey_and_appkey_index = mesh_access_parser_get_u24(&parser);
1067     uint16_t netkey_index = netkey_and_appkey_index & 0xfff;
1068     uint16_t appkey_index = netkey_and_appkey_index >> 12;
1069 
1070     // actual key
1071     uint8_t  appkey[16];
1072     mesh_access_parser_get_key(&parser, appkey);
1073 
1074     // check netkey_index is valid
1075     mesh_network_key_t * network_key = mesh_network_key_list_get(netkey_index);
1076     if (network_key == NULL){
1077         config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX);
1078         mesh_access_message_processed(pdu);
1079         return;
1080     }
1081 
1082     // check if appkey already exists
1083     mesh_transport_key_t * transport_key = mesh_transport_key_get(appkey_index);
1084     if (transport_key){
1085         uint8_t status;
1086         if (transport_key->netkey_index != netkey_index){
1087             // already stored but with different netkey
1088             status = MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX;
1089         } else if (memcmp(transport_key->key, appkey, 16) == 0){
1090             // key identical
1091             status = MESH_FOUNDATION_STATUS_SUCCESS;
1092         } else {
1093             // key differs
1094             status = MESH_FOUNDATION_STATUS_KEY_INDEX_ALREADY_STORED;
1095         }
1096         config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, status);
1097         mesh_access_message_processed(pdu);
1098         return;
1099     }
1100 
1101     // create app key (first get free slot in transport key table)
1102     mesh_transport_key_t * app_key = NULL;
1103     uint16_t internal_index = mesh_transport_key_get_free_index();
1104     if (internal_index > 0){
1105         app_key = btstack_memory_mesh_transport_key_get();
1106     }
1107     if (app_key == NULL) {
1108         config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES);
1109         mesh_access_message_processed(pdu);
1110         return;
1111     }
1112 
1113     // store data
1114     app_key->internal_index = internal_index;
1115     app_key->akf = 1;
1116     app_key->appkey_index = appkey_index;
1117     app_key->netkey_index = netkey_index;
1118     app_key->version = 0;
1119     app_key->old_key = 0;
1120 
1121     memcpy(app_key->key, appkey, 16);
1122 
1123     // calculate AID
1124     access_pdu_in_process = pdu;
1125     mesh_transport_key_calc_aid(&configuration_server_cmac_request, app_key, config_appkey_add_or_update_aid, app_key);
1126 }
1127 
1128 static void config_appkey_update_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1129 
1130     mesh_access_parser_state_t parser;
1131     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1132 
1133     // netkey and appkey index
1134     uint32_t netkey_and_appkey_index = mesh_access_parser_get_u24(&parser);
1135     uint16_t netkey_index = netkey_and_appkey_index & 0xfff;
1136     uint16_t appkey_index = netkey_and_appkey_index >> 12;
1137 
1138     // actual key
1139     uint8_t  appkey[16];
1140     mesh_access_parser_get_key(&parser, appkey);
1141 
1142 
1143 // for PTS testing
1144     // check netkey_index is valid
1145     mesh_network_key_t * network_key = mesh_network_key_list_get(netkey_index);
1146     if (network_key == NULL){
1147         config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX);
1148         mesh_access_message_processed(pdu);
1149         return;
1150     }
1151 
1152     // check if appkey already exists
1153     mesh_transport_key_t * existing_app_key = mesh_transport_key_get(appkey_index);
1154     if (!existing_app_key) {
1155         config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_INVALID_APPKEY_INDEX);
1156         mesh_access_message_processed(pdu);
1157         return;
1158     }
1159 
1160     if (existing_app_key->netkey_index != netkey_index){
1161         // already stored but with different netkey
1162         config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_INVALID_BINDING);
1163         mesh_access_message_processed(pdu);
1164         return;
1165     }
1166 
1167     if (memcmp(existing_app_key->key, appkey, 16) == 0){
1168         // key identical
1169         config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_SUCCESS);
1170         mesh_access_message_processed(pdu);
1171         return;
1172     }
1173 
1174     // create app key
1175     mesh_transport_key_t * new_app_key = NULL;
1176     uint16_t internal_index = mesh_transport_key_get_free_index();
1177     if (internal_index > 0){
1178         new_app_key = btstack_memory_mesh_transport_key_get();
1179     }
1180     if (new_app_key == NULL) {
1181         config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES);
1182         mesh_access_message_processed(pdu);
1183         return;
1184     }
1185 
1186     // store data
1187     new_app_key->internal_index = internal_index;
1188     new_app_key->appkey_index = appkey_index;
1189     new_app_key->netkey_index = netkey_index;
1190     new_app_key->key_refresh  = 1;
1191     new_app_key->version = (uint8_t)(existing_app_key->version + 1);
1192     memcpy(new_app_key->key, appkey, 16);
1193 
1194     // mark old key
1195     existing_app_key->old_key = 1;
1196 
1197     // calculate AID
1198     access_pdu_in_process = pdu;
1199     mesh_transport_key_calc_aid(&configuration_server_cmac_request, new_app_key, config_appkey_add_or_update_aid, new_app_key);
1200 }
1201 
1202 static void config_appkey_delete_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1203     mesh_access_parser_state_t parser;
1204     mesh_access_parser_init(&parser, (mesh_pdu_t *) pdu);
1205 
1206     // netkey and appkey index
1207     uint32_t netkey_and_appkey_index = mesh_access_parser_get_u24(&parser);
1208     uint16_t netkey_index = netkey_and_appkey_index & 0xfff;
1209     uint16_t appkey_index = netkey_and_appkey_index >> 12;
1210 
1211     // check netkey_index is valid
1212     mesh_network_key_t * network_key = mesh_network_key_list_get(netkey_index);
1213     if (network_key == NULL){
1214         config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX);
1215         mesh_access_message_processed(pdu);
1216         return;
1217     }
1218 
1219     // check if appkey already exists
1220     mesh_transport_key_t * transport_key = mesh_transport_key_get(appkey_index);
1221     if (transport_key){
1222         mesh_configuration_server_delete_appkey(transport_key);
1223     }
1224 
1225     config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_SUCCESS);
1226     mesh_access_message_processed(pdu);
1227 }
1228 
1229 static void config_appkey_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1230     mesh_access_parser_state_t parser;
1231     mesh_access_parser_init(&parser, (mesh_pdu_t *) pdu);
1232     uint16_t netkey_index = mesh_access_parser_get_u16(&parser);
1233 
1234     config_appkey_list(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_index);
1235     mesh_access_message_processed(pdu);
1236 }
1237 
1238 // Configuration Model Subscriptions (messages)
1239 
1240 static void config_model_subscription_list_status(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest, uint8_t status, uint16_t element_address, uint32_t model_identifier, mesh_model_t * target_model){
1241     UNUSED(mesh_model);
1242 
1243     uint16_t opcode;
1244     if (mesh_model_is_bluetooth_sig(model_identifier)){
1245         opcode = MESH_FOUNDATION_OPERATION_SIG_MODEL_SUBSCRIPTION_LIST;
1246     } else {
1247         opcode = MESH_FOUNDATION_OPERATION_VENDOR_MODEL_SUBSCRIPTION_LIST;
1248     }
1249 
1250     mesh_transport_pdu_t * transport_pdu = mesh_access_transport_init(opcode);
1251     if (!transport_pdu) return;
1252 
1253     // setup segmented message
1254     mesh_access_transport_add_uint8(transport_pdu, status);
1255     mesh_access_transport_add_uint16(transport_pdu, element_address);
1256     mesh_access_transport_add_model_identifier(transport_pdu, model_identifier);
1257 
1258     if (target_model != NULL){
1259         uint16_t i;
1260         for (i = 0; i < MAX_NR_MESH_SUBSCRIPTION_PER_MODEL; i++){
1261             if (target_model->subscriptions[i] == MESH_ADDRESS_UNSASSIGNED) continue;
1262             if (mesh_network_address_virtual(target_model->subscriptions[i])) continue;
1263             mesh_access_transport_add_uint16(transport_pdu, target_model->subscriptions[i]);
1264         }
1265     }
1266     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
1267 }
1268 
1269 static void config_model_subscription_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1270     mesh_access_parser_state_t parser;
1271     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1272 
1273     uint16_t element_address  = mesh_access_parser_get_u16(&parser);
1274     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1275 
1276     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1277     mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1278 
1279     config_model_subscription_list_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, model_identifier, target_model);
1280     mesh_access_message_processed(pdu);
1281 }
1282 
1283 static void config_model_subscription_status(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest, uint8_t status, uint16_t element_address, uint16_t address, uint32_t model_identifier){
1284     UNUSED(mesh_model);
1285 
1286     // setup message
1287     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_foundation_config_model_subscription_status,
1288                                                                                 status, element_address, address, model_identifier);
1289     if (!transport_pdu) return;
1290     // send as segmented access pdu
1291     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
1292 }
1293 
1294 static void config_model_subscription_add_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1295     mesh_access_parser_state_t parser;
1296     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1297 
1298     uint16_t element_address  = mesh_access_parser_get_u16(&parser);
1299     uint16_t address          = mesh_access_parser_get_u16(&parser);
1300     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1301 
1302     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1303     mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1304 
1305     if (target_model != NULL){
1306         if (mesh_network_address_group(address) && !mesh_network_address_all_nodes(address)){
1307             status = mesh_model_add_subscription(target_model, address);
1308             if (status == MESH_FOUNDATION_STATUS_SUCCESS){
1309                 mesh_model_store_subscriptions(target_model);
1310             }
1311         } else {
1312             status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS;
1313         }
1314     }
1315 
1316     config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, address, model_identifier);
1317     mesh_access_message_processed(pdu);
1318 }
1319 
1320 static void config_model_subscription_virtual_address_add_hash(void *arg){
1321     mesh_model_t * target_model = (mesh_model_t*) arg;
1322     mesh_model_t * mesh_model = mesh_model_get_configuration_server();
1323 
1324     // add if not exists
1325     mesh_virtual_address_t * virtual_address = mesh_virtual_address_for_label_uuid(configuration_server_label_uuid);
1326     if (virtual_address == NULL){
1327         virtual_address = mesh_virtual_address_register(configuration_server_label_uuid, configuration_server_hash);
1328     }
1329 
1330     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1331     uint16_t pseudo_dst = MESH_ADDRESS_UNSASSIGNED;
1332     if (virtual_address == NULL){
1333         status = MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES;
1334     } else {
1335         pseudo_dst = virtual_address->pseudo_dst;
1336         if (!mesh_model_contains_subscription(target_model, pseudo_dst)){
1337             status = mesh_model_add_subscription(target_model, pseudo_dst);
1338             if (status == MESH_FOUNDATION_STATUS_SUCCESS){
1339                 mesh_virtual_address_increase_refcount(virtual_address);
1340                 mesh_model_store_subscriptions(target_model);
1341             }
1342         }
1343     }
1344 
1345     config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(access_pdu_in_process), mesh_pdu_src(access_pdu_in_process), status, configuration_server_element_address, pseudo_dst, target_model->model_identifier);
1346     mesh_access_message_processed(access_pdu_in_process);
1347     return;
1348 }
1349 
1350 static void config_model_subscription_virtual_address_add_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1351     mesh_access_parser_state_t parser;
1352     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1353 
1354     // ElementAddress - Address of the element - should be us
1355     configuration_server_element_address = mesh_access_parser_get_u16(&parser);
1356 
1357     // store label uuid
1358     mesh_access_parser_get_label_uuid(&parser, configuration_server_label_uuid);
1359 
1360     // Model Identifier
1361     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1362 
1363     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1364     mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(configuration_server_element_address, model_identifier, &status);
1365 
1366     if (target_model == NULL){
1367         config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, configuration_server_element_address, MESH_ADDRESS_UNSASSIGNED, model_identifier);
1368         mesh_access_message_processed(pdu);
1369         return;
1370     }
1371 
1372     access_pdu_in_process = pdu;
1373     mesh_virtual_address(&configuration_server_cmac_request, configuration_server_label_uuid, &configuration_server_hash, &config_model_subscription_virtual_address_add_hash, target_model);
1374 }
1375 
1376 static void config_model_subscription_overwrite_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1377     mesh_access_parser_state_t parser;
1378     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1379 
1380     uint16_t element_address  = mesh_access_parser_get_u16(&parser);
1381     uint16_t address          = mesh_access_parser_get_u16(&parser);
1382     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1383 
1384     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1385     mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1386 
1387     if (target_model != NULL){
1388         if (mesh_network_address_group(address) && !mesh_network_address_all_nodes(address)){
1389             mesh_subcription_decrease_virtual_address_ref_count(target_model);
1390             mesh_model_delete_all_subscriptions(mesh_model);
1391             mesh_model_add_subscription(mesh_model, address);
1392             mesh_model_store_subscriptions(target_model);
1393         } else {
1394             status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS;
1395         }
1396     }
1397 
1398     config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, address, model_identifier);
1399     mesh_access_message_processed(pdu);
1400 }
1401 
1402 static void config_model_subscription_virtual_address_overwrite_hash(void *arg){
1403     mesh_model_t * target_model = (mesh_model_t*) arg;
1404     mesh_model_t * mesh_model = mesh_model_get_configuration_server();
1405 
1406     // add if not exists
1407     mesh_virtual_address_t * virtual_address = mesh_virtual_address_for_label_uuid(configuration_server_label_uuid);
1408     if (virtual_address == NULL){
1409         virtual_address = mesh_virtual_address_register(configuration_server_label_uuid, configuration_server_hash);
1410     }
1411 
1412     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1413     uint16_t pseudo_dst = MESH_ADDRESS_UNSASSIGNED;
1414     if (virtual_address == NULL){
1415         status = MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES;
1416     } else {
1417 
1418         // increase refcount first to avoid flash delete + add in a row
1419         mesh_virtual_address_increase_refcount(virtual_address);
1420 
1421         // decrease ref counts for virtual addresses in subscription
1422         mesh_subcription_decrease_virtual_address_ref_count(target_model);
1423 
1424         // clear subscriptions
1425         mesh_model_delete_all_subscriptions(target_model);
1426 
1427         // add new subscription (successfull if MAX_NR_MESH_SUBSCRIPTION_PER_MODEL > 0)
1428         pseudo_dst = virtual_address->pseudo_dst;
1429         mesh_model_add_subscription(target_model, pseudo_dst);
1430 
1431         mesh_model_store_subscriptions(target_model);
1432     }
1433 
1434     config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(access_pdu_in_process), mesh_pdu_src(access_pdu_in_process), status, configuration_server_element_address, pseudo_dst, target_model->model_identifier);
1435     mesh_access_message_processed(access_pdu_in_process);
1436     return;
1437 }
1438 
1439 static void config_model_subscription_virtual_address_overwrite_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1440     mesh_access_parser_state_t parser;
1441     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1442 
1443     // ElementAddress - Address of the element - should be us
1444     configuration_server_element_address = mesh_access_parser_get_u16(&parser);
1445 
1446     // store label uuid
1447     mesh_access_parser_get_label_uuid(&parser, configuration_server_label_uuid);
1448 
1449     // Model Identifier
1450     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1451 
1452     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1453     mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(configuration_server_element_address, model_identifier, &status);
1454 
1455     if (target_model == NULL){
1456         config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, configuration_server_element_address, MESH_ADDRESS_UNSASSIGNED, model_identifier);
1457         mesh_access_message_processed(pdu);
1458         return;
1459     }
1460     access_pdu_in_process = pdu;
1461     mesh_virtual_address(&configuration_server_cmac_request, configuration_server_label_uuid, &configuration_server_hash, &config_model_subscription_virtual_address_overwrite_hash, target_model);
1462 }
1463 
1464 static void config_model_subscription_delete_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1465     mesh_access_parser_state_t parser;
1466     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1467 
1468     uint16_t element_address  = mesh_access_parser_get_u16(&parser);
1469     uint16_t address          = mesh_access_parser_get_u16(&parser);
1470     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1471 
1472     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1473     mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1474 
1475     if (target_model != NULL){
1476         if (mesh_network_address_group(address) && !mesh_network_address_all_nodes(address)){
1477             mesh_model_delete_subscription(target_model, address);
1478             mesh_model_store_subscriptions(target_model);
1479         } else {
1480             status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS;
1481         }
1482     }
1483 
1484     config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, address, model_identifier);
1485     mesh_access_message_processed(pdu);
1486 }
1487 
1488 static void config_model_subscription_virtual_address_delete_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1489     mesh_access_parser_state_t parser;
1490     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1491 
1492     uint16_t element_address  = mesh_access_parser_get_u16(&parser);
1493     mesh_access_parser_get_label_uuid(&parser, configuration_server_label_uuid);
1494     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1495 
1496     mesh_virtual_address_t * virtual_address = mesh_virtual_address_for_label_uuid(configuration_server_label_uuid);
1497     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1498     mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1499 
1500     if ((target_model != NULL) && (virtual_address != NULL) && mesh_model_contains_subscription(target_model, virtual_address->pseudo_dst)){
1501         mesh_virtual_address_decrease_refcount(virtual_address);
1502         mesh_model_delete_subscription(target_model, virtual_address->pseudo_dst);
1503         mesh_model_store_subscriptions(target_model);
1504      }
1505 
1506     config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, virtual_address->hash, model_identifier);
1507     mesh_access_message_processed(pdu);
1508 }
1509 
1510 static void config_model_subscription_delete_all_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1511     mesh_access_parser_state_t parser;
1512     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1513 
1514     uint16_t element_address  = mesh_access_parser_get_u16(&parser);
1515     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1516 
1517     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1518     mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1519 
1520     if (target_model != NULL){
1521         mesh_subcription_decrease_virtual_address_ref_count(target_model);
1522         mesh_model_delete_all_subscriptions(target_model);
1523         mesh_model_store_subscriptions(target_model);
1524     }
1525 
1526     config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, MESH_ADDRESS_UNSASSIGNED, model_identifier);
1527     mesh_access_message_processed(pdu);
1528 }
1529 
1530 // Configuration Model to AppKey List
1531 
1532 static void config_model_app_status(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest, uint8_t status, uint16_t element_address, uint16_t appkey_index, uint32_t model_identifier){
1533     UNUSED(mesh_model);
1534 
1535     // setup message
1536     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_foundation_config_model_app_status,
1537                                                             status, element_address, appkey_index, model_identifier);
1538     if (!transport_pdu) return;
1539 
1540     // send as segmented access pdu
1541     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
1542 }
1543 
1544 static void config_model_app_list(mesh_model_t * config_server_model, uint16_t netkey_index, uint16_t dest, uint8_t status, uint16_t element_address, uint32_t model_identifier, mesh_model_t * mesh_model){
1545     UNUSED(config_server_model);
1546 
1547     uint16_t opcode;
1548     if (mesh_model_is_bluetooth_sig(model_identifier)){
1549         opcode = MESH_FOUNDATION_OPERATION_SIG_MODEL_APP_LIST;
1550     } else {
1551         opcode = MESH_FOUNDATION_OPERATION_VENDOR_MODEL_APP_LIST;
1552     }
1553     mesh_transport_pdu_t * transport_pdu = mesh_access_transport_init(opcode);
1554     if (!transport_pdu) return;
1555 
1556     mesh_access_transport_add_uint8(transport_pdu, status);
1557     mesh_access_transport_add_uint16(transport_pdu, element_address);
1558     if (mesh_model_is_bluetooth_sig(model_identifier)) {
1559         mesh_access_transport_add_uint16(transport_pdu, mesh_model_get_model_id(model_identifier));
1560     } else {
1561         mesh_access_transport_add_uint32(transport_pdu, model_identifier);
1562     }
1563 
1564     // add list of appkey indexes
1565     if (mesh_model){
1566         uint16_t i;
1567         for (i=0;i<MAX_NR_MESH_APPKEYS_PER_MODEL;i++){
1568             uint16_t appkey_index = mesh_model->appkey_indices[i];
1569             if (appkey_index == MESH_APPKEY_INVALID) continue;
1570             mesh_access_transport_add_uint16(transport_pdu, appkey_index);
1571         }
1572     }
1573 
1574     // send as segmented access pdu
1575     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
1576 }
1577 
1578 static void config_model_app_bind_handler(mesh_model_t *config_server_model, mesh_pdu_t * pdu) {
1579     mesh_access_parser_state_t parser;
1580     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1581 
1582     uint16_t element_address = mesh_access_parser_get_u16(&parser);
1583     uint16_t appkey_index    = mesh_access_parser_get_u16(&parser);
1584     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1585 
1586     uint8_t status;
1587     do {
1588         // validate address and look up model
1589         mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1590         if (target_model == NULL) break;
1591 
1592         // validate app key exists
1593         mesh_transport_key_t * app_key = mesh_transport_key_get(appkey_index);
1594         if (!app_key){
1595             status = MESH_FOUNDATION_STATUS_INVALID_APPKEY_INDEX;
1596             break;
1597         }
1598 
1599         // Configuration Server only allows device keys
1600         if (mesh_model_is_configuration_server(model_identifier)){
1601             status = MESH_FOUNDATION_STATUS_CANNOT_BIND;
1602             break;
1603         }
1604         status = mesh_model_bind_appkey(target_model, appkey_index);
1605 
1606     } while (0);
1607 
1608     config_model_app_status(config_server_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, appkey_index, model_identifier);
1609     mesh_access_message_processed(pdu);
1610 }
1611 
1612 static void config_model_app_unbind_handler(mesh_model_t *config_server_model, mesh_pdu_t * pdu) {
1613     mesh_access_parser_state_t parser;
1614     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1615 
1616     uint16_t element_address = mesh_access_parser_get_u16(&parser);
1617     uint16_t appkey_index    = mesh_access_parser_get_u16(&parser);
1618     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1619 
1620     uint8_t status;
1621     do {
1622         // validate address and look up model
1623         mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1624         if (target_model == NULL) break;
1625 
1626         // validate app key exists
1627         mesh_transport_key_t * app_key = mesh_transport_key_get(appkey_index);
1628         if (!app_key){
1629             status = MESH_FOUNDATION_STATUS_INVALID_APPKEY_INDEX;
1630             break;
1631         }
1632         mesh_model_unbind_appkey(target_model, appkey_index);
1633         status = MESH_FOUNDATION_STATUS_SUCCESS;
1634     } while (0);
1635 
1636     config_model_app_status(config_server_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, appkey_index, model_identifier);
1637     mesh_access_message_processed(pdu);
1638 }
1639 
1640 static void config_model_app_get_handler(mesh_model_t *config_server_model, mesh_pdu_t * pdu){
1641     mesh_access_parser_state_t parser;
1642     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1643 
1644     uint16_t element_address = mesh_access_parser_get_u16(&parser);
1645     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1646 
1647     uint8_t status;
1648     mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1649     config_model_app_list(config_server_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, model_identifier, target_model);
1650     mesh_access_message_processed(pdu);
1651 }
1652 
1653 // Model Publication
1654 
1655 static void config_model_publication_changed(mesh_model_t *mesh_model, mesh_publication_model_t * new_publication_model){
1656 
1657     // stop publication
1658     mesh_model_publication_stop(mesh_model);
1659 
1660     // update model publication state
1661     memcpy(mesh_model->publication_model, &configuration_server_publication_model, sizeof(mesh_publication_model_t));
1662 
1663     // store
1664     mesh_model_store_publication(mesh_model);
1665 
1666     // start publication if address is set (nothing happens if period = 0 and retransmit = 0)
1667     if (new_publication_model->address == MESH_ADDRESS_UNSASSIGNED) return;
1668 
1669     // start to publish
1670     mesh_model_publication_start(mesh_model);
1671 }
1672 
1673 
1674 static void
1675 config_model_publication_status(mesh_model_t *mesh_model, uint16_t netkey_index, uint16_t dest, uint8_t status,
1676                                     uint16_t element_address, uint32_t model_identifier, mesh_publication_model_t *publication_model) {
1677     UNUSED(mesh_model);
1678 
1679     // setup message
1680     uint16_t app_key_index_and_credential_flag = (publication_model->friendship_credential_flag << 12) | publication_model->appkey_index;
1681     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(
1682             &mesh_foundation_config_model_app_status, status, element_address, publication_model->address,
1683             app_key_index_and_credential_flag,
1684             publication_model->ttl, publication_model->period, publication_model->retransmit, model_identifier);
1685     if (!transport_pdu) return;
1686 
1687     // send as segmented access pdu
1688     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
1689 }
1690 
1691 static void
1692 config_model_publication_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1693 
1694     // set defaults
1695     memset(&configuration_server_publication_model, 0, sizeof(mesh_publication_model_t));
1696 
1697     mesh_access_parser_state_t parser;
1698     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1699 
1700     // ElementAddress - Address of the element - should be us
1701     uint16_t element_address = mesh_access_parser_get_u16(&parser);
1702 
1703     // PublishAddress, 16 bit
1704     configuration_server_publication_model.address = mesh_access_parser_get_u16(&parser);
1705 
1706     // AppKeyIndex (12), CredentialFlag (1), RFU (3)
1707     uint16_t temp = mesh_access_parser_get_u16(&parser);
1708     configuration_server_publication_model.appkey_index = temp & 0x0fff;
1709     configuration_server_publication_model.friendship_credential_flag = (temp >> 12) & 1;
1710 
1711     // TTL
1712     configuration_server_publication_model.ttl        = mesh_access_parser_get_u8(&parser);
1713 
1714     // Period
1715     configuration_server_publication_model.period     = mesh_access_parser_get_u8(&parser);
1716 
1717     // Retransmit
1718     configuration_server_publication_model.retransmit = mesh_access_parser_get_u8(&parser);
1719 
1720     // Model Identifier
1721     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1722     uint8_t status;
1723     mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1724 
1725     // TODO validate params
1726 
1727     if (target_model){
1728         if (target_model->publication_model == NULL){
1729             status = MESH_FOUNDATION_STATUS_CANNOT_SET;
1730         } else {
1731 
1732             // decrease ref count if old virtual address
1733             if (mesh_network_address_virtual(configuration_server_publication_model.address)) {
1734                 mesh_virtual_address_t * current_virtual_address = mesh_virtual_address_for_pseudo_dst(configuration_server_publication_model.address);
1735                 mesh_virtual_address_decrease_refcount(current_virtual_address);
1736             }
1737 
1738             // restart publication
1739             config_model_publication_changed(target_model, &configuration_server_publication_model);
1740         }
1741     }
1742 
1743     // send status
1744     config_model_publication_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, model_identifier, &configuration_server_publication_model);
1745     mesh_access_message_processed(pdu);
1746 }
1747 
1748 static void config_model_publication_virtual_address_set_hash(void *arg){
1749     mesh_model_t *mesh_model = (mesh_model_t*) arg;
1750 
1751     // add if not exist
1752     mesh_virtual_address_t * virtual_address = mesh_virtual_address_for_label_uuid(configuration_server_label_uuid);
1753     if (virtual_address == NULL){
1754         virtual_address = mesh_virtual_address_register(configuration_server_label_uuid, configuration_server_hash);
1755     }
1756 
1757     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1758     if (virtual_address == NULL){
1759         status = MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES;
1760     } else {
1761 
1762         // increase ref count if new virtual address
1763         mesh_virtual_address_increase_refcount(virtual_address);
1764 
1765         // decrease ref count if old virtual address
1766         if (mesh_network_address_virtual(configuration_server_publication_model.address)) {
1767             mesh_virtual_address_t * current_virtual_address = mesh_virtual_address_for_pseudo_dst(configuration_server_publication_model.address);
1768             mesh_virtual_address_decrease_refcount(current_virtual_address);
1769         }
1770 
1771         configuration_server_publication_model.address = virtual_address->pseudo_dst;
1772         mesh_virtual_address_increase_refcount(virtual_address);
1773 
1774         // restart publication
1775         config_model_publication_changed(configuration_server_target_model, &configuration_server_publication_model);
1776     }
1777 
1778     // send status
1779     config_model_publication_status(mesh_model, mesh_pdu_netkey_index(access_pdu_in_process), mesh_pdu_src(access_pdu_in_process), status, configuration_server_element_address, configuration_server_model_identifier, &configuration_server_publication_model);
1780 
1781     mesh_access_message_processed(access_pdu_in_process);
1782 }
1783 
1784 static void
1785 config_model_publication_virtual_address_set_handler(mesh_model_t *mesh_model,
1786                                                      mesh_pdu_t * pdu) {
1787 
1788     // set defaults
1789     memset(&configuration_server_publication_model, 0, sizeof(mesh_publication_model_t));
1790 
1791     mesh_access_parser_state_t parser;
1792     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1793 
1794     // ElementAddress - Address of the element
1795     configuration_server_element_address = mesh_access_parser_get_u16(&parser);
1796 
1797     // store label uuid
1798     mesh_access_parser_get_label_uuid(&parser, configuration_server_label_uuid);
1799 
1800     // AppKeyIndex (12), CredentialFlag (1), RFU (3)
1801     uint16_t temp = mesh_access_parser_get_u16(&parser);
1802     configuration_server_publication_model.appkey_index = temp & 0x0fff;
1803     configuration_server_publication_model.friendship_credential_flag = (temp >> 12) & 1;
1804     configuration_server_publication_model.ttl        = mesh_access_parser_get_u8(&parser);
1805     configuration_server_publication_model.period     = mesh_access_parser_get_u8(&parser);
1806     configuration_server_publication_model.retransmit = mesh_access_parser_get_u8(&parser);
1807 
1808     // Model Identifier
1809     configuration_server_model_identifier = mesh_access_parser_get_model_identifier(&parser);
1810 
1811     uint8_t status;
1812     configuration_server_target_model = mesh_access_model_for_address_and_model_identifier(configuration_server_element_address, configuration_server_model_identifier, &status);
1813 
1814     // model exists, but no publication model
1815     if (configuration_server_target_model != NULL && configuration_server_target_model->publication_model == NULL){
1816         status = MESH_FOUNDATION_STATUS_CANNOT_SET;
1817     }
1818 
1819     // on error, no need to calculate virtual address hash
1820     if (status != MESH_FOUNDATION_STATUS_SUCCESS){
1821         config_model_publication_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, configuration_server_element_address, configuration_server_model_identifier, &configuration_server_publication_model);
1822         mesh_access_message_processed(pdu);
1823         return;
1824     }
1825 
1826     access_pdu_in_process = pdu;
1827     mesh_virtual_address(&configuration_server_cmac_request, configuration_server_label_uuid, &configuration_server_publication_model.address, &config_model_publication_virtual_address_set_hash, mesh_model);
1828 }
1829 
1830 static void
1831 config_model_publication_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1832 
1833 
1834     mesh_access_parser_state_t parser;
1835     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1836 
1837     // ElementAddress - Address of the element - should be us
1838     uint16_t element_address = mesh_access_parser_get_u16(&parser);
1839 
1840     // Model Identifier
1841     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1842 
1843     uint8_t status;
1844     mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1845 
1846     mesh_publication_model_t * publication_model;
1847 
1848     if (target_model == NULL){
1849         // use defaults
1850         memset(&configuration_server_publication_model, 0, sizeof(mesh_publication_model_t));
1851         publication_model = &configuration_server_publication_model;
1852     } else {
1853         publication_model = target_model->publication_model;
1854     }
1855 
1856     config_model_publication_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, configuration_server_element_address, model_identifier, publication_model);
1857     mesh_access_message_processed(pdu);
1858 }
1859 
1860 // Heartbeat Publication
1861 
1862 static void config_heartbeat_publication_emit(mesh_heartbeat_publication_t * mesh_heartbeat_publication){
1863 
1864     printf("CONFIG_SERVER_HEARTBEAT: Emit (dest %04x, count %u, period %u ms)\n",
1865         mesh_heartbeat_publication->destination,
1866         mesh_heartbeat_publication->count,
1867         mesh_heartbeat_publication->period_ms);
1868 
1869     // active features
1870     mesh_heartbeat_publication->active_features = mesh_foundation_get_features();
1871 
1872     mesh_network_pdu_t * network_pdu = mesh_network_pdu_get();
1873     if (network_pdu){
1874         uint8_t data[3];
1875         data[0] = mesh_heartbeat_publication->ttl;
1876         big_endian_store_16(data, 1, mesh_heartbeat_publication->active_features);
1877         mesh_upper_transport_setup_control_pdu((mesh_pdu_t *) network_pdu, mesh_heartbeat_publication->netkey_index,
1878                 mesh_heartbeat_publication->ttl, mesh_node_get_primary_element_address(), mesh_heartbeat_publication->destination,
1879                 MESH_TRANSPORT_OPCODE_HEARTBEAT, data, sizeof(data));
1880         mesh_upper_transport_send_control_pdu((mesh_pdu_t *) network_pdu);
1881     }
1882 
1883     // forever
1884     if (mesh_heartbeat_publication->count < 0xffffu) {
1885         mesh_heartbeat_publication->count--;
1886     }
1887 }
1888 void mesh_configuration_server_feature_changed(void){
1889     mesh_model_t * mesh_model = mesh_model_get_configuration_server();
1890     mesh_heartbeat_publication_t * mesh_heartbeat_publication = &((mesh_configuration_server_model_context_t*) mesh_model->model_data)->heartbeat_publication;
1891 
1892     // active features
1893     uint16_t active_features = mesh_foundation_get_features();
1894     if (mesh_heartbeat_publication->active_features == active_features) return;
1895     config_heartbeat_publication_emit(mesh_heartbeat_publication);
1896 }
1897 
1898 static void config_heartbeat_publication_timeout_handler(btstack_timer_source_t * ts){
1899 
1900     mesh_heartbeat_publication_t * mesh_heartbeat_publication = (mesh_heartbeat_publication_t*) ts;
1901 
1902     // emit beat
1903     config_heartbeat_publication_emit(mesh_heartbeat_publication);
1904 
1905     // all sent?
1906     if (mesh_heartbeat_publication->count == 0) return;
1907 
1908     // periodic publication?
1909     if (mesh_heartbeat_publication->period_ms == 0) return;
1910 
1911     btstack_run_loop_set_timer(ts, mesh_heartbeat_publication->period_ms);
1912     btstack_run_loop_add_timer(ts);
1913 }
1914 
1915 static void config_heartbeat_publication_status(mesh_model_t *mesh_model, uint16_t netkey_index, uint16_t dest, uint8_t status, mesh_heartbeat_publication_t * mesh_heartbeat_publication){
1916     UNUSED(mesh_model);
1917 
1918     // setup message
1919     uint8_t count_log = heartbeat_count_log(mesh_heartbeat_publication->count);
1920     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(
1921             &mesh_foundation_config_heartbeat_publication_status,
1922             status,
1923             mesh_heartbeat_publication->destination,
1924             count_log,
1925             mesh_heartbeat_publication->period_log,
1926             mesh_heartbeat_publication->ttl,
1927             mesh_heartbeat_publication->features,
1928             mesh_heartbeat_publication->netkey_index);
1929     if (!transport_pdu) return;
1930     printf("MESH config_heartbeat_publication_status count = %u => count_log = %u\n", mesh_heartbeat_publication->count, count_log);
1931 
1932     // send as segmented access pdu
1933     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
1934 }
1935 
1936 static void config_heartbeat_publication_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1937 
1938     mesh_heartbeat_publication_t requested_publication;
1939 
1940     mesh_access_parser_state_t parser;
1941     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1942 
1943     // Destination address for Heartbeat messages
1944     requested_publication.destination = mesh_access_parser_get_u16(&parser);
1945     // Number of Heartbeat messages to be sent
1946     requested_publication.count = heartbeat_pwr2(mesh_access_parser_get_u8(&parser));
1947     //  Period for sending Heartbeat messages
1948     requested_publication.period_log = mesh_access_parser_get_u8(&parser);
1949     //  TTL to be used when sending Heartbeat messages
1950     requested_publication.ttl = mesh_access_parser_get_u8(&parser);
1951     // Bit field indicating features that trigger Heartbeat messages when changed
1952     requested_publication.features = mesh_access_parser_get_u16(&parser) & MESH_HEARTBEAT_FEATURES_SUPPORTED_MASK;
1953     // NetKey Index
1954     requested_publication.netkey_index = mesh_access_parser_get_u16(&parser);
1955 
1956     // store period as ms
1957     requested_publication.period_ms = heartbeat_pwr2(requested_publication.period_log) * 1000;
1958 
1959     mesh_heartbeat_publication_t * mesh_heartbeat_publication = &((mesh_configuration_server_model_context_t*) mesh_model->model_data)->heartbeat_publication;
1960 
1961     // validate fields
1962     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1963     mesh_network_key_t * network_key = mesh_network_key_list_get(requested_publication.netkey_index);
1964     if (network_key == NULL){
1965         status = MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX;
1966     } else {
1967         printf("MESH config_heartbeat_publication_set, destination %x, count = %x, period = %u s\n",
1968             requested_publication.destination, requested_publication.count, requested_publication.period_ms);
1969 
1970         // accept update
1971         memcpy(mesh_heartbeat_publication, &requested_publication, sizeof(mesh_heartbeat_publication_t));
1972     }
1973 
1974     config_heartbeat_publication_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, mesh_heartbeat_publication);
1975 
1976     mesh_access_message_processed(pdu);
1977 
1978     if (status != MESH_FOUNDATION_STATUS_SUCCESS) return;
1979 
1980     // check if heartbeats should be disabled
1981     if (mesh_heartbeat_publication->destination == MESH_ADDRESS_UNSASSIGNED || mesh_heartbeat_publication->period_log == 0) {
1982         btstack_run_loop_remove_timer(&mesh_heartbeat_publication->timer);
1983         printf("MESH config_heartbeat_publication_set, disable\n");
1984         return;
1985     }
1986 
1987     // NOTE: defer first heartbeat to allow config status getting sent first
1988     btstack_run_loop_set_timer_handler(&mesh_heartbeat_publication->timer, config_heartbeat_publication_timeout_handler);
1989     btstack_run_loop_set_timer_context(&mesh_heartbeat_publication->timer, mesh_heartbeat_publication);
1990     btstack_run_loop_set_timer(&mesh_heartbeat_publication->timer, 2000);
1991     btstack_run_loop_add_timer(&mesh_heartbeat_publication->timer);
1992 }
1993 
1994 static void config_heartbeat_publication_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1995     mesh_heartbeat_publication_t * mesh_heartbeat_publication = &((mesh_configuration_server_model_context_t*) mesh_model->model_data)->heartbeat_publication;
1996     config_heartbeat_publication_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), MESH_FOUNDATION_STATUS_SUCCESS, mesh_heartbeat_publication);
1997     mesh_access_message_processed(pdu);
1998 }
1999 
2000 // Heartbeat Subscription
2001 
2002 static void config_heartbeat_subscription_status(mesh_model_t *mesh_model, uint16_t netkey_index, uint16_t dest, uint8_t status, mesh_heartbeat_subscription_t * mesh_heartbeat_subscription){
2003     UNUSED(mesh_model);
2004 
2005     // setup message
2006     uint8_t count_log = heartbeat_count_log(mesh_heartbeat_subscription->count_log);
2007     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(
2008             &mesh_foundation_config_heartbeat_subscription_status,
2009             status,
2010             mesh_heartbeat_subscription->source,
2011             mesh_heartbeat_subscription->destination,
2012             mesh_heartbeat_subscription->period_log,
2013             count_log,
2014             mesh_heartbeat_subscription->min_hops,
2015             mesh_heartbeat_subscription->max_hops);
2016     if (!transport_pdu) return;
2017     printf("MESH config_heartbeat_subscription_status count = %u => count_log = %u\n", mesh_heartbeat_subscription->count_log, count_log);
2018 
2019     // send as segmented access pdu
2020     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
2021 }
2022 static int config_heartbeat_subscription_enabled(mesh_heartbeat_subscription_t * mesh_heartbeat_subscription){
2023     return mesh_network_address_unicast(mesh_heartbeat_subscription->source) && mesh_heartbeat_subscription->period_log > 0 &&
2024         (mesh_network_address_unicast(mesh_heartbeat_subscription->destination) || mesh_network_address_group(mesh_heartbeat_subscription->destination));
2025 }
2026 
2027 static void config_heartbeat_subscription_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
2028     mesh_access_parser_state_t parser;
2029     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
2030 
2031     mesh_heartbeat_subscription_t requested_subscription;
2032 
2033     // Destination address for Heartbeat messages
2034     requested_subscription.source = mesh_access_parser_get_u16(&parser);
2035     // Destination address for Heartbeat messages
2036     requested_subscription.destination = mesh_access_parser_get_u16(&parser);
2037     //  Period for sending Heartbeat messages
2038     requested_subscription.period_log = mesh_access_parser_get_u8(&parser);
2039 
2040     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
2041     if (requested_subscription.period_log > 0x11u){
2042         status = MESH_FOUNDATION_STATUS_CANNOT_SET;
2043     } else if ((requested_subscription.source != MESH_ADDRESS_UNSASSIGNED)       &&
2044                !mesh_network_address_unicast(requested_subscription.source)){
2045         status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS;
2046     } else if ((requested_subscription.destination != MESH_ADDRESS_UNSASSIGNED)  &&
2047                !mesh_network_address_unicast(requested_subscription.destination) &&
2048                !mesh_network_address_group(requested_subscription.destination)){
2049         status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS;
2050     }
2051 
2052     if (status != MESH_FOUNDATION_STATUS_SUCCESS){
2053         config_heartbeat_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, &requested_subscription);
2054         mesh_access_message_processed(pdu);
2055         return;
2056     }
2057 
2058     mesh_heartbeat_subscription_t * mesh_heartbeat_subscription = &((mesh_configuration_server_model_context_t*) mesh_model->model_data)->heartbeat_subscription;
2059 
2060     if (config_heartbeat_subscription_enabled(mesh_heartbeat_subscription)){
2061         requested_subscription.count_log  = 0u;
2062         requested_subscription.min_hops   = 0x7Fu;
2063         requested_subscription.max_hops   = 0u;
2064     } else {
2065         requested_subscription.source = MESH_ADDRESS_UNSASSIGNED;
2066         requested_subscription.destination = MESH_ADDRESS_UNSASSIGNED;
2067         requested_subscription.period_log = 0u;
2068         requested_subscription.count_log  = 0u;
2069         requested_subscription.min_hops   = 0u;
2070         requested_subscription.max_hops   = 0u;
2071     }
2072 
2073     // accept request
2074     memcpy(mesh_heartbeat_subscription, &requested_subscription, sizeof(mesh_heartbeat_subscription_t));
2075 
2076     printf("MESH config_heartbeat_subscription_set, destination %x, count = %x, period = %u s\n",
2077             mesh_heartbeat_subscription->destination, mesh_heartbeat_subscription->count_log, heartbeat_pwr2(mesh_heartbeat_subscription->period_log));
2078 
2079     config_heartbeat_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, mesh_heartbeat_subscription);
2080     mesh_access_message_processed(pdu);
2081 }
2082 
2083 
2084 static void config_heartbeat_subscription_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
2085     mesh_heartbeat_subscription_t * mesh_heartbeat_subscription = &((mesh_configuration_server_model_context_t*) mesh_model->model_data)->heartbeat_subscription;
2086     config_heartbeat_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), MESH_FOUNDATION_STATUS_SUCCESS, mesh_heartbeat_subscription);
2087     mesh_access_message_processed(pdu);
2088 }
2089 
2090 // KeyRefresh Phase
2091 
2092 static void config_key_refresh_phase_status(mesh_model_t *mesh_model, uint16_t netkey_index_dest, uint16_t dest, uint8_t status, uint16_t netkey_index,
2093     mesh_key_refresh_state_t key_refresh_state){
2094     UNUSED(mesh_model);
2095 
2096     // setup message
2097     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(
2098         &mesh_key_refresh_phase_status,
2099         status,
2100         netkey_index,
2101         key_refresh_state);
2102     if (!transport_pdu) return;
2103 
2104     // send as segmented access pdu
2105     config_server_send_message(netkey_index_dest, dest, (mesh_pdu_t *) transport_pdu);
2106 }
2107 
2108 static void config_key_refresh_phase_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
2109     mesh_access_parser_state_t parser;
2110     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
2111     uint16_t netkey_index = mesh_access_parser_get_u16(&parser);
2112     mesh_subnet_t * subnet = mesh_subnet_get_by_netkey_index(netkey_index);
2113 
2114     uint8_t status = MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX;
2115     mesh_key_refresh_state_t key_refresh_state = MESH_KEY_REFRESH_NOT_ACTIVE;
2116 
2117     if (subnet != NULL){
2118         status = MESH_FOUNDATION_STATUS_SUCCESS;
2119         key_refresh_state = subnet->key_refresh;
2120     }
2121 
2122     config_key_refresh_phase_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, netkey_index, key_refresh_state);
2123     mesh_access_message_processed(pdu);
2124 }
2125 
2126 static void config_key_refresh_phase_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
2127     mesh_access_parser_state_t parser;
2128     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
2129     uint16_t netkey_index = mesh_access_parser_get_u16(&parser);
2130     uint8_t  key_refresh_phase_transition = mesh_access_parser_get_u8(&parser);
2131     mesh_subnet_t * subnet = mesh_subnet_get_by_netkey_index(netkey_index);
2132 
2133     uint8_t status = MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX;
2134 
2135     if (subnet != NULL){
2136         status = MESH_FOUNDATION_STATUS_SUCCESS;
2137 
2138         switch (key_refresh_phase_transition){
2139             case 0x02:
2140                 switch (subnet->key_refresh){
2141                     case MESH_KEY_REFRESH_FIRST_PHASE:
2142                     case MESH_KEY_REFRESH_SECOND_PHASE:
2143                         subnet->key_refresh = MESH_KEY_REFRESH_SECOND_PHASE;
2144                         break;
2145                     default:
2146                         break;
2147                 }
2148                 break;
2149             case 0x03:
2150                 switch (subnet->key_refresh){
2151                     case MESH_KEY_REFRESH_FIRST_PHASE:
2152                     case MESH_KEY_REFRESH_SECOND_PHASE:
2153                         // key refresh phase 3 entered
2154                         mesh_access_key_refresh_revoke_keys(subnet);
2155                         subnet->key_refresh = MESH_KEY_REFRESH_NOT_ACTIVE;
2156                         break;
2157                     default:
2158                         break;
2159                 }
2160                 break;
2161             default:
2162                 status = MESH_FOUNDATION_STATUS_CANNOT_SET;
2163                 break;
2164         }
2165     }
2166 
2167     config_key_refresh_phase_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, netkey_index, subnet->key_refresh);
2168     mesh_access_message_processed(pdu);
2169 }
2170 
2171 
2172 static void config_node_reset_status(mesh_model_t *mesh_model, uint16_t netkey_index, uint16_t dest){
2173     UNUSED(mesh_model);
2174 
2175     // setup message
2176     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_foundation_node_reset_status);
2177     if (!transport_pdu) return;
2178 
2179     // send as segmented access pdu
2180     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
2181 }
2182 
2183 static void config_node_reset_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
2184     mesh_node_reset();
2185     config_node_reset_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
2186     mesh_access_message_processed(pdu);
2187 }
2188 
2189 static void low_power_node_poll_timeout_status(mesh_model_t *mesh_model, uint16_t netkey_index_dest, uint16_t dest, uint8_t status){
2190     UNUSED(mesh_model);
2191 
2192     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(
2193         &mesh_foundation_low_power_node_poll_timeout_status,
2194         status,
2195         0,  // The unicast address of the Low Power node
2196         0); // The current value of the PollTimeout timer of the Low Power node
2197     if (!transport_pdu) return;
2198     printf("TODO: send unicast address of the Low Power node and the current value of the PollTimeout timer, instead of 0s\n");
2199     // send as segmented access pdu
2200     config_server_send_message(netkey_index_dest, dest, (mesh_pdu_t *) transport_pdu);
2201 }
2202 
2203 static void config_low_power_node_poll_timeout_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
2204     mesh_access_parser_state_t parser;
2205     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
2206     printf("TODO: implement get the current value of PollTimeout timer of the Low Power node within a Friend node\n");
2207     low_power_node_poll_timeout_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), MESH_FOUNDATION_STATUS_SUCCESS);
2208     mesh_access_message_processed(pdu);
2209 }
2210 
2211 static void config_node_identity_status(mesh_model_t *mesh_model, uint16_t netkey_index_dest, uint16_t dest, uint8_t status, uint16_t netkey_index,
2212     mesh_node_identity_state_t node_identity_state){
2213     UNUSED(mesh_model);
2214 
2215     // setup message
2216     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(
2217         &mesh_foundation_node_identity_status,
2218         status,
2219         netkey_index,
2220         node_identity_state);
2221     if (!transport_pdu) return;
2222 
2223     // send as segmented access pdu
2224     config_server_send_message(netkey_index_dest, dest, (mesh_pdu_t *) transport_pdu);
2225 }
2226 
2227 static void config_node_identity_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
2228     mesh_access_parser_state_t parser;
2229     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
2230     uint16_t netkey_index = mesh_access_parser_get_u16(&parser);
2231 
2232     mesh_node_identity_state_t node_identity_state = MESH_NODE_IDENTITY_STATE_ADVERTISING_NOT_SUPPORTED;
2233     uint8_t status = mesh_proxy_get_advertising_with_node_id_status(netkey_index, &node_identity_state);
2234 
2235     config_node_identity_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, netkey_index, node_identity_state);
2236     mesh_access_message_processed(pdu);
2237 }
2238 
2239 static void config_node_identity_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
2240     mesh_access_parser_state_t parser;
2241     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
2242     uint16_t netkey_index = mesh_access_parser_get_u16(&parser);
2243     mesh_node_identity_state_t node_identity_state = (mesh_node_identity_state_t) mesh_access_parser_get_u8(&parser);
2244 
2245     uint8_t status = mesh_proxy_set_advertising_with_node_id(netkey_index, node_identity_state);
2246 
2247     config_node_identity_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, netkey_index, node_identity_state);
2248     mesh_access_message_processed(pdu);
2249 }
2250 
2251 //
2252 
2253 const static mesh_operation_t mesh_configuration_server_model_operations[] = {
2254     { MESH_FOUNDATION_OPERATION_APPKEY_ADD,                                  19, config_appkey_add_handler },
2255     { MESH_FOUNDATION_OPERATION_APPKEY_DELETE,                                3, config_appkey_delete_handler },
2256     { MESH_FOUNDATION_OPERATION_APPKEY_GET,                                   2, config_appkey_get_handler },
2257     { MESH_FOUNDATION_OPERATION_APPKEY_UPDATE,                               19, config_appkey_update_handler },
2258     { MESH_FOUNDATION_OPERATION_NETKEY_ADD,                                  18, config_netkey_add_handler },
2259     { MESH_FOUNDATION_OPERATION_NETKEY_UPDATE,                               18, config_netkey_update_handler },
2260     { MESH_FOUNDATION_OPERATION_NETKEY_DELETE,                                2, config_netkey_delete_handler },
2261     { MESH_FOUNDATION_OPERATION_NETKEY_GET,                                   0, config_netkey_get_handler },
2262     { MESH_FOUNDATION_OPERATION_COMPOSITION_DATA_GET,                         1, config_composition_data_get_handler },
2263     { MESH_FOUNDATION_OPERATION_BEACON_GET,                                   0, config_beacon_get_handler },
2264     { MESH_FOUNDATION_OPERATION_BEACON_SET,                                   1, config_beacon_set_handler },
2265     { MESH_FOUNDATION_OPERATION_DEFAULT_TTL_GET,                              0, config_default_ttl_get_handler },
2266     { MESH_FOUNDATION_OPERATION_DEFAULT_TTL_SET,                              1, config_default_ttl_set_handler },
2267     { MESH_FOUNDATION_OPERATION_FRIEND_GET,                                   0, config_friend_get_handler },
2268     { MESH_FOUNDATION_OPERATION_FRIEND_SET,                                   1, config_friend_set_handler },
2269     { MESH_FOUNDATION_OPERATION_NETWORK_TRANSMIT_GET,                         0, config_model_network_transmit_get_handler },
2270     { MESH_FOUNDATION_OPERATION_NETWORK_TRANSMIT_SET,                         1, config_model_network_transmit_set_handler },
2271     { MESH_FOUNDATION_OPERATION_GATT_PROXY_GET,                               0, config_gatt_proxy_get_handler },
2272     { MESH_FOUNDATION_OPERATION_GATT_PROXY_SET,                               1, config_gatt_proxy_set_handler },
2273     { MESH_FOUNDATION_OPERATION_RELAY_GET,                                    0, config_relay_get_handler },
2274     { MESH_FOUNDATION_OPERATION_RELAY_SET,                                    1, config_relay_set_handler },
2275     { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_ADD,                       6, config_model_subscription_add_handler },
2276     { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_ADD,      20, config_model_subscription_virtual_address_add_handler },
2277     { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_DELETE,                    6, config_model_subscription_delete_handler },
2278     { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_DELETE,   20, config_model_subscription_virtual_address_delete_handler },
2279     { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_OVERWRITE,                 6, config_model_subscription_overwrite_handler },
2280     { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_OVERWRITE,20, config_model_subscription_virtual_address_overwrite_handler },
2281     { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_DELETE_ALL,                4, config_model_subscription_delete_all_handler },
2282     { MESH_FOUNDATION_OPERATION_SIG_MODEL_SUBSCRIPTION_GET,                   4, config_model_subscription_get_handler },
2283     { MESH_FOUNDATION_OPERATION_VENDOR_MODEL_SUBSCRIPTION_GET,                6, config_model_subscription_get_handler },
2284     { MESH_FOUNDATION_OPERATION_SIG_MODEL_APP_GET,                            4, config_model_app_get_handler },
2285     { MESH_FOUNDATION_OPERATION_VENDOR_MODEL_APP_GET,                         6, config_model_app_get_handler },
2286     { MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_SET,                       11, config_model_publication_set_handler },
2287     { MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_VIRTUAL_ADDRESS_SET,       25, config_model_publication_virtual_address_set_handler },
2288     { MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_GET,                        4, config_model_publication_get_handler },
2289     { MESH_FOUNDATION_OPERATION_MODEL_APP_BIND,                               6, config_model_app_bind_handler },
2290     { MESH_FOUNDATION_OPERATION_MODEL_APP_UNBIND,                             6, config_model_app_unbind_handler },
2291     { MESH_FOUNDATION_OPERATION_HEARTBEAT_PUBLICATION_GET,                    0, config_heartbeat_publication_get_handler },
2292     { MESH_FOUNDATION_OPERATION_HEARTBEAT_PUBLICATION_SET,                    9, config_heartbeat_publication_set_handler },
2293     { MESH_FOUNDATION_OPERATION_HEARTBEAT_SUBSCRIPTION_GET,                   0, config_heartbeat_subscription_get_handler},
2294     { MESH_FOUNDATION_OPERATION_HEARTBEAT_SUBSCRIPTION_SET,                   5, config_heartbeat_subscription_set_handler},
2295     { MESH_FOUNDATION_OPERATION_KEY_REFRESH_PHASE_GET,                        2, config_key_refresh_phase_get_handler },
2296     { MESH_FOUNDATION_OPERATION_KEY_REFRESH_PHASE_SET,                        3, config_key_refresh_phase_set_handler },
2297     { MESH_FOUNDATION_OPERATION_NODE_RESET,                                   0, config_node_reset_handler },
2298     { MESH_FOUNDATION_OPERATION_LOW_POWER_NODE_POLL_TIMEOUT_GET,              2, config_low_power_node_poll_timeout_get_handler },
2299     { MESH_FOUNDATION_OPERATION_NODE_IDENTITY_GET,                            2, config_node_identity_get_handler },
2300     { MESH_FOUNDATION_OPERATION_NODE_IDENTITY_SET,                            3, config_node_identity_set_handler },
2301     { 0, 0, NULL }
2302 };
2303 
2304 const mesh_operation_t * mesh_configuration_server_get_operations(void){
2305     return mesh_configuration_server_model_operations;
2306 }
2307 
2308 static uint32_t mesh_tag_for_prov_data(void){
2309     return ((uint32_t) 'P' << 24) | ((uint32_t) 'R' << 16) | ((uint32_t) 'O' <<  8) | (uint32_t)'V';
2310 }
2311 
2312 void mesh_node_reset(void){
2313     mesh_configuration_server_setup_tlv();
2314 
2315     // PROV
2316     btstack_tlv_singleton_impl->delete_tag(btstack_tlv_singleton_context, mesh_tag_for_prov_data());
2317     // everything else
2318     mesh_delete_network_keys();
2319     mesh_delete_app_keys();
2320     mesh_delete_appkey_lists();
2321     mesh_delete_virtual_addresses();
2322     mesh_delete_subscriptions();
2323     mesh_delete_publications();
2324 }
2325 
2326 typedef struct {
2327     uint16_t unicast_address;
2328     uint8_t  flags;
2329     uint8_t  device_key[16];
2330 
2331 } mesh_persistent_provisioning_data_t;
2332 
2333 void mesh_node_store_provisioning_data(mesh_provisioning_data_t * provisioning_data){
2334 
2335     // fill persistent prov data
2336     mesh_persistent_provisioning_data_t persistent_provisioning_data;
2337 
2338     persistent_provisioning_data.unicast_address = provisioning_data->unicast_address;
2339     memcpy(persistent_provisioning_data.device_key, provisioning_data->device_key, 16);
2340 
2341     // store in tlv
2342     btstack_tlv_get_instance(&btstack_tlv_singleton_impl, &btstack_tlv_singleton_context);
2343     btstack_tlv_singleton_impl->store_tag(btstack_tlv_singleton_context, mesh_tag_for_prov_data(), (uint8_t *) &persistent_provisioning_data, sizeof(mesh_persistent_provisioning_data_t));
2344 
2345     // store IV Index and sequence number
2346     mesh_store_iv_index_after_provisioning(provisioning_data->iv_index);
2347 
2348     // store primary network key
2349     mesh_store_network_key(provisioning_data->network_key);
2350 }
2351 
2352 int mesh_node_startup_from_tlv(void){
2353 
2354     mesh_persistent_provisioning_data_t persistent_provisioning_data;
2355     btstack_tlv_get_instance(&btstack_tlv_singleton_impl, &btstack_tlv_singleton_context);
2356 
2357     // load provisioning data
2358     uint32_t prov_len = btstack_tlv_singleton_impl->get_tag(btstack_tlv_singleton_context, mesh_tag_for_prov_data(), (uint8_t *) &persistent_provisioning_data, sizeof(mesh_persistent_provisioning_data_t));
2359     printf("Provisioning data available: %u\n", prov_len ? 1 : 0);
2360     if (prov_len){
2361 
2362         // copy into mesh_provisioning_data
2363         mesh_provisioning_data_t provisioning_data;
2364         memcpy(provisioning_data.device_key, persistent_provisioning_data.device_key, 16);
2365         provisioning_data.unicast_address = persistent_provisioning_data.unicast_address;
2366         provisioning_data.flags = persistent_provisioning_data.flags;
2367         provisioning_data.network_key = NULL;
2368 
2369         // load iv index
2370         uint32_t iv_index;
2371         uint32_t sequence_number;
2372         int ok = mesh_load_iv_index_and_sequence_number(&iv_index, &sequence_number);
2373         if (ok){
2374             // bump sequence number to account for interval updates
2375             sequence_number += MESH_SEQUENCE_NUMBER_STORAGE_INTERVAL;
2376             mesh_sequence_number_set(sequence_number);
2377             mesh_store_iv_index_and_sequence_number();
2378             log_info("IV Index: %08x, Sequence Number %08x", (int) iv_index, (int) sequence_number);
2379             provisioning_data.iv_index = iv_index;
2380         }
2381 
2382         // load network keys
2383         mesh_load_network_keys();
2384         // load app keys
2385         mesh_load_app_keys();
2386         // load model to appkey bindings
2387         mesh_load_appkey_lists();
2388         // load virtual addresses
2389         mesh_load_virtual_addresses();
2390         // load model subscriptions
2391         mesh_load_subscriptions();
2392         // load model publications
2393         mesh_load_publications();
2394         // load foundation state
2395         mesh_foundation_state_load();
2396 
2397         mesh_access_setup_from_provisioning_data(&provisioning_data);
2398 
2399 #if defined(ENABLE_MESH_ADV_BEARER) || defined(ENABLE_MESH_PB_ADV)
2400         // start sending Secure Network Beacon
2401         mesh_subnet_t * subnet = mesh_subnet_get_by_netkey_index(0);
2402         if (subnet){
2403             beacon_secure_network_start(subnet);
2404         }
2405 #endif
2406         return 1;
2407     } else {
2408         mesh_access_setup_without_provisiong_data();
2409         return 0;
2410     }
2411 }
2412 
2413