xref: /btstack/src/mesh/mesh_configuration_client.c (revision 908a73e3703656d22c2ada2c658b9f9ae0312c17)
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 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){
233     uint8_t  ttl  = mesh_foundation_default_ttl_get();
234     mesh_upper_transport_setup_access_pdu_header(pdu, netkey_index, appkey_index, ttl, src, dest, 0);
235     mesh_access_send_acknowledged_pdu(pdu, mesh_access_acknowledged_message_retransmissions(), ack_opcode);
236 }
237 
238 static uint8_t mesh_access_validate_envelop_params(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
239     btstack_assert(mesh_model != NULL);
240     // TODO: validate other params
241     UNUSED(mesh_model);
242     UNUSED(dest);
243     UNUSED(netkey_index);
244     UNUSED(appkey_index);
245 
246     return ERROR_CODE_SUCCESS;
247 }
248 
249 uint8_t mesh_configuration_client_send_beacon_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
250     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
251     if (status != ERROR_CODE_SUCCESS) return status;
252 
253     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_beacon_get);
254     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
255 
256     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);
257     return ERROR_CODE_SUCCESS;
258 }
259 
260 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){
261     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
262     if (status != ERROR_CODE_SUCCESS) return status;
263 
264     if (beacon > 1) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
265 
266     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_beacon_set, beacon);
267     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
268 
269     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);
270     return ERROR_CODE_SUCCESS;
271 }
272 
273 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){
274     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
275     if (status != ERROR_CODE_SUCCESS) return status;
276 
277     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_composition_data_get, page);
278     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
279 
280     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_GET);
281     return ERROR_CODE_SUCCESS;
282 }
283 
284 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){
285     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
286     if (status != ERROR_CODE_SUCCESS) return status;
287 
288     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_default_ttl_get);
289     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
290 
291     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_GET);
292     return ERROR_CODE_SUCCESS;
293 }
294 
295 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){
296     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
297     if (status != ERROR_CODE_SUCCESS) return status;
298 
299     if (ttl == 0x01 || ttl >= 0x80) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
300 
301     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_default_ttl_set, ttl);
302     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
303 
304     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_SET);
305     return ERROR_CODE_SUCCESS;
306 }
307 
308 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){
309     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
310     if (status != ERROR_CODE_SUCCESS) return status;
311 
312     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_gatt_proxy_get);
313     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
314 
315     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_GET);
316     return ERROR_CODE_SUCCESS;
317 }
318 
319 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){
320     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
321     if (status != ERROR_CODE_SUCCESS) return status;
322 
323     if (gatt_proxy_state > 2) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
324 
325     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_gatt_proxy_set, gatt_proxy_state);
326     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
327 
328     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_SET);
329     return ERROR_CODE_SUCCESS;
330 }
331 
332 uint8_t mesh_configuration_client_send_relay_get(mesh_model_t * mesh_model, uint16_t dest, uint16_t netkey_index, uint16_t appkey_index){
333     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
334     if (status != ERROR_CODE_SUCCESS) return status;
335 
336     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_relay_get);
337     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
338 
339     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_GET);
340     return ERROR_CODE_SUCCESS;
341 }
342 
343 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){
344     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
345     if (status != ERROR_CODE_SUCCESS) return status;
346 
347     if (relay_retransmit_count > 0x07) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
348     if (relay_retransmit_interval_steps > 0x1F) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
349 
350     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);
351     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
352 
353     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);
354     return ERROR_CODE_SUCCESS;
355 }
356 
357 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){
358     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
359     if (status != ERROR_CODE_SUCCESS) return status;
360 
361     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_publication_get, dest, model_id);
362     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
363 
364     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_GET);
365     return ERROR_CODE_SUCCESS;
366 }
367 
368 static uint8_t mesh_validate_publication_model_config_parameters(mesh_publication_model_config_t * publication_config, bool use_unicast_address){
369     if (publication_config->appkey_index > 0xFFF) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
370     if (publication_config->credential_flag > 1) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
371     if (publication_config->publish_retransmit_count > 0x07) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
372     if (publication_config->publish_retransmit_interval_steps > 0x1F) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
373     if (use_unicast_address && mesh_network_address_virtual(publication_config->publish_address_unicast)) return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
374     return ERROR_CODE_SUCCESS;
375 }
376 
377 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){
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     if (!mesh_network_address_unicast(dest) ||
382         mesh_validate_publication_model_config_parameters(publication_config, true) != ERROR_CODE_SUCCESS){
383         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
384     }
385 
386     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_publication_set,
387         dest,
388         publication_config->publish_address_unicast,
389         (publication_config->credential_flag << 12) | publication_config->appkey_index,
390         publication_config->publish_ttl,
391         publication_config->publish_period,
392         (publication_config->publish_retransmit_interval_steps << 3) | publication_config->publish_retransmit_count,
393         model_id);
394     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
395 
396     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) network_pdu, MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_SET);
397     return ERROR_CODE_SUCCESS;
398 
399 }
400 
401 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){
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     if (!mesh_network_address_unicast(dest) ||
406         mesh_validate_publication_model_config_parameters(publication_config, false) != ERROR_CODE_SUCCESS){
407         return ERROR_CODE_PARAMETER_OUT_OF_MANDATORY_RANGE;
408     }
409 
410     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_model_publication_virtual_address_set,
411         dest,
412         publication_config->publish_address_virtual,
413         (publication_config->credential_flag << 12) | publication_config->appkey_index,
414         publication_config->publish_ttl,
415         publication_config->publish_period,
416         (publication_config->publish_retransmit_interval_steps << 3) | publication_config->publish_retransmit_count,
417         model_id);
418     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
419 
420     mesh_configuration_client_send_acknowledged(mesh_access_get_element_address(mesh_model), dest, netkey_index, appkey_index, (mesh_pdu_t *) transport_pdu, MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_VIRTUAL_ADDRESS_SET);
421     return ERROR_CODE_SUCCESS;
422 }
423 
424 
425 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){
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_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_subscription_add, dest, address, model_id);
430     if (!network_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 *) network_pdu, MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_ADD);
433     return ERROR_CODE_SUCCESS;
434 }
435 
436 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){
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     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_model_subscription_virtual_address_add, dest, address, model_id);
441     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
442 
443     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_VIRTUAL_ADDRESS_ADD);
444     return ERROR_CODE_SUCCESS;
445 }
446 
447 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){
448     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
449     if (status != ERROR_CODE_SUCCESS) return status;
450 
451     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_subscription_delete, dest, address, model_id);
452     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
453 
454     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_DELETE);
455     return ERROR_CODE_SUCCESS;
456 }
457 
458 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){
459     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
460     if (status != ERROR_CODE_SUCCESS) return status;
461 
462     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_model_subscription_virtual_address_delete, dest, address, model_id);
463     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
464 
465     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_VIRTUAL_ADDRESS_DELETE);
466     return ERROR_CODE_SUCCESS;
467 }
468 
469 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){
470         uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
471     if (status != ERROR_CODE_SUCCESS) return status;
472 
473     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_subscription_overwrite, dest, address, model_id);
474     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
475 
476     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_OVERWRITE);
477     return ERROR_CODE_SUCCESS;
478 }
479 
480 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){
481     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
482     if (status != ERROR_CODE_SUCCESS) return status;
483 
484     mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message(&mesh_configuration_client_model_subscription_virtual_address_overwrite, dest, address, model_id);
485     if (!transport_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
486 
487     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_VIRTUAL_ADDRESS_OVERWRITE);
488     return ERROR_CODE_SUCCESS;
489 }
490 
491 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){
492         uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
493     if (status != ERROR_CODE_SUCCESS) return status;
494 
495     mesh_network_pdu_t * network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_model_subscription_delete_all, dest, address, model_id);
496     if (!network_pdu) return BTSTACK_MEMORY_ALLOC_FAILED;
497 
498     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_DELETE_ALL);
499     return ERROR_CODE_SUCCESS;
500 }
501 
502 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){
503     uint8_t status = mesh_access_validate_envelop_params(mesh_model, dest, netkey_index, appkey_index);
504     if (status != ERROR_CODE_SUCCESS) return status;
505 
506     mesh_network_pdu_t * network_pdu = NULL;
507     uint32_t ack_opcode = MESH_FOUNDATION_OPERATION_SIG_MODEL_SUBSCRIPTION_GET;
508 
509     if (mesh_model_is_bluetooth_sig(model_id)){
510         network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_sig_model_subscription_get, dest, model_id);
511     } else {
512         network_pdu = mesh_access_setup_unsegmented_message(&mesh_configuration_client_vendor_model_subscription_get, dest, model_id);
513         ack_opcode = MESH_FOUNDATION_OPERATION_VENDOR_MODEL_SUBSCRIPTION_GET;
514     }
515 
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, ack_opcode);
519     return ERROR_CODE_SUCCESS;
520 }
521 
522 // Model Operations
523 static void mesh_configuration_client_composition_data_status_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
524     // Composition Data has variable of element descriptions, with two lists of model lists
525     // Pass raw data to application but provide convenient setters instead of parsing pdu here
526 
527     // reuse part of the mesh_network_t / mesh_transport_t struct to create event without memcpy or allocation
528     uint8_t * data = mesh_pdu_data(pdu);
529     uint8_t * event = &data[-6];
530 
531     int pos = 0;
532     event[pos++] = HCI_EVENT_MESH_META;
533     // Composite Data might be larger than 251 bytes - in this case only lower 8 bit are stored here. packet size is correct
534     event[pos++] = (uint8_t) (6 + mesh_pdu_len(pdu));
535     event[pos++] = MESH_SUBEVENT_CONFIGURATION_COMPOSITION_DATA;
536     // dest
537     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
538     pos += 2;
539     event[pos++] = ERROR_CODE_SUCCESS;
540 
541     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
542     mesh_access_message_processed(pdu);
543 }
544 
545 uint8_t mesh_subevent_configuration_composition_data_get_page(const uint8_t * event){
546     return event[6];
547 }
548 
549 uint16_t mesh_subevent_configuration_composition_data_get_cid(const uint8_t * event){
550     return little_endian_read_16(event, 7);
551 }
552 
553 uint16_t mesh_subevent_configuration_composition_data_get_pid(const uint8_t * event){
554     return little_endian_read_16(event, 9);
555 }
556 
557 uint16_t mesh_subevent_configuration_composition_data_get_vid(const uint8_t * event){
558     return little_endian_read_16(event, 11);
559 }
560 
561 uint16_t mesh_subevent_configuration_composition_data_get_crpl(const uint8_t * event){
562     return little_endian_read_16(event, 13);
563 }
564 
565 uint16_t mesh_subevent_configuration_composition_data_get_features(const uint8_t * event){
566     return little_endian_read_16(event, 15);
567 }
568 
569 
570 static inline void mesh_configuration_client_handle_uint8_value(mesh_model_t *mesh_model, mesh_pdu_t * pdu, uint8_t subevent_type){
571     mesh_access_parser_state_t parser;
572     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
573 
574     uint8_t value = mesh_access_parser_get_u8(&parser);
575 
576     uint8_t event[7];
577     int pos = 0;
578 
579     event[pos++] = HCI_EVENT_MESH_META;
580     event[pos++] = sizeof(event) - 2;
581     event[pos++] = subevent_type;
582     // dest
583     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
584     pos += 2;
585     event[pos++] = ERROR_CODE_SUCCESS;
586     event[pos++] = value;
587 
588     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
589     mesh_access_message_processed(pdu);
590 }
591 
592 static void mesh_configuration_client_beacon_status_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
593     mesh_configuration_client_handle_uint8_value(mesh_model, pdu, MESH_SUBEVENT_CONFIGURATION_BEACON);
594 }
595 
596 static void mesh_configuration_client_default_ttl_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
597     mesh_configuration_client_handle_uint8_value(mesh_model, pdu, MESH_SUBEVENT_CONFIGURATION_DEFAULT_TTL);
598 }
599 
600 static void mesh_configuration_client_gatt_proxy_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
601     mesh_configuration_client_handle_uint8_value(mesh_model, pdu, MESH_SUBEVENT_CONFIGURATION_GATT_PROXY);
602 }
603 
604 static void mesh_configuration_client_relay_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
605     mesh_access_parser_state_t parser;
606     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
607 
608     uint8_t relay = mesh_access_parser_get_u8(&parser);
609     uint8_t retransmition = mesh_access_parser_get_u8(&parser);
610 
611     uint8_t event[9];
612 
613     int pos = 0;
614     event[pos++] = HCI_EVENT_MESH_META;
615     event[pos++] = sizeof(event) - 2;
616     event[pos++] = MESH_SUBEVENT_CONFIGURATION_RELAY;
617     // dest
618     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
619     pos += 2;
620     event[pos++] = ERROR_CODE_SUCCESS;
621     event[pos++] = relay;
622     event[pos++] = (retransmition >> 5) + 1;
623     event[pos++] = ((retransmition & 0x07) + 1) * 10;
624 
625     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
626     mesh_access_message_processed(pdu);
627 }
628 
629 static void mesh_configuration_client_model_publication_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
630     mesh_access_parser_state_t parser;
631     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
632     uint8_t  status = mesh_access_parser_get_u8(&parser);
633     uint16_t publish_addres = mesh_access_parser_get_u16(&parser);
634 
635     uint16_t value = mesh_access_parser_get_u16(&parser);
636     uint16_t appkey_index = value & 0xFFF;
637     uint8_t  credential_flag = (value & 0x1000) >> 12;
638 
639     uint8_t publish_ttl = mesh_access_parser_get_u8(&parser);
640     uint8_t publish_period = mesh_access_parser_get_u8(&parser);
641 
642     uint8_t retransmit = mesh_access_parser_get_u8(&parser);
643     uint8_t publish_retransmit_count = retransmit & 0x111;
644     uint8_t publish_retransmit_interval_steps = retransmit >> 5;
645     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
646 
647     uint8_t event[19];
648     int pos = 0;
649     event[pos++] = HCI_EVENT_MESH_META;
650     event[pos++] = sizeof(event) - 2;
651     event[pos++] = MESH_SUBEVENT_CONFIGURATION_MODEL_PUBLICATION;
652     // dest
653     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
654     pos += 2;
655     event[pos++] = status;
656 
657     little_endian_store_16(event, pos, publish_addres);
658     pos += 2;
659 
660     little_endian_store_16(event, pos, appkey_index);
661     pos += 2;
662 
663     event[pos++] = credential_flag;
664     event[pos++] = publish_ttl;
665     event[pos++] = publish_period;
666     event[pos++] = publish_retransmit_count;
667     event[pos++] = publish_retransmit_interval_steps;
668 
669     little_endian_store_32(event, pos, model_identifier);
670     pos += 4;
671 
672     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
673     mesh_access_message_processed(pdu);
674 }
675 
676 static void mesh_configuration_client_model_subscription_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
677     mesh_access_parser_state_t parser;
678     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
679     uint8_t  status = mesh_access_parser_get_u8(&parser);
680     uint16_t address = mesh_access_parser_get_u16(&parser);
681     uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
682 
683     uint8_t event[12];
684     int pos = 0;
685     event[pos++] = HCI_EVENT_MESH_META;
686     event[pos++] = sizeof(event) - 2;
687     event[pos++] = MESH_SUBEVENT_CONFIGURATION_MODEL_SUBSCRIPTION;
688     // dest
689     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
690     pos += 2;
691     event[pos++] = status;
692 
693     little_endian_store_16(event, pos, address);
694     pos += 2;
695 
696     little_endian_store_32(event, pos, model_identifier);
697     pos += 4;
698 
699     (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos);
700     mesh_access_message_processed(pdu);
701 }
702 
703 static void mesh_configuration_client_model_subscription_event(mesh_model_t *mesh_model, mesh_pdu_t * pdu, uint8_t subevent_type){
704     mesh_access_parser_state_t parser;
705     mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
706     uint8_t  status = mesh_access_parser_get_u8(&parser);
707     uint16_t address = mesh_access_parser_get_u16(&parser);
708     uint32_t model_identifier;
709 
710     if (subevent_type == MESH_SUBEVENT_CONFIGURATION_SIG_MODEL_SUBSCRIPTION_LIST_ITEM) {
711         model_identifier = mesh_access_parser_get_sig_model_identifier(&parser);
712     } else {
713         model_identifier = mesh_access_parser_get_vendor_model_identifier(&parser);
714     }
715     uint8_t list_size = mesh_access_parser_available(&parser)/2;
716 
717     uint8_t event[12];
718     int pos = 0;
719     event[pos++] = HCI_EVENT_MESH_META;
720     event[pos++] = sizeof(event) - 2;
721     event[pos++] = subevent_type;
722     // dest
723     little_endian_store_16(event, pos, mesh_pdu_src(pdu));
724     pos += 2;
725     event[pos++] = status;
726 
727     little_endian_store_16(event, pos, address);
728     pos += 2;
729 
730     event[pos++] = list_size;
731     uint8_t i;
732     for (i = 0; i < list_size; i++){
733         event[pos++] = i;
734         little_endian_store_16(event, pos, mesh_access_parser_get_u16(&parser));
735         (*mesh_model->model_packet_handler)(HCI_EVENT_PACKET, 0, event, pos + 2);
736     }
737     mesh_access_message_processed(pdu);
738 }
739 
740 static void mesh_configuration_client_sig_model_subscription_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
741     mesh_configuration_client_model_subscription_event(mesh_model, pdu, MESH_SUBEVENT_CONFIGURATION_SIG_MODEL_SUBSCRIPTION_LIST_ITEM);
742 }
743 
744 static void mesh_configuration_client_vendor_model_subscription_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
745         mesh_configuration_client_model_subscription_event(mesh_model, pdu, MESH_SUBEVENT_CONFIGURATION_VENDOR_MODEL_SUBSCRIPTION_LIST_ITEM);
746 }
747 
748 const static mesh_operation_t mesh_configuration_client_model_operations[] = {
749     { MESH_FOUNDATION_OPERATION_BEACON_STATUS,                  1, mesh_configuration_client_beacon_status_handler },
750     { MESH_FOUNDATION_OPERATION_COMPOSITION_DATA_STATUS,       10, mesh_configuration_client_composition_data_status_handler },
751     { MESH_FOUNDATION_OPERATION_DEFAULT_TTL_STATUS,             1, mesh_configuration_client_default_ttl_handler },
752     { MESH_FOUNDATION_OPERATION_GATT_PROXY_STATUS,              1, mesh_configuration_client_gatt_proxy_handler },
753     { MESH_FOUNDATION_OPERATION_RELAY_STATUS,                   2, mesh_configuration_client_relay_handler },
754     { MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_STATUS,      12, mesh_configuration_client_model_publication_handler },
755     { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_STATUS,      7, mesh_configuration_client_model_subscription_handler },
756     { MESH_FOUNDATION_OPERATION_SIG_MODEL_SUBSCRIPTION_LIST,    5, mesh_configuration_client_sig_model_subscription_handler},
757     { MESH_FOUNDATION_OPERATION_VENDOR_MODEL_SUBSCRIPTION_LIST, 7, mesh_configuration_client_vendor_model_subscription_handler},
758     { 0, 0, NULL }
759 };
760 
761 const mesh_operation_t * mesh_configuration_client_get_operations(void){
762     return mesh_configuration_client_model_operations;
763 }
764 
765 void mesh_configuration_client_register_packet_handler(mesh_model_t *configuration_client_model, btstack_packet_handler_t events_packet_handler){
766     btstack_assert(events_packet_handler != NULL);
767     btstack_assert(configuration_client_model != NULL);
768 
769     configuration_client_model->model_packet_handler = events_packet_handler;
770 }
771 
772