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