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