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