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