xref: /btstack/src/mesh/mesh_configuration_client.c (revision 1b464e99afd70ddaf6b75be1ba7cc563a5f5dfd8)
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 const mesh_access_message_t mesh_configuration_client_node_identity_get = {
260         MESH_FOUNDATION_OPERATION_NODE_IDENTITY_GET, "2"
261 };
262 static const mesh_access_message_t mesh_configuration_client_node_identity_set = {
263         MESH_FOUNDATION_OPERATION_NODE_IDENTITY_SET, "21"
264 };
265 
266 static const mesh_access_message_t mesh_configuration_client_model_app_bind = {
267         MESH_FOUNDATION_OPERATION_MODEL_APP_BIND, "22m"
268 };
269 static const mesh_access_message_t mesh_configuration_client_model_app_unbind = {
270         MESH_FOUNDATION_OPERATION_MODEL_APP_UNBIND, "22m"
271 };
272 
273 static const mesh_access_message_t mesh_configuration_client_sig_model_app_get = {
274         MESH_FOUNDATION_OPERATION_SIG_MODEL_APP_GET, "2m"
275 };
276 static const mesh_access_message_t mesh_configuration_client_vendor_model_app_get = {
277         MESH_FOUNDATION_OPERATION_VENDOR_MODEL_APP_GET, "2m"
278 };
279 
280 static const mesh_access_message_t mesh_configuration_client_node_reset = {
281         MESH_FOUNDATION_OPERATION_NODE_RESET, ""
282 };
283 
284 static const mesh_access_message_t mesh_configuration_client_friend_get = {
285         MESH_FOUNDATION_OPERATION_FRIEND_GET, ""
286 };
287 static const mesh_access_message_t mesh_configuration_client_friend_set = {
288         MESH_FOUNDATION_OPERATION_FRIEND_SET, "1"
289 };
290 
291 static const mesh_access_message_t mesh_configuration_client_key_refresh_phase_get = {
292         MESH_FOUNDATION_OPERATION_KEY_REFRESH_PHASE_GET, "2"
293 };
294 static const mesh_access_message_t mesh_configuration_client_key_refresh_phase_set = {
295         MESH_FOUNDATION_OPERATION_KEY_REFRESH_PHASE_SET, "21"
296 };
297 
298 static const mesh_access_message_t mesh_configuration_client_heartbeat_publication_get = {
299         MESH_FOUNDATION_OPERATION_HEARTBEAT_PUBLICATION_GET, ""
300 };
301 static const mesh_access_message_t mesh_configuration_client_heartbeat_publication_set = {
302         MESH_FOUNDATION_OPERATION_HEARTBEAT_PUBLICATION_SET, "211122"
303 };
304 
305 static const mesh_access_message_t mesh_configuration_client_heartbeat_subscription_get = {
306         MESH_FOUNDATION_OPERATION_HEARTBEAT_SUBSCRIPTION_GET, ""
307 };
308 static const mesh_access_message_t mesh_configuration_client_heartbeat_subscription_set = {
309         MESH_FOUNDATION_OPERATION_HEARTBEAT_SUBSCRIPTION_SET, "221"
310 };
311 
312 static const mesh_access_message_t mesh_configuration_client_low_power_node_poll_timeout_get = {
313         MESH_FOUNDATION_OPERATION_LOW_POWER_NODE_POLL_TIMEOUT_GET, ""
314 };
315 
316 
317 static const mesh_access_message_t mesh_configuration_network_transmit_get = {
318         MESH_FOUNDATION_OPERATION_NETWORK_TRANSMIT_GET, ""
319 };
320 static const mesh_access_message_t mesh_configuration_network_transmit_set = {
321         MESH_FOUNDATION_OPERATION_NETWORK_TRANSMIT_SET, "1"
322 };
323 
324 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){
325     uint8_t  ttl  = mesh_foundation_default_ttl_get();
326     mesh_upper_transport_setup_access_pdu_header(pdu, netkey_index, appkey_index, ttl, src, dest, 0);
327     mesh_access_send_acknowledged_pdu(pdu, mesh_access_acknowledged_message_retransmissions(), ack_opcode);
328 }
329 
330 static uint8_t mesh_access_validate_envelop_params(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
331     btstack_assert(mesh_model != NULL);
332     // TODO: validate other params
333     UNUSED(mesh_model);
334     UNUSED(dest);
335     UNUSED(netkey_index);
336     UNUSED(appkey_index);
337 
338     return ERROR_CODE_SUCCESS;
339 }
340 
341 uint8_t mesh_configuration_client_send_beacon_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
342     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
343     if (status != ERROR_CODE_SUCCESS) return status;
344 
345     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_beacon_get);
346     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
347 
348     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);
349     return ERROR_CODE_SUCCESS;
350 }
351 
352 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){
353     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
354     if (status != ERROR_CODE_SUCCESS) return status;
355 
356     if (beacon > 1) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
357 
358     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_beacon_set, beacon);
359     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
360 
361     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);
362     return ERROR_CODE_SUCCESS;
363 }
364 
365 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){
366     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
367     if (status != ERROR_CODE_SUCCESS) return status;
368 
369     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_composition_data_get, page);
370     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
371 
372     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);
373     return ERROR_CODE_SUCCESS;
374 }
375 
376 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){
377     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
378     if (status != ERROR_CODE_SUCCESS) return status;
379 
380     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_default_ttl_get);
381     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
382 
383     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);
384     return ERROR_CODE_SUCCESS;
385 }
386 
387 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){
388     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
389     if (status != ERROR_CODE_SUCCESS) return status;
390 
391     if (ttl == 0x01 || ttl >= 0x80) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
392 
393     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_default_ttl_set, ttl);
394     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
395 
396     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);
397     return ERROR_CODE_SUCCESS;
398 }
399 
400 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){
401     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
402     if (status != ERROR_CODE_SUCCESS) return status;
403 
404     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_gatt_proxy_get);
405     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
406 
407     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);
408     return ERROR_CODE_SUCCESS;
409 }
410 
411 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){
412     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
413     if (status != ERROR_CODE_SUCCESS) return status;
414 
415     if (gatt_proxy_state > 2) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
416 
417     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_gatt_proxy_set, gatt_proxy_state);
418     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
419 
420     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);
421     return ERROR_CODE_SUCCESS;
422 }
423 
424 uint8_t mesh_configuration_client_send_relay_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
425     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
426     if (status != ERROR_CODE_SUCCESS) return status;
427 
428     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_relay_get);
429     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
430 
431     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);
432     return ERROR_CODE_SUCCESS;
433 }
434 
435 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){
436     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
437     if (status != ERROR_CODE_SUCCESS) return status;
438 
439     if (relay_retransmit_count > 0x07) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
440     if (relay_retransmit_interval_steps > 0x1F) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
441 
442     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);
443     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
444 
445     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);
446     return ERROR_CODE_SUCCESS;
447 }
448 
449 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){
450     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
451     if (status != ERROR_CODE_SUCCESS) return status;
452 
453     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_publication_get, dest, model_id);
454     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
455 
456     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);
457     return ERROR_CODE_SUCCESS;
458 }
459 
460 static uint8_t mesh_validate_publication_model_config_parameters(mesh_publication_model_config_t * publication_config, bool use_unicast_address){
461     if (publication_config->appkey_index > 0xFFF) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
462     if (publication_config->credential_flag > 1) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
463     if (publication_config->publish_retransmit_count > 0x07) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
464     if (publication_config->publish_retransmit_interval_steps > 0x1F) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
465     if (use_unicast_address && mesh_network_address_virtual(publication_config->publish_address_unicast)) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
466     return ERROR_CODE_SUCCESS;
467 }
468 
469 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){
470     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
471     if (status != ERROR_CODE_SUCCESS) return status;
472 
473     if (!mesh_network_address_unicast(dest) ||
474         mesh_validate_publication_model_config_parameters(publication_config, true) != ERROR_CODE_SUCCESS){
475         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
476     }
477 
478     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_publication_set,
479         dest,
480         publication_config->publish_address_unicast,
481         (publication_config->credential_flag << 12) | publication_config->appkey_index,
482         publication_config->publish_ttl,
483         publication_config->publish_period,
484         (publication_config->publish_retransmit_interval_steps << 3) | publication_config->publish_retransmit_count,
485         model_id);
486     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
487 
488     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);
489     return ERROR_CODE_SUCCESS;
490 
491 }
492 
493 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){
494     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
495     if (status != ERROR_CODE_SUCCESS) return status;
496 
497     if (!mesh_network_address_unicast(dest) ||
498         mesh_validate_publication_model_config_parameters(publication_config, false) != ERROR_CODE_SUCCESS){
499         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
500     }
501 
502     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_model_publication_virtual_address_set,
503         dest,
504         publication_config->publish_address_virtual,
505         (publication_config->credential_flag << 12) | publication_config->appkey_index,
506         publication_config->publish_ttl,
507         publication_config->publish_period,
508         (publication_config->publish_retransmit_interval_steps << 3) | publication_config->publish_retransmit_count,
509         model_id);
510     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
511 
512     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);
513     return ERROR_CODE_SUCCESS;
514 }
515 
516 
517 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){
518     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
519     if (status != ERROR_CODE_SUCCESS) return status;
520 
521     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_subscription_add, dest, address, model_id);
522     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
523 
524     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);
525     return ERROR_CODE_SUCCESS;
526 }
527 
528 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){
529     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
530     if (status != ERROR_CODE_SUCCESS) return status;
531 
532     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_model_subscription_virtual_address_add, dest, address, model_id);
533     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
534 
535     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);
536     return ERROR_CODE_SUCCESS;
537 }
538 
539 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){
540     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
541     if (status != ERROR_CODE_SUCCESS) return status;
542 
543     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_subscription_delete, dest, address, model_id);
544     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
545 
546     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);
547     return ERROR_CODE_SUCCESS;
548 }
549 
550 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){
551     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
552     if (status != ERROR_CODE_SUCCESS) return status;
553 
554     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_model_subscription_virtual_address_delete, dest, address, model_id);
555     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
556 
557     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);
558     return ERROR_CODE_SUCCESS;
559 }
560 
561 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){
562         uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
563     if (status != ERROR_CODE_SUCCESS) return status;
564 
565     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_subscription_overwrite, dest, address, model_id);
566     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
567 
568     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);
569     return ERROR_CODE_SUCCESS;
570 }
571 
572 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){
573     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
574     if (status != ERROR_CODE_SUCCESS) return status;
575 
576     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_model_subscription_virtual_address_overwrite, dest, address, model_id);
577     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
578 
579     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);
580     return ERROR_CODE_SUCCESS;
581 }
582 
583 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){
584         uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
585     if (status != ERROR_CODE_SUCCESS) return status;
586 
587     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_subscription_delete_all, dest, address, model_id);
588     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
589 
590     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);
591     return ERROR_CODE_SUCCESS;
592 }
593 
594 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){
595     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
596     if (status != ERROR_CODE_SUCCESS) return status;
597 
598     mesh_network_pdu_t * network_pdu = NULL;
599     uint32_t ack_opcode = MESH_FOUNDATION_OPERATION_SIG_MODEL_SUBSCRIPTION_LIST;
600 
601     if (mesh_model_is_bluetooth_sig(model_id)){
602         network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_sig_model_subscription_get, dest, model_id);
603     } else {
604         network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_vendor_model_subscription_get, dest, model_id);
605         ack_opcode = MESH_FOUNDATION_OPERATION_VENDOR_MODEL_SUBSCRIPTION_LIST;
606     }
607 
608     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
609 
610     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, ack_opcode);
611     return ERROR_CODE_SUCCESS;
612 }
613 
614 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){
615     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
616     if (status != ERROR_CODE_SUCCESS) return status;
617 
618     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_netkey_add, index, netkey);
619     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
620 
621     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);
622     return ERROR_CODE_SUCCESS;
623 }
624 
625 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){
626     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
627     if (status != ERROR_CODE_SUCCESS) return status;
628 
629     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_netkey_update, index, netkey);
630     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
631 
632     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);
633     return ERROR_CODE_SUCCESS;
634 }
635 
636 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){
637     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
638     if (status != ERROR_CODE_SUCCESS) return status;
639 
640     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_netkey_delete, index);
641     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
642 
643     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);
644     return ERROR_CODE_SUCCESS;
645 }
646 
647 uint8_t mesh_configuration_client_send_netkey_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
648     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
649     if (status != ERROR_CODE_SUCCESS) return status;
650 
651     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_netkey_get);
652     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
653 
654     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);
655     return ERROR_CODE_SUCCESS;
656 }
657 
658 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){
659     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
660     if (status != ERROR_CODE_SUCCESS) return status;
661 
662     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_appkey_add, netk_index << 12 | appk_index, appkey);
663     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
664 
665     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);
666     return ERROR_CODE_SUCCESS;
667 }
668 
669 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){
670     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
671     if (status != ERROR_CODE_SUCCESS) return status;
672 
673     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_appkey_update, netk_index << 12 | appk_index, appkey);
674     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
675 
676     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);
677     return ERROR_CODE_SUCCESS;
678 }
679 
680 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){
681     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
682     if (status != ERROR_CODE_SUCCESS) return status;
683 
684     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_appkey_delete, netk_index << 12 | appk_index);
685     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
686 
687     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);
688     return ERROR_CODE_SUCCESS;
689 }
690 
691 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){
692     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
693     if (status != ERROR_CODE_SUCCESS) return status;
694 
695     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_appkey_get, netk_index);
696     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
697 
698     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);
699     return ERROR_CODE_SUCCESS;
700 }
701 
702 uint8_t mesh_configuration_client_send_node_identity_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint16_t netk_index){
703     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
704     if (status != ERROR_CODE_SUCCESS) return status;
705 
706     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_node_identity_get, netk_index);
707     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
708 
709     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_NODE_IDENTITY_STATUS);
710     return ERROR_CODE_SUCCESS;
711 }
712 
713 uint8_t mesh_configuration_client_send_node_identity_set(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint16_t netk_index, mesh_node_identity_state_t node_identity_state){
714     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
715     if (status != ERROR_CODE_SUCCESS) return status;
716 
717     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_node_identity_set, netk_index, node_identity_state);
718     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
719 
720     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_NODE_IDENTITY_STATUS);
721     return ERROR_CODE_SUCCESS;
722 }
723 
724 uint8_t mesh_configuration_client_send_model_app_bind_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint16_t appk_index, uint32_t model_identifier){
725     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
726     if (status != ERROR_CODE_SUCCESS) return status;
727 
728     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_model_app_bind, dest, appk_index, model_identifier);
729     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
730 
731     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_APP_STATUS);
732     return ERROR_CODE_SUCCESS;
733 }
734 
735 uint8_t mesh_configuration_client_send_model_app_unbind_set(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint16_t appk_index, uint32_t model_identifier){
736     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
737     if (status != ERROR_CODE_SUCCESS) return status;
738 
739     mesh_network_pdu_t * transport_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_app_unbind, dest, appk_index, model_identifier);
740     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
741 
742     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_APP_STATUS);
743     return ERROR_CODE_SUCCESS;
744 }
745 
746 uint8_t mesh_configuration_client_send_model_app_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint32_t model_identifier){
747     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
748     if (status != ERROR_CODE_SUCCESS) return status;
749 
750     mesh_network_pdu_t * transport_pdu;
751     uint32_t ack_opcode = MESH_FOUNDATION_OPERATION_SIG_MODEL_APP_LIST;
752 
753     if (mesh_model_is_bluetooth_sig(model_identifier)){
754         transport_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_sig_model_app_get, dest, model_identifier);
755     } else {
756         transport_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_vendor_model_app_get, dest, model_identifier);
757         ack_opcode = MESH_FOUNDATION_OPERATION_VENDOR_MODEL_APP_LIST;
758     }
759 
760     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) transport_pdu, ack_opcode);
761     return ERROR_CODE_SUCCESS;
762 }
763 
764 uint8_t mesh_configuration_client_send_node_reset(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
765     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
766     if (status != ERROR_CODE_SUCCESS) return status;
767 
768     mesh_network_pdu_t * transport_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_node_reset);
769     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
770 
771     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_NODE_RESET_STATUS);
772     return ERROR_CODE_SUCCESS;
773 }
774 
775 uint8_t mesh_configuration_client_send_friend_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
776     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
777     if (status != ERROR_CODE_SUCCESS) return status;
778 
779     mesh_network_pdu_t * transport_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_friend_get);
780     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
781 
782     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_FRIEND_STATUS);
783     return ERROR_CODE_SUCCESS;
784 }
785 
786 uint8_t mesh_configuration_client_send_friend_set(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, mesh_friend_state_t friend_state){
787     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
788     if (status != ERROR_CODE_SUCCESS) return status;
789 
790     mesh_network_pdu_t * transport_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_friend_set, friend_state);
791     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
792 
793     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_FRIEND_STATUS);
794     return ERROR_CODE_SUCCESS;
795 }
796 
797 uint8_t mesh_configuration_client_send_key_refresh_phase_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint16_t netk_index){
798     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
799     if (status != ERROR_CODE_SUCCESS) return status;
800 
801     mesh_network_pdu_t * transport_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_key_refresh_phase_get, netk_index);
802     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
803 
804     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_KEY_REFRESH_PHASE_STATUS);
805     return ERROR_CODE_SUCCESS;
806 }
807 
808 uint8_t mesh_configuration_client_send_key_refresh_phase_set(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint16_t netk_index, uint8_t transition){
809     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
810     if (status != ERROR_CODE_SUCCESS) return status;
811 
812     mesh_network_pdu_t * transport_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_key_refresh_phase_set, netk_index, transition);
813     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
814 
815     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_KEY_REFRESH_PHASE_STATUS);
816     return ERROR_CODE_SUCCESS;
817 }
818 
819 uint8_t mesh_configuration_client_send_heartbeat_publication_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
820     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
821     if (status != ERROR_CODE_SUCCESS) return status;
822 
823     mesh_network_pdu_t * transport_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_heartbeat_publication_get);
824     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
825 
826     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_HEARTBEAT_PUBLICATION_STATUS);
827     return ERROR_CODE_SUCCESS;
828 }
829 
830 uint8_t mesh_configuration_client_send_heartbeat_publication_set(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, mesh_heartbeat_publication_state_t publication_state){
831     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
832     if (status != ERROR_CODE_SUCCESS) return status;
833 
834     mesh_network_pdu_t * transport_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_heartbeat_publication_set,
835         publication_state.destination,
836         mesh_heartbeat_period_log(publication_state.count),
837         mesh_heartbeat_period_log(publication_state.period_s),
838         publication_state.ttl,
839         publication_state.features,
840         publication_state.netkey_index);
841 
842     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
843 
844     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_HEARTBEAT_PUBLICATION_STATUS);
845     return ERROR_CODE_SUCCESS;
846 }
847 
848 uint8_t mesh_configuration_client_send_heartbeat_subscription_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
849     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
850     if (status != ERROR_CODE_SUCCESS) return status;
851 
852     mesh_network_pdu_t * transport_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_heartbeat_subscription_get);
853     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
854 
855     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_HEARTBEAT_SUBSCRIPTION_STATUS);
856     return ERROR_CODE_SUCCESS;
857 }
858 
859 uint8_t mesh_configuration_client_send_heartbeat_subscription_set(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint16_t heartbeat_source, uint16_t heartbeat_destination, uint16_t period_s){
860         uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
861     if (status != ERROR_CODE_SUCCESS) return status;
862 
863     mesh_network_pdu_t * transport_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_heartbeat_subscription_set, heartbeat_source, heartbeat_destination, mesh_heartbeat_period_log(period_s));
864     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
865 
866     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_HEARTBEAT_SUBSCRIPTION_STATUS);
867     return ERROR_CODE_SUCCESS;
868 }
869 
870 uint8_t mesh_configuration_client_send_low_power_node_poll_timeout_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
871     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
872     if (status != ERROR_CODE_SUCCESS) return status;
873 
874     mesh_network_pdu_t * transport_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_low_power_node_poll_timeout_get);
875     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
876 
877     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_LOW_POWER_NODE_POLL_TIMEOUT_STATUS);
878     return ERROR_CODE_SUCCESS;
879 }
880 
881 uint8_t mesh_configuration_client_send_network_transmit_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
882     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
883     if (status != ERROR_CODE_SUCCESS) return status;
884 
885     mesh_network_pdu_t * transport_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_network_transmit_get);
886     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
887 
888     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_NETWORK_TRANSMIT_STATUS);
889     return ERROR_CODE_SUCCESS;
890 }
891 
892 uint8_t mesh_configuration_client_send_network_transmit_set(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index, uint8_t transmit_count, uint16_t transmit_interval_steps_ms){
893     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
894     if (status != ERROR_CODE_SUCCESS) return status;
895 
896     uint8_t transmit_interval_steps_10ms = (uint8_t) (transmit_interval_steps_ms/10);
897     if (transmit_interval_steps_10ms > 0){
898         transmit_interval_steps_10ms -= 1;
899     }
900 
901     mesh_network_pdu_t * transport_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_network_transmit_set, (transmit_count << 5) | (transmit_interval_steps_10ms & 0x1F));
902     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
903 
904     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_NETWORK_TRANSMIT_STATUS);
905     return ERROR_CODE_SUCCESS;
906 }
907 
908 // Model Operations
909 static void mesh_configuration_client_composition_data_status_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
910     // Composition Data has variable of element descriptions, with two lists of model lists
911     // Pass raw data to application but provide convenient setters instead of parsing pdu here
912 
913     // reuse part of the mesh_network_t / mesh_transport_t struct to create event without memcpy or allocation
914     uint8_t * data = mesh_pdu_data(pdu);
915     uint8_t * event = &data[-6];
916 
917     int pos = 0;
918     event[pos++] = HCI_EVENT_MESH_META;
919     // Composite Data might be larger than 251 bytes - in this case only lower 8 bit are stored here. packet size is correct
920     event[pos++] = (uint8_t) (6 + mesh_pdu_len(pdu));
921     event[pos++] = MESH_SUBEVENT_CONFIGURATION_COMPOSITION_DATA;
922     // dest
923     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
924     pos += 2;
925     event[pos++] = ERROR_CODE_SUCCESS;
926 
927     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
928     mesh_access_message_processed(pdu);
929 }
930 
931 uint8_t mesh_subevent_configuration_composition_data_get_page(const uint8_t * event){
932     return event[6];
933 }
934 
935 uint16_t mesh_subevent_configuration_composition_data_get_cid(const uint8_t * event){
936     return little_endian_read_16(event, 7);
937 }
938 
939 uint16_t mesh_subevent_configuration_composition_data_get_pid(const uint8_t * event){
940     return little_endian_read_16(event, 9);
941 }
942 
943 uint16_t mesh_subevent_configuration_composition_data_get_vid(const uint8_t * event){
944     return little_endian_read_16(event, 11);
945 }
946 
947 uint16_t mesh_subevent_configuration_composition_data_get_crpl(const uint8_t * event){
948     return little_endian_read_16(event, 13);
949 }
950 
951 uint16_t mesh_subevent_configuration_composition_data_get_features(const uint8_t * event){
952     return little_endian_read_16(event, 15);
953 }
954 
955 
956 static inline void mesh_configuration_client_handle_uint8_value(mesh_model_t *mesh_model, mesh_pdu_t * pdu, uint8_t subevent_type){
957     mesh_access_parser_state_t parser;
958     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
959 
960     uint8_t value = mesh_access_parser_get_u8(&parser);
961 
962     uint8_t event[7];
963     int pos = 0;
964 
965     event[pos++] = HCI_EVENT_MESH_META;
966     event[pos++] = sizeof(event) - 2;
967     event[pos++] = subevent_type;
968     // dest
969     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
970     pos += 2;
971     event[pos++] = ERROR_CODE_SUCCESS;
972     event[pos++] = value;
973 
974     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
975     mesh_access_message_processed(pdu);
976 }
977 
978 static void mesh_configuration_client_beacon_status_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
979     mesh_configuration_client_handle_uint8_value(mesh_model, pdu, MESH_SUBEVENT_CONFIGURATION_BEACON);
980 }
981 
982 static void mesh_configuration_client_default_ttl_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
983     mesh_configuration_client_handle_uint8_value(mesh_model, pdu, MESH_SUBEVENT_CONFIGURATION_DEFAULT_TTL);
984 }
985 
986 static void mesh_configuration_client_gatt_proxy_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
987     mesh_configuration_client_handle_uint8_value(mesh_model, pdu, MESH_SUBEVENT_CONFIGURATION_GATT_PROXY);
988 }
989 
990 static void mesh_configuration_client_relay_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
991     mesh_access_parser_state_t parser;
992     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
993 
994     uint8_t relay = mesh_access_parser_get_u8(&parser);
995     uint8_t retransmition = mesh_access_parser_get_u8(&parser);
996 
997     uint8_t event[9];
998 
999     int pos = 0;
1000     event[pos++] = HCI_EVENT_MESH_META;
1001     event[pos++] = sizeof(event) - 2;
1002     event[pos++] = MESH_SUBEVENT_CONFIGURATION_RELAY;
1003     // dest
1004     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
1005     pos += 2;
1006     event[pos++] = ERROR_CODE_SUCCESS;
1007     event[pos++] = relay;
1008     event[pos++] = (retransmition >> 5) + 1;
1009     event[pos++] = ((retransmition & 0x07) + 1) * 10;
1010 
1011     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
1012     mesh_access_message_processed(pdu);
1013 }
1014 
1015 static void mesh_configuration_client_model_publication_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1016     mesh_access_parser_state_t parser;
1017     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1018     uint8_t  status = mesh_access_parser_get_u8(&parser);
1019     uint16_t publish_addres = mesh_access_parser_get_u16(&parser);
1020 
1021     uint16_t value = mesh_access_parser_get_u16(&parser);
1022     uint16_t appkey_index = value & 0xFFF;
1023     uint8_t  credential_flag = (value & 0x1000) >> 12;
1024 
1025     uint8_t publish_ttl = mesh_access_parser_get_u8(&parser);
1026     uint8_t publish_period = mesh_access_parser_get_u8(&parser);
1027 
1028     uint8_t retransmit = mesh_access_parser_get_u8(&parser);
1029     uint8_t publish_retransmit_count = retransmit & 0x111;
1030     uint8_t publish_retransmit_interval_steps = retransmit >> 5;
1031     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1032 
1033     uint8_t event[19];
1034     int pos = 0;
1035     event[pos++] = HCI_EVENT_MESH_META;
1036     event[pos++] = sizeof(event) - 2;
1037     event[pos++] = MESH_SUBEVENT_CONFIGURATION_MODEL_PUBLICATION;
1038     // dest
1039     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
1040     pos += 2;
1041     event[pos++] = status;
1042 
1043     little_endian_store_16(event, pos, publish_addres);
1044     pos += 2;
1045 
1046     little_endian_store_16(event, pos, appkey_index);
1047     pos += 2;
1048 
1049     event[pos++] = credential_flag;
1050     event[pos++] = publish_ttl;
1051     event[pos++] = publish_period;
1052     event[pos++] = publish_retransmit_count;
1053     event[pos++] = publish_retransmit_interval_steps;
1054 
1055     little_endian_store_32(event, pos, model_identifier);
1056     pos += 4;
1057 
1058     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
1059     mesh_access_message_processed(pdu);
1060 }
1061 
1062 static void mesh_configuration_client_model_subscription_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1063     mesh_access_parser_state_t parser;
1064     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1065     uint8_t  status = mesh_access_parser_get_u8(&parser);
1066     uint16_t address = mesh_access_parser_get_u16(&parser);
1067     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1068 
1069     uint8_t event[12];
1070     int pos = 0;
1071     event[pos++] = HCI_EVENT_MESH_META;
1072     event[pos++] = sizeof(event) - 2;
1073     event[pos++] = MESH_SUBEVENT_CONFIGURATION_MODEL_SUBSCRIPTION;
1074     // dest
1075     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
1076     pos += 2;
1077     event[pos++] = status;
1078 
1079     little_endian_store_16(event, pos, address);
1080     pos += 2;
1081 
1082     little_endian_store_32(event, pos, model_identifier);
1083     pos += 4;
1084 
1085     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
1086     mesh_access_message_processed(pdu);
1087 }
1088 
1089 static void mesh_configuration_client_model_subscription_event(mesh_model_t *mesh_model, mesh_pdu_t * pdu, bool is_sig_model){
1090     mesh_access_parser_state_t parser;
1091     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1092     uint8_t  status = mesh_access_parser_get_u8(&parser);
1093     uint16_t element_address = mesh_access_parser_get_u16(&parser);
1094     uint32_t model_identifier;
1095 
1096     if (element_address != mesh_pdu_src(pdu)){
1097         log_info("MESH_SUBEVENT_CONFIGURATION_MODEL_SUBSCRIPTION_LIST_ITEM event, element_address differs from mesh_pdu_src");
1098     }
1099 
1100     if (is_sig_model == true) {
1101         model_identifier = mesh_access_parser_get_sig_model_identifier(&parser);
1102     } else {
1103         model_identifier = mesh_access_parser_get_vendor_model_identifier(&parser);
1104     }
1105     uint8_t list_size = mesh_access_parser_available(&parser)/2;
1106 
1107     uint8_t event[14];
1108     int pos = 0;
1109     event[pos++] = HCI_EVENT_MESH_META;
1110     event[pos++] = sizeof(event) - 2;
1111     event[pos++] = MESH_SUBEVENT_CONFIGURATION_MODEL_SUBSCRIPTION_LIST_ITEM;
1112     // dest
1113     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
1114     pos += 2;
1115     event[pos++] = status;
1116 
1117     little_endian_store_32(event, pos, model_identifier);
1118     pos += 4;
1119 
1120     event[pos++] = list_size;
1121     uint8_t i;
1122     for (i = 0; i < list_size; i++){
1123         event[pos++] = i;
1124         little_endian_store_16(event, pos, mesh_access_parser_get_u16(&parser));
1125         (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos + 2);
1126     }
1127     mesh_access_message_processed(pdu);
1128 }
1129 
1130 static void mesh_configuration_client_sig_model_subscription_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1131     mesh_configuration_client_model_subscription_event(mesh_model, pdu, true);
1132 }
1133 
1134 static void mesh_configuration_client_vendor_model_subscription_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1135         mesh_configuration_client_model_subscription_event(mesh_model, pdu, false);
1136 }
1137 
1138 static void mesh_configuration_client_netkey_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1139     mesh_access_parser_state_t parser;
1140     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1141     uint8_t  status = mesh_access_parser_get_u8(&parser);
1142 
1143     uint8_t event[6];
1144     int pos = 0;
1145     event[pos++] = HCI_EVENT_MESH_META;
1146     event[pos++] = sizeof(event) - 2;
1147     event[pos++] = MESH_SUBEVENT_CONFIGURATION_NETKEY_INDEX;
1148     // dest
1149     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
1150     pos += 2;
1151     event[pos++] = status;
1152     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
1153     mesh_access_message_processed(pdu);
1154 }
1155 
1156 static void mesh_configuration_client_netkey_list_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1157     mesh_access_parser_state_t parser;
1158     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1159     uint8_t status = 0;
1160     uint8_t list_size = mesh_access_parser_available(&parser)/2;
1161 
1162     uint8_t event[10];
1163     int pos = 0;
1164     event[pos++] = HCI_EVENT_MESH_META;
1165     event[pos++] = sizeof(event) - 2;
1166     event[pos++] = MESH_SUBEVENT_CONFIGURATION_NETKEY_INDEX_LIST_ITEM;
1167     // dest
1168     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
1169     pos += 2;
1170     event[pos++] = status;
1171 
1172     event[pos++] = list_size;
1173     uint8_t i;
1174     for (i = 0; i < list_size; i++){
1175         event[pos++] = i;
1176         little_endian_store_16(event, pos, mesh_access_parser_get_u16(&parser));
1177         (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos + 2);
1178     }
1179     mesh_access_message_processed(pdu);
1180 }
1181 
1182 static void mesh_configuration_client_appkey_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1183     mesh_access_parser_state_t parser;
1184     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1185     uint8_t  status = mesh_access_parser_get_u8(&parser);
1186     uint32_t netappkey_index = mesh_access_parser_get_u24(&parser);
1187     uint16_t netkey_index = netappkey_index >> 12;
1188     uint16_t appkey_index = netappkey_index & 0xFFF;
1189 
1190     uint8_t event[10];
1191     int pos = 0;
1192     event[pos++] = HCI_EVENT_MESH_META;
1193     event[pos++] = sizeof(event) - 2;
1194     event[pos++] = MESH_SUBEVENT_CONFIGURATION_APPKEY_INDEX;
1195     // dest
1196     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
1197     pos += 2;
1198     event[pos++] = status;
1199     little_endian_store_16(event, pos, netkey_index);
1200     pos += 2;
1201     little_endian_store_16(event, pos, appkey_index);
1202     pos += 2;
1203 
1204     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
1205     mesh_access_message_processed(pdu);
1206 }
1207 
1208 static void mesh_configuration_client_appkey_list_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1209     mesh_access_parser_state_t parser;
1210     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1211     uint8_t status = 0;
1212     uint8_t list_size = mesh_access_parser_available(&parser)/2;
1213 
1214     uint8_t event[12];
1215     int pos = 0;
1216     event[pos++] = HCI_EVENT_MESH_META;
1217     event[pos++] = sizeof(event) - 2;
1218     event[pos++] = MESH_SUBEVENT_CONFIGURATION_APPKEY_INDEX_LIST_ITEM;
1219     // dest
1220     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
1221     pos += 2;
1222     event[pos++] = status;
1223 
1224     event[pos++] = list_size;
1225     uint8_t i;
1226     for (i = 0; i < list_size; i++){
1227         event[pos++] = i;
1228         uint32_t netappkey_index = mesh_access_parser_get_u24(&parser);
1229         little_endian_store_16(event, pos, netappkey_index >> 12);
1230         little_endian_store_16(event, pos + 2, netappkey_index & 0xFFF);
1231         (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos + 4);
1232     }
1233     mesh_access_message_processed(pdu);
1234 }
1235 
1236 static void mesh_configuration_client_node_identity_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1237     mesh_access_parser_state_t parser;
1238     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1239     uint8_t  status = mesh_access_parser_get_u8(&parser);
1240     uint16_t netkey_index = mesh_access_parser_get_u16(&parser);
1241     uint8_t  identity_status = mesh_access_parser_get_u8(&parser);
1242 
1243     uint8_t event[9];
1244     int pos = 0;
1245     event[pos++] = HCI_EVENT_MESH_META;
1246     event[pos++] = sizeof(event) - 2;
1247     event[pos++] = MESH_SUBEVENT_CONFIGURATION_NODE_IDENTITY;
1248     // dest
1249     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
1250     pos += 2;
1251     event[pos++] = status;
1252     little_endian_store_16(event, pos, netkey_index);
1253     pos += 2;
1254     event[pos++] = identity_status;
1255 
1256     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
1257     mesh_access_message_processed(pdu);
1258 }
1259 
1260 static void mesh_configuration_client_model_app_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1261     mesh_access_parser_state_t parser;
1262     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1263     uint8_t  status = mesh_access_parser_get_u8(&parser);
1264     uint16_t element_address = mesh_access_parser_get_u16(&parser);
1265     uint16_t appkey_index = mesh_access_parser_get_u16(&parser);
1266     uint32_t model_id = 0;
1267 
1268     if (element_address != mesh_pdu_src(pdu)){
1269         log_info("MESH_SUBEVENT_CONFIGURATION_MODEL_APP event, element_address differs from mesh_pdu_src");
1270     }
1271 
1272     if (mesh_access_parser_available(&parser) == 4){
1273         model_id = mesh_access_parser_get_u32(&parser);
1274     } else {
1275         model_id = mesh_access_parser_get_u16(&parser);
1276     }
1277 
1278     uint8_t event[12];
1279     int pos = 0;
1280     event[pos++] = HCI_EVENT_MESH_META;
1281     event[pos++] = sizeof(event) - 2;
1282     event[pos++] = MESH_SUBEVENT_CONFIGURATION_MODEL_APP;
1283     // dest
1284     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
1285     pos += 2;
1286     event[pos++] = status;
1287 
1288     little_endian_store_16(event, pos, appkey_index);
1289     pos += 2;
1290     little_endian_store_32(event, pos, model_id);
1291     pos += 4;
1292 
1293     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
1294     mesh_access_message_processed(pdu);
1295 }
1296 
1297 
1298 static void mesh_configuration_client_model_app_list_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu, bool is_sig_model){
1299     mesh_access_parser_state_t parser;
1300     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1301 
1302     uint8_t  status = mesh_access_parser_get_u8(&parser);
1303     uint16_t element_address = mesh_access_parser_get_u16(&parser);
1304     uint32_t model_identifier;
1305 
1306     if (element_address != mesh_pdu_src(pdu)){
1307         log_info("MESH_SUBEVENT_CONFIGURATION_MODEL_APP_LIST_ITEM event, element_address differs from mesh_pdu_src");
1308     }
1309 
1310     if (is_sig_model == true) {
1311         model_identifier = mesh_access_parser_get_sig_model_identifier(&parser);
1312     } else {
1313         model_identifier = mesh_access_parser_get_vendor_model_identifier(&parser);
1314     }
1315 
1316     uint8_t  list_size = mesh_access_parser_available(&parser)/2;
1317 
1318     uint8_t event[14];
1319     int pos = 0;
1320     event[pos++] = HCI_EVENT_MESH_META;
1321     event[pos++] = sizeof(event) - 2;
1322     event[pos++] = MESH_SUBEVENT_CONFIGURATION_MODEL_APP_LIST_ITEM;
1323     // dest
1324     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
1325     pos += 2;
1326     event[pos++] = status;
1327 
1328     little_endian_store_32(event, pos, model_identifier);
1329     pos += 4;
1330 
1331     event[pos++] = list_size;
1332     uint8_t i;
1333     for (i = 0; i < list_size; i++){
1334         event[pos++] = i;
1335         uint16_t appkey_index = mesh_access_parser_get_u16(&parser);
1336         little_endian_store_16(event, pos, appkey_index);
1337         (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos + 2);
1338     }
1339     mesh_access_message_processed(pdu);
1340 }
1341 
1342 static void mesh_configuration_client_sig_model_app_list_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1343     mesh_configuration_client_model_app_list_handler(mesh_model, pdu, true);
1344 }
1345 
1346 static void mesh_configuration_client_vendor_model_app_list_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1347     mesh_configuration_client_model_app_list_handler(mesh_model, pdu, false);
1348 }
1349 
1350 static void mesh_configuration_client_node_reset_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1351     uint8_t event[6];
1352     int pos = 0;
1353     event[pos++] = HCI_EVENT_MESH_META;
1354     event[pos++] = sizeof(event) - 2;
1355     event[pos++] = MESH_SUBEVENT_CONFIGURATION_NODE_RESET;
1356     // dest
1357     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
1358     pos += 2;
1359     event[pos++] = ERROR_CODE_SUCCESS;
1360 
1361     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
1362     mesh_access_message_processed(pdu);
1363 }
1364 
1365 static void mesh_configuration_client_friend_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1366     mesh_access_parser_state_t parser;
1367     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1368     uint8_t friend_state = mesh_access_parser_get_u8(&parser);
1369 
1370     uint8_t event[7];
1371     int pos = 0;
1372     event[pos++] = HCI_EVENT_MESH_META;
1373     event[pos++] = sizeof(event) - 2;
1374     event[pos++] = MESH_SUBEVENT_CONFIGURATION_FRIEND;
1375     // dest
1376     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
1377     pos += 2;
1378     event[pos++] = ERROR_CODE_SUCCESS;
1379     event[pos++] = friend_state;
1380 
1381     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
1382     mesh_access_message_processed(pdu);
1383 }
1384 
1385 static void mesh_configuration_client_key_refresh_phase_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1386     mesh_access_parser_state_t parser;
1387     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1388     uint8_t  status = mesh_access_parser_get_u8(&parser);
1389     uint16_t netkey_index = mesh_access_parser_get_u16(&parser);
1390     uint8_t  phase = mesh_access_parser_get_u8(&parser);
1391 
1392     uint8_t event[9];
1393     int pos = 0;
1394     event[pos++] = HCI_EVENT_MESH_META;
1395     event[pos++] = sizeof(event) - 2;
1396     event[pos++] = MESH_SUBEVENT_CONFIGURATION_KEY_REFRESH_PHASE;
1397     // dest
1398     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
1399     pos += 2;
1400     event[pos++] = status;
1401     little_endian_store_16(event, pos, netkey_index);
1402     pos += 2;
1403     event[pos++] = phase;
1404 
1405     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
1406     mesh_access_message_processed(pdu);
1407 }
1408 
1409 static void mesh_configuration_client_heartbeat_publication_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1410     mesh_access_parser_state_t parser;
1411     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1412     uint8_t  status     = mesh_access_parser_get_u8(&parser);
1413     uint16_t dest       = mesh_access_parser_get_u16(&parser);
1414     uint8_t  count      = mesh_heartbeat_pwr2(mesh_access_parser_get_u8(&parser));
1415     uint16_t period_s   = mesh_heartbeat_pwr2(mesh_access_parser_get_u8(&parser));
1416     uint8_t  ttl        = mesh_access_parser_get_u8(&parser);
1417     uint16_t features   = mesh_access_parser_get_u16(&parser);
1418     uint16_t netkey_index = mesh_access_parser_get_u16(&parser);
1419 
1420     uint8_t event[17];
1421     int pos = 0;
1422     event[pos++] = HCI_EVENT_MESH_META;
1423     event[pos++] = sizeof(event) - 2;
1424     event[pos++] = MESH_SUBEVENT_CONFIGURATION_HEARTBEAT_PUBLICATION;
1425     // dest
1426     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
1427     pos += 2;
1428     event[pos++] = status;
1429     little_endian_store_16(event, pos, dest);
1430     pos += 2;
1431     little_endian_store_16(event, pos, count);
1432     pos += 2;
1433     little_endian_store_16(event, pos, period_s);
1434     pos += 2;
1435     event[pos++] = ttl;
1436     little_endian_store_16(event, pos, features);
1437     pos += 2;
1438     little_endian_store_16(event, pos, netkey_index);
1439     pos += 2;
1440     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
1441     mesh_access_message_processed(pdu);
1442 }
1443 
1444 static void mesh_configuration_client_heartbeat_subscription_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1445     mesh_access_parser_state_t parser;
1446     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1447     uint8_t  status     = mesh_access_parser_get_u8(&parser);
1448     uint16_t source     = mesh_access_parser_get_u16(&parser);
1449     uint16_t dest       = mesh_access_parser_get_u16(&parser);
1450     uint16_t period_s   = mesh_heartbeat_pwr2(mesh_access_parser_get_u8(&parser));
1451     uint16_t count      = mesh_heartbeat_pwr2(mesh_access_parser_get_u8(&parser));
1452     uint8_t  min_hops   = mesh_access_parser_get_u8(&parser);
1453     uint8_t  max_hops   = mesh_access_parser_get_u8(&parser);
1454 
1455     uint8_t event[16];
1456     int pos = 0;
1457     event[pos++] = HCI_EVENT_MESH_META;
1458     event[pos++] = sizeof(event) - 2;
1459     event[pos++] = MESH_SUBEVENT_CONFIGURATION_HEARTBEAT_SUBSCRIPTION;
1460     // dest
1461     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
1462     pos += 2;
1463     event[pos++] = status;
1464     little_endian_store_16(event, pos, dest);
1465     pos += 2;
1466     little_endian_store_16(event, pos, source);
1467     pos += 2;
1468     little_endian_store_16(event, pos, count);
1469     pos += 2;
1470     little_endian_store_16(event, pos, period_s);
1471     pos += 2;
1472     event[pos++] = min_hops;
1473     event[pos++] = max_hops;
1474 
1475     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
1476     mesh_access_message_processed(pdu);
1477 }
1478 
1479 static void mesh_configuration_client_low_power_node_poll_timeout_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1480     mesh_access_parser_state_t parser;
1481     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1482     uint16_t lpn_address  = mesh_access_parser_get_u16(&parser);
1483     uint32_t poll_timeout = mesh_access_parser_get_u24(&parser);
1484 
1485     uint8_t event[11];
1486     int pos = 0;
1487     event[pos++] = HCI_EVENT_MESH_META;
1488     event[pos++] = sizeof(event) - 2;
1489     event[pos++] = MESH_SUBEVENT_CONFIGURATION_LOW_POWER_NODE_POLL_TIMEOUT;
1490     // dest
1491     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
1492     pos += 2;
1493     event[pos++] = ERROR_CODE_SUCCESS;
1494 
1495     little_endian_store_16(event, pos, lpn_address);
1496     pos += 2;
1497 
1498     little_endian_store_24(event, pos, poll_timeout);
1499     pos += 3;
1500 
1501     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
1502     mesh_access_message_processed(pdu);
1503 }
1504 
1505 static void mesh_configuration_client_network_transmit_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1506     mesh_access_parser_state_t parser;
1507     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1508     uint8_t value  = mesh_access_parser_get_u8(&parser);
1509     uint8_t transmit_count = value >> 5;
1510     uint8_t transmit_interval_steps_10ms = value & 0x1F;
1511 
1512     uint8_t event[9];
1513     int pos = 0;
1514     event[pos++] = HCI_EVENT_MESH_META;
1515     event[pos++] = sizeof(event) - 2;
1516     event[pos++] = MESH_SUBEVENT_CONFIGURATION_NETWORK_TRANSMIT;
1517     // dest
1518     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
1519     pos += 2;
1520     event[pos++] = ERROR_CODE_SUCCESS;
1521 
1522     event[pos++] = transmit_count;
1523     little_endian_store_16(event, pos, (transmit_interval_steps_10ms + 1) * 10);
1524     pos += 2;
1525 
1526     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
1527     mesh_access_message_processed(pdu);
1528 }
1529 
1530 const static mesh_operation_t mesh_configuration_client_model_operations[] = {
1531     { MESH_FOUNDATION_OPERATION_BEACON_STATUS,                      1, mesh_configuration_client_beacon_status_handler },
1532     { MESH_FOUNDATION_OPERATION_COMPOSITION_DATA_STATUS,           10, mesh_configuration_client_composition_data_status_handler },
1533     { MESH_FOUNDATION_OPERATION_DEFAULT_TTL_STATUS,                 1, mesh_configuration_client_default_ttl_handler },
1534     { MESH_FOUNDATION_OPERATION_GATT_PROXY_STATUS,                  1, mesh_configuration_client_gatt_proxy_handler },
1535     { MESH_FOUNDATION_OPERATION_RELAY_STATUS,                       2, mesh_configuration_client_relay_handler },
1536     { MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_STATUS,          12, mesh_configuration_client_model_publication_handler },
1537     { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_STATUS,          7, mesh_configuration_client_model_subscription_handler },
1538     { MESH_FOUNDATION_OPERATION_SIG_MODEL_SUBSCRIPTION_LIST,        5, mesh_configuration_client_sig_model_subscription_handler},
1539     { MESH_FOUNDATION_OPERATION_VENDOR_MODEL_SUBSCRIPTION_LIST,     7, mesh_configuration_client_vendor_model_subscription_handler},
1540     { MESH_FOUNDATION_OPERATION_NETKEY_STATUS,                      3, mesh_configuration_client_netkey_handler },
1541     { MESH_FOUNDATION_OPERATION_NETKEY_LIST,                        0, mesh_configuration_client_netkey_list_handler },
1542     { MESH_FOUNDATION_OPERATION_APPKEY_STATUS,                      4, mesh_configuration_client_appkey_handler },
1543     { MESH_FOUNDATION_OPERATION_APPKEY_LIST,                        3, mesh_configuration_client_appkey_list_handler },
1544     { MESH_FOUNDATION_OPERATION_NODE_IDENTITY_STATUS,               4, mesh_configuration_client_node_identity_handler },
1545     { MESH_FOUNDATION_OPERATION_MODEL_APP_STATUS,                   7, mesh_configuration_client_model_app_handler },
1546     { MESH_FOUNDATION_OPERATION_SIG_MODEL_APP_LIST,                 5, mesh_configuration_client_sig_model_app_list_handler },
1547     { MESH_FOUNDATION_OPERATION_VENDOR_MODEL_APP_LIST,              7, mesh_configuration_client_vendor_model_app_list_handler },
1548     { MESH_FOUNDATION_OPERATION_NODE_RESET_STATUS,                  0, mesh_configuration_client_node_reset_handler },
1549     { MESH_FOUNDATION_OPERATION_FRIEND_STATUS,                      1, mesh_configuration_client_friend_handler },
1550     { MESH_FOUNDATION_OPERATION_KEY_REFRESH_PHASE_STATUS,           4, mesh_configuration_client_key_refresh_phase_handler },
1551     { MESH_FOUNDATION_OPERATION_HEARTBEAT_PUBLICATION_STATUS,      12, mesh_configuration_client_heartbeat_publication_handler },
1552     { MESH_FOUNDATION_OPERATION_HEARTBEAT_SUBSCRIPTION_STATUS,     11, mesh_configuration_client_heartbeat_subscription_handler },
1553     { MESH_FOUNDATION_OPERATION_LOW_POWER_NODE_POLL_TIMEOUT_STATUS, 5, mesh_configuration_client_low_power_node_poll_timeout_handler},
1554     { MESH_FOUNDATION_OPERATION_NETWORK_TRANSMIT_STATUS,            1, mesh_configuration_client_network_transmit_handler},
1555     { 0, 0, NULL }
1556 };
1557 
1558 const mesh_operation_t * mesh_configuration_client_get_operations(void){
1559     return mesh_configuration_client_model_operations;
1560 }
1561 
1562 void mesh_configuration_client_register_packet_handler(mesh_model_t *configuration_client_model, btstack_packet_handler_t events_packet_handler){
1563     btstack_assert(events_packet_handler != NULL);
1564     btstack_assert(configuration_client_model != NULL);
1565 
1566     configuration_client_model->model_packet_handler = events_packet_handler;
1567 }
1568 
1569