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