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