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