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