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