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