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