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