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