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