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