xref: /btstack/src/mesh/mesh_configuration_client.c (revision 8d4cf36ecc136b92ee80a64b86081eb75b509ce2)
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 
274 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){
275     uint8_t  ttl  = mesh_foundation_default_ttl_get();
276     mesh_upper_transport_setup_access_pdu_header(pdu, netkey_index, appkey_index, ttl, src, dest, 0);
277     mesh_access_send_acknowledged_pdu(pdu, mesh_access_acknowledged_message_retransmissions(), ack_opcode);
278 }
279 
280 static uint8_t mesh_access_validate_envelop_params(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
281     btstack_assert(mesh_model != NULL);
282     // TODO: validate other params
283     UNUSED(mesh_model);
284     UNUSED(dest);
285     UNUSED(netkey_index);
286     UNUSED(appkey_index);
287 
288     return ERROR_CODE_SUCCESS;
289 }
290 
291 uint8_t mesh_configuration_client_send_beacon_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
292     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
293     if (status != ERROR_CODE_SUCCESS) return status;
294 
295     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_beacon_get);
296     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
297 
298     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);
299     return ERROR_CODE_SUCCESS;
300 }
301 
302 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){
303     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
304     if (status != ERROR_CODE_SUCCESS) return status;
305 
306     if (beacon > 1) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
307 
308     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_beacon_set, beacon);
309     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
310 
311     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);
312     return ERROR_CODE_SUCCESS;
313 }
314 
315 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){
316     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
317     if (status != ERROR_CODE_SUCCESS) return status;
318 
319     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_composition_data_get, page);
320     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
321 
322     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);
323     return ERROR_CODE_SUCCESS;
324 }
325 
326 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){
327     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
328     if (status != ERROR_CODE_SUCCESS) return status;
329 
330     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_default_ttl_get);
331     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
332 
333     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);
334     return ERROR_CODE_SUCCESS;
335 }
336 
337 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){
338     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
339     if (status != ERROR_CODE_SUCCESS) return status;
340 
341     if (ttl == 0x01 || ttl >= 0x80) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
342 
343     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_default_ttl_set, ttl);
344     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
345 
346     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);
347     return ERROR_CODE_SUCCESS;
348 }
349 
350 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){
351     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
352     if (status != ERROR_CODE_SUCCESS) return status;
353 
354     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_gatt_proxy_get);
355     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
356 
357     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);
358     return ERROR_CODE_SUCCESS;
359 }
360 
361 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){
362     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
363     if (status != ERROR_CODE_SUCCESS) return status;
364 
365     if (gatt_proxy_state > 2) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
366 
367     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_gatt_proxy_set, gatt_proxy_state);
368     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
369 
370     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);
371     return ERROR_CODE_SUCCESS;
372 }
373 
374 uint8_t mesh_configuration_client_send_relay_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
375     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
376     if (status != ERROR_CODE_SUCCESS) return status;
377 
378     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_relay_get);
379     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
380 
381     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);
382     return ERROR_CODE_SUCCESS;
383 }
384 
385 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){
386     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
387     if (status != ERROR_CODE_SUCCESS) return status;
388 
389     if (relay_retransmit_count > 0x07) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
390     if (relay_retransmit_interval_steps > 0x1F) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
391 
392     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);
393     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
394 
395     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);
396     return ERROR_CODE_SUCCESS;
397 }
398 
399 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){
400     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
401     if (status != ERROR_CODE_SUCCESS) return status;
402 
403     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_publication_get, dest, model_id);
404     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
405 
406     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);
407     return ERROR_CODE_SUCCESS;
408 }
409 
410 static uint8_t mesh_validate_publication_model_config_parameters(mesh_publication_model_config_t * publication_config, bool use_unicast_address){
411     if (publication_config->appkey_index > 0xFFF) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
412     if (publication_config->credential_flag > 1) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
413     if (publication_config->publish_retransmit_count > 0x07) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
414     if (publication_config->publish_retransmit_interval_steps > 0x1F) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
415     if (use_unicast_address && mesh_network_address_virtual(publication_config->publish_address_unicast)) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
416     return ERROR_CODE_SUCCESS;
417 }
418 
419 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){
420     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
421     if (status != ERROR_CODE_SUCCESS) return status;
422 
423     if (!mesh_network_address_unicast(dest) ||
424         mesh_validate_publication_model_config_parameters(publication_config, true) != ERROR_CODE_SUCCESS){
425         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
426     }
427 
428     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_publication_set,
429         dest,
430         publication_config->publish_address_unicast,
431         (publication_config->credential_flag << 12) | publication_config->appkey_index,
432         publication_config->publish_ttl,
433         publication_config->publish_period,
434         (publication_config->publish_retransmit_interval_steps << 3) | publication_config->publish_retransmit_count,
435         model_id);
436     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
437 
438     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);
439     return ERROR_CODE_SUCCESS;
440 
441 }
442 
443 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){
444     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
445     if (status != ERROR_CODE_SUCCESS) return status;
446 
447     if (!mesh_network_address_unicast(dest) ||
448         mesh_validate_publication_model_config_parameters(publication_config, false) != ERROR_CODE_SUCCESS){
449         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
450     }
451 
452     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_model_publication_virtual_address_set,
453         dest,
454         publication_config->publish_address_virtual,
455         (publication_config->credential_flag << 12) | publication_config->appkey_index,
456         publication_config->publish_ttl,
457         publication_config->publish_period,
458         (publication_config->publish_retransmit_interval_steps << 3) | publication_config->publish_retransmit_count,
459         model_id);
460     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
461 
462     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);
463     return ERROR_CODE_SUCCESS;
464 }
465 
466 
467 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){
468     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
469     if (status != ERROR_CODE_SUCCESS) return status;
470 
471     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_subscription_add, dest, address, model_id);
472     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
473 
474     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);
475     return ERROR_CODE_SUCCESS;
476 }
477 
478 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){
479     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
480     if (status != ERROR_CODE_SUCCESS) return status;
481 
482     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_model_subscription_virtual_address_add, dest, address, model_id);
483     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
484 
485     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);
486     return ERROR_CODE_SUCCESS;
487 }
488 
489 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){
490     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
491     if (status != ERROR_CODE_SUCCESS) return status;
492 
493     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_subscription_delete, dest, address, model_id);
494     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
495 
496     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);
497     return ERROR_CODE_SUCCESS;
498 }
499 
500 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){
501     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
502     if (status != ERROR_CODE_SUCCESS) return status;
503 
504     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_model_subscription_virtual_address_delete, dest, address, model_id);
505     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
506 
507     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);
508     return ERROR_CODE_SUCCESS;
509 }
510 
511 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){
512         uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
513     if (status != ERROR_CODE_SUCCESS) return status;
514 
515     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_subscription_overwrite, dest, address, model_id);
516     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
517 
518     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);
519     return ERROR_CODE_SUCCESS;
520 }
521 
522 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){
523     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
524     if (status != ERROR_CODE_SUCCESS) return status;
525 
526     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_model_subscription_virtual_address_overwrite, dest, address, model_id);
527     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
528 
529     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);
530     return ERROR_CODE_SUCCESS;
531 }
532 
533 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){
534         uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
535     if (status != ERROR_CODE_SUCCESS) return status;
536 
537     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_subscription_delete_all, dest, address, model_id);
538     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
539 
540     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);
541     return ERROR_CODE_SUCCESS;
542 }
543 
544 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){
545     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
546     if (status != ERROR_CODE_SUCCESS) return status;
547 
548     mesh_network_pdu_t * network_pdu = NULL;
549     uint32_t ack_opcode = MESH_FOUNDATION_OPERATION_SIG_MODEL_SUBSCRIPTION_LIST;
550 
551     if (mesh_model_is_bluetooth_sig(model_id)){
552         network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_sig_model_subscription_get, dest, model_id);
553     } else {
554         network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_vendor_model_subscription_get, dest, model_id);
555         ack_opcode = MESH_FOUNDATION_OPERATION_VENDOR_MODEL_SUBSCRIPTION_LIST;
556     }
557 
558     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
559 
560     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, ack_opcode);
561     return ERROR_CODE_SUCCESS;
562 }
563 
564 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){
565     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
566     if (status != ERROR_CODE_SUCCESS) return status;
567 
568     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_netkey_add, index, netkey);
569     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
570 
571     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);
572     return ERROR_CODE_SUCCESS;
573 }
574 
575 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){
576     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
577     if (status != ERROR_CODE_SUCCESS) return status;
578 
579     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_netkey_update, index, netkey);
580     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
581 
582     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);
583     return ERROR_CODE_SUCCESS;
584 }
585 
586 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){
587     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
588     if (status != ERROR_CODE_SUCCESS) return status;
589 
590     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_netkey_delete, index);
591     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
592 
593     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);
594     return ERROR_CODE_SUCCESS;
595 }
596 
597 uint8_t mesh_configuration_client_send_netkey_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
598     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
599     if (status != ERROR_CODE_SUCCESS) return status;
600 
601     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_netkey_get);
602     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
603 
604     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);
605     return ERROR_CODE_SUCCESS;
606 }
607 
608 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){
609     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
610     if (status != ERROR_CODE_SUCCESS) return status;
611 
612     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_appkey_add, netk_index << 12 | appk_index, appkey);
613     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
614 
615     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);
616     return ERROR_CODE_SUCCESS;
617 }
618 
619 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){
620     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
621     if (status != ERROR_CODE_SUCCESS) return status;
622 
623     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_appkey_update, netk_index << 12 | appk_index, appkey);
624     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
625 
626     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);
627     return ERROR_CODE_SUCCESS;
628 }
629 
630 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){
631     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
632     if (status != ERROR_CODE_SUCCESS) return status;
633 
634     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_appkey_delete, netk_index << 12 | appk_index);
635     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
636 
637     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);
638     return ERROR_CODE_SUCCESS;
639 }
640 
641 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){
642     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
643     if (status != ERROR_CODE_SUCCESS) return status;
644 
645     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_appkey_get, netk_index);
646     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
647 
648     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);
649     return ERROR_CODE_SUCCESS;
650 }
651 
652 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){
653     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
654     if (status != ERROR_CODE_SUCCESS) return status;
655 
656     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_node_identity_get, netk_index);
657     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
658 
659     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);
660     return ERROR_CODE_SUCCESS;
661 }
662 
663 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){
664     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
665     if (status != ERROR_CODE_SUCCESS) return status;
666 
667     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_node_identity_set, netk_index, node_identity_state);
668     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
669 
670     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);
671     return ERROR_CODE_SUCCESS;
672 }
673 
674 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){
675     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
676     if (status != ERROR_CODE_SUCCESS) return status;
677 
678     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_model_app_bind, dest, appk_index, model_identifier);
679     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
680 
681     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);
682     return ERROR_CODE_SUCCESS;
683 }
684 
685 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){
686     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
687     if (status != ERROR_CODE_SUCCESS) return status;
688 
689     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_model_app_unbind, dest, appk_index, model_identifier);
690     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
691 
692     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);
693     return ERROR_CODE_SUCCESS;
694 }
695 
696 
697 // Model Operations
698 static void mesh_configuration_client_composition_data_status_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
699     // Composition Data has variable of element descriptions, with two lists of model lists
700     // Pass raw data to application but provide convenient setters instead of parsing pdu here
701 
702     // reuse part of the mesh_network_t / mesh_transport_t struct to create event without memcpy or allocation
703     uint8_t * data = mesh_pdu_data(pdu);
704     uint8_t * event = &data[-6];
705 
706     int pos = 0;
707     event[pos++] = HCI_EVENT_MESH_META;
708     // Composite Data might be larger than 251 bytes - in this case only lower 8 bit are stored here. packet size is correct
709     event[pos++] = (uint8_t) (6 + mesh_pdu_len(pdu));
710     event[pos++] = MESH_SUBEVENT_CONFIGURATION_COMPOSITION_DATA;
711     // dest
712     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
713     pos += 2;
714     event[pos++] = ERROR_CODE_SUCCESS;
715 
716     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
717     mesh_access_message_processed(pdu);
718 }
719 
720 uint8_t mesh_subevent_configuration_composition_data_get_page(const uint8_t * event){
721     return event[6];
722 }
723 
724 uint16_t mesh_subevent_configuration_composition_data_get_cid(const uint8_t * event){
725     return little_endian_read_16(event, 7);
726 }
727 
728 uint16_t mesh_subevent_configuration_composition_data_get_pid(const uint8_t * event){
729     return little_endian_read_16(event, 9);
730 }
731 
732 uint16_t mesh_subevent_configuration_composition_data_get_vid(const uint8_t * event){
733     return little_endian_read_16(event, 11);
734 }
735 
736 uint16_t mesh_subevent_configuration_composition_data_get_crpl(const uint8_t * event){
737     return little_endian_read_16(event, 13);
738 }
739 
740 uint16_t mesh_subevent_configuration_composition_data_get_features(const uint8_t * event){
741     return little_endian_read_16(event, 15);
742 }
743 
744 
745 static inline void mesh_configuration_client_handle_uint8_value(mesh_model_t *mesh_model, mesh_pdu_t * pdu, uint8_t subevent_type){
746     mesh_access_parser_state_t parser;
747     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
748 
749     uint8_t value = mesh_access_parser_get_u8(&parser);
750 
751     uint8_t event[7];
752     int pos = 0;
753 
754     event[pos++] = HCI_EVENT_MESH_META;
755     event[pos++] = sizeof(event) - 2;
756     event[pos++] = subevent_type;
757     // dest
758     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
759     pos += 2;
760     event[pos++] = ERROR_CODE_SUCCESS;
761     event[pos++] = value;
762 
763     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
764     mesh_access_message_processed(pdu);
765 }
766 
767 static void mesh_configuration_client_beacon_status_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
768     mesh_configuration_client_handle_uint8_value(mesh_model, pdu, MESH_SUBEVENT_CONFIGURATION_BEACON);
769 }
770 
771 static void mesh_configuration_client_default_ttl_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
772     mesh_configuration_client_handle_uint8_value(mesh_model, pdu, MESH_SUBEVENT_CONFIGURATION_DEFAULT_TTL);
773 }
774 
775 static void mesh_configuration_client_gatt_proxy_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
776     mesh_configuration_client_handle_uint8_value(mesh_model, pdu, MESH_SUBEVENT_CONFIGURATION_GATT_PROXY);
777 }
778 
779 static void mesh_configuration_client_relay_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
780     mesh_access_parser_state_t parser;
781     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
782 
783     uint8_t relay = mesh_access_parser_get_u8(&parser);
784     uint8_t retransmition = mesh_access_parser_get_u8(&parser);
785 
786     uint8_t event[9];
787 
788     int pos = 0;
789     event[pos++] = HCI_EVENT_MESH_META;
790     event[pos++] = sizeof(event) - 2;
791     event[pos++] = MESH_SUBEVENT_CONFIGURATION_RELAY;
792     // dest
793     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
794     pos += 2;
795     event[pos++] = ERROR_CODE_SUCCESS;
796     event[pos++] = relay;
797     event[pos++] = (retransmition >> 5) + 1;
798     event[pos++] = ((retransmition & 0x07) + 1) * 10;
799 
800     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
801     mesh_access_message_processed(pdu);
802 }
803 
804 static void mesh_configuration_client_model_publication_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
805     mesh_access_parser_state_t parser;
806     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
807     uint8_t  status = mesh_access_parser_get_u8(&parser);
808     uint16_t publish_addres = mesh_access_parser_get_u16(&parser);
809 
810     uint16_t value = mesh_access_parser_get_u16(&parser);
811     uint16_t appkey_index = value & 0xFFF;
812     uint8_t  credential_flag = (value & 0x1000) >> 12;
813 
814     uint8_t publish_ttl = mesh_access_parser_get_u8(&parser);
815     uint8_t publish_period = mesh_access_parser_get_u8(&parser);
816 
817     uint8_t retransmit = mesh_access_parser_get_u8(&parser);
818     uint8_t publish_retransmit_count = retransmit & 0x111;
819     uint8_t publish_retransmit_interval_steps = retransmit >> 5;
820     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
821 
822     uint8_t event[19];
823     int pos = 0;
824     event[pos++] = HCI_EVENT_MESH_META;
825     event[pos++] = sizeof(event) - 2;
826     event[pos++] = MESH_SUBEVENT_CONFIGURATION_MODEL_PUBLICATION;
827     // dest
828     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
829     pos += 2;
830     event[pos++] = status;
831 
832     little_endian_store_16(event, pos, publish_addres);
833     pos += 2;
834 
835     little_endian_store_16(event, pos, appkey_index);
836     pos += 2;
837 
838     event[pos++] = credential_flag;
839     event[pos++] = publish_ttl;
840     event[pos++] = publish_period;
841     event[pos++] = publish_retransmit_count;
842     event[pos++] = publish_retransmit_interval_steps;
843 
844     little_endian_store_32(event, pos, model_identifier);
845     pos += 4;
846 
847     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
848     mesh_access_message_processed(pdu);
849 }
850 
851 static void mesh_configuration_client_model_subscription_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
852     mesh_access_parser_state_t parser;
853     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
854     uint8_t  status = mesh_access_parser_get_u8(&parser);
855     uint16_t address = mesh_access_parser_get_u16(&parser);
856     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
857 
858     uint8_t event[12];
859     int pos = 0;
860     event[pos++] = HCI_EVENT_MESH_META;
861     event[pos++] = sizeof(event) - 2;
862     event[pos++] = MESH_SUBEVENT_CONFIGURATION_MODEL_SUBSCRIPTION;
863     // dest
864     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
865     pos += 2;
866     event[pos++] = status;
867 
868     little_endian_store_16(event, pos, address);
869     pos += 2;
870 
871     little_endian_store_32(event, pos, model_identifier);
872     pos += 4;
873 
874     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
875     mesh_access_message_processed(pdu);
876 }
877 
878 static void mesh_configuration_client_model_subscription_event(mesh_model_t *mesh_model, mesh_pdu_t * pdu, uint8_t subevent_type){
879     mesh_access_parser_state_t parser;
880     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
881     uint8_t  status = mesh_access_parser_get_u8(&parser);
882     uint16_t address = mesh_access_parser_get_u16(&parser);
883     uint32_t model_identifier;
884 
885     if (subevent_type == MESH_SUBEVENT_CONFIGURATION_SIG_MODEL_SUBSCRIPTION_LIST_ITEM) {
886         model_identifier = mesh_access_parser_get_sig_model_identifier(&parser);
887     } else {
888         model_identifier = mesh_access_parser_get_vendor_model_identifier(&parser);
889     }
890     uint8_t list_size = mesh_access_parser_available(&parser)/2;
891 
892     uint8_t event[12];
893     int pos = 0;
894     event[pos++] = HCI_EVENT_MESH_META;
895     event[pos++] = sizeof(event) - 2;
896     event[pos++] = subevent_type;
897     // dest
898     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
899     pos += 2;
900     event[pos++] = status;
901 
902     little_endian_store_16(event, pos, address);
903     pos += 2;
904 
905     event[pos++] = list_size;
906     uint8_t i;
907     for (i = 0; i < list_size; i++){
908         event[pos++] = i;
909         little_endian_store_16(event, pos, mesh_access_parser_get_u16(&parser));
910         (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos + 2);
911     }
912     mesh_access_message_processed(pdu);
913 }
914 
915 static void mesh_configuration_client_sig_model_subscription_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
916     mesh_configuration_client_model_subscription_event(mesh_model, pdu, MESH_SUBEVENT_CONFIGURATION_SIG_MODEL_SUBSCRIPTION_LIST_ITEM);
917 }
918 
919 static void mesh_configuration_client_vendor_model_subscription_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
920         mesh_configuration_client_model_subscription_event(mesh_model, pdu, MESH_SUBEVENT_CONFIGURATION_VENDOR_MODEL_SUBSCRIPTION_LIST_ITEM);
921 }
922 
923 static void mesh_configuration_client_netkey_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
924     mesh_access_parser_state_t parser;
925     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
926     uint8_t  status = mesh_access_parser_get_u8(&parser);
927 
928     uint8_t event[6];
929     int pos = 0;
930     event[pos++] = HCI_EVENT_MESH_META;
931     event[pos++] = sizeof(event) - 2;
932     event[pos++] = MESH_SUBEVENT_CONFIGURATION_NETKEY_INDEX;
933     // dest
934     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
935     pos += 2;
936     event[pos++] = status;
937     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
938     mesh_access_message_processed(pdu);
939 }
940 
941 static void mesh_configuration_client_netkey_list_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
942     mesh_access_parser_state_t parser;
943     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
944     uint8_t status = 0;
945     uint8_t list_size = mesh_access_parser_available(&parser)/2;
946 
947     uint8_t event[10];
948     int pos = 0;
949     event[pos++] = HCI_EVENT_MESH_META;
950     event[pos++] = sizeof(event) - 2;
951     event[pos++] = MESH_SUBEVENT_CONFIGURATION_NETKEY_INDEX_LIST_ITEM;
952     // dest
953     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
954     pos += 2;
955     event[pos++] = status;
956 
957     event[pos++] = list_size;
958     uint8_t i;
959     for (i = 0; i < list_size; i++){
960         event[pos++] = i;
961         little_endian_store_16(event, pos, mesh_access_parser_get_u16(&parser));
962         (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos + 2);
963     }
964     mesh_access_message_processed(pdu);
965 }
966 
967 static void mesh_configuration_client_appkey_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
968     mesh_access_parser_state_t parser;
969     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
970     uint8_t  status = mesh_access_parser_get_u8(&parser);
971     uint32_t netappkey_index = mesh_access_parser_get_u24(&parser);
972     uint16_t netkey_index = netappkey_index >> 12;
973     uint16_t appkey_index = netappkey_index & 0xFFF;
974 
975     uint8_t event[10];
976     int pos = 0;
977     event[pos++] = HCI_EVENT_MESH_META;
978     event[pos++] = sizeof(event) - 2;
979     event[pos++] = MESH_SUBEVENT_CONFIGURATION_APPKEY_INDEX;
980     // dest
981     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
982     pos += 2;
983     event[pos++] = status;
984     little_endian_store_16(event, pos, netkey_index);
985     pos += 2;
986     little_endian_store_16(event, pos, appkey_index);
987     pos += 2;
988 
989     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
990     mesh_access_message_processed(pdu);
991 }
992 
993 static void mesh_configuration_client_appkey_list_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
994     mesh_access_parser_state_t parser;
995     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
996     uint8_t status = 0;
997     uint8_t list_size = mesh_access_parser_available(&parser)/2;
998 
999     uint8_t event[12];
1000     int pos = 0;
1001     event[pos++] = HCI_EVENT_MESH_META;
1002     event[pos++] = sizeof(event) - 2;
1003     event[pos++] = MESH_SUBEVENT_CONFIGURATION_APPKEY_INDEX_LIST_ITEM;
1004     // dest
1005     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
1006     pos += 2;
1007     event[pos++] = status;
1008 
1009     event[pos++] = list_size;
1010     uint8_t i;
1011     for (i = 0; i < list_size; i++){
1012         event[pos++] = i;
1013         uint32_t netappkey_index = mesh_access_parser_get_u24(&parser);
1014         little_endian_store_16(event, pos, netappkey_index >> 12);
1015         little_endian_store_16(event, pos + 2, netappkey_index & 0xFFF);
1016         (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos + 4);
1017     }
1018     mesh_access_message_processed(pdu);
1019 }
1020 
1021 static void mesh_configuration_client_node_identity_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1022     mesh_access_parser_state_t parser;
1023     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1024     uint8_t  status = mesh_access_parser_get_u8(&parser);
1025     uint16_t netkey_index = mesh_access_parser_get_u16(&parser);
1026     uint8_t  identity_status = mesh_access_parser_get_u8(&parser);
1027 
1028     uint8_t event[9];
1029     int pos = 0;
1030     event[pos++] = HCI_EVENT_MESH_META;
1031     event[pos++] = sizeof(event) - 2;
1032     event[pos++] = MESH_SUBEVENT_CONFIGURATION_NODE_IDENTITY;
1033     // dest
1034     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
1035     pos += 2;
1036     event[pos++] = status;
1037     little_endian_store_16(event, pos, netkey_index);
1038     pos += 2;
1039     event[pos++] = identity_status;
1040 
1041     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
1042     mesh_access_message_processed(pdu);
1043 }
1044 
1045 static void mesh_configuration_client_model_app_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1046     mesh_access_parser_state_t parser;
1047     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1048     uint8_t  status = mesh_access_parser_get_u8(&parser);
1049     uint16_t element_address = mesh_access_parser_get_u16(&parser);
1050     uint16_t appkey_index = mesh_access_parser_get_u16(&parser);
1051     uint32_t model_id = 0;
1052 
1053     if (mesh_access_parser_available(&parser) == 4){
1054         model_id = mesh_access_parser_get_u32(&parser);
1055     } else {
1056         model_id = mesh_access_parser_get_u16(&parser);
1057     }
1058 
1059     uint8_t event[9];
1060     int pos = 0;
1061     event[pos++] = HCI_EVENT_MESH_META;
1062     event[pos++] = sizeof(event) - 2;
1063     event[pos++] = MESH_SUBEVENT_CONFIGURATION_MODEL_APP;
1064     // dest
1065     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
1066     pos += 2;
1067     event[pos++] = status;
1068 
1069     little_endian_store_16(event, pos, element_address);
1070     pos += 2;
1071     little_endian_store_16(event, pos, appkey_index);
1072     pos += 2;
1073     little_endian_store_32(event, pos, model_id);
1074     pos += 4;
1075 
1076     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
1077     mesh_access_message_processed(pdu);
1078 }
1079 
1080 
1081 const static mesh_operation_t mesh_configuration_client_model_operations[] = {
1082     { MESH_FOUNDATION_OPERATION_BEACON_STATUS,                  1, mesh_configuration_client_beacon_status_handler },
1083     { MESH_FOUNDATION_OPERATION_COMPOSITION_DATA_STATUS,       10, mesh_configuration_client_composition_data_status_handler },
1084     { MESH_FOUNDATION_OPERATION_DEFAULT_TTL_STATUS,             1, mesh_configuration_client_default_ttl_handler },
1085     { MESH_FOUNDATION_OPERATION_GATT_PROXY_STATUS,              1, mesh_configuration_client_gatt_proxy_handler },
1086     { MESH_FOUNDATION_OPERATION_RELAY_STATUS,                   2, mesh_configuration_client_relay_handler },
1087     { MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_STATUS,      12, mesh_configuration_client_model_publication_handler },
1088     { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_STATUS,      7, mesh_configuration_client_model_subscription_handler },
1089     { MESH_FOUNDATION_OPERATION_SIG_MODEL_SUBSCRIPTION_LIST,    5, mesh_configuration_client_sig_model_subscription_handler},
1090     { MESH_FOUNDATION_OPERATION_VENDOR_MODEL_SUBSCRIPTION_LIST, 7, mesh_configuration_client_vendor_model_subscription_handler},
1091     { MESH_FOUNDATION_OPERATION_NETKEY_STATUS,                  3, mesh_configuration_client_netkey_handler },
1092     { MESH_FOUNDATION_OPERATION_NETKEY_LIST,                    0, mesh_configuration_client_netkey_list_handler },
1093     { MESH_FOUNDATION_OPERATION_APPKEY_STATUS,                  4, mesh_configuration_client_appkey_handler },
1094     { MESH_FOUNDATION_OPERATION_APPKEY_LIST,                    3, mesh_configuration_client_appkey_list_handler },
1095     { MESH_FOUNDATION_OPERATION_NODE_IDENTITY_STATUS,           4, mesh_configuration_client_node_identity_handler },
1096     { MESH_FOUNDATION_OPERATION_MODEL_APP_STATUS,               7, mesh_configuration_client_model_app_handler },
1097     { 0, 0, NULL }
1098 };
1099 
1100 const mesh_operation_t * mesh_configuration_client_get_operations(void){
1101     return mesh_configuration_client_model_operations;
1102 }
1103 
1104 void mesh_configuration_client_register_packet_handler(mesh_model_t *configuration_client_model, btstack_packet_handler_t events_packet_handler){
1105     btstack_assert(events_packet_handler != NULL);
1106     btstack_assert(configuration_client_model != NULL);
1107 
1108     configuration_client_model->model_packet_handler = events_packet_handler;
1109 }
1110 
1111