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