xref: /btstack/src/mesh/mesh_configuration_client.c (revision b629980d78242a435bb137d16ea0ab5c47ebfca9)
1 /*
2  * Copyright (C) 2019 BlueKitchen GmbH
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holders nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  * 4. Any redistribution, use, or modification is done solely for
17  *    personal benefit and not for any commercial purpose or for
18  *    monetary gain.
19  *
20  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Please inquire about commercial licensing options at
34  * [email protected]
35  *
36  */
37 
38 #define BTSTACK_FILE__ "mesh_configuration_client.c"
39 
40 #include <string.h>
41 #include <stdio.h>
42 
43 #include "mesh/mesh_configuration_client.h"
44 
45 #include "bluetooth_company_id.h"
46 #include "btstack_debug.h"
47 #include "btstack_memory.h"
48 #include "btstack_util.h"
49 
50 #include "mesh/mesh_access.h"
51 #include "mesh/mesh_foundation.h"
52 #include "mesh/mesh_generic_model.h"
53 #include "mesh/mesh_keys.h"
54 #include "mesh/mesh_network.h"
55 #include "mesh/mesh_upper_transport.h"
56 
57 
58 // Mesh Composition Data Element iterator
59 #define MESH_VENDOR_MODEL_SIZE                                  4
60 #define MESH_SIG_MODEL_SIZE                                     2
61 #define MESH_COMPOSITION_DATA_ELEMENT_DESCRIPTION_OFFSET       17
62 #define MESH_COMPOSITION_DATA_ELEMENT_LOCATION_DESCRIPTOR_LEN   2
63 #define MESH_COMPOSITION_DATA_ELEMENT_MODEL_SIZE_LEN            1
64 
65 static inline uint16_t mesh_composition_data_iterator_sig_model_list_size(mesh_composite_data_iterator_t * it){
66     return it->elements[it->offset + 2] * MESH_SIG_MODEL_SIZE;
67 }
68 
69 static inline uint16_t mesh_composition_data_iterator_vendor_model_list_size(mesh_composite_data_iterator_t * it){
70     return it->elements[it->offset + 3] * MESH_VENDOR_MODEL_SIZE;
71 }
72 
73 static inline uint16_t mesh_composition_data_iterator_element_len(mesh_composite_data_iterator_t * it){
74     uint16_t sig_model_list_size    = mesh_composition_data_iterator_sig_model_list_size(it);
75     uint16_t vendor_model_list_size = mesh_composition_data_iterator_vendor_model_list_size(it);
76     uint16_t previous_fields_len = MESH_COMPOSITION_DATA_ELEMENT_LOCATION_DESCRIPTOR_LEN + 2 * MESH_COMPOSITION_DATA_ELEMENT_MODEL_SIZE_LEN;
77 
78     return previous_fields_len + sig_model_list_size + vendor_model_list_size;;
79 }
80 
81 uint16_t mesh_subevent_configuration_composition_data_get_num_elements(const uint8_t * event, uint16_t size){
82     uint16_t pos = MESH_COMPOSITION_DATA_ELEMENT_DESCRIPTION_OFFSET;
83     uint16_t num_elements = 0;
84 
85     while ((pos + 4) <= size){
86         // location descriptor
87         pos += 2;
88         uint8_t num_sig_model_ids = event[pos++];
89         uint8_t num_vendor_model_ids = event[pos++];
90         pos += (num_sig_model_ids + num_vendor_model_ids) * 2;
91         num_elements++;
92     }
93     return num_elements;
94 }
95 
96 void mesh_composition_data_iterator_init(mesh_composite_data_iterator_t * it, const uint8_t * elements, uint16_t size){
97     it->elements = elements;
98     it->size = size;
99     it->offset = MESH_COMPOSITION_DATA_ELEMENT_DESCRIPTION_OFFSET;
100 }
101 
102 bool mesh_composition_data_iterator_has_next_element(mesh_composite_data_iterator_t * it){
103     return (it->offset + mesh_composition_data_iterator_element_len(it)) <= it->size;
104 }
105 
106 void mesh_composition_data_iterator_next_element(mesh_composite_data_iterator_t * it){
107     it->sig_model_iterator.models = &it->elements[it->offset + 4];
108     it->sig_model_iterator.size = mesh_composition_data_iterator_sig_model_list_size(it);
109     it->sig_model_iterator.offset = 0;
110 
111     it->vendor_model_iterator.models = &it->elements[it->offset + 4 + it->sig_model_iterator.size];
112     it->vendor_model_iterator.size = mesh_composition_data_iterator_vendor_model_list_size(it);
113     it->vendor_model_iterator.offset = 0;
114 
115     it->loc = little_endian_read_16(it->elements, it->offset);
116     it->offset += mesh_composition_data_iterator_element_len(it);
117 }
118 
119 uint16_t mesh_composition_data_iterator_element_loc(mesh_composite_data_iterator_t * it){
120     return it->loc;
121 }
122 
123 bool mesh_composition_data_iterator_has_next_sig_model(mesh_composite_data_iterator_t * it){
124     return (it->sig_model_iterator.offset + MESH_SIG_MODEL_SIZE) <= it->sig_model_iterator.size;
125 }
126 
127 void mesh_composition_data_iterator_next_sig_model(mesh_composite_data_iterator_t * it){
128     it->sig_model_iterator.id = little_endian_read_16(it->sig_model_iterator.models, it->sig_model_iterator.offset);
129     it->sig_model_iterator.offset += 2;
130 }
131 
132 uint16_t mesh_composition_data_iterator_sig_model_id(mesh_composite_data_iterator_t * it){
133     return (uint16_t)it->sig_model_iterator.id;
134 }
135 
136 bool mesh_composition_data_iterator_has_next_vendor_model(mesh_composite_data_iterator_t * it){
137     return (it->vendor_model_iterator.offset + MESH_VENDOR_MODEL_SIZE) <= it->vendor_model_iterator.size;
138 }
139 
140 void mesh_composition_data_iterator_next_vendor_model(mesh_composite_data_iterator_t * it){
141     uint16_t vendor_id = little_endian_read_16(it->vendor_model_iterator.models, it->vendor_model_iterator.offset);
142     it->vendor_model_iterator.offset += 2;
143     uint16_t model_id = little_endian_read_16(it->vendor_model_iterator.models, it->vendor_model_iterator.offset);
144     it->vendor_model_iterator.offset += 2;
145     it->vendor_model_iterator.id = mesh_model_get_model_identifier(vendor_id, model_id);
146 }
147 
148 uint32_t mesh_composition_data_iterator_vendor_model_id(mesh_composite_data_iterator_t * it){
149     return it->vendor_model_iterator.id;
150 }
151 
152 // Configuration client messages
153 
154 static const mesh_access_message_t mesh_configuration_client_beacon_get = {
155         MESH_FOUNDATION_OPERATION_BEACON_GET, ""
156 };
157 static const mesh_access_message_t mesh_configuration_client_beacon_set = {
158         MESH_FOUNDATION_OPERATION_BEACON_SET, "1"
159 };
160 
161 
162 static const mesh_access_message_t mesh_configuration_client_composition_data_get = {
163         MESH_FOUNDATION_OPERATION_COMPOSITION_DATA_GET, "1"
164 };
165 
166 
167 static const mesh_access_message_t mesh_configuration_client_default_ttl_get = {
168         MESH_FOUNDATION_OPERATION_DEFAULT_TTL_GET, ""
169 };
170 static const mesh_access_message_t mesh_configuration_client_default_ttl_set = {
171         MESH_FOUNDATION_OPERATION_DEFAULT_TTL_SET, "1"
172 };
173 
174 
175 static const mesh_access_message_t mesh_configuration_client_gatt_proxy_get = {
176         MESH_FOUNDATION_OPERATION_GATT_PROXY_GET, ""
177 };
178 static const mesh_access_message_t mesh_configuration_client_gatt_proxy_set = {
179         MESH_FOUNDATION_OPERATION_GATT_PROXY_SET, "1"
180 };
181 
182 
183 static const mesh_access_message_t mesh_configuration_client_relay_get = {
184         MESH_FOUNDATION_OPERATION_RELAY_GET, ""
185 };
186 static const mesh_access_message_t mesh_configuration_client_relay_set = {
187         MESH_FOUNDATION_OPERATION_RELAY_SET, "11"
188 };
189 
190 static const mesh_access_message_t mesh_configuration_client_model_publication_get = {
191         MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_GET, "2m"
192 };
193 static const mesh_access_message_t mesh_configuration_client_model_publication_set = {
194         MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_SET, "222111m"
195 };
196 static const mesh_access_message_t mesh_configuration_client_model_publication_virtual_address_set = {
197         MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_VIRTUAL_ADDRESS_SET, "2P2111m"
198 };
199 
200 
201 static const mesh_access_message_t mesh_configuration_client_model_subscription_add = {
202         MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_ADD, "22m"
203 };
204 static const mesh_access_message_t mesh_configuration_client_model_subscription_virtual_address_add = {
205         MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_ADD, "2Pm"
206 };
207 static const mesh_access_message_t mesh_configuration_client_model_subscription_delete = {
208         MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_DELETE, "22m"
209 };
210 static const mesh_access_message_t mesh_configuration_client_model_subscription_virtual_address_delete = {
211         MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_DELETE, "2Pm"
212 };
213 static const mesh_access_message_t mesh_configuration_client_model_subscription_overwrite = {
214         MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_OVERWRITE, "22m"
215 };
216 static const mesh_access_message_t mesh_configuration_client_model_subscription_virtual_address_overwrite = {
217         MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_OVERWRITE, "2Pm"
218 };
219 static const mesh_access_message_t mesh_configuration_client_model_subscription_delete_all = {
220         MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_DELETE_ALL, "22m"
221 };
222 
223 
224 static const mesh_access_message_t mesh_configuration_client_sig_model_subscription_get = {
225         MESH_FOUNDATION_OPERATION_SIG_MODEL_SUBSCRIPTION_GET, "22"
226 };
227 
228 static const mesh_access_message_t mesh_configuration_client_vendor_model_subscription_get = {
229         MESH_FOUNDATION_OPERATION_VENDOR_MODEL_SUBSCRIPTION_GET, "24"
230 };
231 
232 static const mesh_access_message_t mesh_configuration_client_netkey_add = {
233         MESH_FOUNDATION_OPERATION_NETKEY_ADD, "2P"
234 };
235 static const mesh_access_message_t mesh_configuration_client_netkey_update = {
236         MESH_FOUNDATION_OPERATION_NETKEY_UPDATE, "2P"
237 };
238 static const mesh_access_message_t mesh_configuration_client_netkey_delete = {
239         MESH_FOUNDATION_OPERATION_NETKEY_DELETE, "2"
240 };
241 static const mesh_access_message_t mesh_configuration_client_netkey_get = {
242         MESH_FOUNDATION_OPERATION_NETKEY_GET, ""
243 };
244 
245 
246 static const mesh_access_message_t mesh_configuration_client_appkey_add = {
247         MESH_FOUNDATION_OPERATION_APPKEY_ADD, "3P"
248 };
249 static const mesh_access_message_t mesh_configuration_client_appkey_update = {
250         MESH_FOUNDATION_OPERATION_APPKEY_UPDATE, "3P"
251 };
252 static const mesh_access_message_t mesh_configuration_client_appkey_delete = {
253         MESH_FOUNDATION_OPERATION_APPKEY_DELETE, "3"
254 };
255 static const mesh_access_message_t mesh_configuration_client_appkey_get = {
256         MESH_FOUNDATION_OPERATION_APPKEY_GET, "2"
257 };
258 
259 static void mesh_configuration_client_send_acknowledged(uint16_t src, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, mesh_pdu_t *pdu, uint32_t ack_opcode){
260     uint8_t  ttl  = mesh_foundation_default_ttl_get();
261     mesh_upper_transport_setup_access_pdu_header(pdu, netkey_index, appkey_index, ttl, src, dest, 0);
262     mesh_access_send_acknowledged_pdu(pdu, mesh_access_acknowledged_message_retransmissions(), ack_opcode);
263 }
264 
265 static uint8_t mesh_access_validate_envelop_params(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
266     btstack_assert(mesh_model != NULL);
267     // TODO: validate other params
268     UNUSED(mesh_model);
269     UNUSED(dest);
270     UNUSED(netkey_index);
271     UNUSED(appkey_index);
272 
273     return ERROR_CODE_SUCCESS;
274 }
275 
276 uint8_t mesh_configuration_client_send_beacon_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
277     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
278     if (status != ERROR_CODE_SUCCESS) return status;
279 
280     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_beacon_get);
281     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
282 
283     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_BEACON_STATUS);
284     return ERROR_CODE_SUCCESS;
285 }
286 
287 uint8_t mesh_configuration_client_send_beacon_set(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint8_t beacon){
288     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
289     if (status != ERROR_CODE_SUCCESS) return status;
290 
291     if (beacon > 1) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
292 
293     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_beacon_set, beacon);
294     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
295 
296     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_BEACON_STATUS);
297     return ERROR_CODE_SUCCESS;
298 }
299 
300 uint8_t mesh_configuration_client_send_composition_data_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint8_t page){
301     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
302     if (status != ERROR_CODE_SUCCESS) return status;
303 
304     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_composition_data_get, page);
305     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
306 
307     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_COMPOSITION_DATA_STATUS);
308     return ERROR_CODE_SUCCESS;
309 }
310 
311 uint8_t mesh_configuration_client_send_default_ttl_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
312     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
313     if (status != ERROR_CODE_SUCCESS) return status;
314 
315     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_default_ttl_get);
316     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
317 
318     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_DEFAULT_TTL_STATUS);
319     return ERROR_CODE_SUCCESS;
320 }
321 
322 uint8_t mesh_configuration_client_send_default_ttl_set(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint8_t ttl){
323     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
324     if (status != ERROR_CODE_SUCCESS) return status;
325 
326     if (ttl == 0x01 || ttl >= 0x80) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
327 
328     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_default_ttl_set, ttl);
329     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
330 
331     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_DEFAULT_TTL_STATUS);
332     return ERROR_CODE_SUCCESS;
333 }
334 
335 uint8_t mesh_configuration_client_send_gatt_proxy_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
336     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
337     if (status != ERROR_CODE_SUCCESS) return status;
338 
339     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_gatt_proxy_get);
340     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
341 
342     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_GATT_PROXY_STATUS);
343     return ERROR_CODE_SUCCESS;
344 }
345 
346 uint8_t mesh_configuration_client_send_gatt_proxy_set(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint8_t gatt_proxy_state){
347     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
348     if (status != ERROR_CODE_SUCCESS) return status;
349 
350     if (gatt_proxy_state > 2) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
351 
352     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_gatt_proxy_set, gatt_proxy_state);
353     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
354 
355     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_GATT_PROXY_STATUS);
356     return ERROR_CODE_SUCCESS;
357 }
358 
359 uint8_t mesh_configuration_client_send_relay_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
360     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
361     if (status != ERROR_CODE_SUCCESS) return status;
362 
363     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_relay_get);
364     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
365 
366     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_RELAY_STATUS);
367     return ERROR_CODE_SUCCESS;
368 }
369 
370 uint8_t mesh_configuration_client_send_relay_set(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint8_t relay, uint8_t relay_retransmit_count, uint8_t relay_retransmit_interval_steps){
371     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
372     if (status != ERROR_CODE_SUCCESS) return status;
373 
374     if (relay_retransmit_count > 0x07) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
375     if (relay_retransmit_interval_steps > 0x1F) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
376 
377     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_relay_set, relay, (relay_retransmit_count << 5) | relay_retransmit_interval_steps);
378     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
379 
380     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_RELAY_SET);
381     return ERROR_CODE_SUCCESS;
382 }
383 
384 uint8_t mesh_configuration_client_send_model_publication_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint32_t model_id){
385     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
386     if (status != ERROR_CODE_SUCCESS) return status;
387 
388     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_publication_get, dest, model_id);
389     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
390 
391     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_STATUS);
392     return ERROR_CODE_SUCCESS;
393 }
394 
395 static uint8_t mesh_validate_publication_model_config_parameters(mesh_publication_model_config_t * publication_config, bool use_unicast_address){
396     if (publication_config->appkey_index > 0xFFF) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
397     if (publication_config->credential_flag > 1) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
398     if (publication_config->publish_retransmit_count > 0x07) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
399     if (publication_config->publish_retransmit_interval_steps > 0x1F) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
400     if (use_unicast_address && mesh_network_address_virtual(publication_config->publish_address_unicast)) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
401     return ERROR_CODE_SUCCESS;
402 }
403 
404 uint8_t mesh_configuration_client_send_model_publication_set(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint32_t model_id, mesh_publication_model_config_t * publication_config){
405     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
406     if (status != ERROR_CODE_SUCCESS) return status;
407 
408     if (!mesh_network_address_unicast(dest) ||
409         mesh_validate_publication_model_config_parameters(publication_config, true) != ERROR_CODE_SUCCESS){
410         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
411     }
412 
413     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_publication_set,
414         dest,
415         publication_config->publish_address_unicast,
416         (publication_config->credential_flag << 12) | publication_config->appkey_index,
417         publication_config->publish_ttl,
418         publication_config->publish_period,
419         (publication_config->publish_retransmit_interval_steps << 3) | publication_config->publish_retransmit_count,
420         model_id);
421     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
422 
423     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_STATUS);
424     return ERROR_CODE_SUCCESS;
425 
426 }
427 
428 uint8_t mesh_configuration_client_send_model_publication_virtual_address_set(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint32_t model_id, mesh_publication_model_config_t * publication_config){
429     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
430     if (status != ERROR_CODE_SUCCESS) return status;
431 
432     if (!mesh_network_address_unicast(dest) ||
433         mesh_validate_publication_model_config_parameters(publication_config, false) != ERROR_CODE_SUCCESS){
434         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
435     }
436 
437     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_model_publication_virtual_address_set,
438         dest,
439         publication_config->publish_address_virtual,
440         (publication_config->credential_flag << 12) | publication_config->appkey_index,
441         publication_config->publish_ttl,
442         publication_config->publish_period,
443         (publication_config->publish_retransmit_interval_steps << 3) | publication_config->publish_retransmit_count,
444         model_id);
445     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
446 
447     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) transport_pdu, MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_STATUS);
448     return ERROR_CODE_SUCCESS;
449 }
450 
451 
452 uint8_t mesh_configuration_client_send_model_subscription_add(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint16_t address, uint32_t model_id){
453     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
454     if (status != ERROR_CODE_SUCCESS) return status;
455 
456     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_subscription_add, dest, address, model_id);
457     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
458 
459     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_STATUS);
460     return ERROR_CODE_SUCCESS;
461 }
462 
463 uint8_t mesh_configuration_client_send_model_subscription_virtual_address_add(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint8_t * address, uint32_t model_id){
464     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
465     if (status != ERROR_CODE_SUCCESS) return status;
466 
467     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_model_subscription_virtual_address_add, dest, address, model_id);
468     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
469 
470     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) transport_pdu, MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_STATUS);
471     return ERROR_CODE_SUCCESS;
472 }
473 
474 uint8_t mesh_configuration_client_send_model_subscription_delete(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint16_t address, uint32_t model_id){
475     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
476     if (status != ERROR_CODE_SUCCESS) return status;
477 
478     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_subscription_delete, dest, address, model_id);
479     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
480 
481     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_STATUS);
482     return ERROR_CODE_SUCCESS;
483 }
484 
485 uint8_t mesh_configuration_client_send_model_subscription_virtual_address_delete(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint8_t * address, uint32_t model_id){
486     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
487     if (status != ERROR_CODE_SUCCESS) return status;
488 
489     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_model_subscription_virtual_address_delete, dest, address, model_id);
490     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
491 
492     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) transport_pdu, MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_STATUS);
493     return ERROR_CODE_SUCCESS;
494 }
495 
496 uint8_t mesh_configuration_client_send_model_subscription_overwrite(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint16_t address, uint32_t model_id){
497         uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
498     if (status != ERROR_CODE_SUCCESS) return status;
499 
500     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_subscription_overwrite, dest, address, model_id);
501     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
502 
503     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_STATUS);
504     return ERROR_CODE_SUCCESS;
505 }
506 
507 uint8_t mesh_configuration_client_send_model_subscription_virtual_address_overwrite(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint8_t * address, uint32_t model_id){
508     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
509     if (status != ERROR_CODE_SUCCESS) return status;
510 
511     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_model_subscription_virtual_address_overwrite, dest, address, model_id);
512     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
513 
514     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) transport_pdu, MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_STATUS);
515     return ERROR_CODE_SUCCESS;
516 }
517 
518 uint8_t mesh_configuration_client_send_model_subscription_delete_all(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint16_t address, uint32_t model_id){
519         uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
520     if (status != ERROR_CODE_SUCCESS) return status;
521 
522     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_subscription_delete_all, dest, address, model_id);
523     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
524 
525     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_STATUS);
526     return ERROR_CODE_SUCCESS;
527 }
528 
529 uint8_t mesh_configuration_client_send_model_subscription_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint32_t model_id){
530     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
531     if (status != ERROR_CODE_SUCCESS) return status;
532 
533     mesh_network_pdu_t * network_pdu = NULL;
534     uint32_t ack_opcode = MESH_FOUNDATION_OPERATION_SIG_MODEL_SUBSCRIPTION_LIST;
535 
536     if (mesh_model_is_bluetooth_sig(model_id)){
537         network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_sig_model_subscription_get, dest, model_id);
538     } else {
539         network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_vendor_model_subscription_get, dest, model_id);
540         ack_opcode = MESH_FOUNDATION_OPERATION_VENDOR_MODEL_SUBSCRIPTION_LIST;
541     }
542 
543     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
544 
545     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, ack_opcode);
546     return ERROR_CODE_SUCCESS;
547 }
548 
549 uint8_t mesh_configuration_client_send_netkey_add(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint16_t index, uint8_t * netkey){
550     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
551     if (status != ERROR_CODE_SUCCESS) return status;
552 
553     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_netkey_add, index, netkey);
554     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
555 
556     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) transport_pdu, MESH_FOUNDATION_OPERATION_NETKEY_STATUS);
557     return ERROR_CODE_SUCCESS;
558 }
559 
560 uint8_t mesh_configuration_client_send_netkey_update(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint16_t index, uint8_t * netkey){
561     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
562     if (status != ERROR_CODE_SUCCESS) return status;
563 
564     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_netkey_update, index, netkey);
565     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
566 
567     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) transport_pdu, MESH_FOUNDATION_OPERATION_NETKEY_STATUS);
568     return ERROR_CODE_SUCCESS;
569 }
570 
571 uint8_t mesh_configuration_client_send_netkey_delete(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint16_t index){
572     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
573     if (status != ERROR_CODE_SUCCESS) return status;
574 
575     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_netkey_delete, index);
576     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
577 
578     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) transport_pdu, MESH_FOUNDATION_OPERATION_NETKEY_STATUS);
579     return ERROR_CODE_SUCCESS;
580 }
581 
582 uint8_t mesh_configuration_client_send_netkey_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
583     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
584     if (status != ERROR_CODE_SUCCESS) return status;
585 
586     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_netkey_get);
587     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
588 
589     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) transport_pdu, MESH_FOUNDATION_OPERATION_NETKEY_LIST);
590     return ERROR_CODE_SUCCESS;
591 }
592 
593 uint8_t mesh_configuration_client_send_appkey_add(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint16_t netk_index, uint16_t appk_index, uint8_t * appkey){
594     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
595     if (status != ERROR_CODE_SUCCESS) return status;
596 
597     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_appkey_add, netk_index << 12 | appk_index, appkey);
598     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
599 
600     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) transport_pdu, MESH_FOUNDATION_OPERATION_APPKEY_STATUS);
601     return ERROR_CODE_SUCCESS;
602 }
603 
604 uint8_t mesh_configuration_client_send_appkey_update(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint16_t netk_index, uint16_t appk_index, uint8_t * appkey){
605     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
606     if (status != ERROR_CODE_SUCCESS) return status;
607 
608     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_appkey_update, netk_index << 12 | appk_index, appkey);
609     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
610 
611     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) transport_pdu, MESH_FOUNDATION_OPERATION_APPKEY_STATUS);
612     return ERROR_CODE_SUCCESS;
613 }
614 
615 uint8_t mesh_configuration_client_send_appkey_delete(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint16_t netk_index, uint16_t appk_index){
616     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
617     if (status != ERROR_CODE_SUCCESS) return status;
618 
619     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_appkey_delete, netk_index << 12 | appk_index);
620     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
621 
622     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) transport_pdu, MESH_FOUNDATION_OPERATION_APPKEY_STATUS);
623     return ERROR_CODE_SUCCESS;
624 }
625 
626 uint8_t mesh_configuration_client_send_appkey_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint16_t netk_index){
627     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
628     if (status != ERROR_CODE_SUCCESS) return status;
629 
630     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_appkey_get, netk_index);
631     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
632 
633     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) transport_pdu, MESH_FOUNDATION_OPERATION_APPKEY_LIST);
634     return ERROR_CODE_SUCCESS;
635 }
636 
637 // Model Operations
638 static void mesh_configuration_client_composition_data_status_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
639     // Composition Data has variable of element descriptions, with two lists of model lists
640     // Pass raw data to application but provide convenient setters instead of parsing pdu here
641 
642     // reuse part of the mesh_network_t / mesh_transport_t struct to create event without memcpy or allocation
643     uint8_t * data = mesh_pdu_data(pdu);
644     uint8_t * event = &data[-6];
645 
646     int pos = 0;
647     event[pos++] = HCI_EVENT_MESH_META;
648     // Composite Data might be larger than 251 bytes - in this case only lower 8 bit are stored here. packet size is correct
649     event[pos++] = (uint8_t) (6 + mesh_pdu_len(pdu));
650     event[pos++] = MESH_SUBEVENT_CONFIGURATION_COMPOSITION_DATA;
651     // dest
652     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
653     pos += 2;
654     event[pos++] = ERROR_CODE_SUCCESS;
655 
656     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
657     mesh_access_message_processed(pdu);
658 }
659 
660 uint8_t mesh_subevent_configuration_composition_data_get_page(const uint8_t * event){
661     return event[6];
662 }
663 
664 uint16_t mesh_subevent_configuration_composition_data_get_cid(const uint8_t * event){
665     return little_endian_read_16(event, 7);
666 }
667 
668 uint16_t mesh_subevent_configuration_composition_data_get_pid(const uint8_t * event){
669     return little_endian_read_16(event, 9);
670 }
671 
672 uint16_t mesh_subevent_configuration_composition_data_get_vid(const uint8_t * event){
673     return little_endian_read_16(event, 11);
674 }
675 
676 uint16_t mesh_subevent_configuration_composition_data_get_crpl(const uint8_t * event){
677     return little_endian_read_16(event, 13);
678 }
679 
680 uint16_t mesh_subevent_configuration_composition_data_get_features(const uint8_t * event){
681     return little_endian_read_16(event, 15);
682 }
683 
684 
685 static inline void mesh_configuration_client_handle_uint8_value(mesh_model_t *mesh_model, mesh_pdu_t * pdu, uint8_t subevent_type){
686     mesh_access_parser_state_t parser;
687     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
688 
689     uint8_t value = mesh_access_parser_get_u8(&parser);
690 
691     uint8_t event[7];
692     int pos = 0;
693 
694     event[pos++] = HCI_EVENT_MESH_META;
695     event[pos++] = sizeof(event) - 2;
696     event[pos++] = subevent_type;
697     // dest
698     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
699     pos += 2;
700     event[pos++] = ERROR_CODE_SUCCESS;
701     event[pos++] = value;
702 
703     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
704     mesh_access_message_processed(pdu);
705 }
706 
707 static void mesh_configuration_client_beacon_status_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
708     mesh_configuration_client_handle_uint8_value(mesh_model, pdu, MESH_SUBEVENT_CONFIGURATION_BEACON);
709 }
710 
711 static void mesh_configuration_client_default_ttl_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
712     mesh_configuration_client_handle_uint8_value(mesh_model, pdu, MESH_SUBEVENT_CONFIGURATION_DEFAULT_TTL);
713 }
714 
715 static void mesh_configuration_client_gatt_proxy_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
716     mesh_configuration_client_handle_uint8_value(mesh_model, pdu, MESH_SUBEVENT_CONFIGURATION_GATT_PROXY);
717 }
718 
719 static void mesh_configuration_client_relay_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
720     mesh_access_parser_state_t parser;
721     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
722 
723     uint8_t relay = mesh_access_parser_get_u8(&parser);
724     uint8_t retransmition = mesh_access_parser_get_u8(&parser);
725 
726     uint8_t event[9];
727 
728     int pos = 0;
729     event[pos++] = HCI_EVENT_MESH_META;
730     event[pos++] = sizeof(event) - 2;
731     event[pos++] = MESH_SUBEVENT_CONFIGURATION_RELAY;
732     // dest
733     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
734     pos += 2;
735     event[pos++] = ERROR_CODE_SUCCESS;
736     event[pos++] = relay;
737     event[pos++] = (retransmition >> 5) + 1;
738     event[pos++] = ((retransmition & 0x07) + 1) * 10;
739 
740     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
741     mesh_access_message_processed(pdu);
742 }
743 
744 static void mesh_configuration_client_model_publication_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
745     mesh_access_parser_state_t parser;
746     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
747     uint8_t  status = mesh_access_parser_get_u8(&parser);
748     uint16_t publish_addres = mesh_access_parser_get_u16(&parser);
749 
750     uint16_t value = mesh_access_parser_get_u16(&parser);
751     uint16_t appkey_index = value & 0xFFF;
752     uint8_t  credential_flag = (value & 0x1000) >> 12;
753 
754     uint8_t publish_ttl = mesh_access_parser_get_u8(&parser);
755     uint8_t publish_period = mesh_access_parser_get_u8(&parser);
756 
757     uint8_t retransmit = mesh_access_parser_get_u8(&parser);
758     uint8_t publish_retransmit_count = retransmit & 0x111;
759     uint8_t publish_retransmit_interval_steps = retransmit >> 5;
760     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
761 
762     uint8_t event[19];
763     int pos = 0;
764     event[pos++] = HCI_EVENT_MESH_META;
765     event[pos++] = sizeof(event) - 2;
766     event[pos++] = MESH_SUBEVENT_CONFIGURATION_MODEL_PUBLICATION;
767     // dest
768     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
769     pos += 2;
770     event[pos++] = status;
771 
772     little_endian_store_16(event, pos, publish_addres);
773     pos += 2;
774 
775     little_endian_store_16(event, pos, appkey_index);
776     pos += 2;
777 
778     event[pos++] = credential_flag;
779     event[pos++] = publish_ttl;
780     event[pos++] = publish_period;
781     event[pos++] = publish_retransmit_count;
782     event[pos++] = publish_retransmit_interval_steps;
783 
784     little_endian_store_32(event, pos, model_identifier);
785     pos += 4;
786 
787     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
788     mesh_access_message_processed(pdu);
789 }
790 
791 static void mesh_configuration_client_model_subscription_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
792     mesh_access_parser_state_t parser;
793     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
794     uint8_t  status = mesh_access_parser_get_u8(&parser);
795     uint16_t address = mesh_access_parser_get_u16(&parser);
796     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
797 
798     uint8_t event[12];
799     int pos = 0;
800     event[pos++] = HCI_EVENT_MESH_META;
801     event[pos++] = sizeof(event) - 2;
802     event[pos++] = MESH_SUBEVENT_CONFIGURATION_MODEL_SUBSCRIPTION;
803     // dest
804     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
805     pos += 2;
806     event[pos++] = status;
807 
808     little_endian_store_16(event, pos, address);
809     pos += 2;
810 
811     little_endian_store_32(event, pos, model_identifier);
812     pos += 4;
813 
814     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
815     mesh_access_message_processed(pdu);
816 }
817 
818 static void mesh_configuration_client_model_subscription_event(mesh_model_t *mesh_model, mesh_pdu_t * pdu, uint8_t subevent_type){
819     mesh_access_parser_state_t parser;
820     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
821     uint8_t  status = mesh_access_parser_get_u8(&parser);
822     uint16_t address = mesh_access_parser_get_u16(&parser);
823     uint32_t model_identifier;
824 
825     if (subevent_type == MESH_SUBEVENT_CONFIGURATION_SIG_MODEL_SUBSCRIPTION_LIST_ITEM) {
826         model_identifier = mesh_access_parser_get_sig_model_identifier(&parser);
827     } else {
828         model_identifier = mesh_access_parser_get_vendor_model_identifier(&parser);
829     }
830     uint8_t list_size = mesh_access_parser_available(&parser)/2;
831 
832     uint8_t event[12];
833     int pos = 0;
834     event[pos++] = HCI_EVENT_MESH_META;
835     event[pos++] = sizeof(event) - 2;
836     event[pos++] = subevent_type;
837     // dest
838     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
839     pos += 2;
840     event[pos++] = status;
841 
842     little_endian_store_16(event, pos, address);
843     pos += 2;
844 
845     event[pos++] = list_size;
846     uint8_t i;
847     for (i = 0; i < list_size; i++){
848         event[pos++] = i;
849         little_endian_store_16(event, pos, mesh_access_parser_get_u16(&parser));
850         (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos + 2);
851     }
852     mesh_access_message_processed(pdu);
853 }
854 
855 static void mesh_configuration_client_sig_model_subscription_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
856     mesh_configuration_client_model_subscription_event(mesh_model, pdu, MESH_SUBEVENT_CONFIGURATION_SIG_MODEL_SUBSCRIPTION_LIST_ITEM);
857 }
858 
859 static void mesh_configuration_client_vendor_model_subscription_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
860         mesh_configuration_client_model_subscription_event(mesh_model, pdu, MESH_SUBEVENT_CONFIGURATION_VENDOR_MODEL_SUBSCRIPTION_LIST_ITEM);
861 }
862 
863 static void mesh_configuration_client_netkey_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
864     mesh_access_parser_state_t parser;
865     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
866     uint8_t  status = mesh_access_parser_get_u8(&parser);
867 
868     uint8_t event[6];
869     int pos = 0;
870     event[pos++] = HCI_EVENT_MESH_META;
871     event[pos++] = sizeof(event) - 2;
872     event[pos++] = MESH_SUBEVENT_CONFIGURATION_NETKEY_INDEX;
873     // dest
874     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
875     pos += 2;
876     event[pos++] = status;
877     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
878     mesh_access_message_processed(pdu);
879 }
880 
881 static void mesh_configuration_client_netkey_list_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
882     mesh_access_parser_state_t parser;
883     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
884     uint8_t  status = 0;
885     uint8_t list_size = mesh_access_parser_available(&parser)/2;
886 
887     uint8_t event[10];
888     int pos = 0;
889     event[pos++] = HCI_EVENT_MESH_META;
890     event[pos++] = sizeof(event) - 2;
891     event[pos++] = MESH_SUBEVENT_CONFIGURATION_NETKEY_INDEX_LIST_ITEM;
892     // dest
893     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
894     pos += 2;
895     event[pos++] = status;
896 
897     event[pos++] = list_size;
898     uint8_t i;
899     for (i = 0; i < list_size; i++){
900         event[pos++] = i;
901         little_endian_store_16(event, pos, mesh_access_parser_get_u16(&parser));
902         (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos + 2);
903     }
904     mesh_access_message_processed(pdu);
905 }
906 
907 static void mesh_configuration_client_appkey_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
908     mesh_access_parser_state_t parser;
909     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
910     uint8_t  status = mesh_access_parser_get_u8(&parser);
911     uint32_t netappkey_index = mesh_access_parser_get_u24(&parser);
912     uint16_t netkey_index = netappkey_index >> 12;
913     uint16_t appkey_index = netappkey_index & 0xFFF;
914 
915     uint8_t event[10];
916     int pos = 0;
917     event[pos++] = HCI_EVENT_MESH_META;
918     event[pos++] = sizeof(event) - 2;
919     event[pos++] = MESH_SUBEVENT_CONFIGURATION_APPKEY_INDEX;
920     // dest
921     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
922     pos += 2;
923     event[pos++] = status;
924     little_endian_store_16(event, pos, netkey_index);
925     pos += 2;
926     little_endian_store_16(event, pos, appkey_index);
927     pos += 2;
928 
929     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
930     mesh_access_message_processed(pdu);
931 }
932 
933 static void mesh_configuration_client_appkey_list_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
934     mesh_access_parser_state_t parser;
935     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
936     uint8_t  status = 0;
937     uint8_t list_size = mesh_access_parser_available(&parser)/2;
938 
939     uint8_t event[12];
940     int pos = 0;
941     event[pos++] = HCI_EVENT_MESH_META;
942     event[pos++] = sizeof(event) - 2;
943     event[pos++] = MESH_SUBEVENT_CONFIGURATION_APPKEY_INDEX_LIST_ITEM;
944     // dest
945     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
946     pos += 2;
947     event[pos++] = status;
948 
949     event[pos++] = list_size;
950     uint8_t i;
951     for (i = 0; i < list_size; i++){
952         event[pos++] = i;
953         uint32_t netappkey_index = mesh_access_parser_get_u24(&parser);
954         little_endian_store_16(event, pos, netappkey_index >> 12);
955         little_endian_store_16(event, pos + 2, netappkey_index & 0xFFF);
956         (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos + 4);
957     }
958     mesh_access_message_processed(pdu);
959 }
960 
961 const static mesh_operation_t mesh_configuration_client_model_operations[] = {
962     { MESH_FOUNDATION_OPERATION_BEACON_STATUS,                  1, mesh_configuration_client_beacon_status_handler },
963     { MESH_FOUNDATION_OPERATION_COMPOSITION_DATA_STATUS,       10, mesh_configuration_client_composition_data_status_handler },
964     { MESH_FOUNDATION_OPERATION_DEFAULT_TTL_STATUS,             1, mesh_configuration_client_default_ttl_handler },
965     { MESH_FOUNDATION_OPERATION_GATT_PROXY_STATUS,              1, mesh_configuration_client_gatt_proxy_handler },
966     { MESH_FOUNDATION_OPERATION_RELAY_STATUS,                   2, mesh_configuration_client_relay_handler },
967     { MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_STATUS,      12, mesh_configuration_client_model_publication_handler },
968     { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_STATUS,      7, mesh_configuration_client_model_subscription_handler },
969     { MESH_FOUNDATION_OPERATION_SIG_MODEL_SUBSCRIPTION_LIST,    5, mesh_configuration_client_sig_model_subscription_handler},
970     { MESH_FOUNDATION_OPERATION_VENDOR_MODEL_SUBSCRIPTION_LIST, 7, mesh_configuration_client_vendor_model_subscription_handler},
971     { MESH_FOUNDATION_OPERATION_NETKEY_STATUS,                  3, mesh_configuration_client_netkey_handler },
972     { MESH_FOUNDATION_OPERATION_NETKEY_LIST,                    0, mesh_configuration_client_netkey_list_handler },
973     { MESH_FOUNDATION_OPERATION_APPKEY_STATUS,                  4, mesh_configuration_client_appkey_handler },
974     { MESH_FOUNDATION_OPERATION_APPKEY_LIST,                    3, mesh_configuration_client_appkey_list_handler },
975     { 0, 0, NULL }
976 };
977 
978 const mesh_operation_t * mesh_configuration_client_get_operations(void){
979     return mesh_configuration_client_model_operations;
980 }
981 
982 void mesh_configuration_client_register_packet_handler(mesh_model_t *configuration_client_model, btstack_packet_handler_t events_packet_handler){
983     btstack_assert(events_packet_handler != NULL);
984     btstack_assert(configuration_client_model != NULL);
985 
986     configuration_client_model->model_packet_handler = events_packet_handler;
987 }
988 
989