xref: /btstack/src/mesh/mesh_configuration_server.c (revision 85f51b6478f1219796449800aea71a89f912cabf)
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 == 0 || (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     // setup new key
713     uint16_t internal_index = mesh_network_key_get_free_index();
714     mesh_network_key_t * new_network_key = btstack_memory_mesh_network_key_get();
715     if (internal_index == 0 || new_network_key == NULL){
716         config_netkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES, netkey_index);
717         mesh_access_message_processed(access_pdu_in_process);
718         return;
719     }
720 
721     // setup new key
722     new_network_key->internal_index = internal_index;
723     new_network_key->netkey_index   = netkey_index;
724     new_network_key->version        = (uint8_t)(subnet->old_key->version + 1);
725     memcpy(new_network_key->net_key, new_netkey, 16);
726 
727     // store in subnet (not active yet)
728     subnet->new_key = new_network_key;
729 
730     // derive other keys
731     access_pdu_in_process = pdu;
732     mesh_network_key_derive(&configuration_server_cmac_request, new_network_key, config_netkey_update_derived, subnet);
733 }
734 
735 static void config_netkey_delete_handler(mesh_model_t * mesh_model, mesh_pdu_t * pdu) {
736     mesh_access_parser_state_t parser;
737     mesh_access_parser_init(&parser, (mesh_pdu_t *) pdu);
738 
739     // get params
740     uint16_t netkey_index = mesh_access_parser_get_u16(&parser);
741 
742     // get existing network_key
743     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
744 
745     // remove subnet
746     mesh_subnet_t * subnet = mesh_subnet_get_by_netkey_index(netkey_index);
747     if (subnet != NULL){
748         // A NetKey shall not be deleted from the NetKey List using a message secured with this NetKey.
749         // Also prevents deleting the last network key
750         if (netkey_index != mesh_pdu_netkey_index(pdu)){
751 
752             // remove all appkeys for this netkey
753             mesh_transport_key_iterator_t it;
754             mesh_transport_key_iterator_init(&it, netkey_index);
755             while (mesh_transport_key_iterator_has_more(&it)){
756                 mesh_transport_key_t * transport_key = mesh_transport_key_iterator_get_next(&it);
757                 mesh_configuration_server_delete_appkey(transport_key);
758             }
759 
760             // delete old/current key
761             mesh_access_netkey_finalize(subnet->old_key);
762             subnet->old_key = NULL;
763 
764             // delete new key
765             if (subnet->new_key != NULL){
766                 mesh_access_netkey_finalize(subnet->new_key);
767                 subnet->new_key = NULL;
768             }
769 
770             // remove subnet
771             mesh_subnet_remove(subnet);
772             btstack_memory_mesh_subnet_free(subnet);
773 
774         } else {
775             status = MESH_FOUNDATION_STATUS_CANNOT_REMOVE;
776         }
777     }
778     config_netkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, netkey_index);
779 }
780 
781 static void config_netkey_get_handler(mesh_model_t * mesh_model, mesh_pdu_t * pdu){
782     config_netkey_list(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
783     mesh_access_message_processed(pdu);
784 }
785 
786 // AppKey List
787 
788 static void config_appkey_status(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest, uint32_t netkey_and_appkey_index, uint8_t status){
789     UNUSED(mesh_model);
790 
791     // setup message
792     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_foundation_config_appkey_status,
793                                                                                status, netkey_and_appkey_index);
794     if (!transport_pdu) return;
795 
796     // send as segmented access pdu
797     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
798 }
799 
800 static void config_appkey_list(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest, uint32_t netkey_index_of_list){
801     UNUSED(mesh_model);
802 
803     mesh_transport_pdu_t * transport_pdu = mesh_access_transport_init(MESH_FOUNDATION_OPERATION_APPKEY_LIST);
804     if (!transport_pdu) return;
805 
806     // check netkey_index is valid
807     mesh_network_key_t * network_key = mesh_network_key_list_get(netkey_index_of_list);
808     uint8_t status;
809     if (network_key == NULL){
810         status = MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX;
811     } else {
812         status = MESH_FOUNDATION_STATUS_SUCCESS;
813     }
814     mesh_access_transport_add_uint8(transport_pdu, status);
815     mesh_access_transport_add_uint16(transport_pdu, netkey_index_of_list);
816 
817     // add list of appkey indexes
818     mesh_transport_key_iterator_t it;
819     mesh_transport_key_iterator_init(&it, netkey_index_of_list);
820     while (mesh_transport_key_iterator_has_more(&it)){
821         mesh_transport_key_t * transport_key = mesh_transport_key_iterator_get_next(&it);
822         mesh_access_transport_add_uint16(transport_pdu, transport_key->appkey_index);
823     }
824 
825     // send as segmented access pdu
826     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
827 }
828 
829 static void config_appkey_add_or_update_aid(void *arg){
830     mesh_transport_key_t * transport_key = (mesh_transport_key_t *) arg;
831 
832     printf("Config Appkey Add/Update: NetKey Index 0x%04x, AppKey Index 0x%04x, AID %02x: ", transport_key->netkey_index, transport_key->appkey_index, transport_key->aid);
833     printf_hexdump(transport_key->key, 16);
834 
835     // store in TLV
836     mesh_store_app_key(transport_key);
837 
838     // add app key
839     mesh_transport_key_add(transport_key);
840 
841     uint32_t netkey_and_appkey_index = (transport_key->appkey_index << 12) | transport_key->netkey_index;
842     config_appkey_status(mesh_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);
843 
844     mesh_access_message_processed(access_pdu_in_process);
845 }
846 
847 static void config_appkey_add_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
848 
849     mesh_access_parser_state_t parser;
850     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
851 
852     // netkey and appkey index
853     uint32_t netkey_and_appkey_index = mesh_access_parser_get_u24(&parser);
854     uint16_t netkey_index = netkey_and_appkey_index & 0xfff;
855     uint16_t appkey_index = netkey_and_appkey_index >> 12;
856 
857     // actual key
858     uint8_t  appkey[16];
859     mesh_access_parser_get_key(&parser, appkey);
860 
861     // check netkey_index is valid
862     mesh_network_key_t * network_key = mesh_network_key_list_get(netkey_index);
863     if (network_key == NULL){
864         config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX);
865         mesh_access_message_processed(pdu);
866         return;
867     }
868 
869     // check if appkey already exists
870     mesh_transport_key_t * transport_key = mesh_transport_key_get(appkey_index);
871     if (transport_key){
872         uint8_t status;
873         if (transport_key->netkey_index != netkey_index){
874             // already stored but with different netkey
875             status = MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX;
876         } else if (memcmp(transport_key->key, appkey, 16) == 0){
877             // key identical
878             status = MESH_FOUNDATION_STATUS_SUCCESS;
879         } else {
880             // key differs
881             status = MESH_FOUNDATION_STATUS_KEY_INDEX_ALREADY_STORED;
882         }
883         config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, status);
884         mesh_access_message_processed(pdu);
885         return;
886     }
887 
888     // create app key (first get free slot in transport key table)
889     mesh_transport_key_t * app_key = NULL;
890     uint16_t internal_index = mesh_transport_key_get_free_index();
891     if (internal_index > 0){
892         app_key = btstack_memory_mesh_transport_key_get();
893     }
894     if (app_key == NULL) {
895         config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES);
896         mesh_access_message_processed(pdu);
897         return;
898     }
899 
900     // store data
901     app_key->internal_index = internal_index;
902     app_key->akf = 1;
903     app_key->appkey_index = appkey_index;
904     app_key->netkey_index = netkey_index;
905     app_key->version = 0;
906     app_key->old_key = 0;
907 
908     memcpy(app_key->key, appkey, 16);
909 
910     // calculate AID
911     access_pdu_in_process = pdu;
912     mesh_transport_key_calc_aid(&configuration_server_cmac_request, app_key, config_appkey_add_or_update_aid, app_key);
913 }
914 
915 static void config_appkey_update_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
916 
917     mesh_access_parser_state_t parser;
918     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
919 
920     // netkey and appkey index
921     uint32_t netkey_and_appkey_index = mesh_access_parser_get_u24(&parser);
922     uint16_t netkey_index = netkey_and_appkey_index & 0xfff;
923     uint16_t appkey_index = netkey_and_appkey_index >> 12;
924 
925     // actual key
926     uint8_t  appkey[16];
927     mesh_access_parser_get_key(&parser, appkey);
928 
929 
930 // for PTS testing
931     // check netkey_index is valid
932     mesh_network_key_t * network_key = mesh_network_key_list_get(netkey_index);
933     if (network_key == NULL){
934         config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX);
935         mesh_access_message_processed(pdu);
936         return;
937     }
938 
939     // check if appkey already exists
940     mesh_transport_key_t * existing_app_key = mesh_transport_key_get(appkey_index);
941     if (!existing_app_key) {
942         config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_INVALID_APPKEY_INDEX);
943         mesh_access_message_processed(pdu);
944         return;
945     }
946 
947     if (existing_app_key->netkey_index != netkey_index){
948         // already stored but with different netkey
949         config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_INVALID_BINDING);
950         mesh_access_message_processed(pdu);
951         return;
952     }
953 
954     if (memcmp(existing_app_key->key, appkey, 16) == 0){
955         // key identical
956         config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_SUCCESS);
957         mesh_access_message_processed(pdu);
958         return;
959     }
960 
961     // create app key
962     mesh_transport_key_t * new_app_key = NULL;
963     uint16_t internal_index = mesh_transport_key_get_free_index();
964     if (internal_index > 0){
965         new_app_key = btstack_memory_mesh_transport_key_get();
966     }
967     if (new_app_key == NULL) {
968         config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES);
969         mesh_access_message_processed(pdu);
970         return;
971     }
972 
973     // store data
974     new_app_key->internal_index = internal_index;
975     new_app_key->appkey_index = appkey_index;
976     new_app_key->netkey_index = netkey_index;
977     new_app_key->key_refresh  = 1;
978     new_app_key->version = (uint8_t)(existing_app_key->version + 1);
979     memcpy(new_app_key->key, appkey, 16);
980 
981     // mark old key
982     existing_app_key->old_key = 1;
983 
984     // calculate AID
985     access_pdu_in_process = pdu;
986     mesh_transport_key_calc_aid(&configuration_server_cmac_request, new_app_key, config_appkey_add_or_update_aid, new_app_key);
987 }
988 
989 static void config_appkey_delete_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
990     mesh_access_parser_state_t parser;
991     mesh_access_parser_init(&parser, (mesh_pdu_t *) pdu);
992 
993     // netkey and appkey index
994     uint32_t netkey_and_appkey_index = mesh_access_parser_get_u24(&parser);
995     uint16_t netkey_index = netkey_and_appkey_index & 0xfff;
996     uint16_t appkey_index = netkey_and_appkey_index >> 12;
997 
998     // check netkey_index is valid
999     mesh_network_key_t * network_key = mesh_network_key_list_get(netkey_index);
1000     if (network_key == NULL){
1001         config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX);
1002         mesh_access_message_processed(pdu);
1003         return;
1004     }
1005 
1006     // check if appkey already exists
1007     mesh_transport_key_t * transport_key = mesh_transport_key_get(appkey_index);
1008     if (transport_key){
1009         mesh_configuration_server_delete_appkey(transport_key);
1010     }
1011 
1012     config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_SUCCESS);
1013     mesh_access_message_processed(pdu);
1014 }
1015 
1016 static void config_appkey_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1017     mesh_access_parser_state_t parser;
1018     mesh_access_parser_init(&parser, (mesh_pdu_t *) pdu);
1019     uint16_t netkey_index = mesh_access_parser_get_u16(&parser);
1020 
1021     config_appkey_list(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_index);
1022     mesh_access_message_processed(pdu);
1023 }
1024 
1025 // Configuration Model Subscriptions (messages)
1026 
1027 static void config_model_subscription_list_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){
1028     UNUSED(mesh_model);
1029 
1030     uint16_t opcode;
1031     if (mesh_model_is_bluetooth_sig(model_identifier)){
1032         opcode = MESH_FOUNDATION_OPERATION_SIG_MODEL_SUBSCRIPTION_LIST;
1033     } else {
1034         opcode = MESH_FOUNDATION_OPERATION_VENDOR_MODEL_SUBSCRIPTION_LIST;
1035     }
1036 
1037     mesh_transport_pdu_t * transport_pdu = mesh_access_transport_init(opcode);
1038     if (!transport_pdu) return;
1039 
1040     // setup segmented message
1041     mesh_access_transport_add_uint8(transport_pdu, status);
1042     mesh_access_transport_add_uint16(transport_pdu, element_address);
1043     mesh_access_transport_add_model_identifier(transport_pdu, model_identifier);
1044 
1045     if (target_model != NULL){
1046         uint16_t i;
1047         for (i = 0; i < MAX_NR_MESH_SUBSCRIPTION_PER_MODEL; i++){
1048             if (target_model->subscriptions[i] == MESH_ADDRESS_UNSASSIGNED) continue;
1049             if (mesh_network_address_virtual(target_model->subscriptions[i])) continue;
1050             mesh_access_transport_add_uint16(transport_pdu, target_model->subscriptions[i]);
1051         }
1052     }
1053     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
1054 }
1055 
1056 static void config_model_subscription_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1057     mesh_access_parser_state_t parser;
1058     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1059 
1060     uint16_t element_address  = mesh_access_parser_get_u16(&parser);
1061     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1062 
1063     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1064     mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1065 
1066     config_model_subscription_list_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, model_identifier, target_model);
1067     mesh_access_message_processed(pdu);
1068 }
1069 
1070 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){
1071     UNUSED(mesh_model);
1072 
1073     // setup message
1074     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_foundation_config_model_subscription_status,
1075                                                                                 status, element_address, address, model_identifier);
1076     if (!transport_pdu) return;
1077     // send as segmented access pdu
1078     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
1079 }
1080 
1081 static void config_model_subscription_add_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1082     mesh_access_parser_state_t parser;
1083     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1084 
1085     uint16_t element_address  = mesh_access_parser_get_u16(&parser);
1086     uint16_t address          = mesh_access_parser_get_u16(&parser);
1087     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1088 
1089     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1090     mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1091 
1092     if (target_model != NULL){
1093         if (mesh_network_address_group(address) && !mesh_network_address_all_nodes(address)){
1094             status = mesh_model_add_subscription(target_model, address);
1095             if (status == MESH_FOUNDATION_STATUS_SUCCESS){
1096                 mesh_model_store_subscriptions(target_model);
1097             }
1098         } else {
1099             status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS;
1100         }
1101     }
1102 
1103     config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, address, model_identifier);
1104     mesh_access_message_processed(pdu);
1105 }
1106 
1107 static void config_model_subscription_virtual_address_add_hash(void *arg){
1108     mesh_model_t * target_model = (mesh_model_t*) arg;
1109     mesh_model_t * mesh_model = mesh_model_get_configuration_server();
1110 
1111     // add if not exists
1112     mesh_virtual_address_t * virtual_address = mesh_virtual_address_for_label_uuid(configuration_server_label_uuid);
1113     if (virtual_address == NULL){
1114         virtual_address = mesh_virtual_address_register(configuration_server_label_uuid, configuration_server_hash);
1115     }
1116 
1117     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1118     uint16_t pseudo_dst = MESH_ADDRESS_UNSASSIGNED;
1119     if (virtual_address == NULL){
1120         status = MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES;
1121     } else {
1122         pseudo_dst = virtual_address->pseudo_dst;
1123         if (!mesh_model_contains_subscription(target_model, pseudo_dst)){
1124             status = mesh_model_add_subscription(target_model, pseudo_dst);
1125             if (status == MESH_FOUNDATION_STATUS_SUCCESS){
1126                 mesh_virtual_address_increase_refcount(virtual_address);
1127                 mesh_model_store_subscriptions(target_model);
1128             }
1129         }
1130     }
1131 
1132     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);
1133     mesh_access_message_processed(access_pdu_in_process);
1134     return;
1135 }
1136 
1137 static void config_model_subscription_virtual_address_add_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1138     mesh_access_parser_state_t parser;
1139     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1140 
1141     // ElementAddress - Address of the element - should be us
1142     configuration_server_element_address = mesh_access_parser_get_u16(&parser);
1143 
1144     // store label uuid
1145     mesh_access_parser_get_label_uuid(&parser, configuration_server_label_uuid);
1146 
1147     // Model Identifier
1148     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1149 
1150     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1151     mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(configuration_server_element_address, model_identifier, &status);
1152 
1153     if (target_model == NULL){
1154         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);
1155         mesh_access_message_processed(pdu);
1156         return;
1157     }
1158 
1159     access_pdu_in_process = pdu;
1160     mesh_virtual_address(&configuration_server_cmac_request, configuration_server_label_uuid, &configuration_server_hash, &config_model_subscription_virtual_address_add_hash, target_model);
1161 }
1162 
1163 static void config_model_subscription_overwrite_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1164     mesh_access_parser_state_t parser;
1165     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1166 
1167     uint16_t element_address  = mesh_access_parser_get_u16(&parser);
1168     uint16_t address          = mesh_access_parser_get_u16(&parser);
1169     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1170 
1171     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1172     mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1173 
1174     if (target_model != NULL){
1175         if (mesh_network_address_group(address) && !mesh_network_address_all_nodes(address)){
1176             mesh_subcription_decrease_virtual_address_ref_count(target_model);
1177             mesh_model_delete_all_subscriptions(mesh_model);
1178             mesh_model_add_subscription(mesh_model, address);
1179             mesh_model_store_subscriptions(target_model);
1180         } else {
1181             status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS;
1182         }
1183     }
1184 
1185     config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, address, model_identifier);
1186     mesh_access_message_processed(pdu);
1187 }
1188 
1189 static void config_model_subscription_virtual_address_overwrite_hash(void *arg){
1190     mesh_model_t * target_model = (mesh_model_t*) arg;
1191     mesh_model_t * mesh_model = mesh_model_get_configuration_server();
1192 
1193     // add if not exists
1194     mesh_virtual_address_t * virtual_address = mesh_virtual_address_for_label_uuid(configuration_server_label_uuid);
1195     if (virtual_address == NULL){
1196         virtual_address = mesh_virtual_address_register(configuration_server_label_uuid, configuration_server_hash);
1197     }
1198 
1199     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1200     uint16_t pseudo_dst = MESH_ADDRESS_UNSASSIGNED;
1201     if (virtual_address == NULL){
1202         status = MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES;
1203     } else {
1204 
1205         // increase refcount first to avoid flash delete + add in a row
1206         mesh_virtual_address_increase_refcount(virtual_address);
1207 
1208         // decrease ref counts for virtual addresses in subscription
1209         mesh_subcription_decrease_virtual_address_ref_count(target_model);
1210 
1211         // clear subscriptions
1212         mesh_model_delete_all_subscriptions(target_model);
1213 
1214         // add new subscription (successfull if MAX_NR_MESH_SUBSCRIPTION_PER_MODEL > 0)
1215         pseudo_dst = virtual_address->pseudo_dst;
1216         mesh_model_add_subscription(target_model, pseudo_dst);
1217 
1218         mesh_model_store_subscriptions(target_model);
1219     }
1220 
1221     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);
1222     mesh_access_message_processed(access_pdu_in_process);
1223     return;
1224 }
1225 
1226 static void config_model_subscription_virtual_address_overwrite_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1227     mesh_access_parser_state_t parser;
1228     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1229 
1230     // ElementAddress - Address of the element - should be us
1231     configuration_server_element_address = mesh_access_parser_get_u16(&parser);
1232 
1233     // store label uuid
1234     mesh_access_parser_get_label_uuid(&parser, configuration_server_label_uuid);
1235 
1236     // Model Identifier
1237     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1238 
1239     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1240     mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(configuration_server_element_address, model_identifier, &status);
1241 
1242     if (target_model == NULL){
1243         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);
1244         mesh_access_message_processed(pdu);
1245         return;
1246     }
1247     access_pdu_in_process = pdu;
1248     mesh_virtual_address(&configuration_server_cmac_request, configuration_server_label_uuid, &configuration_server_hash, &config_model_subscription_virtual_address_overwrite_hash, target_model);
1249 }
1250 
1251 static void config_model_subscription_delete_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1252     mesh_access_parser_state_t parser;
1253     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1254 
1255     uint16_t element_address  = mesh_access_parser_get_u16(&parser);
1256     uint16_t address          = mesh_access_parser_get_u16(&parser);
1257     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1258 
1259     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1260     mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1261 
1262     if (target_model != NULL){
1263         if (mesh_network_address_group(address) && !mesh_network_address_all_nodes(address)){
1264             mesh_model_delete_subscription(target_model, address);
1265             mesh_model_store_subscriptions(target_model);
1266         } else {
1267             status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS;
1268         }
1269     }
1270 
1271     config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, address, model_identifier);
1272     mesh_access_message_processed(pdu);
1273 }
1274 
1275 static void config_model_subscription_virtual_address_delete_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1276     mesh_access_parser_state_t parser;
1277     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1278 
1279     uint16_t element_address  = mesh_access_parser_get_u16(&parser);
1280     mesh_access_parser_get_label_uuid(&parser, configuration_server_label_uuid);
1281     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1282 
1283     mesh_virtual_address_t * virtual_address = mesh_virtual_address_for_label_uuid(configuration_server_label_uuid);
1284     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1285     mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1286 
1287     if ((target_model != NULL) && (virtual_address != NULL) && mesh_model_contains_subscription(target_model, virtual_address->pseudo_dst)){
1288         mesh_virtual_address_decrease_refcount(virtual_address);
1289         mesh_model_delete_subscription(target_model, virtual_address->pseudo_dst);
1290         mesh_model_store_subscriptions(target_model);
1291      }
1292 
1293     config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, virtual_address->hash, model_identifier);
1294     mesh_access_message_processed(pdu);
1295 }
1296 
1297 static void config_model_subscription_delete_all_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1298     mesh_access_parser_state_t parser;
1299     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1300 
1301     uint16_t element_address  = mesh_access_parser_get_u16(&parser);
1302     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1303 
1304     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1305     mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1306 
1307     if (target_model != NULL){
1308         mesh_subcription_decrease_virtual_address_ref_count(target_model);
1309         mesh_model_delete_all_subscriptions(target_model);
1310         mesh_model_store_subscriptions(target_model);
1311     }
1312 
1313     config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, MESH_ADDRESS_UNSASSIGNED, model_identifier);
1314     mesh_access_message_processed(pdu);
1315 }
1316 
1317 // Configuration Model to AppKey List
1318 
1319 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){
1320     UNUSED(mesh_model);
1321 
1322     // setup message
1323     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_foundation_config_model_app_status,
1324                                                             status, element_address, appkey_index, model_identifier);
1325     if (!transport_pdu) return;
1326 
1327     // send as segmented access pdu
1328     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
1329 }
1330 
1331 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){
1332     UNUSED(config_server_model);
1333 
1334     uint16_t opcode;
1335     if (mesh_model_is_bluetooth_sig(model_identifier)){
1336         opcode = MESH_FOUNDATION_OPERATION_SIG_MODEL_APP_LIST;
1337     } else {
1338         opcode = MESH_FOUNDATION_OPERATION_VENDOR_MODEL_APP_LIST;
1339     }
1340     mesh_transport_pdu_t * transport_pdu = mesh_access_transport_init(opcode);
1341     if (!transport_pdu) return;
1342 
1343     mesh_access_transport_add_uint8(transport_pdu, status);
1344     mesh_access_transport_add_uint16(transport_pdu, element_address);
1345     if (mesh_model_is_bluetooth_sig(model_identifier)) {
1346         mesh_access_transport_add_uint16(transport_pdu, mesh_model_get_model_id(model_identifier));
1347     } else {
1348         mesh_access_transport_add_uint32(transport_pdu, model_identifier);
1349     }
1350 
1351     // add list of appkey indexes
1352     if (mesh_model){
1353         uint16_t i;
1354         for (i=0;i<MAX_NR_MESH_APPKEYS_PER_MODEL;i++){
1355             uint16_t appkey_index = mesh_model->appkey_indices[i];
1356             if (appkey_index == MESH_APPKEY_INVALID) continue;
1357             mesh_access_transport_add_uint16(transport_pdu, appkey_index);
1358         }
1359     }
1360 
1361     // send as segmented access pdu
1362     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
1363 }
1364 
1365 static void config_model_app_bind_handler(mesh_model_t *config_server_model, mesh_pdu_t * pdu) {
1366     mesh_access_parser_state_t parser;
1367     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1368 
1369     uint16_t element_address = mesh_access_parser_get_u16(&parser);
1370     uint16_t appkey_index    = mesh_access_parser_get_u16(&parser);
1371     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1372 
1373     uint8_t status;
1374     do {
1375         // validate address and look up model
1376         mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1377         if (target_model == NULL) break;
1378 
1379         // validate app key exists
1380         mesh_transport_key_t * app_key = mesh_transport_key_get(appkey_index);
1381         if (!app_key){
1382             status = MESH_FOUNDATION_STATUS_INVALID_APPKEY_INDEX;
1383             break;
1384         }
1385 
1386         // Configuration Server only allows device keys
1387         if (mesh_model_is_configuration_server(model_identifier)){
1388             status = MESH_FOUNDATION_STATUS_CANNOT_BIND;
1389             break;
1390         }
1391         status = mesh_model_bind_appkey(target_model, appkey_index);
1392 
1393     } while (0);
1394 
1395     config_model_app_status(config_server_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, appkey_index, model_identifier);
1396     mesh_access_message_processed(pdu);
1397 }
1398 
1399 static void config_model_app_unbind_handler(mesh_model_t *config_server_model, mesh_pdu_t * pdu) {
1400     mesh_access_parser_state_t parser;
1401     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1402 
1403     uint16_t element_address = mesh_access_parser_get_u16(&parser);
1404     uint16_t appkey_index    = mesh_access_parser_get_u16(&parser);
1405     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1406 
1407     uint8_t status;
1408     do {
1409         // validate address and look up model
1410         mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1411         if (target_model == NULL) break;
1412 
1413         // validate app key exists
1414         mesh_transport_key_t * app_key = mesh_transport_key_get(appkey_index);
1415         if (!app_key){
1416             status = MESH_FOUNDATION_STATUS_INVALID_APPKEY_INDEX;
1417             break;
1418         }
1419 
1420         // stop publishing
1421         mesh_configuration_server_stop_publishing_using_appkey(target_model, appkey_index);
1422 
1423         // unbind appkey
1424         mesh_model_unbind_appkey(target_model, appkey_index);
1425 
1426         status = MESH_FOUNDATION_STATUS_SUCCESS;
1427     } while (0);
1428 
1429     config_model_app_status(config_server_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, appkey_index, model_identifier);
1430     mesh_access_message_processed(pdu);
1431 }
1432 
1433 static void config_model_app_get_handler(mesh_model_t *config_server_model, mesh_pdu_t * pdu){
1434     mesh_access_parser_state_t parser;
1435     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1436 
1437     uint16_t element_address = mesh_access_parser_get_u16(&parser);
1438     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1439 
1440     uint8_t status;
1441     mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1442     config_model_app_list(config_server_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, model_identifier, target_model);
1443     mesh_access_message_processed(pdu);
1444 }
1445 
1446 // Model Publication
1447 static void config_model_publication_changed(mesh_model_t *mesh_model, mesh_publication_model_t * new_publication_model){
1448 
1449     // stop publication
1450     mesh_model_publication_stop(mesh_model);
1451 
1452     if (new_publication_model->address == MESH_ADDRESS_UNSASSIGNED) {
1453         // "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.
1454         mesh_model->publication_model->address = MESH_ADDRESS_UNSASSIGNED;
1455         mesh_model->publication_model->appkey_index = 0;
1456         mesh_model->publication_model->friendship_credential_flag = 0;
1457         mesh_model->publication_model->period = 0;
1458         mesh_model->publication_model->ttl = 0;
1459         mesh_model->publication_model->retransmit = 0;
1460     } else {
1461         // update model publication state
1462         mesh_model->publication_model->address = new_publication_model->address;
1463         mesh_model->publication_model->appkey_index = new_publication_model->appkey_index;
1464         mesh_model->publication_model->friendship_credential_flag = new_publication_model->friendship_credential_flag;
1465         mesh_model->publication_model->period = new_publication_model->period;
1466         mesh_model->publication_model->ttl = new_publication_model->ttl;
1467         mesh_model->publication_model->retransmit = new_publication_model->retransmit;
1468     }
1469 
1470     // store
1471     mesh_model_store_publication(mesh_model);
1472 
1473     // start publication if address is set (nothing happens if period = 0 and retransmit = 0)
1474     if (new_publication_model->address == MESH_ADDRESS_UNSASSIGNED) return;
1475 
1476     // start to publish
1477     mesh_model_publication_start(mesh_model);
1478 }
1479 
1480 
1481 static void
1482 config_model_publication_status(mesh_model_t *mesh_model, uint16_t netkey_index, uint16_t dest, uint8_t status,
1483                                     uint16_t element_address, uint32_t model_identifier, mesh_publication_model_t *publication_model) {
1484     UNUSED(mesh_model);
1485 
1486     // setup message
1487     uint16_t app_key_index_and_credential_flag = 0;
1488     uint16_t publish_address = 0;
1489     uint8_t ttl = 0;
1490     uint8_t period = 0;
1491     uint8_t retransmit = 0;
1492     if (status == MESH_FOUNDATION_STATUS_SUCCESS){
1493         app_key_index_and_credential_flag = (publication_model->friendship_credential_flag << 12) | publication_model->appkey_index;
1494         ttl = publication_model->ttl;
1495         period = publication_model->period;
1496         retransmit = publication_model->retransmit;
1497 
1498         publish_address = publication_model->address;
1499         if (mesh_network_address_virtual(publish_address)){
1500             mesh_virtual_address_t * virtual_address = mesh_virtual_address_for_pseudo_dst(publish_address);
1501             if (virtual_address){
1502                 publish_address = virtual_address->hash;
1503             }
1504         }
1505     }
1506 
1507     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(
1508             &mesh_foundation_config_model_publication_status, status, element_address, publish_address,
1509             app_key_index_and_credential_flag, ttl, period, retransmit, model_identifier);
1510     if (!transport_pdu) return;
1511 
1512     // send as segmented access pdu
1513     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
1514 }
1515 
1516 static void
1517 config_model_publication_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1518 
1519     // set defaults
1520     memset(&configuration_server_publication_model, 0, sizeof(mesh_publication_model_t));
1521 
1522     mesh_access_parser_state_t parser;
1523     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1524 
1525     // ElementAddress
1526     uint16_t element_address = mesh_access_parser_get_u16(&parser);
1527 
1528     // PublishAddress, 16 bit
1529     configuration_server_publication_model.address = mesh_access_parser_get_u16(&parser);
1530 
1531     // AppKeyIndex (12), CredentialFlag (1), RFU (3)
1532     uint16_t temp = mesh_access_parser_get_u16(&parser);
1533     configuration_server_publication_model.appkey_index = temp & 0x0fff;
1534     configuration_server_publication_model.friendship_credential_flag = (temp >> 12) & 1;
1535 
1536     // TTL
1537     configuration_server_publication_model.ttl        = mesh_access_parser_get_u8(&parser);
1538 
1539     // Period
1540     configuration_server_publication_model.period     = mesh_access_parser_get_u8(&parser);
1541 
1542     // Retransmit
1543     configuration_server_publication_model.retransmit = mesh_access_parser_get_u8(&parser);
1544 
1545     // Model Identifier
1546     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1547 
1548     // Get Model for Element + Model Identifier
1549     uint8_t status;
1550     mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1551 
1552     // Check if publicatation model struct provided
1553     if (status == MESH_FOUNDATION_STATUS_SUCCESS) {
1554         if (target_model->publication_model == NULL){
1555             status = MESH_FOUNDATION_STATUS_CANNOT_SET;
1556         }
1557     }
1558 
1559     // Check AppKey
1560     if (status == MESH_FOUNDATION_STATUS_SUCCESS){
1561         // check if appkey already exists
1562         mesh_transport_key_t * app_key = mesh_transport_key_get(configuration_server_publication_model.appkey_index);
1563         if (app_key == NULL) {
1564             status = MESH_FOUNDATION_STATUS_INVALID_APPKEY_INDEX;
1565         }
1566     }
1567 
1568     // Accept set
1569     if (status == MESH_FOUNDATION_STATUS_SUCCESS){
1570         // decrease ref count if old virtual address
1571         if (mesh_network_address_virtual(configuration_server_publication_model.address)) {
1572             mesh_virtual_address_t * current_virtual_address = mesh_virtual_address_for_pseudo_dst(configuration_server_publication_model.address);
1573             mesh_virtual_address_decrease_refcount(current_virtual_address);
1574         }
1575 
1576         // restart publication
1577         config_model_publication_changed(target_model, &configuration_server_publication_model);
1578     }
1579 
1580     // send status
1581     config_model_publication_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, model_identifier, &configuration_server_publication_model);
1582     mesh_access_message_processed(pdu);
1583 }
1584 
1585 static void config_model_publication_virtual_address_set_hash(void *arg){
1586     mesh_model_t *mesh_model = (mesh_model_t*) arg;
1587 
1588     // add if not exist
1589     mesh_virtual_address_t * virtual_address = mesh_virtual_address_for_label_uuid(configuration_server_label_uuid);
1590     if (virtual_address == NULL){
1591         virtual_address = mesh_virtual_address_register(configuration_server_label_uuid, configuration_server_hash);
1592     }
1593 
1594     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1595     if (virtual_address == NULL){
1596         status = MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES;
1597     } else {
1598 
1599         // increase ref count if new virtual address
1600         mesh_virtual_address_increase_refcount(virtual_address);
1601 
1602         // decrease ref count if old virtual address
1603         if (mesh_network_address_virtual(configuration_server_publication_model.address)) {
1604             mesh_virtual_address_t * current_virtual_address = mesh_virtual_address_for_pseudo_dst(configuration_server_publication_model.address);
1605             if (current_virtual_address){
1606                 mesh_virtual_address_decrease_refcount(current_virtual_address);
1607             }
1608         }
1609 
1610         configuration_server_publication_model.address = virtual_address->pseudo_dst;
1611         mesh_virtual_address_increase_refcount(virtual_address);
1612 
1613         // restart publication
1614         config_model_publication_changed(configuration_server_target_model, &configuration_server_publication_model);
1615     }
1616 
1617     // send status
1618     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);
1619 
1620     mesh_access_message_processed(access_pdu_in_process);
1621 }
1622 
1623 static void
1624 config_model_publication_virtual_address_set_handler(mesh_model_t *mesh_model,
1625                                                      mesh_pdu_t * pdu) {
1626 
1627     // set defaults
1628     memset(&configuration_server_publication_model, 0, sizeof(mesh_publication_model_t));
1629 
1630     mesh_access_parser_state_t parser;
1631     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1632 
1633     // ElementAddress - Address of the element
1634     configuration_server_element_address = mesh_access_parser_get_u16(&parser);
1635 
1636     // store label uuid
1637     mesh_access_parser_get_label_uuid(&parser, configuration_server_label_uuid);
1638 
1639     // AppKeyIndex (12), CredentialFlag (1), RFU (3)
1640     uint16_t temp = mesh_access_parser_get_u16(&parser);
1641     configuration_server_publication_model.appkey_index = temp & 0x0fff;
1642     configuration_server_publication_model.friendship_credential_flag = (temp >> 12) & 1;
1643     configuration_server_publication_model.ttl        = mesh_access_parser_get_u8(&parser);
1644     configuration_server_publication_model.period     = mesh_access_parser_get_u8(&parser);
1645     configuration_server_publication_model.retransmit = mesh_access_parser_get_u8(&parser);
1646 
1647     // Model Identifier
1648     configuration_server_model_identifier = mesh_access_parser_get_model_identifier(&parser);
1649 
1650     // Get Model for Element + Model Identifier
1651     uint8_t status;
1652     configuration_server_target_model = mesh_access_model_for_address_and_model_identifier(configuration_server_element_address, configuration_server_model_identifier, &status);
1653 
1654      // Check if publicatation model struct provided
1655      if (status == MESH_FOUNDATION_STATUS_SUCCESS) {
1656         if (configuration_server_target_model->publication_model == NULL){
1657             status = MESH_FOUNDATION_STATUS_CANNOT_SET;
1658         }
1659      }
1660 
1661      // Check AppKey
1662      if (status == MESH_FOUNDATION_STATUS_SUCCESS){
1663          // check if appkey already exists
1664          mesh_transport_key_t * app_key = mesh_transport_key_get(configuration_server_publication_model.appkey_index);
1665          if (app_key == NULL) {
1666              status = MESH_FOUNDATION_STATUS_INVALID_APPKEY_INDEX;
1667          }
1668      }
1669 
1670     // on error, no need to calculate virtual address hash
1671     if (status != MESH_FOUNDATION_STATUS_SUCCESS){
1672         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);
1673         mesh_access_message_processed(pdu);
1674         return;
1675     }
1676 
1677     access_pdu_in_process = pdu;
1678     mesh_virtual_address(&configuration_server_cmac_request, configuration_server_label_uuid, &configuration_server_hash, &config_model_publication_virtual_address_set_hash, mesh_model);
1679 }
1680 
1681 static void
1682 config_model_publication_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1683 
1684 
1685     mesh_access_parser_state_t parser;
1686     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1687 
1688     // ElementAddress - Address of the element - should be us
1689     uint16_t element_address = mesh_access_parser_get_u16(&parser);
1690 
1691     // Model Identifier
1692     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1693 
1694     // Get Model for Element + Model Identifier
1695     uint8_t status;
1696     mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1697 
1698     mesh_publication_model_t * publication_model;
1699     if (target_model == NULL){
1700         // use defaults
1701         memset(&configuration_server_publication_model, 0, sizeof(mesh_publication_model_t));
1702         publication_model = &configuration_server_publication_model;
1703     } else {
1704         publication_model = target_model->publication_model;
1705     }
1706 
1707     config_model_publication_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, model_identifier, publication_model);
1708     mesh_access_message_processed(pdu);
1709 }
1710 
1711 // Heartbeat Publication
1712 
1713 static void config_heartbeat_publication_emit(mesh_heartbeat_publication_t * mesh_heartbeat_publication){
1714 
1715     printf("CONFIG_SERVER_HEARTBEAT: Emit (dest %04x, count %u, period %u ms)\n",
1716         mesh_heartbeat_publication->destination,
1717         mesh_heartbeat_publication->count,
1718         mesh_heartbeat_publication->period_ms);
1719 
1720     // active features
1721     mesh_heartbeat_publication->active_features = mesh_foundation_get_features();
1722 
1723     mesh_network_pdu_t * network_pdu = mesh_network_pdu_get();
1724     if (network_pdu){
1725         uint8_t data[3];
1726         data[0] = mesh_heartbeat_publication->ttl;
1727         big_endian_store_16(data, 1, mesh_heartbeat_publication->active_features);
1728         mesh_upper_transport_setup_control_pdu((mesh_pdu_t *) network_pdu, mesh_heartbeat_publication->netkey_index,
1729                 mesh_heartbeat_publication->ttl, mesh_node_get_primary_element_address(), mesh_heartbeat_publication->destination,
1730                 MESH_TRANSPORT_OPCODE_HEARTBEAT, data, sizeof(data));
1731         mesh_upper_transport_send_control_pdu((mesh_pdu_t *) network_pdu);
1732     }
1733 
1734     // forever
1735     if (mesh_heartbeat_publication->count < 0xffffu) {
1736         mesh_heartbeat_publication->count--;
1737     }
1738 }
1739 void mesh_configuration_server_feature_changed(void){
1740     mesh_model_t * mesh_model = mesh_model_get_configuration_server();
1741     mesh_heartbeat_publication_t * mesh_heartbeat_publication = &((mesh_configuration_server_model_context_t*) mesh_model->model_data)->heartbeat_publication;
1742 
1743     // active features
1744     uint16_t active_features = mesh_foundation_get_features();
1745     if (mesh_heartbeat_publication->active_features == active_features) return;
1746 
1747     config_heartbeat_publication_emit(mesh_heartbeat_publication);
1748 }
1749 
1750 static void config_heartbeat_publication_timeout_handler(btstack_timer_source_t * ts){
1751 
1752     mesh_heartbeat_publication_t * mesh_heartbeat_publication = (mesh_heartbeat_publication_t*) ts;
1753 
1754     // emit beat
1755     config_heartbeat_publication_emit(mesh_heartbeat_publication);
1756 
1757     // all sent?
1758     if (mesh_heartbeat_publication->count == 0) return;
1759 
1760     // periodic publication?
1761     if (mesh_heartbeat_publication->period_ms == 0) return;
1762 
1763     btstack_run_loop_set_timer(ts, mesh_heartbeat_publication->period_ms);
1764     btstack_run_loop_add_timer(ts);
1765 }
1766 
1767 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){
1768     UNUSED(mesh_model);
1769 
1770     // setup message
1771     uint8_t count_log = heartbeat_count_log(mesh_heartbeat_publication->count);
1772     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(
1773             &mesh_foundation_config_heartbeat_publication_status,
1774             status,
1775             mesh_heartbeat_publication->destination,
1776             count_log,
1777             mesh_heartbeat_publication->period_log,
1778             mesh_heartbeat_publication->ttl,
1779             mesh_heartbeat_publication->features,
1780             mesh_heartbeat_publication->netkey_index);
1781     if (!transport_pdu) return;
1782 
1783     printf("MESH config_heartbeat_publication_status count = %u => count_log = %u\n", mesh_heartbeat_publication->count, count_log);
1784 
1785     // send as segmented access pdu
1786     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
1787 }
1788 
1789 static void config_heartbeat_publication_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1790 
1791     mesh_heartbeat_publication_t requested_publication;
1792 
1793     mesh_access_parser_state_t parser;
1794     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1795 
1796     // Destination address for Heartbeat messages
1797     requested_publication.destination = mesh_access_parser_get_u16(&parser);
1798     // Number of Heartbeat messages to be sent
1799     requested_publication.count = heartbeat_pwr2(mesh_access_parser_get_u8(&parser));
1800     //  Period for sending Heartbeat messages
1801     requested_publication.period_log = mesh_access_parser_get_u8(&parser);
1802     //  TTL to be used when sending Heartbeat messages
1803     requested_publication.ttl = mesh_access_parser_get_u8(&parser);
1804     // Bit field indicating features that trigger Heartbeat messages when changed
1805     requested_publication.features = mesh_access_parser_get_u16(&parser) & MESH_HEARTBEAT_FEATURES_SUPPORTED_MASK;
1806     // NetKey Index
1807     requested_publication.netkey_index = mesh_access_parser_get_u16(&parser);
1808 
1809     // store period as ms
1810     requested_publication.period_ms = heartbeat_pwr2(requested_publication.period_log) * 1000;
1811 
1812     mesh_heartbeat_publication_t * mesh_heartbeat_publication = &((mesh_configuration_server_model_context_t*) mesh_model->model_data)->heartbeat_publication;
1813 
1814     // validate fields
1815     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1816     mesh_network_key_t * network_key = mesh_network_key_list_get(requested_publication.netkey_index);
1817     if (network_key == NULL){
1818         status = MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX;
1819     } else {
1820         printf("MESH config_heartbeat_publication_set, destination %x, count = %x, period = %u s\n",
1821             requested_publication.destination, requested_publication.count, requested_publication.period_ms);
1822 
1823         // accept update
1824         memcpy(mesh_heartbeat_publication, &requested_publication, sizeof(mesh_heartbeat_publication_t));
1825     }
1826 
1827     config_heartbeat_publication_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, mesh_heartbeat_publication);
1828 
1829     mesh_access_message_processed(pdu);
1830 
1831     if (status != MESH_FOUNDATION_STATUS_SUCCESS) return;
1832 
1833     // check if heartbeats should be disabled
1834     if (mesh_heartbeat_publication->destination == MESH_ADDRESS_UNSASSIGNED || mesh_heartbeat_publication->period_log == 0) {
1835         btstack_run_loop_remove_timer(&mesh_heartbeat_publication->timer);
1836         printf("MESH config_heartbeat_publication_set, disable\n");
1837         return;
1838     }
1839 
1840     // NOTE: defer first heartbeat to allow config status getting sent first
1841     btstack_run_loop_set_timer_handler(&mesh_heartbeat_publication->timer, config_heartbeat_publication_timeout_handler);
1842     btstack_run_loop_set_timer_context(&mesh_heartbeat_publication->timer, mesh_heartbeat_publication);
1843     btstack_run_loop_set_timer(&mesh_heartbeat_publication->timer, 2000);
1844     btstack_run_loop_add_timer(&mesh_heartbeat_publication->timer);
1845 }
1846 
1847 static void config_heartbeat_publication_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1848     mesh_heartbeat_publication_t * mesh_heartbeat_publication = &((mesh_configuration_server_model_context_t*) mesh_model->model_data)->heartbeat_publication;
1849     config_heartbeat_publication_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), MESH_FOUNDATION_STATUS_SUCCESS, mesh_heartbeat_publication);
1850     mesh_access_message_processed(pdu);
1851 }
1852 
1853 // Heartbeat Subscription
1854 
1855 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){
1856     UNUSED(mesh_model);
1857 
1858     // setup message
1859     uint8_t count_log = heartbeat_count_log(mesh_heartbeat_subscription->count_log);
1860     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(
1861             &mesh_foundation_config_heartbeat_subscription_status,
1862             status,
1863             mesh_heartbeat_subscription->source,
1864             mesh_heartbeat_subscription->destination,
1865             mesh_heartbeat_subscription->period_log,
1866             count_log,
1867             mesh_heartbeat_subscription->min_hops,
1868             mesh_heartbeat_subscription->max_hops);
1869     if (!transport_pdu) return;
1870     printf("MESH config_heartbeat_subscription_status count = %u => count_log = %u\n", mesh_heartbeat_subscription->count_log, count_log);
1871 
1872     // send as segmented access pdu
1873     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
1874 }
1875 static int config_heartbeat_subscription_enabled(mesh_heartbeat_subscription_t * mesh_heartbeat_subscription){
1876     return mesh_network_address_unicast(mesh_heartbeat_subscription->source) && mesh_heartbeat_subscription->period_log > 0 &&
1877         (mesh_network_address_unicast(mesh_heartbeat_subscription->destination) || mesh_network_address_group(mesh_heartbeat_subscription->destination));
1878 }
1879 
1880 static void config_heartbeat_subscription_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1881     mesh_access_parser_state_t parser;
1882     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1883 
1884     mesh_heartbeat_subscription_t requested_subscription;
1885 
1886     // Destination address for Heartbeat messages
1887     requested_subscription.source = mesh_access_parser_get_u16(&parser);
1888     // Destination address for Heartbeat messages
1889     requested_subscription.destination = mesh_access_parser_get_u16(&parser);
1890     //  Period for sending Heartbeat messages
1891     requested_subscription.period_log = mesh_access_parser_get_u8(&parser);
1892 
1893     uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1894     if (requested_subscription.period_log > 0x11u){
1895         status = MESH_FOUNDATION_STATUS_CANNOT_SET;
1896     } else if ((requested_subscription.source != MESH_ADDRESS_UNSASSIGNED)       &&
1897                !mesh_network_address_unicast(requested_subscription.source)){
1898         status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS;
1899     } else if ((requested_subscription.destination != MESH_ADDRESS_UNSASSIGNED)  &&
1900                !mesh_network_address_unicast(requested_subscription.destination) &&
1901                !mesh_network_address_group(requested_subscription.destination)){
1902         status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS;
1903     }
1904 
1905     if (status != MESH_FOUNDATION_STATUS_SUCCESS){
1906         config_heartbeat_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, &requested_subscription);
1907         mesh_access_message_processed(pdu);
1908         return;
1909     }
1910 
1911     mesh_heartbeat_subscription_t * mesh_heartbeat_subscription = &((mesh_configuration_server_model_context_t*) mesh_model->model_data)->heartbeat_subscription;
1912 
1913     if (config_heartbeat_subscription_enabled(mesh_heartbeat_subscription)){
1914         requested_subscription.count_log  = 0u;
1915         requested_subscription.min_hops   = 0x7Fu;
1916         requested_subscription.max_hops   = 0u;
1917     } else {
1918         requested_subscription.source = MESH_ADDRESS_UNSASSIGNED;
1919         requested_subscription.destination = MESH_ADDRESS_UNSASSIGNED;
1920         requested_subscription.period_log = 0u;
1921         requested_subscription.count_log  = 0u;
1922         requested_subscription.min_hops   = 0u;
1923         requested_subscription.max_hops   = 0u;
1924     }
1925 
1926     // accept request
1927     memcpy(mesh_heartbeat_subscription, &requested_subscription, sizeof(mesh_heartbeat_subscription_t));
1928 
1929     printf("MESH config_heartbeat_subscription_set, destination %x, count = %x, period = %u s\n",
1930             mesh_heartbeat_subscription->destination, mesh_heartbeat_subscription->count_log, heartbeat_pwr2(mesh_heartbeat_subscription->period_log));
1931 
1932     config_heartbeat_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, mesh_heartbeat_subscription);
1933     mesh_access_message_processed(pdu);
1934 }
1935 
1936 
1937 static void config_heartbeat_subscription_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1938     mesh_heartbeat_subscription_t * mesh_heartbeat_subscription = &((mesh_configuration_server_model_context_t*) mesh_model->model_data)->heartbeat_subscription;
1939     config_heartbeat_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), MESH_FOUNDATION_STATUS_SUCCESS, mesh_heartbeat_subscription);
1940     mesh_access_message_processed(pdu);
1941 }
1942 
1943 // KeyRefresh Phase
1944 
1945 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,
1946     mesh_key_refresh_state_t key_refresh_state){
1947     UNUSED(mesh_model);
1948 
1949     // setup message
1950     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(
1951         &mesh_key_refresh_phase_status,
1952         status,
1953         netkey_index,
1954         key_refresh_state);
1955     if (!transport_pdu) return;
1956 
1957     // send as segmented access pdu
1958     config_server_send_message(netkey_index_dest, dest, (mesh_pdu_t *) transport_pdu);
1959 }
1960 
1961 static void config_key_refresh_phase_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1962     mesh_access_parser_state_t parser;
1963     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1964     uint16_t netkey_index = mesh_access_parser_get_u16(&parser);
1965     mesh_subnet_t * subnet = mesh_subnet_get_by_netkey_index(netkey_index);
1966 
1967     uint8_t status = MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX;
1968     mesh_key_refresh_state_t key_refresh_state = MESH_KEY_REFRESH_NOT_ACTIVE;
1969 
1970     if (subnet != NULL){
1971         status = MESH_FOUNDATION_STATUS_SUCCESS;
1972         key_refresh_state = subnet->key_refresh;
1973     }
1974 
1975     config_key_refresh_phase_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, netkey_index, key_refresh_state);
1976     mesh_access_message_processed(pdu);
1977 }
1978 
1979 static void config_key_refresh_phase_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1980     mesh_access_parser_state_t parser;
1981     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1982     uint16_t netkey_index = mesh_access_parser_get_u16(&parser);
1983     uint8_t  key_refresh_phase_transition = mesh_access_parser_get_u8(&parser);
1984     mesh_subnet_t * subnet = mesh_subnet_get_by_netkey_index(netkey_index);
1985 
1986     uint8_t status = MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX;
1987 
1988     if (subnet != NULL){
1989         status = MESH_FOUNDATION_STATUS_SUCCESS;
1990 
1991         switch (key_refresh_phase_transition){
1992             case 0x02:
1993                 switch (subnet->key_refresh){
1994                     case MESH_KEY_REFRESH_FIRST_PHASE:
1995                     case MESH_KEY_REFRESH_SECOND_PHASE:
1996                         subnet->key_refresh = MESH_KEY_REFRESH_SECOND_PHASE;
1997                         break;
1998                     default:
1999                         break;
2000                 }
2001                 break;
2002             case 0x03:
2003                 switch (subnet->key_refresh){
2004                     case MESH_KEY_REFRESH_FIRST_PHASE:
2005                     case MESH_KEY_REFRESH_SECOND_PHASE:
2006                         // key refresh phase 3 entered
2007                         mesh_access_key_refresh_revoke_keys(subnet);
2008                         subnet->key_refresh = MESH_KEY_REFRESH_NOT_ACTIVE;
2009                         break;
2010                     default:
2011                         break;
2012                 }
2013                 break;
2014             default:
2015                 status = MESH_FOUNDATION_STATUS_CANNOT_SET;
2016                 break;
2017         }
2018     }
2019 
2020     config_key_refresh_phase_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, netkey_index, subnet->key_refresh);
2021     mesh_access_message_processed(pdu);
2022 }
2023 
2024 
2025 static void config_node_reset_status(mesh_model_t *mesh_model, uint16_t netkey_index, uint16_t dest){
2026     UNUSED(mesh_model);
2027 
2028     // setup message
2029     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_foundation_node_reset_status);
2030     if (!transport_pdu) return;
2031 
2032     // send as segmented access pdu
2033     config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
2034 }
2035 
2036 static void config_node_reset_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
2037     mesh_node_reset();
2038     config_node_reset_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
2039     mesh_access_message_processed(pdu);
2040 }
2041 
2042 static void low_power_node_poll_timeout_status(mesh_model_t *mesh_model, uint16_t netkey_index_dest, uint16_t dest, uint8_t status){
2043     UNUSED(mesh_model);
2044 
2045     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(
2046         &mesh_foundation_low_power_node_poll_timeout_status,
2047         status,
2048         0,  // The unicast address of the Low Power node
2049         0); // The current value of the PollTimeout timer of the Low Power node
2050     if (!transport_pdu) return;
2051     printf("TODO: send unicast address of the Low Power node and the current value of the PollTimeout timer, instead of 0s\n");
2052     // send as segmented access pdu
2053     config_server_send_message(netkey_index_dest, dest, (mesh_pdu_t *) transport_pdu);
2054 }
2055 
2056 static void config_low_power_node_poll_timeout_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
2057     mesh_access_parser_state_t parser;
2058     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
2059     printf("TODO: implement get the current value of PollTimeout timer of the Low Power node within a Friend node\n");
2060     low_power_node_poll_timeout_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), MESH_FOUNDATION_STATUS_SUCCESS);
2061 
2062     mesh_access_message_processed(pdu);
2063 }
2064 
2065 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,
2066     mesh_node_identity_state_t node_identity_state){
2067     UNUSED(mesh_model);
2068 
2069     // setup message
2070     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(
2071         &mesh_foundation_node_identity_status,
2072         status,
2073         netkey_index,
2074         node_identity_state);
2075     if (!transport_pdu) return;
2076 
2077     // send as segmented access pdu
2078     config_server_send_message(netkey_index_dest, dest, (mesh_pdu_t *) transport_pdu);
2079 }
2080 
2081 static void config_node_identity_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
2082     mesh_access_parser_state_t parser;
2083     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
2084     uint16_t netkey_index = mesh_access_parser_get_u16(&parser);
2085 
2086     mesh_node_identity_state_t node_identity_state = MESH_NODE_IDENTITY_STATE_ADVERTISING_NOT_SUPPORTED;
2087     uint8_t status = mesh_proxy_get_advertising_with_node_id_status(netkey_index, &node_identity_state);
2088 
2089     config_node_identity_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, netkey_index, node_identity_state);
2090 
2091     mesh_access_message_processed(pdu);
2092 }
2093 
2094 static void config_node_identity_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
2095     mesh_access_parser_state_t parser;
2096     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
2097     uint16_t netkey_index = mesh_access_parser_get_u16(&parser);
2098     mesh_node_identity_state_t node_identity_state = (mesh_node_identity_state_t) mesh_access_parser_get_u8(&parser);
2099 
2100     uint8_t status = mesh_proxy_set_advertising_with_node_id(netkey_index, node_identity_state);
2101 
2102     config_node_identity_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, netkey_index, node_identity_state);
2103 
2104     mesh_access_message_processed(pdu);
2105 }
2106 
2107 //
2108 
2109 const static mesh_operation_t mesh_configuration_server_model_operations[] = {
2110     { MESH_FOUNDATION_OPERATION_APPKEY_ADD,                                  19, config_appkey_add_handler },
2111     { MESH_FOUNDATION_OPERATION_APPKEY_DELETE,                                3, config_appkey_delete_handler },
2112     { MESH_FOUNDATION_OPERATION_APPKEY_GET,                                   2, config_appkey_get_handler },
2113     { MESH_FOUNDATION_OPERATION_APPKEY_UPDATE,                               19, config_appkey_update_handler },
2114     { MESH_FOUNDATION_OPERATION_NETKEY_ADD,                                  18, config_netkey_add_handler },
2115     { MESH_FOUNDATION_OPERATION_NETKEY_UPDATE,                               18, config_netkey_update_handler },
2116     { MESH_FOUNDATION_OPERATION_NETKEY_DELETE,                                2, config_netkey_delete_handler },
2117     { MESH_FOUNDATION_OPERATION_NETKEY_GET,                                   0, config_netkey_get_handler },
2118     { MESH_FOUNDATION_OPERATION_COMPOSITION_DATA_GET,                         1, config_composition_data_get_handler },
2119     { MESH_FOUNDATION_OPERATION_BEACON_GET,                                   0, config_beacon_get_handler },
2120     { MESH_FOUNDATION_OPERATION_BEACON_SET,                                   1, config_beacon_set_handler },
2121     { MESH_FOUNDATION_OPERATION_DEFAULT_TTL_GET,                              0, config_default_ttl_get_handler },
2122     { MESH_FOUNDATION_OPERATION_DEFAULT_TTL_SET,                              1, config_default_ttl_set_handler },
2123     { MESH_FOUNDATION_OPERATION_FRIEND_GET,                                   0, config_friend_get_handler },
2124     { MESH_FOUNDATION_OPERATION_FRIEND_SET,                                   1, config_friend_set_handler },
2125     { MESH_FOUNDATION_OPERATION_NETWORK_TRANSMIT_GET,                         0, config_model_network_transmit_get_handler },
2126     { MESH_FOUNDATION_OPERATION_NETWORK_TRANSMIT_SET,                         1, config_model_network_transmit_set_handler },
2127     { MESH_FOUNDATION_OPERATION_GATT_PROXY_GET,                               0, config_gatt_proxy_get_handler },
2128     { MESH_FOUNDATION_OPERATION_GATT_PROXY_SET,                               1, config_gatt_proxy_set_handler },
2129     { MESH_FOUNDATION_OPERATION_RELAY_GET,                                    0, config_relay_get_handler },
2130     { MESH_FOUNDATION_OPERATION_RELAY_SET,                                    1, config_relay_set_handler },
2131     { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_ADD,                       6, config_model_subscription_add_handler },
2132     { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_ADD,      20, config_model_subscription_virtual_address_add_handler },
2133     { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_DELETE,                    6, config_model_subscription_delete_handler },
2134     { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_DELETE,   20, config_model_subscription_virtual_address_delete_handler },
2135     { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_OVERWRITE,                 6, config_model_subscription_overwrite_handler },
2136     { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_OVERWRITE,20, config_model_subscription_virtual_address_overwrite_handler },
2137     { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_DELETE_ALL,                4, config_model_subscription_delete_all_handler },
2138     { MESH_FOUNDATION_OPERATION_SIG_MODEL_SUBSCRIPTION_GET,                   4, config_model_subscription_get_handler },
2139     { MESH_FOUNDATION_OPERATION_VENDOR_MODEL_SUBSCRIPTION_GET,                6, config_model_subscription_get_handler },
2140     { MESH_FOUNDATION_OPERATION_SIG_MODEL_APP_GET,                            4, config_model_app_get_handler },
2141     { MESH_FOUNDATION_OPERATION_VENDOR_MODEL_APP_GET,                         6, config_model_app_get_handler },
2142     { MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_SET,                       11, config_model_publication_set_handler },
2143     { MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_VIRTUAL_ADDRESS_SET,       25, config_model_publication_virtual_address_set_handler },
2144     { MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_GET,                        4, config_model_publication_get_handler },
2145     { MESH_FOUNDATION_OPERATION_MODEL_APP_BIND,                               6, config_model_app_bind_handler },
2146     { MESH_FOUNDATION_OPERATION_MODEL_APP_UNBIND,                             6, config_model_app_unbind_handler },
2147     { MESH_FOUNDATION_OPERATION_HEARTBEAT_PUBLICATION_GET,                    0, config_heartbeat_publication_get_handler },
2148     { MESH_FOUNDATION_OPERATION_HEARTBEAT_PUBLICATION_SET,                    9, config_heartbeat_publication_set_handler },
2149     { MESH_FOUNDATION_OPERATION_HEARTBEAT_SUBSCRIPTION_GET,                   0, config_heartbeat_subscription_get_handler},
2150     { MESH_FOUNDATION_OPERATION_HEARTBEAT_SUBSCRIPTION_SET,                   5, config_heartbeat_subscription_set_handler},
2151     { MESH_FOUNDATION_OPERATION_KEY_REFRESH_PHASE_GET,                        2, config_key_refresh_phase_get_handler },
2152     { MESH_FOUNDATION_OPERATION_KEY_REFRESH_PHASE_SET,                        3, config_key_refresh_phase_set_handler },
2153     { MESH_FOUNDATION_OPERATION_NODE_RESET,                                   0, config_node_reset_handler },
2154     { MESH_FOUNDATION_OPERATION_LOW_POWER_NODE_POLL_TIMEOUT_GET,              2, config_low_power_node_poll_timeout_get_handler },
2155     { MESH_FOUNDATION_OPERATION_NODE_IDENTITY_GET,                            2, config_node_identity_get_handler },
2156     { MESH_FOUNDATION_OPERATION_NODE_IDENTITY_SET,                            3, config_node_identity_set_handler },
2157     { 0, 0, NULL }
2158 };
2159 
2160 const mesh_operation_t * mesh_configuration_server_get_operations(void){
2161     return mesh_configuration_server_model_operations;
2162 }
2163 
2164