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 BLUEKITCHEN
24 * GMBH 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_server.c"
39
40 #include <inttypes.h>
41 #include <string.h>
42 #include <stdio.h>
43
44 #include "mesh/mesh_configuration_server.h"
45
46 #include "bluetooth_company_id.h"
47 #include "btstack_debug.h"
48 #include "btstack_memory.h"
49 #include "btstack_tlv.h"
50 #include "btstack_util.h"
51
52 #include "mesh/beacon.h"
53 #include "mesh/gatt_bearer.h"
54 #include "mesh/mesh.h"
55 #include "mesh/mesh_access.h"
56 #include "mesh/mesh_crypto.h"
57 #include "mesh/mesh_foundation.h"
58 #include "mesh/mesh_iv_index_seq_number.h"
59 #include "mesh/mesh_keys.h"
60 #include "mesh/mesh_network.h"
61 #include "mesh/mesh_node.h"
62 #include "mesh/mesh_proxy.h"
63 #include "mesh/mesh_upper_transport.h"
64 #include "mesh/mesh_virtual_addresses.h"
65
66 #define MESH_HEARTBEAT_FEATURES_SUPPORTED_MASK 0x000f
67
68 // current access pdu
69 static mesh_pdu_t * access_pdu_in_process;
70
71 // data from current pdu
72 static uint16_t configuration_server_element_address;
73 static uint32_t configuration_server_model_identifier;
74 static mesh_model_t * configuration_server_target_model;
75 static mesh_publication_model_t configuration_server_publication_model;
76
77 // cmac for virtual address hash and netkey derive
78 static btstack_crypto_aes128_cmac_t configuration_server_cmac_request;
79
80 // used to setup virtual addresses
81 static uint8_t configuration_server_label_uuid[16];
82 static uint16_t configuration_server_hash;
83
84 // heartbeat publication and subscription state for all Configuration Server models - there is only one
85 // static mesh_heartbeat_subscription_t mesh_heartbeat_subscription;
86
87 // for PTS testing
88 static int config_netkey_list_max = 0;
89
90 // TLV
91
mesh_model_is_configuration_server(uint32_t model_identifier)92 static int mesh_model_is_configuration_server(uint32_t model_identifier){
93 return mesh_model_is_bluetooth_sig(model_identifier) && (mesh_model_get_model_id(model_identifier) == MESH_SIG_MODEL_ID_CONFIGURATION_SERVER);
94 }
95
96 // Configuration Model Subscriptions (helper)
97
98 // Model to Appkey List
99
mesh_model_add_subscription(mesh_model_t * mesh_model,uint16_t address)100 static uint8_t mesh_model_add_subscription(mesh_model_t * mesh_model, uint16_t address){
101 uint16_t i;
102 for (i=0;i<MAX_NR_MESH_SUBSCRIPTION_PER_MODEL;i++){
103 if (mesh_model->subscriptions[i] == address) return MESH_FOUNDATION_STATUS_SUCCESS;
104 }
105 for (i=0;i<MAX_NR_MESH_SUBSCRIPTION_PER_MODEL;i++){
106 if (mesh_model->subscriptions[i] == MESH_ADDRESS_UNSASSIGNED) {
107 mesh_model->subscriptions[i] = address;
108 return MESH_FOUNDATION_STATUS_SUCCESS;
109 }
110 }
111 return MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES;
112 }
113
mesh_model_delete_subscription(mesh_model_t * mesh_model,uint16_t address)114 static void mesh_model_delete_subscription(mesh_model_t * mesh_model, uint16_t address){
115 uint16_t i;
116 for (i=0;i<MAX_NR_MESH_SUBSCRIPTION_PER_MODEL;i++){
117 if (mesh_model->subscriptions[i] == address) {
118 mesh_model->subscriptions[i] = MESH_ADDRESS_UNSASSIGNED;
119 }
120 }
121 }
122
mesh_model_delete_all_subscriptions(mesh_model_t * mesh_model)123 static void mesh_model_delete_all_subscriptions(mesh_model_t * mesh_model){
124 uint16_t i;
125 for (i=0;i<MAX_NR_MESH_SUBSCRIPTION_PER_MODEL;i++){
126 mesh_model->subscriptions[i] = MESH_ADDRESS_UNSASSIGNED;
127 }
128 }
129
mesh_subcription_decrease_virtual_address_ref_count(mesh_model_t * mesh_model)130 static void mesh_subcription_decrease_virtual_address_ref_count(mesh_model_t *mesh_model){
131 // decrease ref counts for current virtual subscriptions
132 uint16_t i;
133 for (i = 0; i<MAX_NR_MESH_SUBSCRIPTION_PER_MODEL ; i++){
134 uint16_t src = mesh_model->subscriptions[i];
135 if (mesh_network_address_virtual(src)){
136 mesh_virtual_address_t * virtual_address = mesh_virtual_address_for_pseudo_dst(src);
137 mesh_virtual_address_decrease_refcount(virtual_address);
138 }
139 }
140 }
mesh_configuration_server_stop_publishing_using_appkey(mesh_model_t * mesh_model,uint16_t appkey_index)141 static void mesh_configuration_server_stop_publishing_using_appkey(mesh_model_t * mesh_model, uint16_t appkey_index){
142 // stop publishing if this AppKey was used
143 if (mesh_model->publication_model != NULL){
144 mesh_publication_model_t * publication_model = mesh_model->publication_model;
145 if (publication_model->appkey_index == appkey_index){
146 publication_model->address = MESH_ADDRESS_UNSASSIGNED;
147 publication_model->appkey_index = 0;
148 publication_model->period = 0;
149 publication_model->ttl = 0;
150 publication_model->retransmit = 0;
151
152 mesh_model_store_publication(mesh_model);
153 }
154 }
155 }
156
157 // AppKeys Helper
mesh_configuration_server_delete_appkey(mesh_transport_key_t * transport_key)158 static void mesh_configuration_server_delete_appkey(mesh_transport_key_t * transport_key){
159 uint16_t appkey_index = transport_key->appkey_index;
160
161 // iterate over elements and models
162 mesh_element_iterator_t element_it;
163 mesh_element_iterator_init(&element_it);
164 while (mesh_element_iterator_has_next(&element_it)){
165 mesh_element_t * element = mesh_element_iterator_next(&element_it);
166 mesh_model_iterator_t model_it;
167 mesh_model_iterator_init(&model_it, element);
168 while (mesh_model_iterator_has_next(&model_it)){
169 mesh_model_t * mesh_model = mesh_model_iterator_next(&model_it);
170
171 // remove from Model to AppKey List
172 mesh_model_unbind_appkey(mesh_model, appkey_index);
173
174 // stop publishing if this appkey is used
175 mesh_configuration_server_stop_publishing_using_appkey(mesh_model, appkey_index);
176 }
177 }
178
179 mesh_access_appkey_finalize(transport_key);
180 }
181
182 // Foundatiopn Message
183
184 const mesh_access_message_t mesh_foundation_config_beacon_status = {
185 MESH_FOUNDATION_OPERATION_BEACON_STATUS, "1"
186 };
187 const mesh_access_message_t mesh_foundation_config_default_ttl_status = {
188 MESH_FOUNDATION_OPERATION_DEFAULT_TTL_STATUS, "1"
189 };
190 const mesh_access_message_t mesh_foundation_config_friend_status = {
191 MESH_FOUNDATION_OPERATION_FRIEND_STATUS, "1"
192 };
193 const mesh_access_message_t mesh_foundation_config_gatt_proxy_status = {
194 MESH_FOUNDATION_OPERATION_GATT_PROXY_STATUS, "1"
195 };
196 const mesh_access_message_t mesh_foundation_config_relay_status = {
197 MESH_FOUNDATION_OPERATION_RELAY_STATUS, "11"
198 };
199 const mesh_access_message_t mesh_foundation_config_model_publication_status = {
200 MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_STATUS, "1222111m"
201 };
202 const mesh_access_message_t mesh_foundation_config_model_subscription_status = {
203 MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_STATUS, "122m"
204 };
205 const mesh_access_message_t mesh_foundation_config_netkey_status = {
206 MESH_FOUNDATION_OPERATION_NETKEY_STATUS, "12"
207 };
208 const mesh_access_message_t mesh_foundation_config_appkey_status = {
209 MESH_FOUNDATION_OPERATION_APPKEY_STATUS, "13"
210 };
211 const mesh_access_message_t mesh_foundation_config_model_app_status = {
212 MESH_FOUNDATION_OPERATION_MODEL_APP_STATUS, "122m"
213 };
214 const mesh_access_message_t mesh_foundation_node_reset_status = {
215 MESH_FOUNDATION_OPERATION_NODE_RESET_STATUS, ""
216 };
217 const mesh_access_message_t mesh_foundation_config_heartbeat_publication_status = {
218 MESH_FOUNDATION_OPERATION_HEARTBEAT_PUBLICATION_STATUS, "1211122"
219 };
220 const mesh_access_message_t mesh_foundation_config_network_transmit_status = {
221 MESH_FOUNDATION_OPERATION_NETWORK_TRANSMIT_STATUS, "1"
222 };
223 const mesh_access_message_t mesh_foundation_node_identity_status = {
224 MESH_FOUNDATION_OPERATION_NODE_IDENTITY_STATUS, "121"
225 };
226 const mesh_access_message_t mesh_key_refresh_phase_status = {
227 MESH_FOUNDATION_OPERATION_KEY_REFRESH_PHASE_STATUS, "121"
228 };
229 const mesh_access_message_t mesh_foundation_low_power_node_poll_timeout_status = {
230 MESH_FOUNDATION_OPERATION_LOW_POWER_NODE_POLL_TIMEOUT_STATUS, "23"
231 };
232 const mesh_access_message_t mesh_foundation_config_heartbeat_subscription_status = {
233 MESH_FOUNDATION_OPERATION_HEARTBEAT_SUBSCRIPTION_STATUS, "1221111"
234 };
235
config_server_send_message(uint16_t netkey_index,uint16_t dest,mesh_pdu_t * pdu)236 static void config_server_send_message(uint16_t netkey_index, uint16_t dest, mesh_pdu_t *pdu){
237 // Configuration Server is on primary element and can only use DeviceKey
238 uint16_t appkey_index = MESH_DEVICE_KEY_INDEX;
239 uint16_t src = mesh_node_get_primary_element_address();
240 uint8_t ttl = mesh_foundation_default_ttl_get();
241 mesh_upper_transport_setup_access_pdu_header(pdu, netkey_index, appkey_index, ttl, src, dest, 0);
242 mesh_access_send_unacknowledged_pdu(pdu);
243 }
244
config_composition_data_status(uint16_t netkey_index,uint16_t dest)245 static void config_composition_data_status(uint16_t netkey_index, uint16_t dest){
246
247 printf("Received Config Composition Data Get -> send Config Composition Data Status\n");
248
249 mesh_upper_transport_builder_t builder;
250 mesh_access_message_init(&builder, MESH_FOUNDATION_OPERATION_COMPOSITION_DATA_STATUS);
251
252 // page 0
253 mesh_access_message_add_uint8(&builder, 0);
254
255 // CID
256 mesh_access_message_add_uint16(&builder, mesh_node_get_company_id());
257 // PID
258 mesh_access_message_add_uint16(&builder, mesh_node_get_product_id());
259 // VID
260 mesh_access_message_add_uint16(&builder, mesh_node_get_product_version_id());
261 // CRPL - number of protection list entries
262 mesh_access_message_add_uint16(&builder, 1);
263 // Features - Relay, Proxy, Friend, Lower Power, ...
264 uint16_t features = 0;
265 #ifdef ENABLE_MESH_RELAY
266 features |= 1;
267 #endif
268 #ifdef ENABLE_MESH_PROXY_SERVER
269 features |= 2;
270 #endif
271 mesh_access_message_add_uint16(&builder, features);
272
273 mesh_element_iterator_t element_it;
274 mesh_element_iterator_init(&element_it);
275 while (mesh_element_iterator_has_next(&element_it)){
276 mesh_element_t * element = mesh_element_iterator_next(&element_it);
277
278 // Loc
279 mesh_access_message_add_uint16(&builder, element->loc);
280 // NumS
281 mesh_access_message_add_uint8(&builder, element->models_count_sig);
282 // NumV
283 mesh_access_message_add_uint8(&builder, element->models_count_vendor);
284
285 mesh_model_iterator_t model_it;
286
287 // SIG Models
288 mesh_model_iterator_init(&model_it, element);
289 while (mesh_model_iterator_has_next(&model_it)){
290 mesh_model_t * model = mesh_model_iterator_next(&model_it);
291 if (!mesh_model_is_bluetooth_sig(model->model_identifier)) continue;
292 mesh_access_message_add_model_identifier(&builder, model->model_identifier);
293 }
294 // Vendor Models
295 mesh_model_iterator_init(&model_it, element);
296 while (mesh_model_iterator_has_next(&model_it)){
297 mesh_model_t * model = mesh_model_iterator_next(&model_it);
298 if (mesh_model_is_bluetooth_sig(model->model_identifier)) continue;
299 mesh_access_message_add_model_identifier(&builder, model->model_identifier);
300 }
301 }
302
303 mesh_upper_transport_pdu_t * upper_pdu = mesh_access_message_finalize(&builder);
304
305 // send as segmented access pdu
306 config_server_send_message(netkey_index, dest, (mesh_pdu_t *) upper_pdu);
307 }
308
config_composition_data_get_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)309 static void config_composition_data_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
310 UNUSED(mesh_model);
311 config_composition_data_status(mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
312
313 mesh_access_message_processed(pdu);
314 }
315
config_model_beacon_status(mesh_model_t * mesh_model,uint16_t netkey_index,uint16_t dest)316 static void config_model_beacon_status(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest){
317 UNUSED(mesh_model);
318 // setup message
319 mesh_upper_transport_pdu_t * transport_pdu = mesh_access_setup_message(&mesh_foundation_config_beacon_status,
320 mesh_foundation_beacon_get());
321 if (!transport_pdu) return;
322
323 // send as segmented access pdu
324 config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
325 }
326
config_beacon_get_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)327 static void config_beacon_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
328 config_model_beacon_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
329
330 mesh_access_message_processed(pdu);
331 }
332
config_beacon_set_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)333 static void config_beacon_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
334 mesh_access_parser_state_t parser;
335 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
336
337 uint8_t beacon_enabled = mesh_access_parser_get_uint8(&parser);
338
339 // beacon valid
340 if (beacon_enabled < MESH_FOUNDATION_STATE_NOT_SUPPORTED) {
341 // set and store new value
342 mesh_foundation_beacon_set(beacon_enabled);
343 mesh_foundation_state_store();
344
345 // send status
346 config_model_beacon_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
347 }
348
349 mesh_access_message_processed(pdu);
350 }
351
config_model_default_ttl_status(mesh_model_t * mesh_model,uint16_t netkey_index,uint16_t dest)352 static void config_model_default_ttl_status(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest){
353 UNUSED(mesh_model);
354 // setup message
355 mesh_upper_transport_pdu_t * transport_pdu = mesh_access_setup_message(
356 &mesh_foundation_config_default_ttl_status, mesh_foundation_default_ttl_get());
357 if (!transport_pdu) return;
358
359 // send as segmented access pdu
360 config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
361 }
362
config_default_ttl_get_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)363 static void config_default_ttl_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
364 config_model_default_ttl_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
365
366 mesh_access_message_processed(pdu);
367 }
368
config_default_ttl_set_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)369 static void config_default_ttl_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
370 mesh_access_parser_state_t parser;
371 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
372
373 uint8_t new_ttl = mesh_access_parser_get_uint8(&parser);
374
375 // validate (0x01 and > 0x7f are prohibited)
376 if (new_ttl <= 0x7f && new_ttl != 0x01) {
377
378 // set and store
379 mesh_foundation_default_ttl_set(new_ttl);
380 mesh_foundation_state_store();
381
382 // send status
383 config_model_default_ttl_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
384 }
385
386 mesh_access_message_processed(pdu);
387 }
388
config_friend_status(mesh_model_t * mesh_model,uint16_t netkey_index,uint16_t dest)389 static void config_friend_status(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest){
390 UNUSED(mesh_model);
391
392 // setup message
393 mesh_upper_transport_pdu_t * transport_pdu = mesh_access_setup_message(
394 &mesh_foundation_config_friend_status, mesh_foundation_friend_get());
395 if (!transport_pdu) return;
396
397 // send as segmented access pdu
398 config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
399 }
400
config_friend_get_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)401 static void config_friend_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
402 config_friend_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
403
404 mesh_access_message_processed(pdu);
405 }
406
config_friend_set_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)407 static void config_friend_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
408 mesh_access_parser_state_t parser;
409 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
410
411 uint8_t new_friend_state = mesh_access_parser_get_uint8(&parser);
412
413 // validate
414 if (new_friend_state < MESH_FOUNDATION_STATE_NOT_SUPPORTED) {
415
416 // set and store
417 if (mesh_foundation_friend_get() != MESH_FOUNDATION_STATE_NOT_SUPPORTED){
418 mesh_foundation_friend_set(new_friend_state);
419 mesh_foundation_state_store();
420 }
421
422 // send status
423 config_friend_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
424 }
425
426 mesh_access_message_processed(pdu);
427 }
428
config_model_gatt_proxy_status(mesh_model_t * mesh_model,uint16_t netkey_index,uint16_t dest)429 static void config_model_gatt_proxy_status(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest){
430 UNUSED(mesh_model);
431 // setup message
432 mesh_upper_transport_pdu_t * transport_pdu = mesh_access_setup_message(&mesh_foundation_config_gatt_proxy_status, mesh_foundation_gatt_proxy_get());
433 if (!transport_pdu) return;
434
435 // send as segmented access pdu
436 config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
437 }
438
config_gatt_proxy_get_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)439 static void config_gatt_proxy_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
440 config_model_gatt_proxy_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
441
442 mesh_access_message_processed(pdu);
443 }
444
config_gatt_proxy_set_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)445 static void config_gatt_proxy_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
446 mesh_access_parser_state_t parser;
447 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
448
449 uint8_t enabled = mesh_access_parser_get_uint8(&parser);
450
451 // validate
452 if (enabled < MESH_FOUNDATION_STATE_NOT_SUPPORTED) {
453 // set and store
454 mesh_foundation_gatt_proxy_set(enabled);
455 mesh_foundation_state_store();
456
457 // send status
458 config_model_gatt_proxy_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
459 }
460
461 mesh_access_message_processed(pdu);
462
463 // trigger heartbeat emit on change
464 mesh_configuration_server_feature_changed();
465 }
466
config_model_relay_status(mesh_model_t * mesh_model,uint16_t netkey_index,uint16_t dest)467 static void config_model_relay_status(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest){
468 UNUSED(mesh_model);
469
470 // setup message
471 mesh_upper_transport_pdu_t * transport_pdu = mesh_access_setup_message(&mesh_foundation_config_relay_status,
472 mesh_foundation_relay_get(),
473 mesh_foundation_relay_retransmit_get());
474 if (!transport_pdu) return;
475
476 // send as segmented access pdu
477 config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
478 }
479
config_relay_get_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)480 static void config_relay_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
481 config_model_relay_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
482
483 mesh_access_message_processed(pdu);
484 }
485
config_relay_set_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)486 static void config_relay_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
487
488 mesh_access_parser_state_t parser;
489 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
490
491 // check if valid
492 uint8_t relay = mesh_access_parser_get_uint8(&parser);
493 uint8_t relay_retransmit = mesh_access_parser_get_uint8(&parser);
494
495 // check if valid
496 if (relay <= 1) {
497 // only update if supported
498 if (mesh_foundation_relay_get() != MESH_FOUNDATION_STATE_NOT_SUPPORTED){
499 mesh_foundation_relay_set(relay);
500 mesh_foundation_relay_retransmit_set(relay_retransmit);
501 mesh_foundation_state_store();
502 }
503
504 // send status
505 config_model_relay_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
506 }
507
508 mesh_access_message_processed(pdu);
509
510 // trigger heartbeat emit on change
511 mesh_configuration_server_feature_changed();
512 }
513
config_model_network_transmit_status(mesh_model_t * mesh_model,uint16_t netkey_index,uint16_t dest)514 static void config_model_network_transmit_status(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest){
515 UNUSED(mesh_model);
516
517 // setup message
518 mesh_upper_transport_pdu_t * transport_pdu = mesh_access_setup_message(
519 &mesh_foundation_config_network_transmit_status, mesh_foundation_network_transmit_get());
520 if (!transport_pdu) return;
521
522 // send as segmented access pdu
523 config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
524 }
525
config_model_network_transmit_get_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)526 static void config_model_network_transmit_get_handler(mesh_model_t * mesh_model, mesh_pdu_t * pdu){
527 config_model_network_transmit_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
528
529 mesh_access_message_processed(pdu);
530 }
531
config_model_network_transmit_set_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)532 static void config_model_network_transmit_set_handler(mesh_model_t * mesh_model, mesh_pdu_t * pdu){
533 mesh_access_parser_state_t parser;
534 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
535
536 uint8_t new_ttl = mesh_access_parser_get_uint8(&parser);
537
538 // store
539 mesh_foundation_network_transmit_set(new_ttl);
540 mesh_foundation_state_store();
541
542 //
543 config_model_network_transmit_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
544
545 mesh_access_message_processed(pdu);
546 }
547
548 // NetKey List
549
config_nekey_list_set_max(uint16_t max)550 void config_nekey_list_set_max(uint16_t max){
551 config_netkey_list_max = max;
552 }
553
config_netkey_status(mesh_model_t * mesh_model,uint16_t netkey_index,uint16_t dest,uint8_t status,uint16_t new_netkey_index)554 static void config_netkey_status(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest, uint8_t status, uint16_t new_netkey_index){
555 UNUSED(mesh_model);
556
557 // setup message
558 mesh_upper_transport_pdu_t * transport_pdu = mesh_access_setup_message(
559 &mesh_foundation_config_netkey_status, status, new_netkey_index);
560 if (!transport_pdu) return;
561
562 // send as segmented access pdu
563 config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
564 }
565
config_netkey_list(mesh_model_t * mesh_model,uint16_t netkey_index,uint16_t dest)566 static void config_netkey_list(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest) {
567 UNUSED(mesh_model);
568
569 mesh_upper_transport_builder_t builder;
570 mesh_access_message_init(&builder, MESH_FOUNDATION_OPERATION_NETKEY_LIST);
571
572 // add list of netkey indexes
573 mesh_network_key_iterator_t it;
574 mesh_network_key_iterator_init(&it);
575 while (mesh_network_key_iterator_has_more(&it)){
576 mesh_network_key_t * network_key = mesh_network_key_iterator_get_next(&it);
577 mesh_access_message_add_uint16(&builder, network_key->netkey_index);
578 }
579
580 mesh_upper_transport_pdu_t * upper_pdu = mesh_access_message_finalize(&builder);
581
582 // send as segmented access pdu
583 config_server_send_message(netkey_index, dest, (mesh_pdu_t *) upper_pdu);
584 }
585
config_netkey_add_derived(void * arg)586 static void config_netkey_add_derived(void * arg){
587 mesh_subnet_t * subnet = (mesh_subnet_t *) arg;
588
589 // store network key
590 mesh_store_network_key(subnet->old_key);
591
592 // add key to NetKey List
593 mesh_network_key_add(subnet->old_key);
594
595 // add subnet
596 mesh_subnet_add(subnet);
597
598 #ifdef ENABLE_MESH_PROXY_SERVER
599 mesh_proxy_start_advertising_with_network_id();
600 #endif
601
602 config_netkey_status(mesh_node_get_configuration_server(), mesh_pdu_netkey_index(access_pdu_in_process), mesh_pdu_src(access_pdu_in_process), MESH_FOUNDATION_STATUS_SUCCESS, subnet->netkey_index);
603 mesh_access_message_processed(access_pdu_in_process);
604 }
605
config_netkey_add_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)606 static void config_netkey_add_handler(mesh_model_t * mesh_model, mesh_pdu_t * pdu){
607 mesh_access_parser_state_t parser;
608 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
609
610 // get params
611 uint8_t new_netkey[16];
612 uint16_t new_netkey_index = mesh_access_parser_get_uint16(&parser);
613 mesh_access_parser_get_key(&parser, new_netkey);
614
615 uint8_t status;
616
617 const mesh_subnet_t * existing_subnet = mesh_subnet_get_by_netkey_index(new_netkey_index);
618 if (existing_subnet == NULL){
619
620 // check limit for pts
621 uint16_t internal_index = mesh_network_key_get_free_index();
622 if (internal_index == MESH_KEYS_INVALID_INDEX || (config_netkey_list_max && mesh_network_key_list_count() >= config_netkey_list_max)){
623 status = MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES;
624 } else {
625
626 // allocate new key and subnet
627 mesh_network_key_t * new_network_key = btstack_memory_mesh_network_key_get();
628 mesh_subnet_t * new_subnet = btstack_memory_mesh_subnet_get();
629
630 if (new_network_key == NULL || new_subnet == NULL){
631 if (new_network_key != NULL){
632 btstack_memory_mesh_network_key_free(new_network_key);
633 }
634 if (new_subnet != NULL){
635 btstack_memory_mesh_subnet_free(new_subnet);
636 }
637 status = MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES;
638
639 } else {
640
641 // setup key
642 new_network_key->internal_index = internal_index;
643 new_network_key->netkey_index = new_netkey_index;
644 (void)memcpy(new_network_key->net_key, new_netkey, 16);
645
646 // setup subnet
647 new_subnet->old_key = new_network_key;
648 new_subnet->netkey_index = new_netkey_index;
649 new_subnet->key_refresh = MESH_KEY_REFRESH_NOT_ACTIVE;
650
651 // derive other keys
652 access_pdu_in_process = pdu;
653 mesh_network_key_derive(&configuration_server_cmac_request, new_network_key, config_netkey_add_derived, new_subnet);
654 return;
655 }
656 }
657
658 } else {
659 // network key for netkey index already exists
660 if (memcmp(existing_subnet->old_key->net_key, new_netkey, 16) == 0){
661 // same netkey
662 status = MESH_FOUNDATION_STATUS_SUCCESS;
663 } else {
664 // different netkey
665 status = MESH_FOUNDATION_STATUS_KEY_INDEX_ALREADY_STORED;
666 }
667 }
668
669 // report status
670 config_netkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, new_netkey_index);
671 mesh_access_message_processed(pdu);
672 }
673
config_netkey_update_derived(void * arg)674 static void config_netkey_update_derived(void * arg){
675 mesh_subnet_t * subnet = (mesh_subnet_t *) arg;
676
677 // store network key
678 mesh_store_network_key(subnet->new_key);
679
680 // add key to NetKey List
681 mesh_network_key_add(subnet->new_key);
682
683 // update subnet - Key Refresh Phase 1
684 subnet->key_refresh = MESH_KEY_REFRESH_FIRST_PHASE;
685
686 // report status
687 config_netkey_status(mesh_node_get_configuration_server(), mesh_pdu_netkey_index(access_pdu_in_process), mesh_pdu_src(access_pdu_in_process), MESH_FOUNDATION_STATUS_SUCCESS, subnet->netkey_index);
688 mesh_access_message_processed(access_pdu_in_process);
689 }
690
config_netkey_update_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)691 static void config_netkey_update_handler(mesh_model_t * mesh_model, mesh_pdu_t * pdu) {
692 mesh_access_parser_state_t parser;
693 mesh_access_parser_init(&parser, (mesh_pdu_t *) pdu);
694
695 // get params
696 uint8_t new_netkey[16];
697 uint16_t netkey_index = mesh_access_parser_get_uint16(&parser);
698 mesh_access_parser_get_key(&parser, new_netkey);
699
700 // get existing subnet
701 mesh_subnet_t * subnet = mesh_subnet_get_by_netkey_index(netkey_index);
702 if (subnet == NULL){
703 config_netkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX, netkey_index);
704 mesh_access_message_processed(access_pdu_in_process);
705 return;
706 }
707
708 // get index for new key
709 uint16_t internal_index = mesh_network_key_get_free_index();
710 if (internal_index == MESH_KEYS_INVALID_INDEX){
711 config_netkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES, netkey_index);
712 mesh_access_message_processed(access_pdu_in_process);
713 return;
714 }
715
716 // get new key
717 mesh_network_key_t * new_network_key = btstack_memory_mesh_network_key_get();
718 if (new_network_key == NULL){
719 config_netkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES, netkey_index);
720 mesh_access_message_processed(access_pdu_in_process);
721 return;
722 }
723
724 // setup new key
725 new_network_key->internal_index = internal_index;
726 new_network_key->netkey_index = netkey_index;
727 new_network_key->version = (uint8_t)(subnet->old_key->version + 1);
728 (void)memcpy(new_network_key->net_key, new_netkey, 16);
729
730 // store in subnet (not active yet)
731 subnet->new_key = new_network_key;
732
733 // derive other keys
734 access_pdu_in_process = pdu;
735 mesh_network_key_derive(&configuration_server_cmac_request, new_network_key, config_netkey_update_derived, subnet);
736 }
737
config_netkey_delete_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)738 static void config_netkey_delete_handler(mesh_model_t * mesh_model, mesh_pdu_t * pdu) {
739 mesh_access_parser_state_t parser;
740 mesh_access_parser_init(&parser, (mesh_pdu_t *) pdu);
741
742 // get params
743 uint16_t netkey_index_to_remove = mesh_access_parser_get_uint16(&parser);
744
745 // get message netkey
746 uint16_t netkey_index_pdu = mesh_pdu_netkey_index(pdu);
747
748 // remove subnet
749 uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
750 mesh_subnet_t * subnet = mesh_subnet_get_by_netkey_index(netkey_index_to_remove);
751 if (subnet != NULL){
752 // A NetKey shall not be deleted from the NetKey List using a message secured with this NetKey.
753 // Also prevents deleting the last network key
754 if (netkey_index_to_remove != netkey_index_pdu){
755
756 // remove all appkeys for this netkey
757 mesh_transport_key_iterator_t it;
758 mesh_transport_key_iterator_init(&it, netkey_index_to_remove);
759 while (mesh_transport_key_iterator_has_more(&it)){
760 mesh_transport_key_t * transport_key = mesh_transport_key_iterator_get_next(&it);
761 mesh_configuration_server_delete_appkey(transport_key);
762 }
763
764 // delete old/current key
765 mesh_access_netkey_finalize(subnet->old_key);
766 subnet->old_key = NULL;
767
768 // delete new key
769 if (subnet->new_key != NULL){
770 mesh_access_netkey_finalize(subnet->new_key);
771 subnet->new_key = NULL;
772 }
773
774 // remove subnet
775 mesh_subnet_remove(subnet);
776 btstack_memory_mesh_subnet_free(subnet);
777
778 } else {
779 status = MESH_FOUNDATION_STATUS_CANNOT_REMOVE;
780 }
781 }
782 config_netkey_status(mesh_model, netkey_index_pdu, mesh_pdu_src(pdu), status, netkey_index_to_remove);
783 mesh_access_message_processed(pdu);
784 }
785
config_netkey_get_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)786 static void config_netkey_get_handler(mesh_model_t * mesh_model, mesh_pdu_t * pdu){
787 config_netkey_list(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
788 mesh_access_message_processed(pdu);
789 }
790
791 // AppKey List
792
config_appkey_status(mesh_model_t * mesh_model,uint16_t netkey_index,uint16_t dest,uint32_t netkey_and_appkey_index,uint8_t status)793 static void config_appkey_status(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest, uint32_t netkey_and_appkey_index, uint8_t status){
794 UNUSED(mesh_model);
795
796 // setup message
797 mesh_upper_transport_pdu_t * transport_pdu = mesh_access_setup_message(&mesh_foundation_config_appkey_status,
798 status, netkey_and_appkey_index);
799 if (!transport_pdu) return;
800
801 // send as segmented access pdu
802 config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
803 }
804
config_appkey_list(mesh_model_t * mesh_model,uint16_t netkey_index,uint16_t dest,uint32_t netkey_index_of_list)805 static void config_appkey_list(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest, uint32_t netkey_index_of_list){
806 UNUSED(mesh_model);
807
808 mesh_upper_transport_builder_t builder;
809 mesh_access_message_init(&builder, MESH_FOUNDATION_OPERATION_APPKEY_LIST);
810
811 // check netkey_index is valid
812 mesh_network_key_t * network_key = mesh_network_key_list_get(netkey_index_of_list);
813 uint8_t status;
814 if (network_key == NULL){
815 status = MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX;
816 } else {
817 status = MESH_FOUNDATION_STATUS_SUCCESS;
818 }
819 mesh_access_message_add_uint8(&builder, status);
820 mesh_access_message_add_uint16(&builder, netkey_index_of_list);
821
822 // add list of appkey indexes
823 mesh_transport_key_iterator_t it;
824 mesh_transport_key_iterator_init(&it, netkey_index_of_list);
825 while (mesh_transport_key_iterator_has_more(&it)){
826 mesh_transport_key_t * transport_key = mesh_transport_key_iterator_get_next(&it);
827 if (transport_key->old_key == 1) continue;
828 mesh_access_message_add_uint16(&builder, transport_key->appkey_index);
829 }
830
831 mesh_upper_transport_pdu_t * upper_pdu = mesh_access_message_finalize(&builder);
832
833 // send as segmented access pdu
834 config_server_send_message(netkey_index, dest, (mesh_pdu_t *) upper_pdu);
835 }
836
config_appkey_add_or_update_aid(void * arg)837 static void config_appkey_add_or_update_aid(void *arg){
838 mesh_transport_key_t * transport_key = (mesh_transport_key_t *) arg;
839
840 printf("Config Appkey Add/Update: NetKey Index 0x%04x, AppKey Index 0x%04x, AID %02x: ", transport_key->netkey_index, transport_key->appkey_index, transport_key->aid);
841 printf_hexdump(transport_key->key, 16);
842
843 // store in TLV
844 mesh_store_app_key(transport_key);
845
846 // add app key
847 mesh_transport_key_add(transport_key);
848
849 uint32_t netkey_and_appkey_index = (((uint32_t)transport_key->appkey_index) << 12) | transport_key->netkey_index;
850 config_appkey_status(mesh_node_get_configuration_server(), mesh_pdu_netkey_index(access_pdu_in_process), mesh_pdu_src(access_pdu_in_process), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_SUCCESS);
851
852 mesh_access_message_processed(access_pdu_in_process);
853 }
854
config_appkey_add_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)855 static void config_appkey_add_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
856
857 mesh_access_parser_state_t parser;
858 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
859
860 // netkey and appkey index
861 uint32_t netkey_and_appkey_index = mesh_access_parser_get_uint24(&parser);
862 uint16_t netkey_index = netkey_and_appkey_index & 0xfff;
863 uint16_t appkey_index = netkey_and_appkey_index >> 12;
864
865 // actual key
866 uint8_t appkey[16];
867 mesh_access_parser_get_key(&parser, appkey);
868
869 // check netkey_index is valid
870 mesh_network_key_t * network_key = mesh_network_key_list_get(netkey_index);
871 if (network_key == NULL){
872 config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX);
873 mesh_access_message_processed(pdu);
874 return;
875 }
876
877 // check if appkey already exists
878 mesh_transport_key_t * transport_key = mesh_transport_key_get(appkey_index);
879 if (transport_key){
880 uint8_t status;
881 if (transport_key->netkey_index != netkey_index){
882 // already stored but with different netkey
883 status = MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX;
884 } else if (memcmp(transport_key->key, appkey, 16) == 0){
885 // key identical
886 status = MESH_FOUNDATION_STATUS_SUCCESS;
887 } else {
888 // key differs
889 status = MESH_FOUNDATION_STATUS_KEY_INDEX_ALREADY_STORED;
890 }
891 config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, status);
892 mesh_access_message_processed(pdu);
893 return;
894 }
895
896 // create app key (first get free slot in transport key table)
897 mesh_transport_key_t * app_key = NULL;
898 uint16_t internal_index = mesh_transport_key_get_free_index();
899 if (internal_index > 0){
900 app_key = btstack_memory_mesh_transport_key_get();
901 }
902 if (app_key == NULL) {
903 config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES);
904 mesh_access_message_processed(pdu);
905 return;
906 }
907
908 // store data
909 app_key->internal_index = internal_index;
910 app_key->akf = 1;
911 app_key->appkey_index = appkey_index;
912 app_key->netkey_index = netkey_index;
913 app_key->version = 0;
914 app_key->old_key = 0;
915
916 (void)memcpy(app_key->key, appkey, 16);
917
918 // calculate AID
919 access_pdu_in_process = pdu;
920 mesh_transport_key_calc_aid(&configuration_server_cmac_request, app_key, config_appkey_add_or_update_aid, app_key);
921 }
922
config_appkey_update_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)923 static void config_appkey_update_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
924
925 mesh_access_parser_state_t parser;
926 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
927
928 // netkey and appkey index
929 uint32_t netkey_and_appkey_index = mesh_access_parser_get_uint24(&parser);
930 uint16_t netkey_index = netkey_and_appkey_index & 0xfff;
931 uint16_t appkey_index = netkey_and_appkey_index >> 12;
932
933 // actual key
934 uint8_t appkey[16];
935 mesh_access_parser_get_key(&parser, appkey);
936
937
938 // for PTS testing
939 // check netkey_index is valid
940 mesh_network_key_t * network_key = mesh_network_key_list_get(netkey_index);
941 if (network_key == NULL){
942 config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX);
943 mesh_access_message_processed(pdu);
944 return;
945 }
946
947 // check if appkey already exists
948 mesh_transport_key_t * existing_app_key = mesh_transport_key_get(appkey_index);
949 if (!existing_app_key) {
950 config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_INVALID_APPKEY_INDEX);
951 mesh_access_message_processed(pdu);
952 return;
953 }
954
955 if (existing_app_key->netkey_index != netkey_index){
956 // already stored but with different netkey
957 config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_INVALID_BINDING);
958 mesh_access_message_processed(pdu);
959 return;
960 }
961
962 if (memcmp(existing_app_key->key, appkey, 16) == 0){
963 // key identical
964 config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_SUCCESS);
965 mesh_access_message_processed(pdu);
966 return;
967 }
968
969 // create app key
970 mesh_transport_key_t * new_app_key = NULL;
971 uint16_t internal_index = mesh_transport_key_get_free_index();
972 if (internal_index > 0){
973 new_app_key = btstack_memory_mesh_transport_key_get();
974 }
975 if (new_app_key == NULL) {
976 config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES);
977 mesh_access_message_processed(pdu);
978 return;
979 }
980
981 // store data
982 new_app_key->internal_index = internal_index;
983 new_app_key->appkey_index = appkey_index;
984 new_app_key->netkey_index = netkey_index;
985 new_app_key->key_refresh = 1;
986 new_app_key->version = (uint8_t)(existing_app_key->version + 1);
987 (void)memcpy(new_app_key->key, appkey, 16);
988
989 // mark old key
990 existing_app_key->old_key = 1;
991
992 // calculate AID
993 access_pdu_in_process = pdu;
994 mesh_transport_key_calc_aid(&configuration_server_cmac_request, new_app_key, config_appkey_add_or_update_aid, new_app_key);
995 }
996
config_appkey_delete_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)997 static void config_appkey_delete_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
998 mesh_access_parser_state_t parser;
999 mesh_access_parser_init(&parser, (mesh_pdu_t *) pdu);
1000
1001 // netkey and appkey index
1002 uint32_t netkey_and_appkey_index = mesh_access_parser_get_uint24(&parser);
1003 uint16_t netkey_index = netkey_and_appkey_index & 0xfff;
1004 uint16_t appkey_index = netkey_and_appkey_index >> 12;
1005
1006 // check netkey_index is valid
1007 mesh_network_key_t * network_key = mesh_network_key_list_get(netkey_index);
1008 if (network_key == NULL){
1009 config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX);
1010 mesh_access_message_processed(pdu);
1011 return;
1012 }
1013
1014 // check if appkey already exists
1015 mesh_transport_key_t * transport_key = mesh_transport_key_get(appkey_index);
1016 if (transport_key){
1017 mesh_configuration_server_delete_appkey(transport_key);
1018 }
1019
1020 config_appkey_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_and_appkey_index, MESH_FOUNDATION_STATUS_SUCCESS);
1021 mesh_access_message_processed(pdu);
1022 }
1023
config_appkey_get_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)1024 static void config_appkey_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1025 mesh_access_parser_state_t parser;
1026 mesh_access_parser_init(&parser, (mesh_pdu_t *) pdu);
1027 uint16_t netkey_index = mesh_access_parser_get_uint16(&parser);
1028
1029 config_appkey_list(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), netkey_index);
1030 mesh_access_message_processed(pdu);
1031 }
1032
1033 // Configuration Model Subscriptions (messages)
1034
config_model_subscription_list(mesh_model_t * mesh_model,uint16_t netkey_index,uint16_t dest,uint8_t status,uint16_t element_address,uint32_t model_identifier,mesh_model_t * target_model)1035 static void config_model_subscription_list(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest, uint8_t status, uint16_t element_address, uint32_t model_identifier, mesh_model_t * target_model){
1036 UNUSED(mesh_model);
1037
1038 uint16_t opcode;
1039 if (mesh_model_is_bluetooth_sig(model_identifier)){
1040 opcode = MESH_FOUNDATION_OPERATION_SIG_MODEL_SUBSCRIPTION_LIST;
1041 } else {
1042 opcode = MESH_FOUNDATION_OPERATION_VENDOR_MODEL_SUBSCRIPTION_LIST;
1043 }
1044
1045 mesh_upper_transport_builder_t builder;
1046 mesh_access_message_init(&builder, opcode);
1047
1048 // setup segmented message
1049 mesh_access_message_add_uint8(&builder, status);
1050 mesh_access_message_add_uint16(&builder, element_address);
1051 mesh_access_message_add_model_identifier(&builder, model_identifier);
1052
1053 if (target_model != NULL){
1054 uint16_t i;
1055 for (i = 0; i < MAX_NR_MESH_SUBSCRIPTION_PER_MODEL; i++){
1056 uint16_t address = target_model->subscriptions[i];
1057 if (address == MESH_ADDRESS_UNSASSIGNED) continue;
1058 if (mesh_network_address_virtual(address)) {
1059 mesh_virtual_address_t * virtual_address = mesh_virtual_address_for_pseudo_dst(address);
1060 if (virtual_address == NULL) continue;
1061 address = virtual_address->hash;
1062 }
1063 mesh_access_message_add_uint16(&builder, address);
1064 }
1065 }
1066
1067 mesh_upper_transport_pdu_t * upper_pdu = mesh_access_message_finalize(&builder);
1068
1069 config_server_send_message(netkey_index, dest, (mesh_pdu_t *) upper_pdu);
1070 }
1071
config_model_subscription_get_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)1072 static void config_model_subscription_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1073 mesh_access_parser_state_t parser;
1074 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1075
1076 uint16_t element_address = mesh_access_parser_get_uint16(&parser);
1077 uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1078
1079 uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1080 mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1081
1082 config_model_subscription_list(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, model_identifier, target_model);
1083 mesh_access_message_processed(pdu);
1084 }
1085
config_model_subscription_status(mesh_model_t * mesh_model,uint16_t netkey_index,uint16_t dest,uint8_t status,uint16_t element_address,uint16_t address,uint32_t model_identifier)1086 static void config_model_subscription_status(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest, uint8_t status, uint16_t element_address, uint16_t address, uint32_t model_identifier){
1087 UNUSED(mesh_model);
1088
1089 // setup message
1090 mesh_upper_transport_pdu_t * transport_pdu = mesh_access_setup_message(&mesh_foundation_config_model_subscription_status,
1091 status, element_address, address, model_identifier);
1092 if (!transport_pdu) return;
1093 // send as segmented access pdu
1094 config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
1095 }
1096
config_model_subscription_add_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)1097 static void config_model_subscription_add_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1098 mesh_access_parser_state_t parser;
1099 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1100
1101 uint16_t element_address = mesh_access_parser_get_uint16(&parser);
1102 uint16_t address = mesh_access_parser_get_uint16(&parser);
1103 uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1104
1105 uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1106 mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1107
1108 if (target_model != NULL){
1109 if (mesh_network_address_group(address) && !mesh_network_address_all_nodes(address)){
1110 status = mesh_model_add_subscription(target_model, address);
1111 if (status == MESH_FOUNDATION_STATUS_SUCCESS){
1112 mesh_model_store_subscriptions(target_model);
1113 }
1114 } else {
1115 status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS;
1116 }
1117 }
1118
1119 config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, address, model_identifier);
1120 mesh_access_message_processed(pdu);
1121 }
1122
config_model_subscription_virtual_address_add_hash(void * arg)1123 static void config_model_subscription_virtual_address_add_hash(void *arg){
1124 mesh_model_t * target_model = (mesh_model_t*) arg;
1125 mesh_model_t * mesh_model = mesh_node_get_configuration_server();
1126
1127 // add if not exists
1128 mesh_virtual_address_t * virtual_address = mesh_virtual_address_for_label_uuid(configuration_server_label_uuid);
1129 if (virtual_address == NULL){
1130 virtual_address = mesh_virtual_address_register(configuration_server_label_uuid, configuration_server_hash);
1131 }
1132
1133 uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1134 uint16_t hash_dst = MESH_ADDRESS_UNSASSIGNED;
1135 if (virtual_address == NULL){
1136 status = MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES;
1137 } else {
1138 if (!mesh_model_contains_subscription(target_model, virtual_address->pseudo_dst)){
1139 status = mesh_model_add_subscription(target_model, virtual_address->pseudo_dst);
1140 if (status == MESH_FOUNDATION_STATUS_SUCCESS){
1141 hash_dst = virtual_address->hash;
1142 mesh_virtual_address_increase_refcount(virtual_address);
1143 mesh_model_store_subscriptions(target_model);
1144 }
1145 }
1146 }
1147
1148 config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(access_pdu_in_process), mesh_pdu_src(access_pdu_in_process), status, configuration_server_element_address, hash_dst, target_model->model_identifier);
1149 mesh_access_message_processed(access_pdu_in_process);
1150 return;
1151 }
1152
config_model_subscription_virtual_address_add_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)1153 static void config_model_subscription_virtual_address_add_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1154 mesh_access_parser_state_t parser;
1155 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1156
1157 // ElementAddress - Address of the element - should be us
1158 configuration_server_element_address = mesh_access_parser_get_uint16(&parser);
1159
1160 // store label uuid
1161 mesh_access_parser_get_label_uuid(&parser, configuration_server_label_uuid);
1162
1163 // Model Identifier
1164 uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1165
1166 uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1167 mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(configuration_server_element_address, model_identifier, &status);
1168
1169 if (target_model == NULL){
1170 config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, configuration_server_element_address, MESH_ADDRESS_UNSASSIGNED, model_identifier);
1171 mesh_access_message_processed(pdu);
1172 return;
1173 }
1174
1175 access_pdu_in_process = pdu;
1176 mesh_virtual_address(&configuration_server_cmac_request, configuration_server_label_uuid, &configuration_server_hash, &config_model_subscription_virtual_address_add_hash, target_model);
1177 }
1178
config_model_subscription_overwrite_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)1179 static void config_model_subscription_overwrite_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1180 mesh_access_parser_state_t parser;
1181 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1182
1183 uint16_t element_address = mesh_access_parser_get_uint16(&parser);
1184 uint16_t address = mesh_access_parser_get_uint16(&parser);
1185 uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1186
1187 uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1188 mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1189
1190 if (target_model != NULL){
1191 if (mesh_network_address_group(address) && !mesh_network_address_all_nodes(address)){
1192 mesh_subcription_decrease_virtual_address_ref_count(target_model);
1193 mesh_model_delete_all_subscriptions(target_model);
1194 mesh_model_add_subscription(target_model, address);
1195 mesh_model_store_subscriptions(target_model);
1196 } else {
1197 status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS;
1198 }
1199 }
1200
1201 config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, address, model_identifier);
1202 mesh_access_message_processed(pdu);
1203 }
1204
config_model_subscription_virtual_address_overwrite_hash(void * arg)1205 static void config_model_subscription_virtual_address_overwrite_hash(void *arg){
1206 mesh_model_t * target_model = (mesh_model_t*) arg;
1207 mesh_model_t * mesh_model = mesh_node_get_configuration_server();
1208
1209 // add if not exists
1210 mesh_virtual_address_t * virtual_address = mesh_virtual_address_for_label_uuid(configuration_server_label_uuid);
1211 if (virtual_address == NULL){
1212 virtual_address = mesh_virtual_address_register(configuration_server_label_uuid, configuration_server_hash);
1213 }
1214
1215 uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1216 uint16_t address = MESH_ADDRESS_UNSASSIGNED;;
1217 if (virtual_address == NULL){
1218 status = MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES;
1219 } else {
1220 address = configuration_server_hash;
1221
1222 // increase refcount first to avoid flash delete + add in a row
1223 mesh_virtual_address_increase_refcount(virtual_address);
1224
1225 // decrease ref counts for virtual addresses in subscription
1226 mesh_subcription_decrease_virtual_address_ref_count(target_model);
1227
1228 // clear subscriptions
1229 mesh_model_delete_all_subscriptions(target_model);
1230
1231 // add new subscription (successfull if MAX_NR_MESH_SUBSCRIPTION_PER_MODEL > 0)
1232 mesh_model_add_subscription(target_model, virtual_address->pseudo_dst);
1233
1234 mesh_model_store_subscriptions(target_model);
1235 }
1236
1237 config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(access_pdu_in_process), mesh_pdu_src(access_pdu_in_process), status, configuration_server_element_address, address, target_model->model_identifier);
1238 mesh_access_message_processed(access_pdu_in_process);
1239 return;
1240 }
1241
config_model_subscription_virtual_address_overwrite_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)1242 static void config_model_subscription_virtual_address_overwrite_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1243 mesh_access_parser_state_t parser;
1244 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1245
1246 // ElementAddress - Address of the element - should be us
1247 configuration_server_element_address = mesh_access_parser_get_uint16(&parser);
1248
1249 // store label uuid
1250 mesh_access_parser_get_label_uuid(&parser, configuration_server_label_uuid);
1251
1252 // Model Identifier
1253 uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1254
1255 uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1256 mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(configuration_server_element_address, model_identifier, &status);
1257
1258 if (target_model == NULL){
1259 config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, configuration_server_element_address, MESH_ADDRESS_UNSASSIGNED, model_identifier);
1260 mesh_access_message_processed(pdu);
1261 return;
1262 }
1263 access_pdu_in_process = pdu;
1264 mesh_virtual_address(&configuration_server_cmac_request, configuration_server_label_uuid, &configuration_server_hash, &config_model_subscription_virtual_address_overwrite_hash, target_model);
1265 }
1266
config_model_subscription_delete_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)1267 static void config_model_subscription_delete_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1268 mesh_access_parser_state_t parser;
1269 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1270
1271 uint16_t element_address = mesh_access_parser_get_uint16(&parser);
1272 uint16_t address = mesh_access_parser_get_uint16(&parser);
1273 uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1274
1275 uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1276 mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1277
1278 if (target_model != NULL){
1279 if (mesh_network_address_group(address) && !mesh_network_address_all_nodes(address)){
1280 mesh_model_delete_subscription(target_model, address);
1281 mesh_model_store_subscriptions(target_model);
1282 } else {
1283 status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS;
1284 }
1285 }
1286
1287 config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, address, model_identifier);
1288 mesh_access_message_processed(pdu);
1289 }
1290
config_model_subscription_virtual_address_delete_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)1291 static void config_model_subscription_virtual_address_delete_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1292 mesh_access_parser_state_t parser;
1293 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1294
1295 uint16_t element_address = mesh_access_parser_get_uint16(&parser);
1296 mesh_access_parser_get_label_uuid(&parser, configuration_server_label_uuid);
1297 uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1298
1299 mesh_virtual_address_t * virtual_address = mesh_virtual_address_for_label_uuid(configuration_server_label_uuid);
1300 uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1301 mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1302 uint16_t address = MESH_ADDRESS_UNSASSIGNED;
1303
1304 if ((target_model != NULL) && (virtual_address != NULL) && mesh_model_contains_subscription(target_model, virtual_address->pseudo_dst)){
1305 address = virtual_address->hash;
1306 mesh_model_delete_subscription(target_model, virtual_address->pseudo_dst);
1307 mesh_model_store_subscriptions(target_model);
1308 mesh_virtual_address_decrease_refcount(virtual_address);
1309 }
1310
1311 config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address,address, model_identifier);
1312 mesh_access_message_processed(pdu);
1313 }
1314
config_model_subscription_delete_all_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)1315 static void config_model_subscription_delete_all_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
1316 mesh_access_parser_state_t parser;
1317 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1318
1319 uint16_t element_address = mesh_access_parser_get_uint16(&parser);
1320 uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1321
1322 uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1323 mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1324
1325 if (target_model != NULL){
1326 mesh_subcription_decrease_virtual_address_ref_count(target_model);
1327 mesh_model_delete_all_subscriptions(target_model);
1328 mesh_model_store_subscriptions(target_model);
1329 }
1330
1331 config_model_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, MESH_ADDRESS_UNSASSIGNED, model_identifier);
1332 mesh_access_message_processed(pdu);
1333 }
1334
1335 // Configuration Model to AppKey List
1336
config_model_app_status(mesh_model_t * mesh_model,uint16_t netkey_index,uint16_t dest,uint8_t status,uint16_t element_address,uint16_t appkey_index,uint32_t model_identifier)1337 static void config_model_app_status(mesh_model_t * mesh_model, uint16_t netkey_index, uint16_t dest, uint8_t status, uint16_t element_address, uint16_t appkey_index, uint32_t model_identifier){
1338 UNUSED(mesh_model);
1339
1340 // setup message
1341 mesh_upper_transport_pdu_t * transport_pdu = mesh_access_setup_message(&mesh_foundation_config_model_app_status,
1342 status, element_address, appkey_index, model_identifier);
1343 if (!transport_pdu) return;
1344
1345 // send as segmented access pdu
1346 config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
1347 }
1348
config_model_app_list(mesh_model_t * config_server_model,uint16_t netkey_index,uint16_t dest,uint8_t status,uint16_t element_address,uint32_t model_identifier,mesh_model_t * mesh_model)1349 static void config_model_app_list(mesh_model_t * config_server_model, uint16_t netkey_index, uint16_t dest, uint8_t status, uint16_t element_address, uint32_t model_identifier, mesh_model_t * mesh_model){
1350 UNUSED(config_server_model);
1351
1352 uint16_t opcode;
1353 if (mesh_model_is_bluetooth_sig(model_identifier)){
1354 opcode = MESH_FOUNDATION_OPERATION_SIG_MODEL_APP_LIST;
1355 } else {
1356 opcode = MESH_FOUNDATION_OPERATION_VENDOR_MODEL_APP_LIST;
1357 }
1358
1359 mesh_upper_transport_builder_t builder;
1360 mesh_access_message_init(&builder, opcode);
1361
1362 mesh_access_message_add_uint8(&builder, status);
1363 mesh_access_message_add_uint16(&builder, element_address);
1364 if (mesh_model_is_bluetooth_sig(model_identifier)) {
1365 mesh_access_message_add_uint16(&builder, mesh_model_get_model_id(model_identifier));
1366 } else {
1367 mesh_access_message_add_uint32(&builder, model_identifier);
1368 }
1369
1370 // add list of appkey indexes
1371 if (mesh_model){
1372 uint16_t i;
1373 for (i=0;i<MAX_NR_MESH_APPKEYS_PER_MODEL;i++){
1374 uint16_t appkey_index = mesh_model->appkey_indices[i];
1375 if (appkey_index == MESH_APPKEY_INVALID) continue;
1376 mesh_access_message_add_uint16(&builder, appkey_index);
1377 }
1378 }
1379
1380 mesh_upper_transport_pdu_t * upper_pdu = mesh_access_message_finalize(&builder);
1381
1382 // send as segmented access pdu
1383 config_server_send_message(netkey_index, dest, (mesh_pdu_t *) upper_pdu);
1384 }
1385
config_model_app_bind_handler(mesh_model_t * config_server_model,mesh_pdu_t * pdu)1386 static void config_model_app_bind_handler(mesh_model_t *config_server_model, mesh_pdu_t * pdu) {
1387 mesh_access_parser_state_t parser;
1388 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1389
1390 uint16_t element_address = mesh_access_parser_get_uint16(&parser);
1391 uint16_t appkey_index = mesh_access_parser_get_uint16(&parser);
1392 uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1393
1394 uint8_t status;
1395 do {
1396 // validate address and look up model
1397 mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1398 if (target_model == NULL) break;
1399
1400 // validate app key exists
1401 mesh_transport_key_t * app_key = mesh_transport_key_get(appkey_index);
1402 if (!app_key){
1403 status = MESH_FOUNDATION_STATUS_INVALID_APPKEY_INDEX;
1404 break;
1405 }
1406
1407 // Configuration Server only allows device keys
1408 if (mesh_model_is_configuration_server(model_identifier)){
1409 status = MESH_FOUNDATION_STATUS_CANNOT_BIND;
1410 break;
1411 }
1412 status = mesh_model_bind_appkey(target_model, appkey_index);
1413
1414 } while (0);
1415
1416 config_model_app_status(config_server_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, appkey_index, model_identifier);
1417 mesh_access_message_processed(pdu);
1418 }
1419
config_model_app_unbind_handler(mesh_model_t * config_server_model,mesh_pdu_t * pdu)1420 static void config_model_app_unbind_handler(mesh_model_t *config_server_model, mesh_pdu_t * pdu) {
1421 mesh_access_parser_state_t parser;
1422 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1423
1424 uint16_t element_address = mesh_access_parser_get_uint16(&parser);
1425 uint16_t appkey_index = mesh_access_parser_get_uint16(&parser);
1426 uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1427
1428 uint8_t status;
1429 do {
1430 // validate address and look up model
1431 mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1432 if (target_model == NULL) break;
1433
1434 // validate app key exists
1435 mesh_transport_key_t * app_key = mesh_transport_key_get(appkey_index);
1436 if (!app_key){
1437 status = MESH_FOUNDATION_STATUS_INVALID_APPKEY_INDEX;
1438 break;
1439 }
1440
1441 // stop publishing
1442 mesh_configuration_server_stop_publishing_using_appkey(target_model, appkey_index);
1443
1444 // unbind appkey
1445 mesh_model_unbind_appkey(target_model, appkey_index);
1446
1447 status = MESH_FOUNDATION_STATUS_SUCCESS;
1448 } while (0);
1449
1450 config_model_app_status(config_server_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, appkey_index, model_identifier);
1451 mesh_access_message_processed(pdu);
1452 }
1453
config_model_app_get_handler(mesh_model_t * config_server_model,mesh_pdu_t * pdu)1454 static void config_model_app_get_handler(mesh_model_t *config_server_model, mesh_pdu_t * pdu){
1455 mesh_access_parser_state_t parser;
1456 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1457
1458 uint16_t element_address = mesh_access_parser_get_uint16(&parser);
1459 uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1460
1461 uint8_t status;
1462 mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1463 config_model_app_list(config_server_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, model_identifier, target_model);
1464 mesh_access_message_processed(pdu);
1465 }
1466
1467 // Model Publication
config_model_publication_changed(mesh_model_t * mesh_model,mesh_publication_model_t * new_publication_model)1468 static void config_model_publication_changed(mesh_model_t *mesh_model, mesh_publication_model_t * new_publication_model){
1469
1470 // stop publication
1471 mesh_model_publication_stop(mesh_model);
1472
1473 if (new_publication_model->address == MESH_ADDRESS_UNSASSIGNED) {
1474 // "When the PublishAddress is set to the unassigned address, the values of the AppKeyIndex, CredentialFlag, PublishTTL, PublishPeriod, PublishRetransmitCount, and PublishRetransmitIntervalSteps fields shall be set to 0x00.
1475 mesh_model->publication_model->address = MESH_ADDRESS_UNSASSIGNED;
1476 mesh_model->publication_model->appkey_index = 0;
1477 mesh_model->publication_model->friendship_credential_flag = 0;
1478 mesh_model->publication_model->period = 0;
1479 mesh_model->publication_model->ttl = 0;
1480 mesh_model->publication_model->retransmit = 0;
1481 } else {
1482 // update model publication state
1483 mesh_model->publication_model->address = new_publication_model->address;
1484 mesh_model->publication_model->appkey_index = new_publication_model->appkey_index;
1485 mesh_model->publication_model->friendship_credential_flag = new_publication_model->friendship_credential_flag;
1486 mesh_model->publication_model->period = new_publication_model->period;
1487 mesh_model->publication_model->ttl = new_publication_model->ttl;
1488 mesh_model->publication_model->retransmit = new_publication_model->retransmit;
1489 }
1490
1491 // store
1492 mesh_model_store_publication(mesh_model);
1493
1494 // start publication if address is set (nothing happens if period = 0 and retransmit = 0)
1495 if (new_publication_model->address == MESH_ADDRESS_UNSASSIGNED) return;
1496
1497 // start to publish
1498 mesh_model_publication_start(mesh_model);
1499 }
1500
1501
1502 static void
config_model_publication_status(mesh_model_t * mesh_model,uint16_t netkey_index,uint16_t dest,uint8_t status,uint16_t element_address,uint32_t model_identifier,mesh_publication_model_t * publication_model)1503 config_model_publication_status(mesh_model_t *mesh_model, uint16_t netkey_index, uint16_t dest, uint8_t status,
1504 uint16_t element_address, uint32_t model_identifier, mesh_publication_model_t *publication_model) {
1505 UNUSED(mesh_model);
1506
1507 // setup message
1508 uint16_t app_key_index_and_credential_flag = 0;
1509 uint16_t publish_address = 0;
1510 uint8_t ttl = 0;
1511 uint8_t period = 0;
1512 uint8_t retransmit = 0;
1513 if (status == MESH_FOUNDATION_STATUS_SUCCESS){
1514 app_key_index_and_credential_flag = (publication_model->friendship_credential_flag << 12) | publication_model->appkey_index;
1515 ttl = publication_model->ttl;
1516 period = publication_model->period;
1517 retransmit = publication_model->retransmit;
1518
1519 publish_address = publication_model->address;
1520 if (mesh_network_address_virtual(publish_address)){
1521 mesh_virtual_address_t * virtual_address = mesh_virtual_address_for_pseudo_dst(publish_address);
1522 if (virtual_address){
1523 publish_address = virtual_address->hash;
1524 }
1525 }
1526 }
1527
1528 mesh_upper_transport_pdu_t * transport_pdu = mesh_access_setup_message(
1529 &mesh_foundation_config_model_publication_status, status, element_address, publish_address,
1530 app_key_index_and_credential_flag, ttl, period, retransmit, model_identifier);
1531 if (!transport_pdu) return;
1532
1533 // send as segmented access pdu
1534 config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
1535 }
1536
1537 static void
config_model_publication_set_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)1538 config_model_publication_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1539
1540 // set defaults
1541 memset(&configuration_server_publication_model, 0, sizeof(mesh_publication_model_t));
1542
1543 mesh_access_parser_state_t parser;
1544 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1545
1546 // ElementAddress
1547 uint16_t element_address = mesh_access_parser_get_uint16(&parser);
1548
1549 // PublishAddress, 16 bit
1550 configuration_server_publication_model.address = mesh_access_parser_get_uint16(&parser);
1551
1552 // AppKeyIndex (12), CredentialFlag (1), RFU (3)
1553 uint16_t temp = mesh_access_parser_get_uint16(&parser);
1554 configuration_server_publication_model.appkey_index = temp & 0x0fff;
1555 configuration_server_publication_model.friendship_credential_flag = (temp >> 12) & 1;
1556
1557 // TTL
1558 configuration_server_publication_model.ttl = mesh_access_parser_get_uint8(&parser);
1559
1560 // Period
1561 configuration_server_publication_model.period = mesh_access_parser_get_uint8(&parser);
1562
1563 // Retransmit
1564 configuration_server_publication_model.retransmit = mesh_access_parser_get_uint8(&parser);
1565
1566 // Model Identifier
1567 uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1568
1569 // Get Model for Element + Model Identifier
1570 uint8_t status;
1571 mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1572
1573 // Check if publicatation model struct provided
1574 if (status == MESH_FOUNDATION_STATUS_SUCCESS) {
1575 if (target_model->publication_model == NULL){
1576 status = MESH_FOUNDATION_STATUS_CANNOT_SET;
1577 }
1578 }
1579
1580 // Check AppKey
1581 if (status == MESH_FOUNDATION_STATUS_SUCCESS){
1582 // check if appkey already exists
1583 mesh_transport_key_t * app_key = mesh_transport_key_get(configuration_server_publication_model.appkey_index);
1584 if (app_key == NULL) {
1585 status = MESH_FOUNDATION_STATUS_INVALID_APPKEY_INDEX;
1586 }
1587 }
1588
1589 // Accept set
1590 if (status == MESH_FOUNDATION_STATUS_SUCCESS){
1591 // decrease ref count if old virtual address
1592 if (mesh_network_address_virtual(configuration_server_publication_model.address)) {
1593 mesh_virtual_address_t * current_virtual_address = mesh_virtual_address_for_pseudo_dst(configuration_server_publication_model.address);
1594 mesh_virtual_address_decrease_refcount(current_virtual_address);
1595 }
1596
1597 // restart publication
1598 config_model_publication_changed(target_model, &configuration_server_publication_model);
1599 }
1600
1601 // send status
1602 config_model_publication_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, model_identifier, &configuration_server_publication_model);
1603 mesh_access_message_processed(pdu);
1604 }
1605
config_model_publication_virtual_address_set_hash(void * arg)1606 static void config_model_publication_virtual_address_set_hash(void *arg){
1607 mesh_model_t *mesh_model = (mesh_model_t*) arg;
1608
1609 // add if not exist
1610 mesh_virtual_address_t * virtual_address = mesh_virtual_address_for_label_uuid(configuration_server_label_uuid);
1611 if (virtual_address == NULL){
1612 virtual_address = mesh_virtual_address_register(configuration_server_label_uuid, configuration_server_hash);
1613 }
1614
1615 uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1616 if (virtual_address == NULL){
1617 status = MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES;
1618 } else {
1619
1620 // increase ref count if new virtual address
1621 mesh_virtual_address_increase_refcount(virtual_address);
1622
1623 // decrease ref count if old virtual address
1624 if (mesh_network_address_virtual(configuration_server_publication_model.address)) {
1625 mesh_virtual_address_t * current_virtual_address = mesh_virtual_address_for_pseudo_dst(configuration_server_publication_model.address);
1626 if (current_virtual_address){
1627 mesh_virtual_address_decrease_refcount(current_virtual_address);
1628 }
1629 }
1630
1631 configuration_server_publication_model.address = virtual_address->pseudo_dst;
1632 mesh_virtual_address_increase_refcount(virtual_address);
1633
1634 // restart publication
1635 config_model_publication_changed(configuration_server_target_model, &configuration_server_publication_model);
1636 }
1637
1638 // send status
1639 config_model_publication_status(mesh_model, mesh_pdu_netkey_index(access_pdu_in_process), mesh_pdu_src(access_pdu_in_process), status, configuration_server_element_address, configuration_server_model_identifier, &configuration_server_publication_model);
1640
1641 mesh_access_message_processed(access_pdu_in_process);
1642 }
1643
1644 static void
config_model_publication_virtual_address_set_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)1645 config_model_publication_virtual_address_set_handler(mesh_model_t *mesh_model,
1646 mesh_pdu_t * pdu) {
1647
1648 // set defaults
1649 memset(&configuration_server_publication_model, 0, sizeof(mesh_publication_model_t));
1650
1651 mesh_access_parser_state_t parser;
1652 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1653
1654 // ElementAddress - Address of the element
1655 configuration_server_element_address = mesh_access_parser_get_uint16(&parser);
1656
1657 // store label uuid
1658 mesh_access_parser_get_label_uuid(&parser, configuration_server_label_uuid);
1659
1660 // AppKeyIndex (12), CredentialFlag (1), RFU (3)
1661 uint16_t temp = mesh_access_parser_get_uint16(&parser);
1662 configuration_server_publication_model.appkey_index = temp & 0x0fff;
1663 configuration_server_publication_model.friendship_credential_flag = (temp >> 12) & 1;
1664 configuration_server_publication_model.ttl = mesh_access_parser_get_uint8(&parser);
1665 configuration_server_publication_model.period = mesh_access_parser_get_uint8(&parser);
1666 configuration_server_publication_model.retransmit = mesh_access_parser_get_uint8(&parser);
1667
1668 // Model Identifier
1669 configuration_server_model_identifier = mesh_access_parser_get_model_identifier(&parser);
1670
1671 // Get Model for Element + Model Identifier
1672 uint8_t status;
1673 configuration_server_target_model = mesh_access_model_for_address_and_model_identifier(configuration_server_element_address, configuration_server_model_identifier, &status);
1674
1675 // Check if publicatation model struct provided
1676 if (status == MESH_FOUNDATION_STATUS_SUCCESS) {
1677 if (configuration_server_target_model->publication_model == NULL){
1678 status = MESH_FOUNDATION_STATUS_CANNOT_SET;
1679 }
1680 }
1681
1682 // Check AppKey
1683 if (status == MESH_FOUNDATION_STATUS_SUCCESS){
1684 // check if appkey already exists
1685 mesh_transport_key_t * app_key = mesh_transport_key_get(configuration_server_publication_model.appkey_index);
1686 if (app_key == NULL) {
1687 status = MESH_FOUNDATION_STATUS_INVALID_APPKEY_INDEX;
1688 }
1689 }
1690
1691 // on error, no need to calculate virtual address hash
1692 if (status != MESH_FOUNDATION_STATUS_SUCCESS){
1693 config_model_publication_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, configuration_server_element_address, configuration_server_model_identifier, &configuration_server_publication_model);
1694 mesh_access_message_processed(pdu);
1695 return;
1696 }
1697
1698 access_pdu_in_process = pdu;
1699 mesh_virtual_address(&configuration_server_cmac_request, configuration_server_label_uuid, &configuration_server_hash, &config_model_publication_virtual_address_set_hash, mesh_model);
1700 }
1701
1702 static void
config_model_publication_get_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)1703 config_model_publication_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1704
1705
1706 mesh_access_parser_state_t parser;
1707 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1708
1709 // ElementAddress - Address of the element - should be us
1710 uint16_t element_address = mesh_access_parser_get_uint16(&parser);
1711
1712 // Model Identifier
1713 uint32_t model_identifier = mesh_access_parser_get_model_identifier(&parser);
1714
1715 // Get Model for Element + Model Identifier
1716 uint8_t status;
1717 mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier(element_address, model_identifier, &status);
1718
1719 mesh_publication_model_t * publication_model;
1720 if (target_model == NULL){
1721 // use defaults
1722 memset(&configuration_server_publication_model, 0, sizeof(mesh_publication_model_t));
1723 publication_model = &configuration_server_publication_model;
1724 } else {
1725 publication_model = target_model->publication_model;
1726 }
1727
1728 config_model_publication_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, element_address, model_identifier, publication_model);
1729 mesh_access_message_processed(pdu);
1730 }
1731
1732 // Heartbeat Publication
1733
config_heartbeat_publication_emit(mesh_heartbeat_publication_t * mesh_heartbeat_publication)1734 static void config_heartbeat_publication_emit(mesh_heartbeat_publication_t * mesh_heartbeat_publication){
1735
1736 printf("CONFIG_SERVER_HEARTBEAT: Emit (dest %04x, count %u, period %" PRIu32 " ms)\n",
1737 mesh_heartbeat_publication->destination,
1738 mesh_heartbeat_publication->count,
1739 mesh_heartbeat_publication->period_ms);
1740
1741 // active features
1742 mesh_heartbeat_publication->active_features = mesh_foundation_get_features();
1743
1744 mesh_network_pdu_t * network_pdu = mesh_network_pdu_get();
1745 if (network_pdu){
1746 uint8_t data[3];
1747 data[0] = mesh_heartbeat_publication->ttl;
1748 big_endian_store_16(data, 1, mesh_heartbeat_publication->active_features);
1749 uint8_t status = mesh_upper_transport_setup_unsegmented_control_pdu(network_pdu, mesh_heartbeat_publication->netkey_index,
1750 mesh_heartbeat_publication->ttl, mesh_node_get_primary_element_address(), mesh_heartbeat_publication->destination,
1751 MESH_TRANSPORT_OPCODE_HEARTBEAT, data, sizeof(data));
1752 if (status){
1753 // stop periodic emit on error (netkey got invalid)
1754 mesh_heartbeat_publication->period_ms = 0;
1755 mesh_network_pdu_free(network_pdu);
1756 } else {
1757 mesh_upper_transport_send_control_pdu((mesh_pdu_t *) network_pdu);
1758 }
1759 }
1760
1761 // forever
1762 if (mesh_heartbeat_publication->count > 0 && mesh_heartbeat_publication->count < 0xffffu) {
1763 mesh_heartbeat_publication->count--;
1764 }
1765 }
mesh_configuration_server_feature_changed(void)1766 void mesh_configuration_server_feature_changed(void){
1767 mesh_model_t * mesh_model = mesh_node_get_configuration_server();
1768 mesh_heartbeat_publication_t * mesh_heartbeat_publication = &((mesh_configuration_server_model_context_t*) mesh_model->model_data)->heartbeat_publication;
1769
1770 // filter features by observed features for heartbeats
1771 uint16_t current_features = mesh_foundation_get_features() & mesh_heartbeat_publication->features;
1772 uint16_t previous_features = mesh_heartbeat_publication->active_features & mesh_heartbeat_publication->features;
1773
1774 // changes?
1775 if (current_features == previous_features) return;
1776
1777 config_heartbeat_publication_emit(mesh_heartbeat_publication);
1778 }
1779
config_heartbeat_publication_timeout_handler(btstack_timer_source_t * ts)1780 static void config_heartbeat_publication_timeout_handler(btstack_timer_source_t * ts){
1781
1782 mesh_heartbeat_publication_t * mesh_heartbeat_publication = (mesh_heartbeat_publication_t*) ts;
1783 mesh_heartbeat_publication->timer_active = 0;
1784
1785 // emit beat
1786 config_heartbeat_publication_emit(mesh_heartbeat_publication);
1787
1788 // all sent?
1789 if (mesh_heartbeat_publication->count == 0) return;
1790
1791 // periodic publication?
1792 if (mesh_heartbeat_publication->period_ms == 0) return;
1793
1794 btstack_run_loop_set_timer(ts, mesh_heartbeat_publication->period_ms);
1795 btstack_run_loop_add_timer(ts);
1796 mesh_heartbeat_publication->timer_active = 1;
1797 }
1798
config_heartbeat_publication_status(mesh_model_t * mesh_model,uint16_t netkey_index,uint16_t dest,uint8_t status,mesh_heartbeat_publication_t * mesh_heartbeat_publication)1799 static void config_heartbeat_publication_status(mesh_model_t *mesh_model, uint16_t netkey_index, uint16_t dest, uint8_t status, mesh_heartbeat_publication_t * mesh_heartbeat_publication){
1800 UNUSED(mesh_model);
1801
1802 // setup message
1803 uint8_t count_log = mesh_heartbeat_count_log(mesh_heartbeat_publication->count);
1804 mesh_upper_transport_pdu_t * transport_pdu = mesh_access_setup_message(
1805 &mesh_foundation_config_heartbeat_publication_status,
1806 status,
1807 mesh_heartbeat_publication->destination,
1808 count_log,
1809 mesh_heartbeat_publication->period_log,
1810 mesh_heartbeat_publication->ttl,
1811 mesh_heartbeat_publication->features,
1812 mesh_heartbeat_publication->netkey_index);
1813 if (!transport_pdu) return;
1814
1815 printf("MESH config_heartbeat_publication_status count = %u => count_log = %u\n", mesh_heartbeat_publication->count, count_log);
1816
1817 // send as segmented access pdu
1818 config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
1819 }
1820
config_heartbeat_publication_set_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)1821 static void config_heartbeat_publication_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1822
1823 mesh_heartbeat_publication_t requested_publication;
1824 memset(&requested_publication, 0, sizeof(requested_publication));
1825
1826 mesh_access_parser_state_t parser;
1827 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1828
1829 // Destination address for Heartbeat messages
1830 requested_publication.destination = mesh_access_parser_get_uint16(&parser);
1831 // Number of Heartbeat messages to be sent
1832 requested_publication.count = mesh_heartbeat_pwr2(mesh_access_parser_get_uint8(&parser));
1833 // Period for sending Heartbeat messages
1834 requested_publication.period_log = mesh_access_parser_get_uint8(&parser);
1835 // TTL to be used when sending Heartbeat messages
1836 requested_publication.ttl = mesh_access_parser_get_uint8(&parser);
1837 // Bit field indicating features that trigger Heartbeat messages when changed
1838 requested_publication.features = mesh_access_parser_get_uint16(&parser) & MESH_HEARTBEAT_FEATURES_SUPPORTED_MASK;
1839 // NetKey Index
1840 requested_publication.netkey_index = mesh_access_parser_get_uint16(&parser);
1841
1842 // store period as ms
1843 requested_publication.period_ms = mesh_heartbeat_pwr2(requested_publication.period_log) * 1000;
1844
1845 // store current features
1846 requested_publication.active_features = mesh_foundation_get_features();
1847
1848 mesh_heartbeat_publication_t * mesh_heartbeat_publication = &((mesh_configuration_server_model_context_t*) mesh_model->model_data)->heartbeat_publication;
1849
1850 // validate fields
1851 uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1852 mesh_network_key_t * network_key = mesh_network_key_list_get(requested_publication.netkey_index);
1853 if (network_key == NULL){
1854 status = MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX;
1855 } else {
1856 printf("MESH config_heartbeat_publication_set, destination %x, count = %x, period = %" PRIu32 " s\n",
1857 requested_publication.destination, requested_publication.count, requested_publication.period_ms);
1858
1859 // stop timer if active
1860 // note: accept update below using memcpy overwwrite timer_active flag
1861 if (mesh_heartbeat_publication->timer_active){
1862 btstack_run_loop_remove_timer(&mesh_heartbeat_publication->timer);
1863 mesh_heartbeat_publication->timer_active = 0;
1864 }
1865
1866 // accept update
1867 (void)memcpy(mesh_heartbeat_publication, &requested_publication,
1868 sizeof(mesh_heartbeat_publication_t));
1869 }
1870
1871 config_heartbeat_publication_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, mesh_heartbeat_publication);
1872
1873 mesh_access_message_processed(pdu);
1874
1875 if (status != MESH_FOUNDATION_STATUS_SUCCESS) return;
1876
1877 // check if heartbeats should be disabled
1878 if (mesh_heartbeat_publication->destination == MESH_ADDRESS_UNSASSIGNED || mesh_heartbeat_publication->period_log == 0) {
1879 return;
1880 }
1881
1882 // initial heartbeat after 2000 ms
1883 btstack_run_loop_set_timer_handler(&mesh_heartbeat_publication->timer, config_heartbeat_publication_timeout_handler);
1884 btstack_run_loop_set_timer_context(&mesh_heartbeat_publication->timer, mesh_heartbeat_publication);
1885 btstack_run_loop_set_timer(&mesh_heartbeat_publication->timer, 2000);
1886 btstack_run_loop_add_timer(&mesh_heartbeat_publication->timer);
1887 mesh_heartbeat_publication->timer_active = 1;
1888 }
1889
config_heartbeat_publication_get_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)1890 static void config_heartbeat_publication_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1891 mesh_heartbeat_publication_t * mesh_heartbeat_publication = &((mesh_configuration_server_model_context_t*) mesh_model->model_data)->heartbeat_publication;
1892 config_heartbeat_publication_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), MESH_FOUNDATION_STATUS_SUCCESS, mesh_heartbeat_publication);
1893 mesh_access_message_processed(pdu);
1894 }
1895
1896 // Heartbeat Subscription
1897
config_heartbeat_subscription_status(mesh_model_t * mesh_model,uint16_t netkey_index,uint16_t dest,uint8_t status,mesh_heartbeat_subscription_t * mesh_heartbeat_subscription)1898 static void config_heartbeat_subscription_status(mesh_model_t *mesh_model, uint16_t netkey_index, uint16_t dest, uint8_t status, mesh_heartbeat_subscription_t * mesh_heartbeat_subscription){
1899 UNUSED(mesh_model);
1900
1901 // setup message
1902 uint8_t count_log = mesh_heartbeat_count_log(mesh_heartbeat_subscription->count);
1903 mesh_upper_transport_pdu_t * transport_pdu = mesh_access_setup_message(
1904 &mesh_foundation_config_heartbeat_subscription_status,
1905 status,
1906 mesh_heartbeat_subscription->source,
1907 mesh_heartbeat_subscription->destination,
1908 mesh_heartbeat_subscription->period_log,
1909 count_log,
1910 mesh_heartbeat_subscription->min_hops,
1911 mesh_heartbeat_subscription->max_hops);
1912 if (!transport_pdu) return;
1913 printf("MESH config_heartbeat_subscription_status count = %u => count_log = %u\n", mesh_heartbeat_subscription->count, count_log);
1914
1915 // send as segmented access pdu
1916 config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
1917 }
config_heartbeat_subscription_enabled(mesh_heartbeat_subscription_t * mesh_heartbeat_subscription)1918 static int config_heartbeat_subscription_enabled(mesh_heartbeat_subscription_t * mesh_heartbeat_subscription){
1919 return mesh_network_address_unicast(mesh_heartbeat_subscription->source) && mesh_heartbeat_subscription->period_log > 0 &&
1920 (mesh_network_address_unicast(mesh_heartbeat_subscription->destination) || mesh_network_address_group(mesh_heartbeat_subscription->destination));
1921 }
1922
config_heartbeat_subscription_set_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)1923 static void config_heartbeat_subscription_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
1924 mesh_access_parser_state_t parser;
1925 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
1926
1927 mesh_heartbeat_subscription_t requested_subscription;
1928
1929 // Destination address for Heartbeat messages
1930 requested_subscription.source = mesh_access_parser_get_uint16(&parser);
1931 // Destination address for Heartbeat messages
1932 requested_subscription.destination = mesh_access_parser_get_uint16(&parser);
1933 // Period for sending Heartbeat messages
1934 requested_subscription.period_log = mesh_access_parser_get_uint8(&parser);
1935
1936
1937 // Hearbeat Subscription Soure must be unassigned or a unicast address
1938 int source_address_valid =
1939 (requested_subscription.source == MESH_ADDRESS_UNSASSIGNED) ||
1940 (mesh_network_address_unicast(requested_subscription.source));
1941
1942 // Heartbeat Subscription Destination must be unassigned, unicast (== our primary address), or a group address)
1943 int destination_address_valid =
1944 (requested_subscription.destination == MESH_ADDRESS_UNSASSIGNED) ||
1945 (mesh_network_address_unicast(requested_subscription.destination) && requested_subscription.destination == mesh_node_get_primary_element_address()) ||
1946 (mesh_network_address_group(requested_subscription.destination));
1947
1948 if (!source_address_valid || !destination_address_valid){
1949 printf("MESH config_heartbeat_subscription_set, source %x or destination %x invalid\n", requested_subscription.source, requested_subscription.destination);
1950 mesh_access_message_processed(pdu);
1951 return;
1952 }
1953
1954 int subscription_enabled = config_heartbeat_subscription_enabled(&requested_subscription);
1955 printf("MESH config_heartbeat_subscription_set, source %x destination %x, period = %u s => enabled %u \n", requested_subscription.source,
1956 requested_subscription.destination, mesh_heartbeat_pwr2(requested_subscription.period_log), subscription_enabled);
1957
1958 // ignore messages
1959 uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
1960 if (requested_subscription.period_log > 0x11u){
1961 status = MESH_FOUNDATION_STATUS_CANNOT_SET;
1962 } else if ((requested_subscription.destination != MESH_ADDRESS_UNSASSIGNED) &&
1963 !mesh_network_address_unicast(requested_subscription.destination) &&
1964 !mesh_network_address_group(requested_subscription.destination)){
1965 status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS;
1966 }
1967
1968 if (status != MESH_FOUNDATION_STATUS_SUCCESS){
1969 config_heartbeat_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, &requested_subscription);
1970 mesh_access_message_processed(pdu);
1971 return;
1972 }
1973
1974 mesh_heartbeat_subscription_t * mesh_heartbeat_subscription = &((mesh_configuration_server_model_context_t*) mesh_model->model_data)->heartbeat_subscription;
1975
1976 if (config_heartbeat_subscription_enabled(&requested_subscription)){
1977 mesh_heartbeat_subscription->source = requested_subscription.source;
1978 mesh_heartbeat_subscription->destination = requested_subscription.destination;
1979 mesh_heartbeat_subscription->period_log = requested_subscription.period_log;
1980 mesh_heartbeat_subscription->count = 0;
1981 mesh_heartbeat_subscription->min_hops = 0x7Fu;
1982 mesh_heartbeat_subscription->max_hops = 0u;
1983 mesh_heartbeat_subscription->period_start_ms = btstack_run_loop_get_time_ms();
1984 } else {
1985 #if 0
1986 // code according to Mesh Spec v1.0.1
1987 // "When an element receives a Config Heartbeat Subscription Set message, it shall ... respond with a Config Heartbeat Subscription Status message, setting ...
1988 // If the Source or the Destination field is set to the unassigned address, or the PeriodLog field is set to 0x00, [then]
1989 // - the processing of received Heartbeat messages shall be disabled,
1990 // - the Heartbeat Subscription Source state shall be set to the unassigned address,
1991 // - the Heartbeat Subscription Destination state shall be set to the unassigned address,
1992 // - the Heartbeat Subscription MinHops state shall be unchanged,
1993 // - the Heartbeat Subscription MaxHops state shall be unchanged,
1994 // - and the Heartbeat Subscription Count state shall be unchanged."
1995 // If period_log == 0, then set src + dest to unassigned. If src or dest are unsigned, get triggers status mit count_log == 0
1996 mesh_heartbeat_subscription->source = MESH_ADDRESS_UNSASSIGNED;
1997 mesh_heartbeat_subscription->destination = MESH_ADDRESS_UNSASSIGNED;
1998 #else
1999 // code to satisfy MESH/NODE/CFG/HBS/BV-02-C from PTS 7.4.1 / Mesh TS 1.0.2
2000 if (requested_subscription.source == MESH_ADDRESS_UNSASSIGNED || requested_subscription.destination == MESH_ADDRESS_UNSASSIGNED){
2001 mesh_heartbeat_subscription->source = MESH_ADDRESS_UNSASSIGNED;
2002 mesh_heartbeat_subscription->destination = MESH_ADDRESS_UNSASSIGNED;
2003 }
2004 #endif
2005 mesh_heartbeat_subscription->period_log = 0u;
2006 }
2007
2008 config_heartbeat_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, mesh_heartbeat_subscription);
2009 mesh_access_message_processed(pdu);
2010 }
2011
config_heartbeat_subscription_get_period_remaining_s(mesh_heartbeat_subscription_t * heartbeat_subscription)2012 static uint32_t config_heartbeat_subscription_get_period_remaining_s(mesh_heartbeat_subscription_t * heartbeat_subscription){
2013 // calculate period_log
2014 int32_t time_since_start_s = btstack_time_delta(btstack_run_loop_get_time_ms(), heartbeat_subscription->period_start_ms) / 1000;
2015 int32_t period_s = mesh_heartbeat_pwr2(heartbeat_subscription->period_log);
2016 uint32_t period_remaining_s = 0;
2017 if (time_since_start_s < period_s){
2018 period_remaining_s = period_s - time_since_start_s;
2019 }
2020 printf("Heartbeat: time since start %" PRId32 " s, period %" PRIu32 " s, period remaining %" PRIu32 " s\n", time_since_start_s, period_s, period_remaining_s);
2021 return period_remaining_s;
2022 }
2023
config_heartbeat_subscription_get_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)2024 static void config_heartbeat_subscription_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu) {
2025 mesh_heartbeat_subscription_t * mesh_heartbeat_subscription = &((mesh_configuration_server_model_context_t*) mesh_model->model_data)->heartbeat_subscription;
2026 mesh_heartbeat_subscription_t subscription;
2027 (void)memcpy(&subscription, mesh_heartbeat_subscription,
2028 sizeof(subscription));
2029 if (mesh_heartbeat_subscription->source == MESH_ADDRESS_UNSASSIGNED || mesh_heartbeat_subscription->destination == MESH_ADDRESS_UNSASSIGNED){
2030 memset(&subscription, 0, sizeof(subscription));
2031 } else {
2032 // calculate period_log
2033 uint32_t period_remaining_s = config_heartbeat_subscription_get_period_remaining_s(&subscription);
2034 subscription.period_log = mesh_heartbeat_period_log(period_remaining_s);
2035 }
2036 config_heartbeat_subscription_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), MESH_FOUNDATION_STATUS_SUCCESS, &subscription);
2037 mesh_access_message_processed(pdu);
2038 }
2039
2040 // KeyRefresh Phase
2041
config_key_refresh_phase_status(mesh_model_t * mesh_model,uint16_t netkey_index_dest,uint16_t dest,uint8_t status,uint16_t netkey_index,mesh_key_refresh_state_t key_refresh_state)2042 static void config_key_refresh_phase_status(mesh_model_t *mesh_model, uint16_t netkey_index_dest, uint16_t dest, uint8_t status, uint16_t netkey_index,
2043 mesh_key_refresh_state_t key_refresh_state){
2044 UNUSED(mesh_model);
2045
2046 // setup message
2047 mesh_upper_transport_pdu_t * transport_pdu = mesh_access_setup_message(
2048 &mesh_key_refresh_phase_status,
2049 status,
2050 netkey_index,
2051 key_refresh_state);
2052 if (!transport_pdu) return;
2053
2054 // send as segmented access pdu
2055 config_server_send_message(netkey_index_dest, dest, (mesh_pdu_t *) transport_pdu);
2056 }
2057
config_key_refresh_phase_get_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)2058 static void config_key_refresh_phase_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
2059 mesh_access_parser_state_t parser;
2060 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
2061 uint16_t netkey_index = mesh_access_parser_get_uint16(&parser);
2062 mesh_subnet_t * subnet = mesh_subnet_get_by_netkey_index(netkey_index);
2063
2064 uint8_t status = MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX;
2065 mesh_key_refresh_state_t key_refresh_state = MESH_KEY_REFRESH_NOT_ACTIVE;
2066
2067 if (subnet != NULL){
2068 status = MESH_FOUNDATION_STATUS_SUCCESS;
2069 key_refresh_state = subnet->key_refresh;
2070 }
2071
2072 config_key_refresh_phase_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, netkey_index, key_refresh_state);
2073 mesh_access_message_processed(pdu);
2074 }
2075
config_key_refresh_phase_set_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)2076 static void config_key_refresh_phase_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
2077 mesh_access_parser_state_t parser;
2078 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
2079 uint16_t netkey_index = mesh_access_parser_get_uint16(&parser);
2080 uint8_t key_refresh_phase_transition = mesh_access_parser_get_uint8(&parser);
2081 mesh_subnet_t * subnet = mesh_subnet_get_by_netkey_index(netkey_index);
2082
2083 uint8_t status = MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX;
2084
2085 if (subnet != NULL){
2086 status = MESH_FOUNDATION_STATUS_SUCCESS;
2087
2088 switch (key_refresh_phase_transition){
2089 case 0x02:
2090 switch (subnet->key_refresh){
2091 case MESH_KEY_REFRESH_FIRST_PHASE:
2092 case MESH_KEY_REFRESH_SECOND_PHASE:
2093 subnet->key_refresh = MESH_KEY_REFRESH_SECOND_PHASE;
2094 break;
2095 default:
2096 break;
2097 }
2098 break;
2099 case 0x03:
2100 switch (subnet->key_refresh){
2101 case MESH_KEY_REFRESH_FIRST_PHASE:
2102 case MESH_KEY_REFRESH_SECOND_PHASE:
2103 // key refresh phase 3 entered
2104 mesh_access_key_refresh_revoke_keys(subnet);
2105 subnet->key_refresh = MESH_KEY_REFRESH_NOT_ACTIVE;
2106 break;
2107 default:
2108 break;
2109 }
2110 break;
2111 default:
2112 status = MESH_FOUNDATION_STATUS_CANNOT_SET;
2113 break;
2114 }
2115 }
2116
2117 config_key_refresh_phase_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, netkey_index, subnet->key_refresh);
2118 mesh_access_message_processed(pdu);
2119 }
2120
2121
config_node_reset_status(mesh_model_t * mesh_model,uint16_t netkey_index,uint16_t dest)2122 static void config_node_reset_status(mesh_model_t *mesh_model, uint16_t netkey_index, uint16_t dest){
2123 UNUSED(mesh_model);
2124
2125 // setup message
2126 mesh_upper_transport_pdu_t * transport_pdu = mesh_access_setup_message(&mesh_foundation_node_reset_status);
2127 if (!transport_pdu) return;
2128
2129 // send as segmented access pdu
2130 config_server_send_message(netkey_index, dest, (mesh_pdu_t *) transport_pdu);
2131 }
2132
config_node_reset_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)2133 static void config_node_reset_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
2134 mesh_node_reset();
2135 config_node_reset_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu));
2136 mesh_access_message_processed(pdu);
2137 }
2138
low_power_node_poll_timeout_status(mesh_model_t * mesh_model,uint16_t netkey_index_dest,uint16_t dest,uint8_t status)2139 static void low_power_node_poll_timeout_status(mesh_model_t *mesh_model, uint16_t netkey_index_dest, uint16_t dest, uint8_t status){
2140 UNUSED(mesh_model);
2141
2142 mesh_upper_transport_pdu_t * transport_pdu = mesh_access_setup_message(
2143 &mesh_foundation_low_power_node_poll_timeout_status,
2144 status,
2145 0, // The unicast address of the Low Power node
2146 0); // The current value of the PollTimeout timer of the Low Power node
2147 if (!transport_pdu) return;
2148 printf("TODO: send unicast address of the Low Power node and the current value of the PollTimeout timer, instead of 0s\n");
2149 // send as segmented access pdu
2150 config_server_send_message(netkey_index_dest, dest, (mesh_pdu_t *) transport_pdu);
2151 }
2152
config_low_power_node_poll_timeout_get_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)2153 static void config_low_power_node_poll_timeout_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
2154 mesh_access_parser_state_t parser;
2155 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
2156 printf("TODO: implement get the current value of PollTimeout timer of the Low Power node within a Friend node\n");
2157 low_power_node_poll_timeout_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), MESH_FOUNDATION_STATUS_SUCCESS);
2158
2159 mesh_access_message_processed(pdu);
2160 }
2161
config_node_identity_status(mesh_model_t * mesh_model,uint16_t netkey_index_dest,uint16_t dest,uint8_t status,uint16_t netkey_index,mesh_node_identity_state_t node_identity_state)2162 static void config_node_identity_status(mesh_model_t *mesh_model, uint16_t netkey_index_dest, uint16_t dest, uint8_t status, uint16_t netkey_index,
2163 mesh_node_identity_state_t node_identity_state){
2164 UNUSED(mesh_model);
2165
2166 // setup message
2167 mesh_upper_transport_pdu_t * transport_pdu = mesh_access_setup_message(
2168 &mesh_foundation_node_identity_status,
2169 status,
2170 netkey_index,
2171 node_identity_state);
2172 if (!transport_pdu) return;
2173
2174 // send as segmented access pdu
2175 config_server_send_message(netkey_index_dest, dest, (mesh_pdu_t *) transport_pdu);
2176 }
2177
config_node_identity_get_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)2178 static void config_node_identity_get_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
2179 mesh_access_parser_state_t parser;
2180 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
2181 uint16_t netkey_index = mesh_access_parser_get_uint16(&parser);
2182
2183 mesh_node_identity_state_t node_identity_state = MESH_NODE_IDENTITY_STATE_ADVERTISING_NOT_SUPPORTED;
2184 uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
2185 #ifdef ENABLE_MESH_PROXY_SERVER
2186 status = mesh_proxy_get_advertising_with_node_id_status(netkey_index, &node_identity_state);
2187 #endif
2188 config_node_identity_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, netkey_index, node_identity_state);
2189
2190 mesh_access_message_processed(pdu);
2191 }
2192
config_node_identity_set_handler(mesh_model_t * mesh_model,mesh_pdu_t * pdu)2193 static void config_node_identity_set_handler(mesh_model_t *mesh_model, mesh_pdu_t * pdu){
2194 mesh_access_parser_state_t parser;
2195 mesh_access_parser_init(&parser, (mesh_pdu_t*) pdu);
2196 uint16_t netkey_index = mesh_access_parser_get_uint16(&parser);
2197 mesh_node_identity_state_t node_identity_state = (mesh_node_identity_state_t) mesh_access_parser_get_uint8(&parser);
2198
2199 // ignore invalid state
2200 if (node_identity_state >= MESH_NODE_IDENTITY_STATE_ADVERTISING_NOT_SUPPORTED) {
2201 mesh_access_message_processed(pdu);
2202 return;
2203 }
2204
2205 uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS;
2206 #ifdef ENABLE_MESH_PROXY_SERVER
2207 status = mesh_proxy_set_advertising_with_node_id(netkey_index, node_identity_state);
2208 #else
2209 mesh_subnet_t * network_key = mesh_subnet_get_by_netkey_index(netkey_index);
2210 if (network_key == NULL){
2211 status = MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX;
2212 }
2213 #endif
2214
2215 config_node_identity_status(mesh_model, mesh_pdu_netkey_index(pdu), mesh_pdu_src(pdu), status, netkey_index, node_identity_state);
2216
2217 mesh_access_message_processed(pdu);
2218 }
2219
2220 //
2221
2222 static const mesh_operation_t mesh_configuration_server_model_operations[] = {
2223 { MESH_FOUNDATION_OPERATION_APPKEY_ADD, 19, config_appkey_add_handler },
2224 { MESH_FOUNDATION_OPERATION_APPKEY_DELETE, 3, config_appkey_delete_handler },
2225 { MESH_FOUNDATION_OPERATION_APPKEY_GET, 2, config_appkey_get_handler },
2226 { MESH_FOUNDATION_OPERATION_APPKEY_UPDATE, 19, config_appkey_update_handler },
2227 { MESH_FOUNDATION_OPERATION_NETKEY_ADD, 18, config_netkey_add_handler },
2228 { MESH_FOUNDATION_OPERATION_NETKEY_UPDATE, 18, config_netkey_update_handler },
2229 { MESH_FOUNDATION_OPERATION_NETKEY_DELETE, 2, config_netkey_delete_handler },
2230 { MESH_FOUNDATION_OPERATION_NETKEY_GET, 0, config_netkey_get_handler },
2231 { MESH_FOUNDATION_OPERATION_COMPOSITION_DATA_GET, 1, config_composition_data_get_handler },
2232 { MESH_FOUNDATION_OPERATION_BEACON_GET, 0, config_beacon_get_handler },
2233 { MESH_FOUNDATION_OPERATION_BEACON_SET, 1, config_beacon_set_handler },
2234 { MESH_FOUNDATION_OPERATION_DEFAULT_TTL_GET, 0, config_default_ttl_get_handler },
2235 { MESH_FOUNDATION_OPERATION_DEFAULT_TTL_SET, 1, config_default_ttl_set_handler },
2236 { MESH_FOUNDATION_OPERATION_FRIEND_GET, 0, config_friend_get_handler },
2237 { MESH_FOUNDATION_OPERATION_FRIEND_SET, 1, config_friend_set_handler },
2238 { MESH_FOUNDATION_OPERATION_NETWORK_TRANSMIT_GET, 0, config_model_network_transmit_get_handler },
2239 { MESH_FOUNDATION_OPERATION_NETWORK_TRANSMIT_SET, 1, config_model_network_transmit_set_handler },
2240 { MESH_FOUNDATION_OPERATION_GATT_PROXY_GET, 0, config_gatt_proxy_get_handler },
2241 { MESH_FOUNDATION_OPERATION_GATT_PROXY_SET, 1, config_gatt_proxy_set_handler },
2242 { MESH_FOUNDATION_OPERATION_RELAY_GET, 0, config_relay_get_handler },
2243 { MESH_FOUNDATION_OPERATION_RELAY_SET, 1, config_relay_set_handler },
2244 { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_ADD, 6, config_model_subscription_add_handler },
2245 { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_ADD, 20, config_model_subscription_virtual_address_add_handler },
2246 { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_DELETE, 6, config_model_subscription_delete_handler },
2247 { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_DELETE, 20, config_model_subscription_virtual_address_delete_handler },
2248 { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_OVERWRITE, 6, config_model_subscription_overwrite_handler },
2249 { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_OVERWRITE,20, config_model_subscription_virtual_address_overwrite_handler },
2250 { MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_DELETE_ALL, 4, config_model_subscription_delete_all_handler },
2251 { MESH_FOUNDATION_OPERATION_SIG_MODEL_SUBSCRIPTION_GET, 4, config_model_subscription_get_handler },
2252 { MESH_FOUNDATION_OPERATION_VENDOR_MODEL_SUBSCRIPTION_GET, 6, config_model_subscription_get_handler },
2253 { MESH_FOUNDATION_OPERATION_SIG_MODEL_APP_GET, 4, config_model_app_get_handler },
2254 { MESH_FOUNDATION_OPERATION_VENDOR_MODEL_APP_GET, 6, config_model_app_get_handler },
2255 { MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_SET, 11, config_model_publication_set_handler },
2256 { MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_VIRTUAL_ADDRESS_SET, 25, config_model_publication_virtual_address_set_handler },
2257 { MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_GET, 4, config_model_publication_get_handler },
2258 { MESH_FOUNDATION_OPERATION_MODEL_APP_BIND, 6, config_model_app_bind_handler },
2259 { MESH_FOUNDATION_OPERATION_MODEL_APP_UNBIND, 6, config_model_app_unbind_handler },
2260 { MESH_FOUNDATION_OPERATION_HEARTBEAT_PUBLICATION_GET, 0, config_heartbeat_publication_get_handler },
2261 { MESH_FOUNDATION_OPERATION_HEARTBEAT_PUBLICATION_SET, 9, config_heartbeat_publication_set_handler },
2262 { MESH_FOUNDATION_OPERATION_HEARTBEAT_SUBSCRIPTION_GET, 0, config_heartbeat_subscription_get_handler},
2263 { MESH_FOUNDATION_OPERATION_HEARTBEAT_SUBSCRIPTION_SET, 5, config_heartbeat_subscription_set_handler},
2264 { MESH_FOUNDATION_OPERATION_KEY_REFRESH_PHASE_GET, 2, config_key_refresh_phase_get_handler },
2265 { MESH_FOUNDATION_OPERATION_KEY_REFRESH_PHASE_SET, 3, config_key_refresh_phase_set_handler },
2266 { MESH_FOUNDATION_OPERATION_NODE_RESET, 0, config_node_reset_handler },
2267 { MESH_FOUNDATION_OPERATION_LOW_POWER_NODE_POLL_TIMEOUT_GET, 2, config_low_power_node_poll_timeout_get_handler },
2268 { MESH_FOUNDATION_OPERATION_NODE_IDENTITY_GET, 2, config_node_identity_get_handler },
2269 { MESH_FOUNDATION_OPERATION_NODE_IDENTITY_SET, 3, config_node_identity_set_handler },
2270 { 0, 0, NULL }
2271 };
2272
mesh_configuration_server_get_operations(void)2273 const mesh_operation_t * mesh_configuration_server_get_operations(void){
2274 return mesh_configuration_server_model_operations;
2275 }
2276
mesh_configuration_server_process_heartbeat(mesh_model_t * configuration_server_model,uint16_t src,uint16_t dest,uint8_t hops,uint16_t features)2277 void mesh_configuration_server_process_heartbeat(mesh_model_t * configuration_server_model, uint16_t src, uint16_t dest, uint8_t hops, uint16_t features){
2278 UNUSED(features);
2279 mesh_heartbeat_subscription_t * mesh_heartbeat_subscription = &((mesh_configuration_server_model_context_t*) configuration_server_model->model_data)->heartbeat_subscription;
2280 if (config_heartbeat_subscription_get_period_remaining_s(mesh_heartbeat_subscription) == 0) return;
2281 if (mesh_heartbeat_subscription->source != src) return;
2282 if (mesh_heartbeat_subscription->destination != dest) return;
2283 // update count
2284 if (mesh_heartbeat_subscription->count != 0xffff){
2285 mesh_heartbeat_subscription->count++;
2286 }
2287 // update min/max hops
2288 mesh_heartbeat_subscription->min_hops = (uint8_t) btstack_min(mesh_heartbeat_subscription->min_hops, hops);
2289 mesh_heartbeat_subscription->max_hops = (uint8_t) btstack_max(mesh_heartbeat_subscription->max_hops, hops);
2290
2291 printf("HEARTBEAT, count %u, min %u, max %u hops\n", mesh_heartbeat_subscription->count, mesh_heartbeat_subscription->min_hops, mesh_heartbeat_subscription->max_hops);
2292 }
2293