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