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