2018-10-05 15:13:34 +02:00
/*
* Copyright ( C ) 2014 BlueKitchen GmbH
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
*
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission .
* 4. Any redistribution , use , or modification is done solely for
* personal benefit and not for any commercial purpose or for
* monetary gain .
*
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
* ` ` AS IS ' ' AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL MATTHIAS
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING ,
* BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS
* OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY ,
* OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE .
*
* Please inquire about commercial licensing options at
* contact @ bluekitchen - gmbh . com
*
*/
# define __BTSTACK_FILE__ "mesh.c"
# include <stdint.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include "ble/mesh/adv_bearer.h"
2019-05-08 17:38:18 +02:00
# include "ble/mesh/gatt_bearer.h"
2019-01-24 18:35:21 +01:00
# include "ble/mesh/beacon.h"
# include "ble/mesh/mesh_crypto.h"
2019-04-10 18:02:21 +02:00
# include "ble/mesh/mesh_lower_transport.h"
2018-10-05 15:13:34 +02:00
# include "ble/mesh/pb_adv.h"
2018-11-20 11:22:40 +01:00
# include "ble/mesh/pb_gatt.h"
# include "ble/gatt-service/mesh_provisioning_service_server.h"
2018-10-05 15:13:34 +02:00
# include "provisioning.h"
# include "provisioning_device.h"
2018-11-28 18:01:53 +01:00
# include "mesh_transport.h"
2019-04-22 18:18:40 +02:00
# include "mesh_foundation.h"
2019-06-10 20:05:39 +02:00
# include "mesh_access.h"
2019-06-07 12:10:09 +02:00
# include "mesh_virtual_addresses.h"
2019-05-08 15:54:18 +02:00
# include "mesh.h"
2018-10-05 15:13:34 +02:00
# include "btstack.h"
# include "btstack_tlv.h"
2019-05-08 18:31:29 +02:00
// #define ENABLE_MESH_ADV_BEARER
// #define ENABLE_MESH_PB_ADV
2019-06-03 14:28:17 +02:00
# define ENABLE_MESH_PROXY_SERVER
2019-05-08 18:31:29 +02:00
# define ENABLE_MESH_PB_GATT
2018-10-05 15:13:34 +02:00
# define BEACON_TYPE_SECURE_NETWORK 1
2019-04-16 17:05:14 +02:00
# define PTS_DEFAULT_TTL 10
2018-10-05 15:13:34 +02:00
2019-05-08 17:38:18 +02:00
static void show_usage ( void ) ;
2018-10-05 15:13:34 +02:00
const static uint8_t device_uuid [ ] = { 0x00 , 0x1B , 0xDC , 0x08 , 0x10 , 0x21 , 0x0B , 0x0E , 0x0A , 0x0C , 0x00 , 0x0B , 0x0E , 0x0A , 0x0C , 0x00 } ;
2019-05-08 16:23:08 +02:00
// Mesh Provisioning
2019-06-03 15:37:51 +02:00
static uint8_t adv_data_unprovisioned [ ] = {
2019-05-08 16:23:08 +02:00
// Flags general discoverable, BR/EDR not supported
0x02 , BLUETOOTH_DATA_TYPE_FLAGS , 0x06 ,
// 16-bit Service UUIDs
0x03 , BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS , ORG_BLUETOOTH_SERVICE_MESH_PROVISIONING & 0xff , ORG_BLUETOOTH_SERVICE_MESH_PROVISIONING > > 8 ,
// Service Data (22)
0x15 , BLUETOOTH_DATA_TYPE_SERVICE_DATA , ORG_BLUETOOTH_SERVICE_MESH_PROVISIONING & 0xff , ORG_BLUETOOTH_SERVICE_MESH_PROVISIONING > > 8 ,
// UUID
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
// OOB information
0x00 , 0x00
} ;
2019-06-03 15:37:51 +02:00
const uint8_t adv_data_unprovisioned_len = sizeof ( adv_data_unprovisioned ) ;
2019-05-08 16:23:08 +02:00
2019-06-04 11:44:15 +02:00
// Mesh Proxy, advertise with node id
2019-06-03 15:37:51 +02:00
static adv_bearer_connectable_advertisement_data_item_t connectable_advertisement_item ;
2019-05-08 16:23:08 +02:00
2018-10-05 15:13:34 +02:00
static btstack_packet_callback_registration_t hci_event_callback_registration ;
static void packet_handler ( uint8_t packet_type , uint16_t channel , uint8_t * packet , uint16_t size ) ;
2019-06-06 18:10:08 +02:00
static void mesh_delete_appkey_lists ( void ) ;
2018-10-05 15:13:34 +02:00
static uint8_t mesh_flags ;
2018-11-16 09:36:34 +01:00
static uint16_t pb_transport_cid = MESH_PB_TRANSPORT_INVALID_CID ;
2018-10-05 15:13:34 +02:00
// pin entry
static int ui_chars_for_pin ;
static uint8_t ui_pin [ 17 ] ;
static int ui_pin_offset ;
static const btstack_tlv_t * btstack_tlv_singleton_impl ;
static void * btstack_tlv_singleton_context ;
2018-11-02 18:04:05 +01:00
static uint8_t beacon_key [ 16 ] ;
2019-05-08 18:31:29 +02:00
static uint8_t identity_key [ 16 ] ;
2018-11-02 18:04:05 +01:00
static uint8_t network_id [ 8 ] ;
2018-11-13 15:05:16 +01:00
static uint16_t primary_element_address ;
2019-05-22 15:32:12 +02:00
static int provisioned ;
2019-06-07 12:10:09 +02:00
static uint8_t model_subscription_label_uuid [ 16 ] ;
2019-06-07 12:33:24 +02:00
static uint16_t model_subscription_hash ;
static uint16_t model_subscription_element_address ;
2018-11-02 18:04:05 +01:00
2019-04-24 11:22:35 +02:00
static void mesh_print_hex ( const char * name , const uint8_t * data , uint16_t len ) {
printf ( " %-20s " , name ) ;
printf_hexdump ( data , len ) ;
}
2018-11-16 17:25:30 +01:00
// static void mesh_print_x(const char * name, uint32_t value){
// printf("%20s: 0x%x", name, (int) value);
// }
2019-06-03 17:06:43 +02:00
# ifdef ENABLE_MESH_PROXY_SERVER
2019-06-04 11:44:15 +02:00
// we only support a single active node id advertisement. when new one is started, an active one is stopped
# define MESH_PROXY_NODE_ID_ADVERTISEMENT_TIMEOUT_MS 60000
static adv_bearer_connectable_advertisement_data_item_t mesh_proxy_node_id_advertisement_item ;
static btstack_timer_source_t mesh_proxy_node_id_timer ;
static btstack_crypto_random_t mesh_proxy_node_id_crypto_request_random ;
static btstack_crypto_aes128_t mesh_proxy_node_id_crypto_request_aes128 ;
static uint8_t mesh_proxy_node_id_plaintext [ 16 ] ;
static uint8_t mesh_proxy_node_id_hash [ 16 ] ;
static uint8_t mesh_proxy_node_id_random_value [ 8 ] ;
static const uint8_t adv_data_with_node_identity_template [ ] = {
// Flags general discoverable, BR/EDR not supported
0x02 , BLUETOOTH_DATA_TYPE_FLAGS , 0x06 ,
// 16-bit Service UUIDs
0x03 , BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_16_BIT_SERVICE_CLASS_UUIDS , ORG_BLUETOOTH_SERVICE_MESH_PROXY & 0xff , ORG_BLUETOOTH_SERVICE_MESH_PROXY > > 8 ,
// Service Data
0x14 , BLUETOOTH_DATA_TYPE_SERVICE_DATA , ORG_BLUETOOTH_SERVICE_MESH_PROXY & 0xff , ORG_BLUETOOTH_SERVICE_MESH_PROXY > > 8 ,
// MESH_IDENTIFICATION_NODE_IDENTIFY_TYPE
MESH_IDENTIFICATION_NODE_IDENTIFY_TYPE ,
// Hash - 8 bytes
// Random - 8 bytes
} ;
static void mesh_proxy_start_advertising_with_network_id ( void ) {
2019-06-03 17:06:43 +02:00
mesh_network_key_iterator_t it ;
mesh_network_key_iterator_init ( & it ) ;
while ( mesh_network_key_iterator_has_more ( & it ) ) {
mesh_network_key_t * network_key = mesh_network_key_iterator_get_next ( & it ) ;
2019-06-04 11:44:15 +02:00
log_info ( " Proxy start advertising with network id, netkey index %04x " , network_key - > netkey_index ) ;
2019-06-03 17:06:43 +02:00
adv_bearer_advertisements_add_item ( & network_key - > advertisement_with_network_id ) ;
}
2019-06-06 15:21:03 +02:00
adv_bearer_advertisements_enable ( 1 ) ;
2019-06-03 17:06:43 +02:00
}
2019-06-04 11:44:15 +02:00
static void mesh_proxy_stop_advertising_with_network_id ( void ) {
2019-06-03 17:06:43 +02:00
mesh_network_key_iterator_t it ;
mesh_network_key_iterator_init ( & it ) ;
while ( mesh_network_key_iterator_has_more ( & it ) ) {
mesh_network_key_t * network_key = mesh_network_key_iterator_get_next ( & it ) ;
2019-06-04 11:44:15 +02:00
log_info ( " Proxy stop advertising with network id, netkey index %04x " , network_key - > netkey_index ) ;
2019-06-03 17:06:43 +02:00
adv_bearer_advertisements_remove_item ( & network_key - > advertisement_with_network_id ) ;
}
}
2019-06-04 11:44:15 +02:00
static void mesh_proxy_stop_all_advertising_with_node_id ( void ) {
mesh_network_key_iterator_t it ;
mesh_network_key_iterator_init ( & it ) ;
while ( mesh_network_key_iterator_has_more ( & it ) ) {
mesh_network_key_t * network_key = mesh_network_key_iterator_get_next ( & it ) ;
if ( network_key - > node_id_advertisement_running ! = 0 ) {
adv_bearer_advertisements_remove_item ( & network_key - > advertisement_with_network_id ) ;
btstack_run_loop_remove_timer ( & mesh_proxy_node_id_timer ) ;
network_key - > node_id_advertisement_running = 0 ;
}
}
}
2019-06-03 15:37:51 +02:00
2019-06-04 11:44:15 +02:00
static void mesh_proxy_node_id_timeout_handler ( btstack_timer_source_t * ts ) {
UNUSED ( ts ) ;
mesh_proxy_stop_all_advertising_with_node_id ( ) ;
}
2019-06-03 15:37:51 +02:00
2019-06-04 11:44:15 +02:00
static void mesh_proxy_node_id_handle_get_aes128 ( void * arg ) {
UNUSED ( arg ) ;
memcpy ( connectable_advertisement_item . adv_data , adv_data_with_node_identity_template , 12 ) ;
memcpy ( & connectable_advertisement_item . adv_data [ 12 ] , & mesh_proxy_node_id_hash [ 8 ] , 8 ) ;
memcpy ( & connectable_advertisement_item . adv_data [ 20 ] , mesh_proxy_node_id_random_value , 8 ) ;
2019-05-08 17:38:18 +02:00
// setup advertisements
2019-06-03 15:37:51 +02:00
adv_bearer_advertisements_add_item ( & connectable_advertisement_item ) ;
2019-05-08 17:38:18 +02:00
adv_bearer_advertisements_enable ( 1 ) ;
2019-06-04 11:44:15 +02:00
// set timer
btstack_run_loop_set_timer_handler ( & mesh_proxy_node_id_timer , mesh_proxy_node_id_timeout_handler ) ;
btstack_run_loop_set_timer ( & mesh_proxy_node_id_timer , MESH_PROXY_NODE_ID_ADVERTISEMENT_TIMEOUT_MS ) ;
btstack_run_loop_add_timer ( & mesh_proxy_node_id_timer ) ;
2019-05-08 17:38:18 +02:00
}
2019-06-04 11:44:15 +02:00
static void mesh_proxy_node_id_handle_random ( void * arg ) {
2019-05-08 17:38:18 +02:00
// Hash = e(IdentityKey, Padding | Random | Address) mod 2^64
2019-06-04 11:44:15 +02:00
memset ( mesh_proxy_node_id_plaintext , 0 , sizeof ( mesh_proxy_node_id_plaintext ) ) ;
memcpy ( & mesh_proxy_node_id_plaintext [ 6 ] , mesh_proxy_node_id_random_value , 8 ) ;
big_endian_store_16 ( mesh_proxy_node_id_plaintext , 14 , primary_element_address ) ;
btstack_crypto_aes128_encrypt ( & mesh_proxy_node_id_crypto_request_aes128 , identity_key , mesh_proxy_node_id_plaintext , mesh_proxy_node_id_hash , mesh_proxy_node_id_handle_get_aes128 , NULL ) ;
2019-05-08 17:38:18 +02:00
}
2019-06-04 11:44:15 +02:00
static void mesh_proxy_start_advertising_with_node_id ( uint16_t netkey_index ) {
mesh_proxy_stop_all_advertising_with_node_id ( ) ;
log_info ( " Proxy start advertising with node id, netkey index %04x " , netkey_index ) ;
// setup node id
btstack_crypto_random_generate ( & mesh_proxy_node_id_crypto_request_random , mesh_proxy_node_id_random_value , sizeof ( mesh_proxy_node_id_random_value ) , mesh_proxy_node_id_handle_random , NULL ) ;
}
static void mesh_proxy_stop_advertising_with_node_id ( uint16_t netkey_index ) {
UNUSED ( netkey_index ) ;
log_info ( " Proxy stop advertising with node id, netkey index %04x " , netkey_index ) ;
mesh_proxy_stop_all_advertising_with_node_id ( ) ;
2019-05-08 17:38:18 +02:00
}
# endif
2018-11-06 17:46:14 +01:00
static void mesh_provisioning_dump ( const mesh_provisioning_data_t * data ) {
2018-11-05 16:58:54 +01:00
printf ( " UnicastAddr: 0x%02x \n " , data - > unicast_address ) ;
2018-10-23 19:20:53 +02:00
printf ( " IV Index: 0x%08x \n " , data - > iv_index ) ;
2019-04-24 11:22:35 +02:00
printf ( " DevKey: " ) ; printf_hexdump ( data - > device_key , 16 ) ;
printf ( " NetKey: " ) ; printf_hexdump ( data - > net_key , 16 ) ;
printf ( " NID: 0x%02x \n " , data - > nid ) ;
2018-10-23 19:20:53 +02:00
printf ( " NetworkID: " ) ; printf_hexdump ( data - > network_id , 8 ) ;
printf ( " BeaconKey: " ) ; printf_hexdump ( data - > beacon_key , 16 ) ;
printf ( " EncryptionKey: " ) ; printf_hexdump ( data - > encryption_key , 16 ) ;
printf ( " PrivacyKey: " ) ; printf_hexdump ( data - > privacy_key , 16 ) ;
2019-04-24 11:22:35 +02:00
printf ( " IdentityKey: " ) ; printf_hexdump ( data - > identity_key , 16 ) ;
2018-10-23 19:20:53 +02:00
}
2019-06-03 16:41:49 +02:00
static void mesh_network_key_add_from_provisioning_data ( const mesh_provisioning_data_t * provisioning_data ) {
2019-06-03 16:28:43 +02:00
// get key
mesh_network_key_t * network_key = btstack_memory_mesh_network_key_get ( ) ;
// get single instance
memset ( network_key , 0 , sizeof ( mesh_network_key_t ) ) ;
// NetKey
memcpy ( network_key - > net_key , provisioning_data - > net_key , 16 ) ;
// IdentityKey
memcpy ( network_key - > identity_key , provisioning_data - > identity_key , 16 ) ;
// BeaconKey
memcpy ( network_key - > beacon_key , provisioning_data - > beacon_key , 16 ) ;
// NID
network_key - > nid = provisioning_data - > nid ;
// EncryptionKey
memcpy ( network_key - > encryption_key , provisioning_data - > encryption_key , 16 ) ;
// PrivacyKey
memcpy ( network_key - > privacy_key , provisioning_data - > privacy_key , 16 ) ;
// NetworkID
memcpy ( network_key - > network_id , provisioning_data - > network_id , 8 ) ;
2019-06-03 16:41:49 +02:00
// setup advertisement with network id
2019-06-03 17:06:43 +02:00
network_key - > advertisement_with_network_id . adv_length = gatt_bearer_setup_advertising_with_network_id ( network_key - > advertisement_with_network_id . adv_data , network_key - > network_id ) ;
2019-06-03 16:41:49 +02:00
// finally add
2019-06-03 16:28:43 +02:00
mesh_network_key_add ( network_key ) ;
}
2018-11-06 17:46:14 +01:00
static void mesh_setup_from_provisioning_data ( const mesh_provisioning_data_t * provisioning_data ) {
2019-05-22 15:32:12 +02:00
provisioned = 1 ;
2018-11-06 17:46:14 +01:00
// add to network key list
2019-06-03 16:41:49 +02:00
mesh_network_key_add_from_provisioning_data ( provisioning_data ) ;
2018-11-06 17:46:14 +01:00
// set unicast address
mesh_network_set_primary_element_address ( provisioning_data - > unicast_address ) ;
2019-04-09 17:51:25 +02:00
mesh_lower_transport_set_primary_element_address ( provisioning_data - > unicast_address ) ;
2018-12-04 17:39:48 +01:00
mesh_upper_transport_set_primary_element_address ( provisioning_data - > unicast_address ) ;
2019-06-06 14:36:08 +02:00
mesh_access_set_primary_element_address ( provisioning_data - > unicast_address ) ;
2018-11-13 15:05:16 +01:00
primary_element_address = provisioning_data - > unicast_address ;
2018-11-06 17:46:14 +01:00
// set iv_index
mesh_set_iv_index ( provisioning_data - > iv_index ) ;
2018-11-07 18:07:09 +01:00
// set device_key
mesh_transport_set_device_key ( provisioning_data - > device_key ) ;
2018-11-06 17:46:14 +01:00
// copy beacon key and network id
2019-05-08 18:31:29 +02:00
memcpy ( identity_key , provisioning_data - > identity_key , 16 ) ;
2018-11-06 17:46:14 +01:00
memcpy ( beacon_key , provisioning_data - > beacon_key , 16 ) ;
memcpy ( network_id , provisioning_data - > network_id , 8 ) ;
// for secure beacon
mesh_flags = provisioning_data - > flags ;
// dump data
mesh_provisioning_dump ( provisioning_data ) ;
2019-06-03 15:37:51 +02:00
2019-05-08 17:38:18 +02:00
// Mesh Proxy
2019-06-03 17:06:43 +02:00
# ifdef ENABLE_MESH_PROXY_SERVER
2019-05-08 17:38:18 +02:00
printf ( " Advertise Mesh Proxy Service with Network ID \n " ) ;
2019-06-03 17:06:43 +02:00
mesh_proxy_start_advertising_with_network_id ( ) ;
2019-05-08 17:38:18 +02:00
# endif
2018-11-06 17:46:14 +01:00
}
2019-05-08 18:31:29 +02:00
# ifdef ENABLE_MESH_PB_GATT
2019-05-22 15:32:12 +02:00
static void setup_advertising_unprovisioned ( void ) {
2019-05-08 16:23:08 +02:00
printf ( " Advertise Mesh Provisioning Service \n " ) ;
2019-05-22 15:32:12 +02:00
// dynamically store device uuid into adv data
2019-06-03 15:37:51 +02:00
memcpy ( & adv_data_unprovisioned [ 11 ] , device_uuid , sizeof ( device_uuid ) ) ;
// store in advertisement item
memset ( & connectable_advertisement_item , 0 , sizeof ( connectable_advertisement_item ) ) ;
connectable_advertisement_item . adv_length = adv_data_unprovisioned_len ;
memcpy ( connectable_advertisement_item . adv_data , ( uint8_t * ) adv_data_unprovisioned , adv_data_unprovisioned_len ) ;
2019-05-08 16:23:08 +02:00
// setup advertisements
2019-06-03 15:37:51 +02:00
adv_bearer_advertisements_add_item ( & connectable_advertisement_item ) ;
2019-05-08 16:23:08 +02:00
adv_bearer_advertisements_enable ( 1 ) ;
2019-05-22 15:32:12 +02:00
}
# endif
static void mesh_setup_without_provisiong_data ( void ) {
provisioned = 0 ;
# ifdef ENABLE_MESH_PB_ADV
// PB-ADV
printf ( " Starting Unprovisioned Device Beacon \n " ) ;
beacon_unprovisioned_device_start ( device_uuid , 0 ) ;
# endif
# ifdef ENABLE_MESH_PB_GATT
// PB_GATT
setup_advertising_unprovisioned ( ) ;
2019-05-08 18:31:29 +02:00
# endif
2019-05-08 15:54:18 +02:00
}
2019-06-06 17:20:45 +02:00
static uint32_t mesh_transport_key_tag_for_appkey_index ( uint16_t appkey_index ) {
return ( ( uint32_t ) ' M ' < < 24 ) | ( ( uint32_t ) ' A ' < < 16 ) | ( ( uint32_t ) appkey_index ) ;
}
2019-05-08 17:38:18 +02:00
2019-06-06 17:20:45 +02:00
typedef struct {
uint16_t netkey_index ;
uint16_t appkey_index ;
uint8_t aid ;
uint8_t key [ 16 ] ;
} mesh_persistent_app_key_t ;
2019-05-08 17:38:18 +02:00
2019-06-06 18:17:34 +02:00
# define MESH_APPKEY_INDEX_MAX (16)
2019-06-06 17:20:45 +02:00
void mesh_store_app_key ( uint16_t netkey_index , uint16_t appkey_index , uint8_t aid , const uint8_t * application_key ) {
2019-06-07 10:40:24 +02:00
if ( appkey_index > = MESH_APPKEY_INDEX_MAX ) {
2019-06-06 18:17:34 +02:00
printf ( " Warning: AppKey with AppKey Index %x (>= %u) are not persisted \n " , appkey_index , MESH_APPKEY_INDEX_MAX ) ;
}
2019-06-06 17:20:45 +02:00
mesh_persistent_app_key_t data ;
printf ( " Store AppKey: AppKey Index 0x%06x, AID %02x: " , appkey_index , aid ) ;
printf_hexdump ( application_key , 16 ) ;
uint32_t tag = mesh_transport_key_tag_for_appkey_index ( appkey_index ) ;
data . netkey_index = netkey_index ;
data . appkey_index = appkey_index ;
data . aid = aid ;
memcpy ( data . key , application_key , 16 ) ;
btstack_tlv_singleton_impl - > store_tag ( btstack_tlv_singleton_context , tag , ( uint8_t * ) & data , sizeof ( data ) ) ;
}
static void mesh_load_app_key ( uint16_t appkey_index ) {
mesh_persistent_app_key_t data ;
uint32_t tag = mesh_transport_key_tag_for_appkey_index ( appkey_index ) ;
int app_key_len = btstack_tlv_singleton_impl - > get_tag ( btstack_tlv_singleton_context , tag , ( uint8_t * ) & data , sizeof ( data ) ) ;
if ( app_key_len = = 0 ) return ;
mesh_transport_key_t * key = btstack_memory_mesh_transport_key_get ( ) ;
if ( key = = NULL ) return ;
2019-04-25 22:39:51 +02:00
2019-06-06 17:20:45 +02:00
key - > appkey_index = data . appkey_index ;
key - > netkey_index = data . netkey_index ;
key - > aid = data . aid ;
key - > akf = 1 ;
memcpy ( key - > key , data . key , 16 ) ;
mesh_transport_key_add ( key ) ;
printf ( " Load AppKey: AppKey Index 0x%06x, AID %02x: " , key - > appkey_index , key - > aid ) ;
printf_hexdump ( key - > key , 16 ) ;
2019-04-25 22:39:51 +02:00
}
2019-06-06 17:46:01 +02:00
static void mesh_delete_app_key ( uint16_t appkey_index ) {
uint32_t tag = mesh_transport_key_tag_for_appkey_index ( appkey_index ) ;
btstack_tlv_singleton_impl - > delete_tag ( btstack_tlv_singleton_context , tag ) ;
}
2019-01-28 21:02:10 +01:00
static void mesh_load_app_keys ( void ) {
2019-06-06 17:20:45 +02:00
printf ( " Load App Keys \n " ) ;
// TODO: use TLV iterator
uint16_t appkey_index ;
2019-06-06 17:46:01 +02:00
for ( appkey_index = 0 ; appkey_index < MESH_APPKEY_INDEX_MAX ; appkey_index + + ) {
2019-06-06 17:20:45 +02:00
mesh_load_app_key ( appkey_index ) ;
2019-01-28 21:02:10 +01:00
}
}
2019-06-06 17:46:01 +02:00
static void mesh_delete_app_keys ( void ) {
printf ( " Delete App Keys \n " ) ;
// TODO: use TLV iterator
uint16_t appkey_index ;
for ( appkey_index = 0 ; appkey_index < MESH_APPKEY_INDEX_MAX ; appkey_index + + ) {
mesh_delete_app_key ( appkey_index ) ;
}
}
2019-01-28 21:02:10 +01:00
2018-11-28 18:01:53 +01:00
// helper network layer, temp
static uint8_t mesh_network_send ( uint16_t netkey_index , uint8_t ctl , uint8_t ttl , uint32_t seq , uint16_t src , uint16_t dest , const uint8_t * transport_pdu_data , uint8_t transport_pdu_len ) {
// "3.4.5.2: The output filter of the interface connected to advertising or GATT bearers shall drop all messages with TTL value set to 1."
// if (ttl <= 1) return 0;
// TODO: check transport_pdu_len depending on ctl
// lookup network by netkey_index
const mesh_network_key_t * network_key = mesh_network_key_list_get ( netkey_index ) ;
if ( ! network_key ) return 0 ;
// allocate network_pdu
2019-04-04 10:24:19 +02:00
mesh_network_pdu_t * network_pdu = mesh_network_pdu_get ( ) ;
2018-11-28 18:01:53 +01:00
if ( ! network_pdu ) return 0 ;
// setup network_pdu
mesh_network_setup_pdu ( network_pdu , netkey_index , network_key - > nid , ctl , ttl , seq , src , dest , transport_pdu_data , transport_pdu_len ) ;
// send network_pdu
2019-04-22 18:32:26 +02:00
mesh_lower_transport_send_pdu ( ( mesh_pdu_t * ) network_pdu ) ;
2018-11-28 18:01:53 +01:00
return 0 ;
}
2018-10-05 15:13:34 +02:00
static void packet_handler ( uint8_t packet_type , uint16_t channel , uint8_t * packet , uint16_t size ) {
UNUSED ( channel ) ;
UNUSED ( size ) ;
bd_addr_t addr ;
int i ;
int prov_len ;
2018-11-02 15:18:56 +01:00
mesh_provisioning_data_t provisioning_data ;
2018-10-05 15:13:34 +02:00
switch ( packet_type ) {
case HCI_EVENT_PACKET :
switch ( hci_event_packet_get_type ( packet ) ) {
case BTSTACK_EVENT_STATE :
if ( btstack_event_state_get_state ( packet ) ! = HCI_STATE_WORKING ) break ;
// dump bd_addr in pts format
gap_local_bd_addr ( addr ) ;
printf ( " Local addr: %s - " , bd_addr_to_str ( addr ) ) ;
for ( i = 0 ; i < 6 ; i + + ) {
printf ( " %02x " , addr [ i ] ) ;
}
printf ( " \n " ) ;
// get tlv
btstack_tlv_get_instance ( & btstack_tlv_singleton_impl , & btstack_tlv_singleton_context ) ;
// load provisioning data
2018-10-23 18:43:10 +02:00
prov_len = btstack_tlv_singleton_impl - > get_tag ( btstack_tlv_singleton_context , ' PROV ' , ( uint8_t * ) & provisioning_data , sizeof ( mesh_provisioning_data_t ) ) ;
2018-10-05 15:13:34 +02:00
printf ( " Provisioning data available: %u \n " , prov_len ? 1 : 0 ) ;
2018-10-23 19:20:53 +02:00
if ( prov_len ) {
2018-11-06 17:46:14 +01:00
mesh_setup_from_provisioning_data ( & provisioning_data ) ;
2019-03-27 21:23:47 +01:00
} else {
2019-05-08 15:54:18 +02:00
mesh_setup_without_provisiong_data ( ) ;
2018-10-23 19:20:53 +02:00
}
2019-01-28 21:02:10 +01:00
// load app keys
mesh_load_app_keys ( ) ;
2019-05-22 15:25:05 +02:00
# if defined(ENABLE_MESH_ADV_BEARER) || defined(ENABLE_MESH_PB_ADV)
2019-06-06 18:17:34 +02:00
// load model to appkey bindings
mesh_load_appkey_lists ( ) ;
2018-10-05 15:13:34 +02:00
// setup scanning
gap_set_scan_parameters ( 0 , 0x300 , 0x300 ) ;
gap_start_scan ( ) ;
2019-05-22 15:25:05 +02:00
# endif
2019-01-11 14:57:03 +01:00
//
show_usage ( ) ;
2018-10-05 15:13:34 +02:00
break ;
2019-05-22 15:32:12 +02:00
case HCI_EVENT_DISCONNECTION_COMPLETE :
// enable PB_GATT
if ( provisioned = = 0 ) {
2019-05-22 16:57:07 +02:00
setup_advertising_unprovisioned ( ) ;
2019-06-03 15:37:51 +02:00
} else {
2019-06-03 17:06:43 +02:00
# ifdef ENABLE_MESH_PROXY_SERVER
2019-06-03 15:37:51 +02:00
printf ( " Advertise Mesh Proxy Service with Network ID \n " ) ;
2019-06-03 17:06:43 +02:00
mesh_proxy_start_advertising_with_network_id ( ) ;
2019-06-03 15:37:51 +02:00
# endif
2019-05-22 15:32:12 +02:00
}
break ;
2019-05-22 15:25:05 +02:00
case HCI_EVENT_LE_META :
if ( hci_event_le_meta_get_subevent_code ( packet ) ! = HCI_SUBEVENT_LE_CONNECTION_COMPLETE ) break ;
// disable PB_GATT
2019-06-03 15:37:51 +02:00
printf ( " Connected, stop advertising gatt service \n " ) ;
adv_bearer_advertisements_remove_item ( & connectable_advertisement_item ) ;
2019-05-22 15:25:05 +02:00
break ;
2018-10-05 15:13:34 +02:00
default :
break ;
}
break ;
}
}
2019-05-23 18:16:18 +02:00
static void mesh_provisioning_message_handler ( uint8_t packet_type , uint16_t channel , uint8_t * packet , uint16_t size ) {
2018-10-05 15:13:34 +02:00
if ( packet_type ! = HCI_EVENT_PACKET ) return ;
2018-11-02 15:18:56 +01:00
mesh_provisioning_data_t provisioning_data ;
2019-04-24 15:55:34 +02:00
mesh_network_key_t * network_key ;
2018-10-05 15:13:34 +02:00
switch ( packet [ 0 ] ) {
case HCI_EVENT_MESH_META :
switch ( packet [ 2 ] ) {
2019-06-03 11:30:28 +02:00
case MESH_SUBEVENT_PB_TRANSPORT_LINK_OPEN :
2018-10-05 15:13:34 +02:00
printf ( " Provisioner link opened " ) ;
2019-06-03 11:30:28 +02:00
pb_transport_cid = mesh_subevent_pb_transport_link_open_get_pb_transport_cid ( packet ) ;
2018-11-16 09:36:34 +01:00
break ;
2019-06-03 11:30:28 +02:00
case MESH_SUBEVENT_PB_TRANSPORT_LINK_CLOSED :
2018-11-16 09:36:34 +01:00
pb_transport_cid = MESH_PB_TRANSPORT_INVALID_CID ;
2018-10-05 15:13:34 +02:00
break ;
2019-06-03 11:30:28 +02:00
case MESH_SUBEVENT_PB_PROV_ATTENTION_TIMER :
2018-10-05 15:13:34 +02:00
printf ( " Attention Timer: %u \n " , packet [ 3 ] ) ;
break ;
2019-06-03 11:30:28 +02:00
case MESH_SUBEVENT_PB_PROV_INPUT_OOB_REQUEST :
2018-10-05 15:13:34 +02:00
printf ( " Enter passphrase: " ) ;
fflush ( stdout ) ;
ui_chars_for_pin = 1 ;
ui_pin_offset = 0 ;
break ;
2019-06-03 11:30:28 +02:00
case MESH_SUBEVENT_PB_PROV_COMPLETE :
2018-10-05 15:13:34 +02:00
printf ( " Provisioning complete \n " ) ;
2019-04-24 15:55:34 +02:00
2018-11-07 18:07:09 +01:00
memcpy ( provisioning_data . device_key , provisioning_device_data_get_device_key ( ) , 16 ) ;
2018-11-06 17:46:14 +01:00
provisioning_data . iv_index = provisioning_device_data_get_iv_index ( ) ;
2018-11-05 16:58:54 +01:00
provisioning_data . flags = provisioning_device_data_get_flags ( ) ;
provisioning_data . unicast_address = provisioning_device_data_get_unicast_address ( ) ;
2019-04-24 15:55:34 +02:00
network_key = provisioning_device_data_get_network_key ( ) ;
memcpy ( provisioning_data . net_key , network_key - > net_key , 16 ) ;
memcpy ( provisioning_data . network_id , network_key - > network_id , 8 ) ;
memcpy ( provisioning_data . identity_key , network_key - > identity_key , 16 ) ;
memcpy ( provisioning_data . beacon_key , network_key - > beacon_key , 16 ) ;
memcpy ( provisioning_data . encryption_key , network_key - > encryption_key , 16 ) ;
memcpy ( provisioning_data . privacy_key , network_key - > privacy_key , 16 ) ;
provisioning_data . nid = network_key - > nid ;
2019-06-06 17:46:01 +02:00
// delete old app keys
mesh_delete_app_keys ( ) ;
2019-06-06 18:10:08 +02:00
// delete old model to appkey bindings
mesh_delete_appkey_lists ( ) ;
2018-10-05 15:13:34 +02:00
// store in TLV
2018-10-23 18:43:10 +02:00
btstack_tlv_singleton_impl - > store_tag ( btstack_tlv_singleton_context , ' PROV ' , ( uint8_t * ) & provisioning_data , sizeof ( mesh_provisioning_data_t ) ) ;
2019-06-03 15:37:51 +02:00
// setup after provisioned
2018-11-06 17:46:14 +01:00
mesh_setup_from_provisioning_data ( & provisioning_data ) ;
2019-06-04 11:44:15 +02:00
// start advertising with node id after provisioning
mesh_proxy_start_advertising_with_node_id ( network_key - > netkey_index ) ;
2018-10-05 15:13:34 +02:00
break ;
default :
break ;
}
break ;
default :
break ;
}
}
static void mesh_unprovisioned_beacon_handler ( uint8_t packet_type , uint16_t channel , uint8_t * packet , uint16_t size ) {
2018-11-21 17:10:36 +01:00
if ( packet_type ! = MESH_BEACON_PACKET ) return ;
uint8_t device_uuid [ 16 ] ;
2018-10-05 15:13:34 +02:00
uint16_t oob ;
2018-11-21 17:10:36 +01:00
memcpy ( device_uuid , & packet [ 1 ] , 16 ) ;
oob = big_endian_read_16 ( packet , 17 ) ;
printf ( " received unprovisioned device beacon, oob data %x, device uuid: " , oob ) ;
printf_hexdump ( device_uuid , 16 ) ;
pb_adv_create_link ( device_uuid ) ;
2018-10-05 15:13:34 +02:00
}
uint8_t pts_device_uuid [ 16 ] ;
const char * pts_device_uuid_string = " 001BDC0810210B0E0A0C000B0E0A0C00 " ;
static int scan_hex_byte ( const char * byte_string ) {
int upper_nibble = nibble_for_char ( * byte_string + + ) ;
if ( upper_nibble < 0 ) return - 1 ;
int lower_nibble = nibble_for_char ( * byte_string ) ;
if ( lower_nibble < 0 ) return - 1 ;
return ( upper_nibble < < 4 ) | lower_nibble ;
}
static int btstack_parse_hex ( const char * string , uint16_t len , uint8_t * buffer ) {
int i ;
for ( i = 0 ; i < len ; i + + ) {
int single_byte = scan_hex_byte ( string ) ;
if ( single_byte < 0 ) return 0 ;
string + = 2 ;
buffer [ i ] = ( uint8_t ) single_byte ;
// don't check seperator after last byte
if ( i = = len - 1 ) {
return 1 ;
}
// optional seperator
char separator = * string ;
if ( separator = = ' : ' & & separator = = ' - ' & & separator = = ' ' ) {
string + + ;
}
}
return 1 ;
}
static void btstack_print_hex ( const uint8_t * data , uint16_t len , char separator ) {
int i ;
for ( i = 0 ; i < len ; i + + ) {
printf ( " %02x " , data [ i ] ) ;
if ( separator ) {
printf ( " %c " , separator ) ;
}
}
printf ( " \n " ) ;
}
2019-01-15 17:22:12 +01:00
static uint16_t pts_proxy_dst ;
static int pts_type ;
2018-10-05 15:13:34 +02:00
static uint8_t prov_static_oob_data [ 16 ] ;
static const char * prov_static_oob_string = " 00000000000000000102030405060708 " ;
static uint8_t prov_public_key_data [ 64 ] ;
static const char * prov_public_key_string = " F465E43FF23D3F1B9DC7DFC04DA8758184DBC966204796ECCF0D6CF5E16500CC0201D048BCBBD899EEEFC424164E33C201C2B010CA6B4D43A8A155CAD8ECB279 " ;
static uint8_t prov_private_key_data [ 32 ] ;
static const char * prov_private_key_string = " 529AA0670D72CD6497502ED473502B037E8803B5C60829A5A3CAA219505530BA " ;
static btstack_crypto_aes128_cmac_t mesh_cmac_request ;
static uint8_t mesh_secure_network_beacon [ 22 ] ;
static uint8_t mesh_secure_network_beacon_auth_value [ 16 ] ;
2019-06-06 17:20:45 +02:00
static mesh_transport_key_t pts_application_key ;
2019-01-29 10:24:44 +01:00
static void load_pts_app_key ( void ) {
// PTS app key
2019-06-06 17:20:45 +02:00
btstack_parse_hex ( " 3216D1509884B533248541792B877F98 " , 16 , pts_application_key . key ) ;
pts_application_key . aid = 0x38 ;
mesh_transport_key_add ( & pts_application_key ) ;
2019-03-27 21:23:47 +01:00
printf ( " PTS Application Key (AID %02x): " , 0x38 ) ;
2019-06-06 17:20:45 +02:00
printf_hexdump ( pts_application_key . key , 16 ) ;
2019-01-29 10:24:44 +01:00
}
2018-11-16 15:21:42 +01:00
static void send_pts_network_messsage ( int type ) {
uint8_t lower_transport_pdu_data [ 16 ] ;
2018-11-02 15:18:56 +01:00
uint16_t src = 0x0028 ;
uint16_t dst = 0x0001 ;
uint32_t seq = 0x00 ;
uint8_t ttl = 0 ;
uint8_t ctl = 0 ;
switch ( type ) {
case 0 :
ttl = 0 ;
dst = 0x001 ;
printf ( " unicast ttl=0 \n " ) ;
break ;
case 1 :
dst = 0x001 ;
2019-04-16 17:05:14 +02:00
ttl = PTS_DEFAULT_TTL ;
2018-11-02 15:18:56 +01:00
printf ( " unicast ttl=10 \n " ) ;
break ;
case 2 :
dst = 0x001 ;
ttl = 0x7f ;
printf ( " unicast ttl=0x7f \n " ) ;
break ;
case 3 :
printf ( " virtual \n " ) ;
break ;
case 4 :
printf ( " group \n " ) ;
break ;
case 5 :
printf ( " all-proxies \n " ) ;
break ;
case 6 :
printf ( " all-friends \n " ) ;
break ;
case 7 :
printf ( " all-relays \n " ) ;
break ;
case 8 :
printf ( " all-nodes \n " ) ;
break ;
default :
return ;
}
2018-11-16 15:21:42 +01:00
int lower_transport_pdu_len = 16 ;
memset ( lower_transport_pdu_data , 0x55 , lower_transport_pdu_len ) ;
mesh_network_send ( 0 , ctl , ttl , seq , src , dst , lower_transport_pdu_data , lower_transport_pdu_len ) ;
}
2019-01-29 10:24:44 +01:00
2019-01-11 14:57:03 +01:00
static void send_pts_unsegmented_access_messsage ( void ) {
2018-11-16 15:21:42 +01:00
uint8_t access_pdu_data [ 16 ] ;
2019-01-29 10:24:44 +01:00
load_pts_app_key ( ) ;
2018-11-16 15:21:42 +01:00
uint16_t src = primary_element_address ;
2018-12-04 14:48:26 +01:00
uint16_t dest = 0x0001 ;
2019-04-16 17:05:14 +02:00
uint8_t ttl = PTS_DEFAULT_TTL ;
2018-11-16 15:21:42 +01:00
int access_pdu_len = 1 ;
memset ( access_pdu_data , 0x55 , access_pdu_len ) ;
2018-12-04 14:48:26 +01:00
uint16_t netkey_index = 0 ;
2019-01-11 14:57:03 +01:00
uint16_t appkey_index = 0 ; // MESH_DEVICE_KEY_INDEX;
2018-12-04 14:48:26 +01:00
// send as unsegmented access pdu
2019-04-22 22:48:59 +02:00
mesh_pdu_t * pdu = ( mesh_pdu_t * ) mesh_network_pdu_get ( ) ;
int status = mesh_upper_transport_setup_access_pdu ( pdu , netkey_index , appkey_index , ttl , src , dest , 0 , access_pdu_data , access_pdu_len ) ;
2018-12-10 14:58:54 +01:00
if ( status ) return ;
2019-04-22 22:48:59 +02:00
mesh_upper_transport_send_access_pdu ( pdu ) ;
2018-11-02 15:18:56 +01:00
}
2019-01-11 14:57:03 +01:00
static void send_pts_segmented_access_messsage_unicast ( void ) {
2018-12-10 14:58:54 +01:00
uint8_t access_pdu_data [ 20 ] ;
2019-01-29 10:24:44 +01:00
load_pts_app_key ( ) ;
2018-12-10 14:58:54 +01:00
uint16_t src = primary_element_address ;
uint16_t dest = 0x0001 ;
2019-04-16 17:05:14 +02:00
uint8_t ttl = PTS_DEFAULT_TTL ;
2018-12-10 14:58:54 +01:00
int access_pdu_len = 20 ;
memset ( access_pdu_data , 0x55 , access_pdu_len ) ;
uint16_t netkey_index = 0 ;
uint16_t appkey_index = 0 ; // MESH_DEVICE_KEY_INDEX;
// send as segmented access pdu
2019-04-22 22:48:59 +02:00
mesh_pdu_t * pdu = ( mesh_pdu_t * ) mesh_transport_pdu_get ( ) ;
int status = mesh_upper_transport_setup_access_pdu ( pdu , netkey_index , appkey_index , ttl , src , dest , 0 , access_pdu_data , access_pdu_len ) ;
2018-12-10 14:58:54 +01:00
if ( status ) return ;
2019-04-22 22:48:59 +02:00
mesh_upper_transport_send_access_pdu ( pdu ) ;
2018-12-10 14:58:54 +01:00
}
2019-01-15 17:22:12 +01:00
static void send_pts_segmented_access_messsage_group ( void ) {
2019-01-11 16:53:20 +01:00
uint8_t access_pdu_data [ 20 ] ;
2019-01-29 10:24:44 +01:00
load_pts_app_key ( ) ;
2019-01-11 16:53:20 +01:00
uint16_t src = primary_element_address ;
uint16_t dest = 0xd000 ;
2019-04-16 17:05:14 +02:00
uint8_t ttl = PTS_DEFAULT_TTL ;
2019-01-11 16:53:20 +01:00
2019-01-15 17:22:12 +01:00
int access_pdu_len = 20 ;
memset ( access_pdu_data , 0x55 , access_pdu_len ) ;
uint16_t netkey_index = 0 ;
2019-01-29 10:24:44 +01:00
uint16_t appkey_index = 0 ;
2019-01-15 17:22:12 +01:00
// send as segmented access pdu
2019-04-22 22:48:59 +02:00
mesh_pdu_t * pdu = ( mesh_pdu_t * ) mesh_transport_pdu_get ( ) ;
int status = mesh_upper_transport_setup_access_pdu ( pdu , netkey_index , appkey_index , ttl , src , dest , 0 , access_pdu_data , access_pdu_len ) ;
2019-01-15 17:22:12 +01:00
if ( status ) return ;
2019-04-22 22:48:59 +02:00
mesh_upper_transport_send_access_pdu ( pdu ) ;
2019-01-15 17:22:12 +01:00
}
static void send_pts_segmented_access_messsage_virtual ( void ) {
uint8_t access_pdu_data [ 20 ] ;
2019-01-29 10:24:44 +01:00
load_pts_app_key ( ) ;
2019-01-15 17:22:12 +01:00
uint16_t src = primary_element_address ;
uint16_t dest = pts_proxy_dst ;
2019-04-16 17:05:14 +02:00
uint8_t ttl = PTS_DEFAULT_TTL ;
2019-01-11 16:53:20 +01:00
int access_pdu_len = 20 ;
memset ( access_pdu_data , 0x55 , access_pdu_len ) ;
uint16_t netkey_index = 0 ;
2019-01-29 10:24:44 +01:00
uint16_t appkey_index = 0 ;
2019-01-11 16:53:20 +01:00
// send as segmented access pdu
2019-04-04 10:24:19 +02:00
mesh_transport_pdu_t * transport_pdu = mesh_transport_pdu_get ( ) ;
2019-04-22 22:48:59 +02:00
int status = mesh_upper_transport_setup_access_pdu ( ( mesh_pdu_t * ) transport_pdu , netkey_index , appkey_index , ttl , src , dest , 0 , access_pdu_data , access_pdu_len ) ;
2019-01-11 16:53:20 +01:00
if ( status ) return ;
2019-04-22 22:32:01 +02:00
mesh_upper_transport_send_access_pdu ( ( mesh_pdu_t * ) transport_pdu ) ;
2019-01-11 16:53:20 +01:00
}
2018-12-10 14:58:54 +01:00
2018-10-05 15:13:34 +02:00
static void mesh_secure_network_beacon_auth_value_calculated ( void * arg ) {
UNUSED ( arg ) ;
memcpy ( & mesh_secure_network_beacon [ 14 ] , mesh_secure_network_beacon_auth_value , 8 ) ;
printf ( " Secure Network Beacon \n " ) ;
printf ( " - " ) ;
printf_hexdump ( mesh_secure_network_beacon , sizeof ( mesh_secure_network_beacon ) ) ;
adv_bearer_send_mesh_beacon ( mesh_secure_network_beacon , sizeof ( mesh_secure_network_beacon ) ) ;
}
2019-01-11 14:57:03 +01:00
static void show_usage ( void ) {
bd_addr_t iut_address ;
gap_local_bd_addr ( iut_address ) ;
printf ( " \n --- Bluetooth Mesh Console at %s --- \n " , bd_addr_to_str ( iut_address ) ) ;
printf ( " 1 - Send Unsegmented Access Message \n " ) ;
printf ( " 2 - Send Segmented Access Message - Unicast \n " ) ;
2019-01-15 17:22:12 +01:00
printf ( " 3 - Send Segmented Access Message - Group D000 \n " ) ;
printf ( " 4 - Send Segmented Access Message - Virtual 9779 \n " ) ;
2019-03-29 19:12:01 +01:00
printf ( " 6 - Clear Replay Protection List \n " ) ;
2019-03-27 21:23:47 +01:00
printf ( " 7 - Load PTS App key \n " ) ;
2019-05-22 16:57:07 +02:00
printf ( " 8 - Delete provisioning data \n " ) ;
2019-01-11 14:57:03 +01:00
printf ( " \n " ) ;
}
2018-10-05 15:13:34 +02:00
static void stdin_process ( char cmd ) {
if ( ui_chars_for_pin ) {
printf ( " %c " , cmd ) ;
fflush ( stdout ) ;
if ( cmd = = ' \n ' ) {
printf ( " \n Sending Pin '%s' \n " , ui_pin ) ;
provisioning_device_input_oob_complete_alphanumeric ( 1 , ui_pin , ui_pin_offset ) ;
ui_chars_for_pin = 0 ;
} else {
ui_pin [ ui_pin_offset + + ] = cmd ;
}
return ;
}
switch ( cmd ) {
2018-11-02 15:18:56 +01:00
case ' 0 ' :
2018-11-16 15:21:42 +01:00
send_pts_network_messsage ( pts_type + + ) ;
2018-11-02 15:18:56 +01:00
break ;
2018-10-05 15:13:34 +02:00
case ' 1 ' :
2019-01-11 14:57:03 +01:00
send_pts_unsegmented_access_messsage ( ) ;
2018-11-16 15:21:42 +01:00
break ;
2018-10-05 15:13:34 +02:00
case ' 2 ' :
2019-01-11 14:57:03 +01:00
send_pts_segmented_access_messsage_unicast ( ) ;
2018-12-10 14:58:54 +01:00
break ;
2019-01-11 16:53:20 +01:00
case ' 3 ' :
2019-01-15 17:22:12 +01:00
send_pts_segmented_access_messsage_group ( ) ;
break ;
case ' 4 ' :
send_pts_segmented_access_messsage_virtual ( ) ;
2019-01-11 16:53:20 +01:00
break ;
2019-03-29 19:12:01 +01:00
case ' 6 ' :
printf ( " Clearing Replay Protection List \n " ) ;
mesh_seq_auth_reset ( ) ;
break ;
2019-03-27 21:23:47 +01:00
case ' 7 ' :
load_pts_app_key ( ) ;
break ;
2018-12-10 14:58:54 +01:00
case ' 8 ' :
2019-05-22 16:57:07 +02:00
btstack_tlv_singleton_impl - > delete_tag ( btstack_tlv_singleton_context , ' PROV ' ) ;
2019-06-07 11:19:14 +02:00
mesh_delete_app_keys ( ) ;
mesh_delete_appkey_lists ( ) ;
printf ( " Provisioning data, app keys, model to app key lists deleted \n " ) ;
2019-05-22 17:18:41 +02:00
setup_advertising_unprovisioned ( ) ;
2018-10-05 15:13:34 +02:00
break ;
case ' p ' :
printf ( " + Public Key OOB Enabled \n " ) ;
btstack_parse_hex ( prov_public_key_string , 64 , prov_public_key_data ) ;
btstack_parse_hex ( prov_private_key_string , 32 , prov_private_key_data ) ;
provisioning_device_set_public_key_oob ( prov_public_key_data , prov_private_key_data ) ;
break ;
case ' o ' :
printf ( " + Output OOB Enabled \n " ) ;
provisioning_device_set_output_oob_actions ( 0x08 , 0x08 ) ;
break ;
case ' i ' :
printf ( " + Input OOB Enabled \n " ) ;
provisioning_device_set_input_oob_actions ( 0x08 , 0x08 ) ;
break ;
case ' s ' :
printf ( " + Static OOB Enabled \n " ) ;
btstack_parse_hex ( prov_static_oob_string , 16 , prov_static_oob_data ) ;
provisioning_device_set_static_oob ( 16 , prov_static_oob_data ) ;
break ;
case ' b ' :
printf ( " + Setup Secure Network Beacon \n " ) ;
mesh_secure_network_beacon [ 0 ] = BEACON_TYPE_SECURE_NETWORK ;
mesh_secure_network_beacon [ 1 ] = mesh_flags ;
2018-11-02 18:04:05 +01:00
memcpy ( & mesh_secure_network_beacon [ 2 ] , network_id , 8 ) ;
big_endian_store_32 ( mesh_secure_network_beacon , 10 , mesh_get_iv_index ( ) ) ;
btstack_crypto_aes128_cmac_message ( & mesh_cmac_request , beacon_key , 13 ,
2018-10-05 15:13:34 +02:00
& mesh_secure_network_beacon [ 1 ] , mesh_secure_network_beacon_auth_value , & mesh_secure_network_beacon_auth_value_calculated , NULL ) ;
break ;
2019-01-11 14:57:03 +01:00
case ' ' :
show_usage ( ) ;
break ;
2018-10-05 15:13:34 +02:00
default :
2019-01-11 14:57:03 +01:00
printf ( " Command: '%c' not implemented \n " , cmd ) ;
show_usage ( ) ;
2018-10-05 15:13:34 +02:00
break ;
}
}
2019-04-18 14:05:33 +02:00
// Foundation Model Operations
# define MESH_FOUNDATION_OPERATION_APPKEY_ADD 0x00
2019-04-22 18:08:11 +02:00
# define MESH_FOUNDATION_OPERATION_APPKEY_UPDATE 0x01
2019-04-18 14:05:33 +02:00
# define MESH_FOUNDATION_OPERATION_COMPOSITION_DATA_STATUS 0x02
2019-04-18 18:41:16 +02:00
# define MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_SET 0x03
# define MESH_FOUNDATION_OPERATION_HEALTH_CURRENT_STATUS 0x04
# define MESH_FOUNDATION_OPERATION_HEALTH_FAULT_STATUS 0x05
2019-04-18 14:05:33 +02:00
# define MESH_FOUNDATION_OPERATION_HEARTBEAT_PUBLICATION_STATUS 0x06
2019-04-22 18:08:11 +02:00
# define MESH_FOUNDATION_OPERATION_APPKEY_DELETE 0x8000
2019-04-18 18:41:16 +02:00
# define MESH_FOUNDATION_OPERATION_APPKEY_GET 0x8001
# define MESH_FOUNDATION_OPERATION_APPKEY_LIST 0x8002
2019-04-18 14:05:33 +02:00
# define MESH_FOUNDATION_OPERATION_APPKEY_STATUS 0x8003
2019-04-18 18:41:16 +02:00
# define MESH_FOUNDATION_OPERATION_ATTENTION_GET 0x8004
# define MESH_FOUNDATION_OPERATION_ATTENTION_SET 0x8005
# define MESH_FOUNDATION_OPERATION_ATTENTION_SET_UNACKNOWLEDGED 0x8006
# define MESH_FOUNDATION_OPERATION_ATTENTION_STATUS 0x8007
2019-04-18 14:05:33 +02:00
# define MESH_FOUNDATION_OPERATION_COMPOSITION_DATA_GET 0x8008
# define MESH_FOUNDATION_OPERATION_BEACON_GET 0x8009
# define MESH_FOUNDATION_OPERATION_BEACON_SET 0x800a
# define MESH_FOUNDATION_OPERATION_BEACON_STATUS 0x800b
# define MESH_FOUNDATION_OPERATION_DEFAULT_TTL_GET 0x800c
# define MESH_FOUNDATION_OPERATION_DEFAULT_TTL_SET 0x800d
# define MESH_FOUNDATION_OPERATION_DEFAULT_TTL_STATUS 0x800e
2019-04-18 18:41:16 +02:00
# define MESH_FOUNDATION_OPERATION_FRIEND_GET 0x800f
# define MESH_FOUNDATION_OPERATION_FRIEND_SET 0x8010
# define MESH_FOUNDATION_OPERATION_FRIEND_STATUS 0x8011
2019-04-18 14:05:33 +02:00
# define MESH_FOUNDATION_OPERATION_GATT_PROXY_GET 0x8012
# define MESH_FOUNDATION_OPERATION_GATT_PROXY_SET 0x8013
# define MESH_FOUNDATION_OPERATION_GATT_PROXY_STATUS 0x8014
2019-04-23 19:18:33 +02:00
# define MESH_FOUNDATION_OPERATION_KEY_REFRESH_PHASE_GET 0x8015
# define MESH_FOUNDATION_OPERATION_KEY_REFRESH_PHASE_SET 0x8016
2019-04-22 18:08:11 +02:00
# define MESH_FOUNDATION_OPERATION_KEY_REFRESH_PHASE_STATUS 0x8017
2019-04-18 14:05:33 +02:00
# define MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_GET 0x8018
# define MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_STATUS 0x8019
# define MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_VIRTUAL_ADDRESS_SET 0x801a
# define MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_ADD 0x801b
2019-04-22 18:08:11 +02:00
# define MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_DELETE 0x801c
# define MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_DELETE_ALL 0x801d
2019-04-18 14:05:33 +02:00
# define MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_OVERWRITE 0x801e
# define MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_STATUS 0x801f
# define MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_ADD 0x8020
2019-04-22 18:08:11 +02:00
# define MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_DELETE 0x8021
2019-04-18 14:05:33 +02:00
# define MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_OVERWRITE 0x8022
# define MESH_FOUNDATION_OPERATION_NETWORK_TRANSMIT_GET 0x8023
# define MESH_FOUNDATION_OPERATION_NETWORK_TRANSMIT_SET 0x8024
# define MESH_FOUNDATION_OPERATION_NETWORK_TRANSMIT_STATUS 0x8025
# define MESH_FOUNDATION_OPERATION_RELAY_GET 0x8026
# define MESH_FOUNDATION_OPERATION_RELAY_SET 0x8027
# define MESH_FOUNDATION_OPERATION_RELAY_STATUS 0x8028
2019-04-18 18:41:16 +02:00
# define MESH_FOUNDATION_OPERATION_SIG_MODEL_SUBSCRIPTION_GET 0x8029
# define MESH_FOUNDATION_OPERATION_SIG_MODEL_SUBSCRIPTION_LIST 0x802a
# define MESH_FOUNDATION_OPERATION_VENDOR_MODEL_SUBSCRIPTION_GET 0x802b
# define MESH_FOUNDATION_OPERATION_VENDOR_MODEL_SUBSCRIPTION_LIST 0x802c
# define MESH_FOUNDATION_OPERATION_LOW_POWER_NODE_POLL_TIMEOUT_GET 0x802d
# define MESH_FOUNDATION_OPERATION_LOW_POWER_NODE_POLL_TIMEOUT_STATUS 0x802e
# define MESH_FOUNDATION_OPERATION_HEALTH_FAULT_CLEAR 0x802f
# define MESH_FOUNDATION_OPERATION_HEALTH_FAULT_CLEAR_UNACKNOWLEDGED 0x8030
# define MESH_FOUNDATION_OPERATION_HEALTH_FAULT_GET 0x8031
# define MESH_FOUNDATION_OPERATION_HEALTH_FAULT_TEST 0x8032
# define MESH_FOUNDATION_OPERATION_HEALTH_FAULT_TEST_UNACKNOWLEDGED 0x8033
# define MESH_FOUNDATION_OPERATION_HEALTH_PERIOD_GET 0x8034
# define MESH_FOUNDATION_OPERATION_HEALTH_PERIOD_SET 0x8035
# define MESH_FOUNDATION_OPERATION_HEALTH_PERIOD_SET_UNACKNOWLEDGED 0x8036
# define MESH_FOUNDATION_OPERATION_HEALTH_PERIOD_STATUS 0x8037
2019-04-18 14:05:33 +02:00
# define MESH_FOUNDATION_OPERATION_HEARTBEAT_PUBLICATION_GET 0x8038
# define MESH_FOUNDATION_OPERATION_HEARTBEAT_PUBLICATION_SET 0x8039
# define MESH_FOUNDATION_OPERATION_HEARTBEAT_SUBSCRIPTION_GET 0x803a
# define MESH_FOUNDATION_OPERATION_HEARTBEAT_SUBSCRIPTION_SET 0x803b
# define MESH_FOUNDATION_OPERATION_HEARTBEAT_SUBSCRIPTION_STATUS 0x803c
# define MESH_FOUNDATION_OPERATION_MODEL_APP_BIND 0x803d
# define MESH_FOUNDATION_OPERATION_MODEL_APP_STATUS 0x803e
# define MESH_FOUNDATION_OPERATION_MODEL_APP_UNBIND 0x803f
2019-04-18 18:41:16 +02:00
# define MESH_FOUNDATION_OPERATION_NETKEY_ADD 0x8040
2019-04-22 18:08:11 +02:00
# define MESH_FOUNDATION_OPERATION_NETKEY_DELETE 0x8041
2019-04-18 18:41:16 +02:00
# define MESH_FOUNDATION_OPERATION_NETKEY_GET 0x8042
# define MESH_FOUNDATION_OPERATION_NETKEY_LIST 0x8043
# define MESH_FOUNDATION_OPERATION_NETKEY_STATUS 0x8044
# define MESH_FOUNDATION_OPERATION_NETKEY_UPDATE 0x8045
# define MESH_FOUNDATION_OPERATION_NODE_IDENTITY_GET 0x8046
# define MESH_FOUNDATION_OPERATION_NODE_IDENTITY_SET 0x8047
# define MESH_FOUNDATION_OPERATION_NODE_IDENTITY_STATUS 0x8048
2019-04-18 14:05:33 +02:00
# define MESH_FOUNDATION_OPERATION_NODE_RESET 0x8049
# define MESH_FOUNDATION_OPERATION_NODE_RESET_STATUS 0x804a
2019-04-18 18:41:16 +02:00
# define MESH_FOUNDATION_OPERATION_SIG_MODEL_APP_GET 0x804b
# define MESH_FOUNDATION_OPERATION_SIG_MODEL_APP_LIST 0x804c
# define MESH_FOUNDATION_OPERATION_VENDOR_MODEL_APP_GET 0x804d
# define MESH_FOUNDATION_OPERATION_VENDOR_MODEL_APP_LIST 0x804e
// Foundation Models Status Codes
2019-04-23 19:18:33 +02:00
# define MESH_FOUNDATION_STATUS_SUCCESS 0x00
# define MESH_FOUNDATION_STATUS_INVALID_ADDRESS 0x01
# define MESH_FOUNDATION_STATUS_INVALID_MODEL 0x02
# define MESH_FOUNDATION_STATUS_INVALID_APPKEY_INDEX 0x03
# define MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX 0x04
# define MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES 0x05
# define MESH_FOUNDATION_STATUS_KEY_INDEX_ALREADY_STORED 0x06
# define MESH_FOUNDATION_STATUS_INVALID_PUBLISH_PARAMETER 0x07
# define MESH_FOUNDATION_STATUS_NOT_A_SUBSCRIPTION_MODEL 0x08
# define MESH_FOUNDATION_STATUS_STORAGE_FAILURE 0x09
# define MESH_FOUNDATION_STATUS_FEATURE_NOT_SUPPORTED 0x0a
# define MESH_FOUNDATION_STATUS_CANNOT_UPDATE 0x0b
# define MESH_FOUNDATION_STATUS_CANNOT_REMOVE 0x0c
# define MESH_FOUNDATION_STATUS_CANNOT_BIND 0x0d
# define MESH_FOUNDATION_STATUS_TEMPORARILY_UNABLE_TO_CHANGE_STATE 0x0e
# define MESH_FOUNDATION_STATUS_CANNOT_SET 0x0f
# define MESH_FOUNDATION_STATUS_UNSPECIFIED_ERROR 0x10
# define MESH_FOUNDATION_STATUS_INVALID_BINDING 0x11
2019-04-18 18:41:16 +02:00
// Foundatiopn Message
const mesh_access_message_t mesh_foundation_config_beacon_status = {
MESH_FOUNDATION_OPERATION_BEACON_STATUS , " 1 "
} ;
const mesh_access_message_t mesh_foundation_config_default_ttl_status = {
MESH_FOUNDATION_OPERATION_DEFAULT_TTL_STATUS , " 1 "
} ;
2019-04-22 14:44:46 +02:00
const mesh_access_message_t mesh_foundation_config_friend_status = {
MESH_FOUNDATION_OPERATION_FRIEND_STATUS , " 1 "
} ;
2019-04-18 18:41:16 +02:00
const mesh_access_message_t mesh_foundation_config_gatt_proxy_status = {
MESH_FOUNDATION_OPERATION_GATT_PROXY_STATUS , " 1 "
} ;
const mesh_access_message_t mesh_foundation_config_relay_status = {
MESH_FOUNDATION_OPERATION_RELAY_STATUS , " 11 "
} ;
2019-06-04 12:16:23 +02:00
const mesh_access_message_t mesh_foundation_config_model_publication_status = {
MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_STATUS , " 1222111m "
2019-04-18 18:41:16 +02:00
} ;
2019-06-04 12:16:23 +02:00
const mesh_access_message_t mesh_foundation_config_model_subscription_status = {
MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_STATUS , " 122m "
2019-06-04 10:59:13 +02:00
} ;
2019-04-23 19:18:33 +02:00
const mesh_access_message_t mesh_foundation_config_netkey_status = {
MESH_FOUNDATION_OPERATION_NETKEY_STATUS , " 12 "
} ;
2019-04-18 18:41:16 +02:00
const mesh_access_message_t mesh_foundation_config_appkey_status = {
MESH_FOUNDATION_OPERATION_APPKEY_STATUS , " 13 "
} ;
2019-06-04 12:16:23 +02:00
const mesh_access_message_t mesh_foundation_config_model_app_status = {
MESH_FOUNDATION_OPERATION_MODEL_APP_STATUS , " 122m "
2019-04-28 21:59:26 +02:00
} ;
2019-04-18 18:41:16 +02:00
const mesh_access_message_t mesh_foundation_node_reset_status = {
MESH_FOUNDATION_OPERATION_NODE_RESET_STATUS , " "
} ;
const mesh_access_message_t mesh_foundation_config_heartbeat_publication_status = {
MESH_FOUNDATION_OPERATION_HEARTBEAT_PUBLICATION_STATUS , " 1211122 "
} ;
const mesh_access_message_t mesh_foundation_config_network_transmit_status = {
MESH_FOUNDATION_OPERATION_NETWORK_TRANSMIT_STATUS , " 11 "
} ;
2019-06-03 11:22:34 +02:00
const mesh_access_message_t mesh_foundation_node_identity_status = {
MESH_FOUNDATION_OPERATION_NODE_IDENTITY_STATUS , " 121 "
} ;
2019-06-03 16:36:31 +02:00
const mesh_access_message_t mesh_key_refresh_phase_status = {
MESH_FOUNDATION_OPERATION_KEY_REFRESH_PHASE_STATUS , " 121 "
} ;
2019-06-03 17:30:01 +02:00
const mesh_access_message_t mesh_foundation_low_power_node_poll_timeout_status = {
MESH_FOUNDATION_OPERATION_LOW_POWER_NODE_POLL_TIMEOUT_STATUS , " 23 "
} ;
2019-06-07 15:54:55 +02:00
const mesh_access_message_t mesh_foundation_config_heartbeat_subscription_status = {
MESH_FOUNDATION_OPERATION_HEARTBEAT_SUBSCRIPTION_STATUS , " 1221111 "
} ;
2019-06-03 16:36:31 +02:00
2019-04-12 21:59:57 +02:00
// to sort
2019-04-28 09:33:29 +02:00
// move to btstack_config.h
2019-06-04 11:50:07 +02:00
# define MESH_APPKEY_INVALID 0xffffu
# define MESH_SIG_MODEL_ID_CONFIGURATION_SERVER 0x0000u
# define MESH_SIG_MODEL_ID_CONFIGURATION_CLIENT 0x0001u
# define MESH_SIG_MODEL_ID_HEALTH_SERVER 0x0002u
# define MESH_SIG_MODEL_ID_HEALTH_CLIENT 0x0003u
2019-05-28 19:01:26 +02:00
# define MESH_SIG_MODEL_ID_GENERIC_ON_OFF_SERVER 0x1000u
# define MESH_SIG_MODEL_ID_GENERIC_ON_OFF_CLIENT 0x1001u
2019-06-04 11:50:07 +02:00
# define MESH_BLUEKITCHEN_MODEL_ID_TEST_SERVER 0x0000u
2019-04-28 10:05:04 +02:00
2019-06-03 11:22:34 +02:00
typedef enum {
2019-06-03 16:36:31 +02:00
MESH_NODE_IDENTITY_STATE_ADVERTISING_STOPPED = 0 ,
MESH_NODE_IDENTITY_STATE_ADVERTISING_RUNNING ,
MESH_NODE_IDENTITY_STATE_ADVERTISING_NOT_SUPPORTED
} mesh_node_identity_state_t ;
2019-04-23 19:18:33 +02:00
static btstack_crypto_aes128_cmac_t configuration_server_cmac_request ;
2019-04-22 23:32:39 +02:00
static mesh_pdu_t * access_pdu_in_process ;
2019-04-12 21:59:57 +02:00
typedef struct {
btstack_timer_source_t timer ;
uint16_t destination ;
2019-06-07 15:54:55 +02:00
uint16_t count_log ;
2019-04-12 21:59:57 +02:00
uint8_t period_log ;
uint8_t ttl ;
uint16_t features ;
uint16_t netkey_index ;
} mesh_heartbeat_publication_t ;
2019-06-07 15:54:55 +02:00
typedef struct {
btstack_timer_source_t timer ;
uint16_t source ;
uint16_t destination ;
uint8_t period_log ;
uint8_t count_log ;
uint8_t min_hops ;
uint8_t max_hops ;
} mesh_heartbeat_subscription_t ;
2019-04-12 21:59:57 +02:00
typedef struct {
mesh_heartbeat_publication_t heartbeat_publication ;
2019-04-22 23:00:20 +02:00
} mesh_configuration_server_model_context ;
2019-04-12 21:59:57 +02:00
2019-06-07 15:54:55 +02:00
static mesh_heartbeat_publication_t mesh_heartbeat_publication ;
static mesh_heartbeat_subscription_t mesh_heartbeat_subscription ;
2019-04-12 21:59:57 +02:00
2019-06-06 18:10:08 +02:00
// model to appkey list/binding
2019-06-06 18:17:34 +02:00
# define MESH_MODEL_INDEX_MAX (16)
2019-06-06 18:10:08 +02:00
static uint32_t mesh_model_tag_for_index ( uint16_t internal_model_id ) {
return ( ( uint32_t ) ' M ' < < 24 ) | ( ( uint32_t ) ' B ' < < 16 ) | ( ( uint32_t ) internal_model_id ) ;
}
static void mesh_load_appkey_list ( mesh_model_t * model ) {
uint32_t tag = mesh_model_tag_for_index ( model - > mid ) ;
btstack_tlv_singleton_impl - > store_tag ( btstack_tlv_singleton_context , tag , ( uint8_t * ) & model - > appkey_indices , sizeof ( model - > appkey_indices ) ) ;
}
static void mesh_store_appkey_list ( mesh_model_t * model ) {
2019-06-06 18:17:34 +02:00
if ( model - > mid > = MESH_MODEL_INDEX_MAX ) {
printf ( " Warning: Model with internal model id %x (>= %u) are not persisted \n " , model - > mid , MESH_MODEL_INDEX_MAX ) ;
}
2019-06-06 18:10:08 +02:00
uint32_t tag = mesh_model_tag_for_index ( model - > mid ) ;
btstack_tlv_singleton_impl - > get_tag ( btstack_tlv_singleton_context , tag , ( uint8_t * ) & model - > appkey_indices , sizeof ( model - > appkey_indices ) ) ;
}
static void mesh_load_appkey_lists ( void ) {
printf ( " Load Appkey Lists \n " ) ;
// iterate over elements and models
2019-06-10 20:05:39 +02:00
mesh_element_iterator_t element_it ;
mesh_element_iterator_init ( & element_it ) ;
while ( mesh_element_iterator_has_next ( & element_it ) ) {
mesh_element_t * element = mesh_element_iterator_next ( & element_it ) ;
2019-06-06 18:10:08 +02:00
mesh_model_iterator_t model_it ;
mesh_model_iterator_init ( & model_it , element ) ;
while ( mesh_model_iterator_has_next ( & model_it ) ) {
2019-06-10 20:05:39 +02:00
mesh_model_t * model = mesh_model_iterator_next ( & model_it ) ;
2019-06-06 18:10:08 +02:00
mesh_load_appkey_list ( model ) ;
}
}
}
static void mesh_delete_appkey_lists ( void ) {
printf ( " Delete App Keys \n " ) ;
// iterate over elements and models
uint16_t internal_model_id ;
for ( internal_model_id = 0 ; internal_model_id < MESH_MODEL_INDEX_MAX ; internal_model_id + + ) {
uint32_t tag = mesh_model_tag_for_index ( internal_model_id ) ;
btstack_tlv_singleton_impl - > delete_tag ( btstack_tlv_singleton_context , tag ) ;
}
}
2019-04-28 09:33:29 +02:00
static void mesh_model_reset_appkeys ( mesh_model_t * mesh_model ) {
int i ;
for ( i = 0 ; i < MAX_NR_MESH_APPKEYS_PER_MODEL ; i + + ) {
mesh_model - > appkey_indices [ i ] = MESH_APPKEY_INVALID ;
}
}
2019-04-28 21:59:26 +02:00
static uint8_t mesh_model_bind_appkey ( mesh_model_t * mesh_model , uint16_t appkey_index ) {
int i ;
for ( i = 0 ; i < MAX_NR_MESH_APPKEYS_PER_MODEL ; i + + ) {
if ( mesh_model - > appkey_indices [ i ] = = appkey_index ) return MESH_FOUNDATION_STATUS_SUCCESS ;
}
for ( i = 0 ; i < MAX_NR_MESH_APPKEYS_PER_MODEL ; i + + ) {
if ( mesh_model - > appkey_indices [ i ] = = MESH_APPKEY_INVALID ) {
mesh_model - > appkey_indices [ i ] = appkey_index ;
2019-06-06 18:10:08 +02:00
mesh_store_appkey_list ( mesh_model ) ;
2019-04-28 21:59:26 +02:00
return MESH_FOUNDATION_STATUS_SUCCESS ;
}
}
return MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES ;
}
static void mesh_model_unbind_appkey ( mesh_model_t * mesh_model , uint16_t appkey_index ) {
int i ;
for ( i = 0 ; i < MAX_NR_MESH_APPKEYS_PER_MODEL ; i + + ) {
if ( mesh_model - > appkey_indices [ i ] = = appkey_index ) {
mesh_model - > appkey_indices [ i ] = MESH_APPKEY_INVALID ;
2019-06-06 18:10:08 +02:00
mesh_store_appkey_list ( mesh_model ) ;
2019-04-28 21:59:26 +02:00
}
}
}
2019-06-07 14:54:42 +02:00
static void mesh_model_delete_all_subscriptions ( mesh_model_t * mesh_model ) {
2019-06-04 10:59:13 +02:00
int i ;
for ( i = 0 ; i < MAX_NR_MESH_SUBSCRIPTION_PER_MODEL ; i + + ) {
mesh_model - > subscriptions [ i ] = MESH_ADDRESS_UNSASSIGNED ;
}
}
static uint8_t mesh_model_add_subscription ( mesh_model_t * mesh_model , uint16_t address ) {
int i ;
for ( i = 0 ; i < MAX_NR_MESH_SUBSCRIPTION_PER_MODEL ; i + + ) {
if ( mesh_model - > subscriptions [ i ] = = address ) return MESH_FOUNDATION_STATUS_SUCCESS ;
}
for ( i = 0 ; i < MAX_NR_MESH_SUBSCRIPTION_PER_MODEL ; i + + ) {
if ( mesh_model - > subscriptions [ i ] = = MESH_ADDRESS_UNSASSIGNED ) {
mesh_model - > subscriptions [ i ] = address ;
return MESH_FOUNDATION_STATUS_SUCCESS ;
}
}
return MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES ;
}
static void mesh_model_delete_subscription ( mesh_model_t * mesh_model , uint16_t address ) {
int i ;
for ( i = 0 ; i < MAX_NR_MESH_SUBSCRIPTION_PER_MODEL ; i + + ) {
if ( mesh_model - > subscriptions [ i ] = = address ) {
mesh_model - > subscriptions [ i ] = MESH_ADDRESS_UNSASSIGNED ;
}
}
}
2019-06-07 14:54:42 +02:00
static uint8_t mesh_model_overwrite_subscription ( mesh_model_t * mesh_model , uint16_t address ) {
mesh_model_delete_all_subscriptions ( mesh_model ) ;
return mesh_model_add_subscription ( mesh_model , address ) ;
2019-06-06 14:53:19 +02:00
}
2019-06-10 18:29:12 +02:00
static int mesh_model_contains_subscription ( mesh_model_t * mesh_model , uint16_t address ) {
int i ;
for ( i = 0 ; i < MAX_NR_MESH_SUBSCRIPTION_PER_MODEL ; i + + ) {
if ( mesh_model - > subscriptions [ i ] = = address ) return 1 ;
}
return 0 ;
}
2019-06-04 12:16:23 +02:00
static int mesh_model_is_configuration_server ( uint32_t model_identifier ) {
return mesh_model_is_bluetooth_sig ( model_identifier ) & & ( mesh_model_get_model_id ( model_identifier ) = = MESH_SIG_MODEL_ID_CONFIGURATION_SERVER ) ;
}
2019-04-22 23:21:44 +02:00
static void mesh_access_message_processed ( mesh_pdu_t * pdu ) {
mesh_upper_transport_message_processed_by_higher_layer ( pdu ) ;
}
2019-04-22 23:00:20 +02:00
static void config_server_send_message ( mesh_model_t * mesh_model , uint16_t netkey_index , uint16_t dest ,
mesh_pdu_t * pdu ) {
2019-04-19 23:55:15 +02:00
UNUSED ( mesh_model ) ;
// TODO: use addr from element this model belongs to
uint16_t src = primary_element_address ;
uint16_t appkey_index = MESH_DEVICE_KEY_INDEX ;
uint8_t ttl = mesh_foundation_default_ttl_get ( ) ;
2019-04-22 23:00:20 +02:00
mesh_upper_transport_setup_access_pdu_header ( pdu , netkey_index , appkey_index , ttl , src , dest , 0 ) ;
mesh_upper_transport_send_access_pdu ( pdu ) ;
2019-04-19 23:55:15 +02:00
}
2019-04-22 23:21:44 +02:00
2019-04-19 23:55:15 +02:00
static void config_composition_data_status ( mesh_model_t * mesh_model , uint16_t netkey_index , uint16_t dest ) {
2019-01-24 17:05:13 +01:00
2019-01-24 17:39:26 +01:00
printf ( " Received Config Composition Data Get -> send Config Composition Data Status \n " ) ;
2019-01-24 17:05:13 +01:00
2019-04-16 15:34:28 +02:00
mesh_transport_pdu_t * transport_pdu = mesh_access_transport_init ( MESH_FOUNDATION_OPERATION_COMPOSITION_DATA_STATUS ) ;
if ( ! transport_pdu ) return ;
// page 0
mesh_access_transport_add_uint8 ( transport_pdu , 0 ) ;
2019-01-24 17:05:13 +01:00
// CID
2019-04-16 15:34:28 +02:00
mesh_access_transport_add_uint16 ( transport_pdu , BLUETOOTH_COMPANY_ID_BLUEKITCHEN_GMBH ) ;
2019-01-24 17:05:13 +01:00
// PID
2019-04-16 15:34:28 +02:00
mesh_access_transport_add_uint16 ( transport_pdu , 0 ) ;
2019-01-24 17:05:13 +01:00
// VID
2019-04-16 15:34:28 +02:00
mesh_access_transport_add_uint16 ( transport_pdu , 0 ) ;
2019-01-24 17:05:13 +01:00
// CRPL - number of protection list entries
2019-04-16 15:34:28 +02:00
mesh_access_transport_add_uint16 ( transport_pdu , 1 ) ;
2019-01-24 17:05:13 +01:00
// Features - Relay, Proxy, Friend, Lower Power, ...
2019-04-16 15:34:28 +02:00
mesh_access_transport_add_uint16 ( transport_pdu , 0 ) ;
2019-01-24 17:05:13 +01:00
2019-06-10 20:05:39 +02:00
mesh_element_iterator_t it ;
mesh_element_iterator_init ( & it ) ;
while ( mesh_element_iterator_has_next ( & it ) ) {
mesh_element_t * element = mesh_element_iterator_next ( & it ) ;
2019-06-06 11:33:26 +02:00
// Loc
mesh_access_transport_add_uint16 ( transport_pdu , element - > loc ) ;
// NumS
mesh_access_transport_add_uint8 ( transport_pdu , element - > models_count_sig ) ;
// NumV
mesh_access_transport_add_uint8 ( transport_pdu , element - > models_count_vendor ) ;
mesh_model_iterator_t it ;
// SIG Models
mesh_model_iterator_init ( & it , element ) ;
while ( mesh_model_iterator_has_next ( & it ) ) {
2019-06-10 20:05:39 +02:00
mesh_model_t * model = mesh_model_iterator_next ( & it ) ;
2019-06-06 11:33:26 +02:00
if ( ! mesh_model_is_bluetooth_sig ( model - > model_identifier ) ) continue ;
mesh_access_transport_add_uint16 ( transport_pdu , model - > model_identifier ) ;
}
// Vendor Models
mesh_model_iterator_init ( & it , element ) ;
while ( mesh_model_iterator_has_next ( & it ) ) {
2019-06-10 20:05:39 +02:00
mesh_model_t * model = mesh_model_iterator_next ( & it ) ;
2019-06-06 11:33:26 +02:00
if ( mesh_model_is_bluetooth_sig ( model - > model_identifier ) ) continue ;
mesh_access_transport_add_uint32 ( transport_pdu , model - > model_identifier ) ;
}
2019-06-04 14:12:20 +02:00
}
2019-06-06 11:33:26 +02:00
2019-01-24 17:05:13 +01:00
// send as segmented access pdu
2019-04-22 23:00:20 +02:00
config_server_send_message ( mesh_model , netkey_index , dest , ( mesh_pdu_t * ) transport_pdu ) ;
2019-01-24 17:05:13 +01:00
}
2019-04-17 16:20:07 +02:00
2019-04-21 23:14:36 +02:00
static void config_composition_data_get_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
config_composition_data_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) ) ;
2019-04-22 23:21:44 +02:00
mesh_access_message_processed ( pdu ) ;
2019-04-12 21:59:57 +02:00
}
2019-01-24 17:05:13 +01:00
2019-04-19 23:55:15 +02:00
static void config_model_beacon_status ( mesh_model_t * mesh_model , uint16_t netkey_index , uint16_t dest ) {
2019-04-18 14:05:33 +02:00
// setup message
2019-04-22 12:17:42 +02:00
mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message ( & mesh_foundation_config_beacon_status ,
mesh_foundation_becaon_get ( ) ) ;
2019-04-18 14:05:33 +02:00
if ( ! transport_pdu ) return ;
// send as segmented access pdu
2019-04-22 23:00:20 +02:00
config_server_send_message ( mesh_model , netkey_index , dest , ( mesh_pdu_t * ) transport_pdu ) ;
2019-04-17 16:20:07 +02:00
}
2019-04-21 23:14:36 +02:00
static void config_beacon_get_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
config_model_beacon_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) ) ;
2019-04-22 23:21:44 +02:00
mesh_access_message_processed ( pdu ) ;
2019-04-17 16:20:07 +02:00
}
2019-04-21 23:14:36 +02:00
static void config_beacon_set_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
2019-04-21 22:54:15 +02:00
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
uint8_t beacon_enabled = mesh_access_parser_get_u8 ( & parser ) ;
2019-04-17 16:20:07 +02:00
// beacon valid
2019-04-22 14:44:46 +02:00
if ( beacon_enabled > = MESH_FOUNDATION_STATE_NOT_SUPPORTED ) return ;
2019-04-17 16:20:07 +02:00
// store
2019-04-21 22:54:15 +02:00
mesh_foundation_beacon_set ( beacon_enabled ) ;
2019-04-17 16:20:07 +02:00
//
2019-04-21 23:14:36 +02:00
config_model_beacon_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) ) ;
2019-04-22 23:21:44 +02:00
mesh_access_message_processed ( pdu ) ;
2019-04-17 16:20:07 +02:00
}
2019-04-19 23:55:15 +02:00
static void config_model_default_ttl_status ( mesh_model_t * mesh_model , uint16_t netkey_index , uint16_t dest ) {
2019-04-18 14:05:33 +02:00
// setup message
2019-04-22 12:17:42 +02:00
mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message (
& mesh_foundation_config_default_ttl_status , mesh_foundation_default_ttl_get ( ) ) ;
2019-04-18 14:05:33 +02:00
if ( ! transport_pdu ) return ;
// send as segmented access pdu
2019-04-22 23:00:20 +02:00
config_server_send_message ( mesh_model , netkey_index , dest , ( mesh_pdu_t * ) transport_pdu ) ;
2019-04-16 17:02:14 +02:00
}
2019-04-21 23:14:36 +02:00
static void config_default_ttl_get_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
config_model_default_ttl_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) ) ;
2019-04-22 23:21:44 +02:00
mesh_access_message_processed ( pdu ) ;
2019-04-16 17:02:14 +02:00
}
2019-04-21 23:14:36 +02:00
static void config_default_ttl_set_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
2019-04-21 22:54:15 +02:00
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
uint8_t new_ttl = mesh_access_parser_get_u8 ( & parser ) ;
2019-04-16 17:02:14 +02:00
// ttl valid
if ( new_ttl > 0x7f | | new_ttl = = 0x01 ) return ;
// store
mesh_foundation_default_ttl_set ( new_ttl ) ;
//
2019-04-21 23:14:36 +02:00
config_model_default_ttl_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) ) ;
2019-04-22 23:21:44 +02:00
mesh_access_message_processed ( pdu ) ;
2019-04-16 17:02:14 +02:00
}
2019-04-22 14:44:46 +02:00
static void config_friend_status ( mesh_model_t * mesh_model , uint16_t netkey_index , uint16_t dest ) {
// setup message
mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message (
& mesh_foundation_config_friend_status , mesh_foundation_friend_get ( ) ) ;
if ( ! transport_pdu ) return ;
// send as segmented access pdu
2019-04-22 23:00:20 +02:00
config_server_send_message ( mesh_model , netkey_index , dest , ( mesh_pdu_t * ) transport_pdu ) ;
2019-04-22 14:44:46 +02:00
}
static void config_friend_get_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
config_friend_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) ) ;
2019-04-22 23:21:44 +02:00
mesh_access_message_processed ( pdu ) ;
2019-04-22 14:44:46 +02:00
}
static void config_friend_set_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
uint8_t new_friend_state = mesh_access_parser_get_u8 ( & parser ) ;
// validate
if ( new_friend_state > = MESH_FOUNDATION_STATE_NOT_SUPPORTED ) return ;
// store if supported
if ( mesh_foundation_friend_get ( ) ! = MESH_FOUNDATION_STATE_NOT_SUPPORTED ) {
mesh_foundation_friend_set ( new_friend_state ) ;
}
//
config_friend_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) ) ;
2019-04-22 23:21:44 +02:00
mesh_access_message_processed ( pdu ) ;
2019-04-22 14:44:46 +02:00
}
2019-04-19 23:55:15 +02:00
static void config_model_gatt_proxy_status ( mesh_model_t * mesh_model , uint16_t netkey_index , uint16_t dest ) {
2019-04-18 14:05:33 +02:00
// setup message
2019-04-22 12:17:42 +02:00
mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message (
& mesh_foundation_config_gatt_proxy_status , mesh_foundation_gatt_proxy_get ( ) ) ;
2019-04-18 14:05:33 +02:00
if ( ! transport_pdu ) return ;
// send as segmented access pdu
2019-04-22 23:00:20 +02:00
config_server_send_message ( mesh_model , netkey_index , dest , ( mesh_pdu_t * ) transport_pdu ) ;
2019-04-17 16:34:30 +02:00
}
2019-04-21 23:14:36 +02:00
static void config_gatt_proxy_get_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
config_model_gatt_proxy_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) ) ;
2019-04-22 23:21:44 +02:00
mesh_access_message_processed ( pdu ) ;
2019-04-17 16:34:30 +02:00
}
2019-04-21 23:14:36 +02:00
static void config_gatt_proxy_set_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
2019-04-21 22:54:15 +02:00
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
uint8_t enabled = mesh_access_parser_get_u8 ( & parser ) ;
2019-04-17 16:34:30 +02:00
// ttl valid
if ( enabled > 1 ) return ;
// store
mesh_foundation_gatt_proxy_set ( enabled ) ;
//
2019-04-21 23:14:36 +02:00
config_model_gatt_proxy_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) ) ;
2019-04-22 23:21:44 +02:00
mesh_access_message_processed ( pdu ) ;
2019-04-17 16:34:30 +02:00
}
2019-04-19 23:55:15 +02:00
static void config_model_relay_status ( mesh_model_t * mesh_model , uint16_t netkey_index , uint16_t dest ) {
2019-04-18 14:05:33 +02:00
// setup message
2019-04-22 12:17:42 +02:00
mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message ( & mesh_foundation_config_relay_status ,
mesh_foundation_relay_get ( ) ,
mesh_foundation_relay_retransmit_get ( ) ) ;
2019-04-18 14:05:33 +02:00
if ( ! transport_pdu ) return ;
// send as segmented access pdu
2019-04-22 23:00:20 +02:00
config_server_send_message ( mesh_model , netkey_index , dest , ( mesh_pdu_t * ) transport_pdu ) ;
2019-04-17 18:12:46 +02:00
}
2019-04-21 23:14:36 +02:00
static void config_relay_get_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
config_model_relay_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) ) ;
2019-04-22 23:21:44 +02:00
mesh_access_message_processed ( pdu ) ;
2019-04-17 18:12:46 +02:00
}
2019-04-21 23:14:36 +02:00
static void config_relay_set_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
2019-04-21 22:54:15 +02:00
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
2019-04-17 18:12:46 +02:00
// check if valid
2019-04-21 22:54:15 +02:00
uint8_t relay = mesh_access_parser_get_u8 ( & parser ) ;
uint8_t relay_retransmit = mesh_access_parser_get_u8 ( & parser ) ;
2019-04-17 18:12:46 +02:00
// check if valid
if ( relay > 1 ) return ;
// only update if supported
2019-04-22 14:44:46 +02:00
if ( mesh_foundation_relay_get ( ) ! = MESH_FOUNDATION_STATE_NOT_SUPPORTED ) {
2019-04-17 18:12:46 +02:00
mesh_foundation_relay_set ( relay ) ;
mesh_foundation_relay_retransmit_set ( relay_retransmit ) ;
}
//
2019-04-21 23:14:36 +02:00
config_model_relay_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) ) ;
2019-04-22 23:21:44 +02:00
mesh_access_message_processed ( pdu ) ;
2019-04-17 18:12:46 +02:00
}
2019-04-19 23:55:15 +02:00
static void config_model_network_transmit_status ( mesh_model_t * mesh_model , uint16_t netkey_index , uint16_t dest ) {
2019-04-18 14:05:33 +02:00
// setup message
2019-04-22 12:17:42 +02:00
mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message (
& mesh_foundation_config_network_transmit_status , mesh_foundation_network_transmit_get ( ) ) ;
2019-04-18 14:05:33 +02:00
if ( ! transport_pdu ) return ;
// send as segmented access pdu
2019-04-22 23:00:20 +02:00
config_server_send_message ( mesh_model , netkey_index , dest , ( mesh_pdu_t * ) transport_pdu ) ;
2019-04-17 15:25:28 +02:00
}
2019-04-21 23:14:36 +02:00
static void config_model_network_transmit_get_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
config_model_network_transmit_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) ) ;
2019-04-22 23:21:44 +02:00
mesh_access_message_processed ( pdu ) ;
2019-04-17 15:25:28 +02:00
}
2019-04-21 23:14:36 +02:00
static void config_model_network_transmit_set_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
2019-04-21 22:54:15 +02:00
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
uint8_t new_ttl = mesh_access_parser_get_u8 ( & parser ) ;
2019-04-17 15:25:28 +02:00
// store
mesh_foundation_network_transmit_set ( new_ttl ) ;
//
2019-04-21 23:14:36 +02:00
config_model_network_transmit_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) ) ;
2019-04-22 23:21:44 +02:00
mesh_access_message_processed ( pdu ) ;
2019-04-17 15:25:28 +02:00
}
2019-04-27 17:50:39 +02:00
// NetKey List
static int config_netkey_list_max = 0 ;
static void config_nekey_list_set_max ( uint16_t max ) {
config_netkey_list_max = max ;
}
2019-04-23 19:18:33 +02:00
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 ) {
// setup message
mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message (
& mesh_foundation_config_netkey_status , status , new_netkey_index ) ;
if ( ! transport_pdu ) return ;
// send as segmented access pdu
config_server_send_message ( mesh_model , netkey_index , dest , ( mesh_pdu_t * ) transport_pdu ) ;
}
2019-04-27 17:50:39 +02:00
static void config_netkey_list ( mesh_model_t * mesh_model , uint16_t netkey_index , uint16_t dest ) {
mesh_transport_pdu_t * transport_pdu = mesh_access_transport_init ( MESH_FOUNDATION_OPERATION_NETKEY_LIST ) ;
if ( ! transport_pdu ) return ;
// add list of netkey indexes
mesh_network_key_iterator_t it ;
mesh_network_key_iterator_init ( & it ) ;
while ( mesh_network_key_iterator_has_more ( & it ) ) {
mesh_network_key_t * network_key = mesh_network_key_iterator_get_next ( & it ) ;
mesh_access_transport_add_uint16 ( transport_pdu , network_key - > netkey_index ) ;
}
// send as segmented access pdu
config_server_send_message ( mesh_model , netkey_index , dest , ( mesh_pdu_t * ) transport_pdu ) ;
}
static void config_netkey_add_or_update_derived ( void * arg ) {
2019-06-03 17:06:43 +02:00
# ifdef ENABLE_MESH_PROXY_SERVER
mesh_proxy_stop_advertising_with_network_id ( ) ;
# endif
2019-04-23 19:18:33 +02:00
mesh_network_key_t * network_key = ( mesh_network_key_t * ) arg ;
2019-06-03 16:41:49 +02:00
2019-06-03 17:06:43 +02:00
# ifdef ENABLE_MESH_PROXY_SERVER
2019-06-03 16:41:49 +02:00
// setup advertisement with network id
2019-06-03 17:06:43 +02:00
network_key - > advertisement_with_network_id . adv_length = gatt_bearer_setup_advertising_with_network_id ( network_key - > advertisement_with_network_id . adv_data , network_key - > network_id ) ;
# endif
2019-06-03 16:41:49 +02:00
2019-04-23 19:18:33 +02:00
mesh_network_key_add ( network_key ) ;
2019-06-03 17:06:43 +02:00
# ifdef ENABLE_MESH_PROXY_SERVER
mesh_proxy_start_advertising_with_network_id ( ) ;
# endif
2019-04-23 19:18:33 +02:00
config_netkey_status ( NULL , mesh_pdu_netkey_index ( access_pdu_in_process ) , mesh_pdu_src ( access_pdu_in_process ) , MESH_FOUNDATION_STATUS_SUCCESS , network_key - > netkey_index ) ;
2019-04-27 17:50:39 +02:00
mesh_access_message_processed ( access_pdu_in_process ) ;
2019-04-24 12:34:24 +02:00
}
2019-04-23 19:18:33 +02:00
static void config_netkey_add_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
// get params
uint8_t new_netkey [ 16 ] ;
uint16_t new_netkey_index = mesh_access_parser_get_u16 ( & parser ) ;
2019-04-24 10:40:15 +02:00
mesh_access_parser_get_key ( & parser , new_netkey ) ;
2019-04-23 19:18:33 +02:00
uint8_t status ;
const mesh_network_key_t * existing_network_key = mesh_network_key_list_get ( new_netkey_index ) ;
if ( existing_network_key ) {
// network key for netkey index already exists
if ( memcmp ( existing_network_key - > net_key , new_netkey , 16 ) = = 0 ) {
// same netkey
status = MESH_FOUNDATION_STATUS_SUCCESS ;
} else {
// different netkey
status = MESH_FOUNDATION_STATUS_KEY_INDEX_ALREADY_STORED ;
}
} else {
2019-04-24 12:34:24 +02:00
// check limit for pts
if ( config_netkey_list_max & & mesh_network_key_list_count ( ) > = config_netkey_list_max ) {
2019-04-23 19:18:33 +02:00
status = MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES ;
} else {
2019-04-24 12:34:24 +02:00
// setup new key
mesh_network_key_t * new_network_key = btstack_memory_mesh_network_key_get ( ) ;
if ( new_network_key = = NULL ) {
status = MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES ;
} else {
access_pdu_in_process = pdu ;
new_network_key - > netkey_index = new_netkey_index ;
memcpy ( new_network_key - > net_key , new_netkey , 16 ) ;
2019-04-27 17:50:39 +02:00
mesh_network_key_derive ( & configuration_server_cmac_request , new_network_key , config_netkey_add_or_update_derived , new_network_key ) ;
2019-04-24 12:34:24 +02:00
return ;
}
2019-04-23 19:18:33 +02:00
}
}
config_netkey_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , status , new_netkey_index ) ;
2019-04-27 17:50:39 +02:00
mesh_access_message_processed ( access_pdu_in_process ) ;
2019-04-23 19:18:33 +02:00
}
static void config_netkey_get_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
config_netkey_list ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) ) ;
2019-04-27 17:50:39 +02:00
mesh_access_message_processed ( pdu ) ;
2019-04-23 19:29:25 +02:00
}
static void config_netkey_update_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
// get params
uint8_t new_netkey [ 16 ] ;
uint16_t netkey_index = mesh_access_parser_get_u16 ( & parser ) ;
2019-04-26 23:55:38 +02:00
mesh_access_parser_get_key ( & parser , new_netkey ) ;
2019-04-23 19:29:25 +02:00
// get existing network_key
mesh_network_key_t * network_key = mesh_network_key_list_get ( netkey_index ) ;
if ( network_key = = NULL ) {
config_netkey_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX , netkey_index ) ;
2019-04-27 17:50:39 +02:00
mesh_access_message_processed ( access_pdu_in_process ) ;
return ;
}
// setup new key
mesh_network_key_t * new_network_key = btstack_memory_mesh_network_key_get ( ) ;
if ( new_network_key = = NULL ) {
config_netkey_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES , netkey_index ) ;
mesh_access_message_processed ( access_pdu_in_process ) ;
return ;
2019-04-23 19:29:25 +02:00
}
2019-04-27 17:50:39 +02:00
access_pdu_in_process = pdu ;
new_network_key - > netkey_index = netkey_index ;
new_network_key - > key_refresh = 1 ;
memcpy ( new_network_key - > net_key , new_netkey , 16 ) ;
mesh_network_key_derive ( & configuration_server_cmac_request , new_network_key , config_netkey_add_or_update_derived , new_network_key ) ;
2019-04-23 19:29:25 +02:00
}
2019-04-24 09:40:42 +02:00
static void config_netkey_delete_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
// get params
uint16_t netkey_index = mesh_access_parser_get_u16 ( & parser ) ;
// get existing network_key
2019-04-25 21:39:19 +02:00
uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS ;
2019-04-24 09:40:42 +02:00
mesh_network_key_t * network_key = mesh_network_key_list_get ( netkey_index ) ;
if ( network_key ) {
2019-04-24 10:40:15 +02:00
if ( mesh_network_key_list_count ( ) > 1 ) {
2019-04-27 17:59:46 +02:00
// remove netkey
2019-04-24 10:40:15 +02:00
mesh_network_key_remove ( network_key ) ;
2019-04-27 17:59:46 +02:00
// remove all appkeys for this netkey
mesh_transport_key_iterator_t it ;
mesh_transport_key_iterator_init ( & it , netkey_index ) ;
while ( mesh_transport_key_iterator_has_more ( & it ) ) {
mesh_transport_key_t * transport_key = mesh_transport_key_iterator_get_next ( & it ) ;
2019-06-06 17:46:01 +02:00
uint16_t appkey_index = transport_key - > appkey_index ;
2019-04-27 17:59:46 +02:00
mesh_transport_key_remove ( transport_key ) ;
2019-06-06 17:46:01 +02:00
mesh_delete_app_key ( appkey_index ) ;
2019-04-27 17:59:46 +02:00
}
2019-04-24 10:40:15 +02:00
} else {
// we cannot remove the last network key
status = MESH_FOUNDATION_STATUS_CANNOT_REMOVE ;
}
2019-04-24 09:40:42 +02:00
}
2019-04-24 10:40:15 +02:00
config_netkey_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , status , netkey_index ) ;
2019-04-24 09:40:42 +02:00
}
2019-04-19 23:55:15 +02:00
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 ) {
2019-04-18 14:05:33 +02:00
// setup message
2019-04-22 12:17:42 +02:00
mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message ( & mesh_foundation_config_appkey_status ,
status , netkey_and_appkey_index ) ;
2019-04-18 14:05:33 +02:00
if ( ! transport_pdu ) return ;
// send as segmented access pdu
2019-04-22 23:00:20 +02:00
config_server_send_message ( mesh_model , netkey_index , dest , ( mesh_pdu_t * ) transport_pdu ) ;
2019-01-24 17:39:26 +01:00
}
2019-04-26 22:46:26 +02:00
static void config_appkey_list ( mesh_model_t * mesh_model , uint16_t netkey_index , uint16_t dest , uint32_t netkey_index_of_list ) {
mesh_transport_pdu_t * transport_pdu = mesh_access_transport_init ( MESH_FOUNDATION_OPERATION_APPKEY_LIST ) ;
if ( ! transport_pdu ) return ;
// check netkey_index is valid
mesh_network_key_t * network_key = mesh_network_key_list_get ( netkey_index_of_list ) ;
uint8_t status ;
if ( network_key = = NULL ) {
status = MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX ;
} else {
status = MESH_FOUNDATION_STATUS_SUCCESS ;
}
mesh_access_transport_add_uint8 ( transport_pdu , status ) ;
mesh_access_transport_add_uint16 ( transport_pdu , netkey_index_of_list ) ;
// add list of appkey indexes
mesh_transport_key_iterator_t it ;
2019-04-26 22:51:47 +02:00
mesh_transport_key_iterator_init ( & it , netkey_index_of_list ) ;
2019-04-26 22:46:26 +02:00
while ( mesh_transport_key_iterator_has_more ( & it ) ) {
mesh_transport_key_t * transport_key = mesh_transport_key_iterator_get_next ( & it ) ;
mesh_access_transport_add_uint16 ( transport_pdu , transport_key - > appkey_index ) ;
}
// send as segmented access pdu
config_server_send_message ( mesh_model , netkey_index , dest , ( mesh_pdu_t * ) transport_pdu ) ;
}
2019-04-27 17:56:30 +02:00
static void config_appkey_add_or_udpate_aid ( void * arg ) {
2019-04-25 22:39:51 +02:00
mesh_transport_key_t * transport_key = ( mesh_transport_key_t * ) arg ;
2019-04-22 23:32:39 +02:00
2019-04-27 17:56:30 +02:00
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 ) ;
2019-04-26 21:40:12 +02:00
printf_hexdump ( transport_key - > key , 16 ) ;
2019-01-24 18:35:21 +01:00
2019-01-28 21:02:10 +01:00
// store in TLV
2019-06-06 17:20:45 +02:00
mesh_store_app_key ( transport_key - > netkey_index , transport_key - > appkey_index , transport_key - > aid , transport_key - > key ) ;
2019-01-28 21:02:10 +01:00
2019-04-25 22:39:51 +02:00
// add app key
mesh_transport_key_add ( transport_key ) ;
2019-04-25 21:39:19 +02:00
2019-04-26 21:40:12 +02:00
uint32_t netkey_and_appkey_index = ( transport_key - > appkey_index < < 12 ) | transport_key - > netkey_index ;
config_appkey_status ( NULL , mesh_pdu_netkey_index ( access_pdu_in_process ) , mesh_pdu_src ( access_pdu_in_process ) , netkey_and_appkey_index , MESH_FOUNDATION_STATUS_SUCCESS ) ;
2019-04-22 23:32:39 +02:00
mesh_access_message_processed ( access_pdu_in_process ) ;
2019-01-24 18:35:21 +01:00
}
2019-04-21 23:14:36 +02:00
static void config_appkey_add_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
2019-04-25 22:39:51 +02:00
2019-04-21 22:54:15 +02:00
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
2019-04-26 21:40:12 +02:00
// netkey and appkey index
uint32_t netkey_and_appkey_index = mesh_access_parser_get_u24 ( & parser ) ;
uint16_t netkey_index = netkey_and_appkey_index & 0xfff ;
uint16_t appkey_index = netkey_and_appkey_index > > 12 ;
2019-04-25 22:39:51 +02:00
2019-04-24 10:40:15 +02:00
// actual key
2019-04-26 21:40:12 +02:00
uint8_t appkey [ 16 ] ;
mesh_access_parser_get_key ( & parser , appkey ) ;
// check netkey_index is valid
mesh_network_key_t * network_key = mesh_network_key_list_get ( netkey_index ) ;
if ( network_key = = NULL ) {
config_appkey_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , netkey_and_appkey_index , MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX ) ;
mesh_access_message_processed ( pdu ) ;
return ;
}
// check if appkey already exists
mesh_transport_key_t * transport_key = mesh_transport_key_get ( appkey_index ) ;
if ( transport_key ) {
uint8_t status ;
2019-04-26 23:06:47 +02:00
if ( transport_key - > netkey_index ! = netkey_index ) {
// already stored but with different netkey
status = MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX ;
2019-04-26 23:55:38 +02:00
} else if ( memcmp ( transport_key - > key , appkey , 16 ) = = 0 ) {
2019-04-26 21:40:12 +02:00
// key identical
status = MESH_FOUNDATION_STATUS_SUCCESS ;
} else {
// key differs
status = MESH_FOUNDATION_STATUS_KEY_INDEX_ALREADY_STORED ;
}
config_appkey_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , netkey_and_appkey_index , status ) ;
mesh_access_message_processed ( pdu ) ;
2019-04-26 22:24:37 +02:00
return ;
2019-04-26 21:40:12 +02:00
}
// create app key
mesh_transport_key_t * app_key = btstack_memory_mesh_transport_key_get ( ) ;
if ( app_key = = NULL ) {
config_appkey_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , netkey_and_appkey_index , MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES ) ;
mesh_access_message_processed ( pdu ) ;
return ;
}
// store data
2019-06-06 14:57:27 +02:00
app_key - > akf = 1 ;
2019-04-26 21:40:12 +02:00
app_key - > appkey_index = appkey_index ;
app_key - > netkey_index = netkey_index ;
memcpy ( app_key - > key , appkey , 16 ) ;
2019-01-24 17:39:26 +01:00
2019-01-24 18:35:21 +01:00
// calculate AID
2019-04-22 23:32:39 +02:00
access_pdu_in_process = pdu ;
2019-04-27 17:56:30 +02:00
mesh_transport_key_calc_aid ( & mesh_cmac_request , app_key , config_appkey_add_or_udpate_aid , app_key ) ;
2019-04-26 21:40:12 +02:00
}
2019-04-26 23:55:38 +02:00
static void config_appkey_update_aid ( void * arg ) {
mesh_transport_key_t * transport_key = ( mesh_transport_key_t * ) arg ;
printf ( " Config Appkey Update: NetKey Index 0x%04x, AppKey Index 0x%04x, AID %02x: " , transport_key - > netkey_index , transport_key - > appkey_index , transport_key - > aid ) ;
printf_hexdump ( transport_key - > key , 16 ) ;
// store in TLV
2019-06-06 17:20:45 +02:00
mesh_store_app_key ( transport_key - > netkey_index , transport_key - > appkey_index , transport_key - > aid , transport_key - > key ) ;
2019-04-26 23:55:38 +02:00
uint32_t netkey_and_appkey_index = ( transport_key - > appkey_index < < 12 ) | transport_key - > netkey_index ;
config_appkey_status ( NULL , mesh_pdu_netkey_index ( access_pdu_in_process ) , mesh_pdu_src ( access_pdu_in_process ) , netkey_and_appkey_index , MESH_FOUNDATION_STATUS_SUCCESS ) ;
mesh_access_message_processed ( access_pdu_in_process ) ;
}
static void config_appkey_update_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
// netkey and appkey index
uint32_t netkey_and_appkey_index = mesh_access_parser_get_u24 ( & parser ) ;
uint16_t netkey_index = netkey_and_appkey_index & 0xfff ;
uint16_t appkey_index = netkey_and_appkey_index > > 12 ;
// actual key
uint8_t appkey [ 16 ] ;
mesh_access_parser_get_key ( & parser , appkey ) ;
// check netkey_index is valid
mesh_network_key_t * network_key = mesh_network_key_list_get ( netkey_index ) ;
if ( network_key = = NULL ) {
config_appkey_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , netkey_and_appkey_index , MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX ) ;
mesh_access_message_processed ( pdu ) ;
return ;
}
// check if appkey already exists
mesh_transport_key_t * transport_key = mesh_transport_key_get ( appkey_index ) ;
if ( ! transport_key ) {
config_appkey_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , netkey_and_appkey_index , MESH_FOUNDATION_STATUS_INVALID_APPKEY_INDEX ) ;
mesh_access_message_processed ( pdu ) ;
return ;
}
if ( transport_key - > netkey_index ! = netkey_index ) {
// already stored but with different netkey
2019-04-27 17:50:39 +02:00
config_appkey_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , netkey_and_appkey_index , MESH_FOUNDATION_STATUS_INVALID_BINDING ) ;
2019-04-26 23:55:38 +02:00
mesh_access_message_processed ( pdu ) ;
return ;
}
if ( memcmp ( transport_key - > key , appkey , 16 ) = = 0 ) {
// key identical
config_appkey_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , netkey_and_appkey_index , MESH_FOUNDATION_STATUS_SUCCESS ) ;
mesh_access_message_processed ( pdu ) ;
return ;
}
2019-04-27 17:56:30 +02:00
// create app key
mesh_transport_key_t * app_key = btstack_memory_mesh_transport_key_get ( ) ;
if ( app_key = = NULL ) {
config_appkey_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , netkey_and_appkey_index , MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES ) ;
mesh_access_message_processed ( pdu ) ;
return ;
}
// store data
app_key - > appkey_index = appkey_index ;
app_key - > netkey_index = netkey_index ;
app_key - > key_refresh = 1 ;
memcpy ( app_key - > key , appkey , 16 ) ;
2019-04-26 23:55:38 +02:00
// calculate AID
access_pdu_in_process = pdu ;
2019-04-27 17:56:30 +02:00
mesh_transport_key_calc_aid ( & mesh_cmac_request , app_key , config_appkey_add_or_udpate_aid , app_key ) ;
2019-04-26 23:55:38 +02:00
}
2019-04-26 21:40:12 +02:00
static void config_appkey_delete_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
// netkey and appkey index
uint32_t netkey_and_appkey_index = mesh_access_parser_get_u24 ( & parser ) ;
uint16_t netkey_index = netkey_and_appkey_index & 0xfff ;
uint16_t appkey_index = netkey_and_appkey_index > > 12 ;
// check netkey_index is valid
mesh_network_key_t * network_key = mesh_network_key_list_get ( netkey_index ) ;
if ( network_key = = NULL ) {
config_appkey_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , netkey_and_appkey_index , MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX ) ;
mesh_access_message_processed ( pdu ) ;
return ;
}
// check if appkey already exists
mesh_transport_key_t * transport_key = mesh_transport_key_get ( appkey_index ) ;
if ( transport_key ) {
mesh_transport_key_remove ( transport_key ) ;
2019-06-06 17:46:01 +02:00
mesh_delete_app_key ( appkey_index ) ;
2019-04-26 21:40:12 +02:00
}
config_appkey_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , netkey_and_appkey_index , MESH_FOUNDATION_STATUS_SUCCESS ) ;
mesh_access_message_processed ( pdu ) ;
2019-01-24 17:39:26 +01:00
}
2019-04-26 22:46:26 +02:00
static void config_appkey_get_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
uint16_t netkey_index = mesh_access_parser_get_u16 ( & parser ) ;
config_appkey_list ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , netkey_index ) ;
mesh_access_message_processed ( pdu ) ;
}
2019-04-19 23:55:15 +02:00
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 ) {
2019-04-18 14:05:33 +02:00
// setup message
2019-06-04 12:16:23 +02:00
mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message ( & mesh_foundation_config_model_subscription_status ,
status , element_address , address , model_identifier ) ;
2019-04-18 14:05:33 +02:00
if ( ! transport_pdu ) return ;
// send as segmented access pdu
2019-04-22 23:00:20 +02:00
config_server_send_message ( mesh_model , netkey_index , dest , ( mesh_pdu_t * ) transport_pdu ) ;
2019-03-28 15:04:50 +01:00
}
2019-06-04 10:59:13 +02:00
static mesh_model_t * mesh_access_model_for_address_and_model_identifier ( uint16_t element_address , uint32_t model_identifier , uint8_t * status ) {
2019-06-06 12:45:19 +02:00
mesh_element_t * element = mesh_element_for_unicast_address ( element_address ) ;
if ( element = = NULL ) {
2019-06-04 10:59:13 +02:00
* status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS ;
return NULL ;
}
2019-06-06 11:33:26 +02:00
mesh_model_t * model = mesh_model_get_by_identifier ( element , model_identifier ) ;
2019-06-04 10:59:13 +02:00
if ( model = = NULL ) {
* status = MESH_FOUNDATION_STATUS_INVALID_MODEL ;
} else {
* status = MESH_FOUNDATION_STATUS_SUCCESS ;
}
return model ;
}
2019-04-21 23:14:36 +02:00
static void config_model_subscription_add_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
2019-04-21 22:54:15 +02:00
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
2019-06-04 10:59:13 +02:00
2019-04-21 22:54:15 +02:00
uint16_t element_address = mesh_access_parser_get_u16 ( & parser ) ;
uint16_t address = mesh_access_parser_get_u16 ( & parser ) ;
2019-06-04 12:16:23 +02:00
uint32_t model_identifier = mesh_access_parser_get_model_identifier ( & parser ) ;
2019-06-04 10:59:13 +02:00
uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS ;
mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier ( element_address , model_identifier , & status ) ;
if ( target_model ! = NULL ) {
2019-06-07 11:00:01 +02:00
if ( mesh_network_address_group ( address ) & & ! mesh_network_address_all_nodes ( address ) ) {
status = mesh_model_add_subscription ( target_model , address ) ;
} else {
status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS ;
}
2019-06-04 10:59:13 +02:00
}
2019-04-22 23:21:44 +02:00
2019-06-07 11:00:01 +02:00
config_model_subscription_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , status , element_address , address , model_identifier ) ;
2019-04-22 23:21:44 +02:00
mesh_access_message_processed ( pdu ) ;
2019-03-28 15:04:50 +01:00
}
2019-04-09 14:53:35 +02:00
2019-06-07 12:33:24 +02:00
static void config_model_subscription_virtual_address_add_hash ( void * arg ) {
mesh_model_t * target_model = ( mesh_model_t * ) arg ;
printf ( " Virtual Address Hash: %04x \n " , model_subscription_hash ) ;
// TODO: find a way to get mesh model of Config Server Model
mesh_model_t * mesh_model = NULL ;
// add if not exists
uint16_t pseudo_dst = MESH_ADDRESS_UNSASSIGNED ;
mesh_virtual_address_t * virtual_address = mesh_virtual_address_for_label_uuid ( model_subscription_label_uuid ) ;
if ( virtual_address = = NULL ) {
// add virtual address
pseudo_dst = mesh_virtual_address_register ( model_subscription_label_uuid , model_subscription_hash ) ;
}
uint8_t status ;
if ( pseudo_dst = = MESH_ADDRESS_UNSASSIGNED ) {
status = MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES ;
} else {
status = mesh_model_add_subscription ( target_model , pseudo_dst ) ;
}
config_model_subscription_status ( mesh_model , mesh_pdu_netkey_index ( access_pdu_in_process ) , mesh_pdu_src ( access_pdu_in_process ) , status , model_subscription_element_address , pseudo_dst , target_model - > model_identifier ) ;
mesh_access_message_processed ( access_pdu_in_process ) ;
return ;
}
2019-06-06 14:41:36 +02:00
static void config_model_subscription_virtual_address_add_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
2019-06-07 12:33:24 +02:00
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
// ElementAddress - Address of the element - should be us
model_subscription_element_address = mesh_access_parser_get_u16 ( & parser ) ;
// store label uuid
mesh_access_parser_get_label_uuid ( & parser , model_subscription_label_uuid ) ;
// Model Identifier
uint32_t model_identifier = mesh_access_parser_get_model_identifier ( & parser ) ;
uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS ;
mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier ( model_subscription_element_address , model_identifier , & status ) ;
if ( target_model = = NULL ) {
config_model_subscription_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , status , model_subscription_element_address , MESH_ADDRESS_UNSASSIGNED , model_identifier ) ;
mesh_access_message_processed ( pdu ) ;
return ;
}
access_pdu_in_process = pdu ;
mesh_virtual_address ( & configuration_server_cmac_request , model_subscription_label_uuid , & model_subscription_hash , & config_model_subscription_virtual_address_add_hash , target_model ) ;
2019-04-03 12:22:31 +02:00
}
2019-03-28 15:04:50 +01:00
2019-06-07 14:54:42 +02:00
static void config_model_subscription_virtual_address_overwrite_hash ( void * arg ) {
mesh_model_t * target_model = ( mesh_model_t * ) arg ;
printf ( " Virtual Address Hash: %04x \n " , model_subscription_hash ) ;
// TODO: find a way to get mesh model of Config Server Model
mesh_model_t * mesh_model = NULL ;
// add if not exists
uint16_t pseudo_dst = MESH_ADDRESS_UNSASSIGNED ;
mesh_virtual_address_t * virtual_address = mesh_virtual_address_for_label_uuid ( model_subscription_label_uuid ) ;
if ( virtual_address = = NULL ) {
// add virtual address
pseudo_dst = mesh_virtual_address_register ( model_subscription_label_uuid , model_subscription_hash ) ;
}
uint8_t status ;
if ( pseudo_dst = = MESH_ADDRESS_UNSASSIGNED ) {
status = MESH_FOUNDATION_STATUS_INSUFFICIENT_RESOURCES ;
} else {
status = mesh_model_overwrite_subscription ( target_model , pseudo_dst ) ;
}
config_model_subscription_status ( mesh_model , mesh_pdu_netkey_index ( access_pdu_in_process ) , mesh_pdu_src ( access_pdu_in_process ) , status , model_subscription_element_address , pseudo_dst , target_model - > model_identifier ) ;
mesh_access_message_processed ( access_pdu_in_process ) ;
return ;
}
static void config_model_subscription_virtual_address_overwrite_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
// ElementAddress - Address of the element - should be us
model_subscription_element_address = mesh_access_parser_get_u16 ( & parser ) ;
// store label uuid
mesh_access_parser_get_label_uuid ( & parser , model_subscription_label_uuid ) ;
// Model Identifier
uint32_t model_identifier = mesh_access_parser_get_model_identifier ( & parser ) ;
uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS ;
mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier ( model_subscription_element_address , model_identifier , & status ) ;
if ( target_model = = NULL ) {
config_model_subscription_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , status , model_subscription_element_address , MESH_ADDRESS_UNSASSIGNED , model_identifier ) ;
mesh_access_message_processed ( pdu ) ;
return ;
}
access_pdu_in_process = pdu ;
mesh_virtual_address ( & configuration_server_cmac_request , model_subscription_label_uuid , & model_subscription_hash , & config_model_subscription_virtual_address_overwrite_hash , target_model ) ;
}
2019-06-04 10:59:13 +02:00
static void config_model_subscription_delete_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
uint16_t element_address = mesh_access_parser_get_u16 ( & parser ) ;
uint16_t address = mesh_access_parser_get_u16 ( & parser ) ;
2019-06-04 12:16:23 +02:00
uint32_t model_identifier = mesh_access_parser_get_model_identifier ( & parser ) ;
2019-06-04 10:59:13 +02:00
uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS ;
mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier ( element_address , model_identifier , & status ) ;
if ( target_model ! = NULL ) {
2019-06-07 12:10:09 +02:00
if ( mesh_network_address_group ( address ) & & ! mesh_network_address_all_nodes ( address ) ) {
mesh_model_delete_subscription ( target_model , address ) ;
} else {
status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS ;
}
2019-06-04 10:59:13 +02:00
}
2019-06-07 11:00:01 +02:00
config_model_subscription_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , status , element_address , address , model_identifier ) ;
2019-06-04 10:59:13 +02:00
mesh_access_message_processed ( pdu ) ;
}
2019-06-07 11:10:42 +02:00
static void config_model_subscription_virtual_address_delete_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
uint16_t element_address = mesh_access_parser_get_u16 ( & parser ) ;
2019-06-07 12:10:09 +02:00
mesh_access_parser_get_label_uuid ( & parser , model_subscription_label_uuid ) ;
2019-06-07 11:10:42 +02:00
uint32_t model_identifier = mesh_access_parser_get_model_identifier ( & parser ) ;
2019-06-07 12:33:24 +02:00
mesh_virtual_address_t * virtual_address = mesh_virtual_address_for_label_uuid ( model_subscription_label_uuid ) ;
2019-06-07 11:10:42 +02:00
uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS ;
mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier ( element_address , model_identifier , & status ) ;
2019-06-07 12:10:09 +02:00
if ( ( target_model ! = NULL ) & & ( virtual_address ! = NULL ) ) {
mesh_model_delete_subscription ( target_model , virtual_address - > pseudo_dst ) ;
2019-06-07 11:10:42 +02:00
}
2019-06-07 12:10:09 +02:00
config_model_subscription_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , status , element_address , virtual_address - > hash , model_identifier ) ;
2019-06-07 11:10:42 +02:00
mesh_access_message_processed ( pdu ) ;
}
2019-06-06 14:53:19 +02:00
static void config_model_subscription_delete_all_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
uint16_t element_address = mesh_access_parser_get_u16 ( & parser ) ;
uint32_t model_identifier = mesh_access_parser_get_model_identifier ( & parser ) ;
uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS ;
mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier ( element_address , model_identifier , & status ) ;
if ( target_model ! = NULL ) {
2019-06-07 14:54:42 +02:00
mesh_model_delete_all_subscriptions ( target_model ) ;
2019-06-06 14:53:19 +02:00
}
2019-06-07 11:00:01 +02:00
config_model_subscription_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , status , element_address , MESH_ADDRESS_UNSASSIGNED , model_identifier ) ;
2019-06-07 10:26:17 +02:00
mesh_access_message_processed ( pdu ) ;
}
2019-06-07 11:10:42 +02:00
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 ) {
2019-06-07 10:26:17 +02:00
uint16_t opcode ;
if ( mesh_model_is_bluetooth_sig ( model_identifier ) ) {
opcode = MESH_FOUNDATION_OPERATION_SIG_MODEL_SUBSCRIPTION_LIST ;
} else {
opcode = MESH_FOUNDATION_OPERATION_VENDOR_MODEL_SUBSCRIPTION_LIST ;
}
mesh_transport_pdu_t * transport_pdu = mesh_access_transport_init ( opcode ) ;
if ( ! transport_pdu ) return ;
// setup segmented message
mesh_access_transport_add_uint8 ( transport_pdu , status ) ;
mesh_access_transport_add_uint16 ( transport_pdu , element_address ) ;
mesh_access_transport_add_model_identifier ( transport_pdu , model_identifier ) ;
2019-06-07 11:00:01 +02:00
if ( target_model ! = NULL ) {
2019-06-07 10:26:17 +02:00
int i ;
for ( i = 0 ; i < MAX_NR_MESH_SUBSCRIPTION_PER_MODEL ; i + + ) {
2019-06-07 12:10:09 +02:00
if ( target_model - > subscriptions [ i ] = = MESH_ADDRESS_UNSASSIGNED ) continue ;
if ( mesh_network_address_virtual ( target_model - > subscriptions [ i ] ) ) continue ;
mesh_access_transport_add_uint16 ( transport_pdu , target_model - > subscriptions [ i ] ) ;
2019-06-07 10:26:17 +02:00
}
}
config_server_send_message ( mesh_model , netkey_index , dest , ( mesh_pdu_t * ) transport_pdu ) ;
}
static void config_model_subscription_get_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
uint16_t element_address = mesh_access_parser_get_u16 ( & parser ) ;
uint32_t model_identifier = mesh_access_parser_get_model_identifier ( & parser ) ;
uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS ;
mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier ( element_address , model_identifier , & status ) ;
2019-06-07 11:10:42 +02:00
config_model_subscription_list_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , status , element_address , model_identifier , target_model ) ;
2019-06-06 14:53:19 +02:00
mesh_access_message_processed ( pdu ) ;
}
2019-06-06 14:41:36 +02:00
static void config_model_subscription_overwrite_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
uint16_t element_address = mesh_access_parser_get_u16 ( & parser ) ;
uint16_t address = mesh_access_parser_get_u16 ( & parser ) ;
uint32_t model_identifier = mesh_access_parser_get_model_identifier ( & parser ) ;
uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS ;
mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier ( element_address , model_identifier , & status ) ;
if ( target_model ! = NULL ) {
2019-06-07 11:00:01 +02:00
if ( mesh_network_address_group ( address ) & & ! mesh_network_address_all_nodes ( address ) ) {
2019-06-06 14:41:36 +02:00
mesh_model_overwrite_subscription ( target_model , address ) ;
2019-06-07 11:00:01 +02:00
} else {
status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS ;
}
2019-06-06 14:41:36 +02:00
}
config_model_subscription_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , status , element_address , address , model_identifier ) ;
mesh_access_message_processed ( pdu ) ;
}
2019-06-04 11:38:34 +02:00
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 ) {
2019-04-18 14:05:33 +02:00
// setup message
2019-06-04 12:16:23 +02:00
mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message ( & mesh_foundation_config_model_app_status ,
2019-06-04 11:38:34 +02:00
status , element_address , appkey_index , model_identifier ) ;
2019-04-18 14:05:33 +02:00
if ( ! transport_pdu ) return ;
// send as segmented access pdu
2019-04-22 23:00:20 +02:00
config_server_send_message ( mesh_model , netkey_index , dest , ( mesh_pdu_t * ) transport_pdu ) ;
2019-03-28 17:59:21 +01:00
}
2019-06-04 11:38:34 +02:00
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 ) {
2019-04-28 21:59:26 +02:00
uint16_t opcode ;
2019-06-04 11:38:34 +02:00
if ( mesh_model_is_bluetooth_sig ( model_identifier ) ) {
2019-04-28 21:59:26 +02:00
opcode = MESH_FOUNDATION_OPERATION_SIG_MODEL_APP_LIST ;
} else {
opcode = MESH_FOUNDATION_OPERATION_VENDOR_MODEL_APP_LIST ;
}
mesh_transport_pdu_t * transport_pdu = mesh_access_transport_init ( opcode ) ;
if ( ! transport_pdu ) return ;
mesh_access_transport_add_uint8 ( transport_pdu , status ) ;
mesh_access_transport_add_uint16 ( transport_pdu , element_address ) ;
2019-06-04 11:38:34 +02:00
if ( mesh_model_is_bluetooth_sig ( model_identifier ) ) {
mesh_access_transport_add_uint16 ( transport_pdu , mesh_model_get_model_id ( model_identifier ) ) ;
} else {
mesh_access_transport_add_uint32 ( transport_pdu , model_identifier ) ;
2019-04-28 21:59:26 +02:00
}
2019-06-04 11:38:34 +02:00
2019-04-28 21:59:26 +02:00
// add list of appkey indexes
if ( mesh_model ) {
int i ;
for ( i = 0 ; i < MAX_NR_MESH_APPKEYS_PER_MODEL ; i + + ) {
uint16_t appkey_index = mesh_model - > appkey_indices [ i ] ;
if ( appkey_index = = MESH_APPKEY_INVALID ) continue ;
mesh_access_transport_add_uint16 ( transport_pdu , appkey_index ) ;
}
}
// send as segmented access pdu
config_server_send_message ( mesh_model , netkey_index , dest , ( mesh_pdu_t * ) transport_pdu ) ;
}
static void config_model_app_bind_handler ( mesh_model_t * config_server_model , mesh_pdu_t * pdu ) {
2019-04-21 22:54:15 +02:00
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
2019-06-04 14:30:58 +02:00
2019-04-28 21:59:26 +02:00
uint16_t element_address = mesh_access_parser_get_u16 ( & parser ) ;
uint16_t appkey_index = mesh_access_parser_get_u16 ( & parser ) ;
2019-06-04 12:16:23 +02:00
uint32_t model_identifier = mesh_access_parser_get_model_identifier ( & parser ) ;
2019-04-21 22:54:15 +02:00
2019-04-28 21:59:26 +02:00
uint8_t status ;
do {
2019-06-04 14:30:58 +02:00
// validate address and look up model
mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier ( element_address , model_identifier , & status ) ;
if ( target_model = = NULL ) break ;
2019-04-28 21:59:26 +02:00
// validate app key exists
mesh_transport_key_t * app_key = mesh_transport_key_get ( appkey_index ) ;
if ( ! app_key ) {
status = MESH_FOUNDATION_STATUS_INVALID_APPKEY_INDEX ;
break ;
}
2019-06-04 14:30:58 +02:00
2019-04-28 21:59:26 +02:00
// Configuration Server only allows device keys
2019-06-04 11:38:34 +02:00
if ( mesh_model_is_configuration_server ( model_identifier ) ) {
2019-04-28 21:59:26 +02:00
status = MESH_FOUNDATION_STATUS_CANNOT_BIND ;
break ;
}
2019-06-04 14:30:58 +02:00
status = mesh_model_bind_appkey ( target_model , appkey_index ) ;
2019-03-28 17:59:21 +01:00
2019-04-28 21:59:26 +02:00
} while ( 0 ) ;
2019-04-22 23:21:44 +02:00
2019-06-04 11:38:34 +02:00
config_model_app_status ( config_server_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , status , element_address , appkey_index , model_identifier ) ;
2019-04-22 23:21:44 +02:00
mesh_access_message_processed ( pdu ) ;
2019-03-28 17:59:21 +01:00
}
2019-04-28 21:59:26 +02:00
static void config_model_app_unbind_handler ( mesh_model_t * config_server_model , mesh_pdu_t * pdu ) {
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
2019-06-04 14:30:58 +02:00
2019-04-28 21:59:26 +02:00
uint16_t element_address = mesh_access_parser_get_u16 ( & parser ) ;
uint16_t appkey_index = mesh_access_parser_get_u16 ( & parser ) ;
2019-06-04 12:16:23 +02:00
uint32_t model_identifier = mesh_access_parser_get_model_identifier ( & parser ) ;
2019-04-28 21:59:26 +02:00
uint8_t status ;
do {
2019-06-04 14:30:58 +02:00
// validate address and look up model
mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier ( element_address , model_identifier , & status ) ;
if ( target_model = = NULL ) break ;
2019-04-28 21:59:26 +02:00
// validate app key exists
mesh_transport_key_t * app_key = mesh_transport_key_get ( appkey_index ) ;
if ( ! app_key ) {
status = MESH_FOUNDATION_STATUS_INVALID_APPKEY_INDEX ;
break ;
}
2019-06-04 14:30:58 +02:00
mesh_model_unbind_appkey ( target_model , appkey_index ) ;
2019-04-28 21:59:26 +02:00
status = MESH_FOUNDATION_STATUS_SUCCESS ;
} while ( 0 ) ;
2019-06-04 11:38:34 +02:00
config_model_app_status ( config_server_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , status , element_address , appkey_index , model_identifier ) ;
2019-04-28 21:59:26 +02:00
mesh_access_message_processed ( pdu ) ;
}
static void config_model_app_get ( mesh_model_t * config_server_model , mesh_pdu_t * pdu , int sig_model ) {
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
2019-06-04 14:30:58 +02:00
2019-04-28 21:59:26 +02:00
uint16_t element_address = mesh_access_parser_get_u16 ( & parser ) ;
2019-06-04 12:16:23 +02:00
uint32_t model_identifier = mesh_access_parser_get_model_identifier ( & parser ) ;
2019-04-28 21:59:26 +02:00
uint8_t status ;
2019-06-04 14:30:58 +02:00
mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier ( element_address , model_identifier , & status ) ;
config_model_app_list ( config_server_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , status , element_address , model_identifier , target_model ) ;
2019-04-28 21:59:26 +02:00
mesh_access_message_processed ( pdu ) ;
}
static void config_sig_model_app_get_handler ( mesh_model_t * config_server_model , mesh_pdu_t * pdu ) {
config_model_app_get ( config_server_model , pdu , 1 ) ;
}
static void config_vendor_model_app_get_handler ( mesh_model_t * config_server_model , mesh_pdu_t * pdu ) {
config_model_app_get ( config_server_model , pdu , 0 ) ;
}
2019-04-19 23:55:15 +02:00
static void
2019-06-04 12:16:23 +02:00
config_model_publication_status ( mesh_model_t * mesh_model , uint16_t netkey_index , uint16_t dest , uint8_t status ,
2019-04-19 23:55:15 +02:00
uint32_t model_id , mesh_publication_model_t * publication_model ) {
2019-04-18 18:41:16 +02:00
// setup message
uint16_t app_key_index_and_credential_flag = ( publication_model - > friendship_credential_flag < < 12 ) | publication_model - > appkey_index ;
2019-04-22 12:17:42 +02:00
mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message (
2019-06-04 12:16:23 +02:00
& mesh_foundation_config_model_app_status , status , primary_element_address , publication_model - > address ,
2019-04-22 12:17:42 +02:00
app_key_index_and_credential_flag ,
publication_model - > ttl , publication_model - > period , publication_model - > retransmit , model_id ) ;
2019-04-18 18:41:16 +02:00
if ( ! transport_pdu ) return ;
// send as segmented access pdu
2019-04-22 23:00:20 +02:00
config_server_send_message ( mesh_model , netkey_index , dest , ( mesh_pdu_t * ) transport_pdu ) ;
2019-04-18 18:41:16 +02:00
}
2019-06-04 15:20:03 +02:00
// TODO: avoid temp storage
2019-04-18 18:41:16 +02:00
static mesh_publication_model_t publication_model ;
2019-06-04 15:20:03 +02:00
static mesh_model_t * config_model_publication_model ;
static uint32_t config_model_publication_model_identifier ;
static uint8_t model_publication_label_uuid [ 16 ] ;
2019-04-18 18:41:16 +02:00
2019-04-12 21:59:57 +02:00
static void
2019-04-21 23:14:36 +02:00
config_model_publication_set_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
2019-04-18 18:41:16 +02:00
2019-04-21 22:54:15 +02:00
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
2019-04-18 18:41:16 +02:00
// ElementAddress - Address of the element - should be us
2019-04-21 22:54:15 +02:00
uint16_t element_address = mesh_access_parser_get_u16 ( & parser ) ;
2019-04-18 18:41:16 +02:00
// PublishAddress, 16 bit
2019-04-21 22:54:15 +02:00
publication_model . address = mesh_access_parser_get_u16 ( & parser ) ;
2019-06-04 15:20:03 +02:00
// AppKeyIndex (12), CredentialFlag (1), RFU (3)
uint16_t temp = mesh_access_parser_get_u16 ( & parser ) ;
publication_model . appkey_index = temp & 0x0fff ;
publication_model . friendship_credential_flag = ( temp > > 12 ) & 1 ;
// TTL
publication_model . ttl = mesh_access_parser_get_u8 ( & parser ) ;
// Period
publication_model . period = mesh_access_parser_get_u8 ( & parser ) ;
// Retransmit
publication_model . retransmit = mesh_access_parser_get_u8 ( & parser ) ;
2019-04-21 22:54:15 +02:00
2019-06-04 12:16:23 +02:00
// Model Identifier
uint32_t model_identifier = mesh_access_parser_get_model_identifier ( & parser ) ;
2019-06-04 14:30:58 +02:00
uint8_t status ;
mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier ( element_address , model_identifier , & status ) ;
2019-06-04 15:20:03 +02:00
// TODO validate params
if ( target_model ) {
if ( target_model - > publication_model = = NULL ) {
status = MESH_FOUNDATION_STATUS_CANNOT_SET ;
} else {
if ( publication_model . address = = MESH_ADDRESS_UNSASSIGNED ) {
// unpublish
memset ( & publication_model , 0 , sizeof ( publication_model ) ) ;
}
memcpy ( target_model - > publication_model , & publication_model , sizeof ( mesh_publication_model_t ) ) ;
}
}
// TODO: validate params
2019-04-18 18:41:16 +02:00
// send status
2019-06-04 12:16:23 +02:00
config_model_publication_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , status , model_identifier , & publication_model ) ;
2019-04-22 23:21:44 +02:00
mesh_access_message_processed ( pdu ) ;
2019-04-18 18:41:16 +02:00
}
2019-04-22 23:32:39 +02:00
2019-04-18 18:41:16 +02:00
static void config_model_publication_virtual_address_set_hash ( void * arg ) {
mesh_model_t * mesh_model = ( mesh_model_t * ) arg ;
printf ( " Virtual Address Hash: %04x \n " , publication_model . address ) ;
2019-06-04 15:20:03 +02:00
2019-04-20 00:07:04 +02:00
// TODO: find a way to get netkey_index
2019-04-19 23:55:15 +02:00
uint16_t netkey_index = 0 ;
2019-04-22 23:32:39 +02:00
2019-06-04 15:20:03 +02:00
// update
if ( publication_model . address = = MESH_ADDRESS_UNSASSIGNED ) {
// unpublish
memset ( & publication_model , 0 , sizeof ( publication_model ) ) ;
}
memcpy ( config_model_publication_model - > publication_model , & publication_model , sizeof ( mesh_publication_model_t ) ) ;
2019-06-04 12:16:23 +02:00
// send status
uint8_t status = 0 ;
config_model_publication_status ( mesh_model , mesh_pdu_netkey_index ( access_pdu_in_process ) , mesh_pdu_src ( access_pdu_in_process ) , status , config_model_publication_model_identifier , & publication_model ) ;
2019-04-22 23:32:39 +02:00
mesh_access_message_processed ( access_pdu_in_process ) ;
2019-04-18 18:41:16 +02:00
}
2019-06-07 11:00:01 +02:00
static void
2019-04-18 18:41:16 +02:00
config_model_publication_virtual_address_set_handler ( mesh_model_t * mesh_model ,
2019-04-21 23:14:36 +02:00
mesh_pdu_t * pdu ) {
2019-04-09 15:30:27 +02:00
2019-04-21 22:54:15 +02:00
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
2019-04-18 18:41:16 +02:00
2019-04-21 22:54:15 +02:00
// ElementAddress - Address of the element - should be us
uint16_t element_address = mesh_access_parser_get_u16 ( & parser ) ;
2019-04-18 18:41:16 +02:00
2019-04-22 23:32:39 +02:00
// store label uuid
2019-04-21 22:54:15 +02:00
mesh_access_parser_get_label_uuid ( & parser , model_publication_label_uuid ) ;
2019-04-18 18:41:16 +02:00
2019-04-09 15:30:27 +02:00
// AppKeyIndex (12), CredentialFlag (1), RFU (3)
2019-04-21 22:54:15 +02:00
uint16_t temp = mesh_access_parser_get_u16 ( & parser ) ;
2019-04-18 18:41:16 +02:00
publication_model . appkey_index = temp & 0x0fff ;
publication_model . friendship_credential_flag = ( temp > > 12 ) & 1 ;
2019-04-21 23:14:36 +02:00
publication_model . ttl = mesh_access_parser_get_u8 ( & parser ) ;
publication_model . period = mesh_access_parser_get_u8 ( & parser ) ;
publication_model . retransmit = mesh_access_parser_get_u8 ( & parser ) ;
2019-04-18 18:41:16 +02:00
2019-06-04 12:16:23 +02:00
// Model Identifier
config_model_publication_model_identifier = mesh_access_parser_get_model_identifier ( & parser ) ;
2019-04-21 22:54:15 +02:00
2019-06-04 14:30:58 +02:00
uint8_t status ;
2019-06-04 15:20:03 +02:00
config_model_publication_model = mesh_access_model_for_address_and_model_identifier ( element_address , config_model_publication_model_identifier , & status ) ;
2019-04-21 22:54:15 +02:00
2019-06-04 14:30:58 +02:00
// on error, no need to calculate virtual address hash
if ( status ! = MESH_FOUNDATION_STATUS_SUCCESS ) {
config_model_publication_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , status , config_model_publication_model_identifier , & publication_model ) ;
mesh_access_message_processed ( pdu ) ;
return ;
}
2019-04-18 18:41:16 +02:00
2019-06-04 15:20:03 +02:00
// model exists, but no publication model
if ( config_model_publication_model - > publication_model = = NULL ) {
config_model_publication_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , MESH_FOUNDATION_STATUS_CANNOT_SET , config_model_publication_model_identifier , & publication_model ) ;
mesh_access_message_processed ( pdu ) ;
}
2019-04-22 23:32:39 +02:00
access_pdu_in_process = pdu ;
2019-04-23 19:18:33 +02:00
mesh_virtual_address ( & configuration_server_cmac_request , model_publication_label_uuid , & publication_model . address , & config_model_publication_virtual_address_set_hash , mesh_model ) ;
2019-04-18 18:41:16 +02:00
}
static void
2019-04-21 23:14:36 +02:00
config_model_publication_get_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
2019-04-18 18:41:16 +02:00
2019-04-21 22:54:15 +02:00
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
2019-04-18 18:41:16 +02:00
// ElementAddress - Address of the element - should be us
2019-04-21 22:54:15 +02:00
uint16_t element_address = mesh_access_parser_get_u16 ( & parser ) ;
2019-04-18 18:41:16 +02:00
2019-06-04 12:16:23 +02:00
// Model Identifier
uint32_t model_identifier = mesh_access_parser_get_model_identifier ( & parser ) ;
2019-04-21 22:54:15 +02:00
2019-06-04 14:30:58 +02:00
uint8_t status ;
mesh_model_t * target_model = mesh_access_model_for_address_and_model_identifier ( element_address , model_identifier , & status ) ;
2019-04-18 14:05:33 +02:00
2019-06-07 11:00:01 +02:00
config_model_publication_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , status , model_identifier , target_model - > publication_model ) ;
2019-04-22 23:21:44 +02:00
mesh_access_message_processed ( pdu ) ;
2019-04-09 14:53:35 +02:00
}
2019-04-11 16:50:12 +02:00
2019-04-18 18:41:16 +02:00
2019-04-11 16:50:12 +02:00
// Heartbeat Publication
# define MESH_HEARTBEAT_FEATURES_SUPPORTED_MASK 0x000f
static uint16_t heartbeat_pwr2 ( uint8_t value ) {
if ( ! value ) return 0x0000 ;
if ( value = = 0xff | | value = = 0x11 ) return 0xffff ;
return 1 < < ( value - 1 ) ;
}
static uint8_t heartbeat_count_log ( uint16_t value ) {
if ( ! value ) return 0x00 ;
if ( value = = 0x01 ) return 0x01 ;
if ( value = = 0xffff ) return 0xff ;
// count leading zeros, supported by clang and gcc
return 32 - __builtin_clz ( value - 1 ) + 1 ;
}
2019-04-12 21:59:57 +02:00
static void config_heartbeat_publication_emit ( btstack_timer_source_t * ts ) {
2019-06-07 15:54:55 +02:00
if ( mesh_heartbeat_publication . count_log = = 0 ) return ;
2019-04-12 13:49:18 +02:00
uint32_t time_ms = heartbeat_pwr2 ( mesh_heartbeat_publication . period_log ) * 1000 ;
2019-06-07 15:54:55 +02:00
printf ( " CONFIG_SERVER_HEARTBEAT: Emit (dest %04x, count %u, period %u ms, seq %x) \n " , mesh_heartbeat_publication . destination , mesh_heartbeat_publication . count_log , time_ms , mesh_lower_transport_peek_seq ( ) ) ;
mesh_heartbeat_publication . count_log - - ;
2019-04-12 13:49:18 +02:00
mesh_network_pdu_t * network_pdu = mesh_network_pdu_get ( ) ;
2019-04-11 16:50:12 +02:00
if ( network_pdu ) {
uint8_t data [ 3 ] ;
2019-04-12 13:49:18 +02:00
data [ 0 ] = mesh_heartbeat_publication . ttl ;
big_endian_store_16 ( data , 1 , mesh_heartbeat_publication . features ) ;
2019-04-22 22:24:45 +02:00
mesh_upper_transport_setup_control_pdu ( ( mesh_pdu_t * ) network_pdu , mesh_heartbeat_publication . netkey_index ,
2019-04-11 16:50:12 +02:00
mesh_heartbeat_publication . ttl , primary_element_address , mesh_heartbeat_publication . destination ,
MESH_TRANSPORT_OPCODE_HEARTBEAT , data , sizeof ( data ) ) ;
2019-04-22 22:15:43 +02:00
mesh_upper_transport_send_control_pdu ( ( mesh_pdu_t * ) network_pdu ) ;
2019-04-11 16:50:12 +02:00
}
btstack_run_loop_set_timer ( ts , time_ms ) ;
btstack_run_loop_add_timer ( ts ) ;
}
2019-04-10 18:02:21 +02:00
2019-04-19 23:55:15 +02:00
static void config_heartbeat_publication_status ( mesh_model_t * mesh_model , uint16_t netkey_index , uint16_t dest ) {
2019-04-10 18:02:21 +02:00
2019-04-18 14:05:33 +02:00
// setup message
uint8_t status = 0 ;
2019-06-07 15:54:55 +02:00
uint8_t count_log = heartbeat_count_log ( mesh_heartbeat_publication . count_log ) ;
2019-04-22 12:17:42 +02:00
mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message (
& mesh_foundation_config_heartbeat_publication_status ,
2019-04-18 14:05:33 +02:00
status ,
mesh_heartbeat_publication . destination ,
count_log ,
mesh_heartbeat_publication . period_log ,
mesh_heartbeat_publication . ttl ,
mesh_heartbeat_publication . features ,
mesh_heartbeat_publication . netkey_index ) ;
if ( ! transport_pdu ) return ;
2019-06-07 15:54:55 +02:00
printf ( " MESH config_heartbeat_publication_status count = %u => count_log = %u \n " , mesh_heartbeat_publication . count_log , count_log ) ;
2019-04-18 14:05:33 +02:00
2019-04-20 00:07:04 +02:00
// send as segmented access pdu
2019-04-22 23:00:20 +02:00
config_server_send_message ( mesh_model , netkey_index , dest , ( mesh_pdu_t * ) transport_pdu ) ;
2019-04-10 18:02:21 +02:00
}
2019-04-21 23:14:36 +02:00
static void config_heartbeat_publication_set_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
2019-04-21 22:54:15 +02:00
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
2019-04-10 18:02:21 +02:00
2019-04-11 16:50:12 +02:00
// TODO: validate fields
2019-04-10 18:02:21 +02:00
// Destination address for Heartbeat messages
2019-04-21 22:54:15 +02:00
mesh_heartbeat_publication . destination = mesh_access_parser_get_u16 ( & parser ) ;
2019-04-10 18:02:21 +02:00
// Number of Heartbeat messages to be sent
2019-06-07 15:54:55 +02:00
mesh_heartbeat_publication . count_log = heartbeat_pwr2 ( mesh_access_parser_get_u8 ( & parser ) ) ;
2019-04-10 18:02:21 +02:00
// Period for sending Heartbeat messages
2019-04-21 22:54:15 +02:00
mesh_heartbeat_publication . period_log = mesh_access_parser_get_u8 ( & parser ) ;
2019-04-10 18:02:21 +02:00
// TTL to be used when sending Heartbeat messages
2019-04-21 22:54:15 +02:00
mesh_heartbeat_publication . ttl = mesh_access_parser_get_u8 ( & parser ) ;
2019-04-10 18:02:21 +02:00
// Bit field indicating features that trigger Heartbeat messages when changed
2019-04-21 22:54:15 +02:00
mesh_heartbeat_publication . features = mesh_access_parser_get_u16 ( & parser ) & MESH_HEARTBEAT_FEATURES_SUPPORTED_MASK ;
2019-04-10 18:02:21 +02:00
// NetKey Index
2019-04-21 22:54:15 +02:00
mesh_heartbeat_publication . netkey_index = mesh_access_parser_get_u16 ( & parser ) ;
2019-04-11 16:50:12 +02:00
2019-04-12 13:49:18 +02:00
printf ( " MESH config_heartbeat_publication_set, destination %x, count = %x, period = %u s \n " ,
2019-06-07 15:54:55 +02:00
mesh_heartbeat_publication . destination , mesh_heartbeat_publication . count_log , heartbeat_pwr2 ( mesh_heartbeat_publication . period_log ) ) ;
2019-04-11 16:50:12 +02:00
2019-04-21 23:14:36 +02:00
config_heartbeat_publication_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) ) ;
2019-04-11 16:50:12 +02:00
2019-04-22 23:21:44 +02:00
mesh_access_message_processed ( pdu ) ;
2019-04-21 22:54:15 +02:00
// check if we should enable heartbeats
2019-04-12 13:49:18 +02:00
if ( mesh_heartbeat_publication . destination = = MESH_ADDRESS_UNSASSIGNED ) {
btstack_run_loop_remove_timer ( & mesh_heartbeat_publication . timer ) ;
printf ( " MESH config_heartbeat_publication_set, disable \n " ) ;
return ;
}
// NOTE: defer first heartbeat to allow config status getting sent first
2019-04-11 16:50:12 +02:00
// TODO: check if heartbeat was off before
btstack_run_loop_set_timer_handler ( & mesh_heartbeat_publication . timer , config_heartbeat_publication_emit ) ;
2019-04-12 13:49:18 +02:00
btstack_run_loop_set_timer ( & mesh_heartbeat_publication . timer , 2000 ) ;
btstack_run_loop_add_timer ( & mesh_heartbeat_publication . timer ) ;
2019-04-10 18:02:21 +02:00
}
2019-04-21 23:14:36 +02:00
static void config_heartbeat_publication_get_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
config_heartbeat_publication_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) ) ;
2019-04-22 23:21:44 +02:00
mesh_access_message_processed ( pdu ) ;
2019-04-10 18:02:21 +02:00
}
2019-04-09 14:53:35 +02:00
2019-06-07 15:54:55 +02:00
static void config_heartbeat_subscription_status ( mesh_model_t * mesh_model , uint16_t netkey_index , uint16_t dest ) {
// setup message
uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS ;
uint8_t count_log = heartbeat_count_log ( mesh_heartbeat_subscription . count_log ) ;
mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message (
& mesh_foundation_config_heartbeat_subscription_status ,
status ,
mesh_heartbeat_subscription . source ,
mesh_heartbeat_subscription . destination ,
mesh_heartbeat_subscription . period_log ,
count_log ,
mesh_heartbeat_subscription . min_hops ,
mesh_heartbeat_subscription . max_hops ) ;
if ( ! transport_pdu ) return ;
printf ( " MESH config_heartbeat_subscription_status count = %u => count_log = %u \n " , mesh_heartbeat_subscription . count_log , count_log ) ;
// send as segmented access pdu
config_server_send_message ( mesh_model , netkey_index , dest , ( mesh_pdu_t * ) transport_pdu ) ;
}
static int config_heartbeat_subscription_enabled ( void ) {
return mesh_network_address_unicast ( mesh_heartbeat_subscription . source ) & & mesh_heartbeat_subscription . period_log > 0 & &
( mesh_network_address_unicast ( mesh_heartbeat_subscription . destination ) | | mesh_network_address_group ( mesh_heartbeat_subscription . destination ) ) ;
}
static void config_heartbeat_subscription_set_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
// Destination address for Heartbeat messages
mesh_heartbeat_subscription . source = mesh_access_parser_get_u16 ( & parser ) ;
// Destination address for Heartbeat messages
mesh_heartbeat_subscription . destination = mesh_access_parser_get_u16 ( & parser ) ;
// Period for sending Heartbeat messages
mesh_heartbeat_subscription . period_log = mesh_access_parser_get_u8 ( & parser ) ;
uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS ;
if ( mesh_heartbeat_subscription . period_log > 0x11u ) {
status = MESH_FOUNDATION_STATUS_CANNOT_SET ;
} else if ( ( mesh_heartbeat_subscription . source ! = MESH_ADDRESS_UNSASSIGNED ) & &
! mesh_network_address_unicast ( mesh_heartbeat_subscription . source ) ) {
status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS ;
} else if ( ( mesh_heartbeat_subscription . destination ! = MESH_ADDRESS_UNSASSIGNED ) & &
! mesh_network_address_unicast ( mesh_heartbeat_subscription . destination ) & &
! mesh_network_address_group ( mesh_heartbeat_subscription . destination ) ) {
status = MESH_FOUNDATION_STATUS_INVALID_ADDRESS ;
}
if ( status ! = MESH_FOUNDATION_STATUS_SUCCESS ) {
config_heartbeat_subscription_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) ) ;
mesh_access_message_processed ( pdu ) ;
return ;
}
if ( config_heartbeat_subscription_enabled ( ) ) {
mesh_heartbeat_subscription . count_log = 0u ;
mesh_heartbeat_subscription . min_hops = 0x7Fu ;
mesh_heartbeat_subscription . max_hops = 0u ;
} else {
mesh_heartbeat_subscription . source = MESH_ADDRESS_UNSASSIGNED ;
mesh_heartbeat_subscription . destination = MESH_ADDRESS_UNSASSIGNED ;
mesh_heartbeat_subscription . period_log = 0u ;
// TODO: check if we need to reset these three params
mesh_heartbeat_subscription . count_log = 0u ;
mesh_heartbeat_subscription . min_hops = 0u ;
mesh_heartbeat_subscription . max_hops = 0u ;
}
printf ( " MESH config_heartbeat_subscription_set, destination %x, count = %x, period = %u s \n " ,
mesh_heartbeat_subscription . destination , mesh_heartbeat_subscription . count_log , heartbeat_pwr2 ( mesh_heartbeat_subscription . period_log ) ) ;
config_heartbeat_subscription_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) ) ;
mesh_access_message_processed ( pdu ) ;
// TODO: implement subcription behaviour
}
static void config_heartbeat_subscription_get_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
config_heartbeat_subscription_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) ) ;
mesh_access_message_processed ( pdu ) ;
}
2019-06-03 16:36:31 +02:00
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 ,
mesh_key_refresh_state_t key_refresh_state ) {
// setup message
mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message (
& mesh_key_refresh_phase_status ,
status ,
netkey_index_dest ,
key_refresh_state ) ;
if ( ! transport_pdu ) return ;
// send as segmented access pdu
config_server_send_message ( mesh_model , netkey_index_dest , dest , ( mesh_pdu_t * ) transport_pdu ) ;
}
static void config_key_refresh_phase_get_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
uint16_t netkey_index = mesh_access_parser_get_u16 ( & parser ) ;
mesh_network_key_t * network_key = mesh_network_key_list_get ( netkey_index ) ;
uint8_t status = MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX ;
mesh_key_refresh_state_t key_refresh_state = MESH_KEY_REFRESH_NOT_ACTIVE ;
if ( network_key ! = NULL ) {
status = MESH_FOUNDATION_STATUS_SUCCESS ;
key_refresh_state = network_key - > key_refresh ;
}
config_key_refresh_phase_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , status , netkey_index , key_refresh_state ) ;
mesh_access_message_processed ( pdu ) ;
}
2019-06-03 17:02:42 +02:00
static void config_key_refresh_phase_set_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
uint16_t netkey_index = mesh_access_parser_get_u16 ( & parser ) ;
uint8_t key_refresh_phase_transition = mesh_access_parser_get_u8 ( & parser ) ;
mesh_network_key_t * network_key = mesh_network_key_list_get ( netkey_index ) ;
uint8_t status = MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX ;
if ( network_key ! = NULL ) {
status = MESH_FOUNDATION_STATUS_SUCCESS ;
switch ( key_refresh_phase_transition ) {
case 0x02 :
switch ( network_key - > key_refresh ) {
case MESH_KEY_REFRESH_FIRST_PHASE :
case MESH_KEY_REFRESH_SECOND_PHASE :
network_key - > key_refresh = MESH_KEY_REFRESH_SECOND_PHASE ;
break ;
default :
break ;
}
break ;
case 0x03 :
switch ( network_key - > key_refresh ) {
case MESH_KEY_REFRESH_FIRST_PHASE :
case MESH_KEY_REFRESH_SECOND_PHASE :
// TODO: invoke Key Refresh Phase 3, then
// set network_key->key_refresh = MESH_KEY_REFRESH_NOT_ACTIVE;
printf ( " TODO: invoke Key Refresh Phase 3, then set key refresh phase to MESH_KEY_REFRESH_NOT_ACTIVE \n " ) ;
break ;
default :
break ;
}
break ;
default :
status = MESH_FOUNDATION_STATUS_CANNOT_SET ;
break ;
}
}
config_key_refresh_phase_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , status , netkey_index , network_key - > key_refresh ) ;
mesh_access_message_processed ( pdu ) ;
}
2019-04-19 23:55:15 +02:00
static void config_node_reset_status ( mesh_model_t * mesh_model , uint16_t netkey_index , uint16_t dest ) {
2019-04-18 14:05:33 +02:00
// setup message
2019-04-22 12:17:42 +02:00
mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message ( & mesh_foundation_node_reset_status ) ;
2019-04-18 14:05:33 +02:00
if ( ! transport_pdu ) return ;
// send as segmented access pdu
2019-04-22 23:00:20 +02:00
config_server_send_message ( mesh_model , netkey_index , dest , ( mesh_pdu_t * ) transport_pdu ) ;
2019-04-17 16:20:07 +02:00
}
2019-06-03 16:36:31 +02:00
static void config_node_reset_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
2019-04-17 16:34:30 +02:00
mesh_foundation_node_reset ( ) ;
2019-04-21 23:14:36 +02:00
config_node_reset_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) ) ;
2019-04-22 23:21:44 +02:00
mesh_access_message_processed ( pdu ) ;
2019-04-17 16:20:07 +02:00
}
2019-06-03 17:30:01 +02:00
static void low_power_node_poll_timeout_status ( mesh_model_t * mesh_model , uint16_t netkey_index_dest , uint16_t dest , uint8_t status ) {
mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message (
& mesh_foundation_low_power_node_poll_timeout_status ,
status ,
0 , // The unicast address of the Low Power node
0 ) ; // The current value of the PollTimeout timer of the Low Power node
if ( ! transport_pdu ) return ;
printf ( " TODO: send unicast address of the Low Power node and the current value of the PollTimeout timer, instead of 0s \n " ) ;
// send as segmented access pdu
config_server_send_message ( mesh_model , netkey_index_dest , dest , ( mesh_pdu_t * ) transport_pdu ) ;
}
static void config_low_power_node_poll_timeout_get_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
printf ( " TODO: implement get the current value of PollTimeout timer of the Low Power node within a Friend node \n " ) ;
low_power_node_poll_timeout_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , MESH_FOUNDATION_STATUS_SUCCESS ) ;
mesh_access_message_processed ( pdu ) ;
}
2019-06-03 14:59:07 +02:00
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 ,
2019-06-03 16:36:31 +02:00
mesh_node_identity_state_t node_identity_state ) {
2019-06-03 11:22:34 +02:00
// setup message
mesh_transport_pdu_t * transport_pdu = mesh_access_setup_segmented_message (
& mesh_foundation_node_identity_status ,
status ,
netkey_index_dest ,
2019-06-03 14:59:07 +02:00
node_identity_state ) ;
2019-06-03 11:22:34 +02:00
if ( ! transport_pdu ) return ;
// send as segmented access pdu
config_server_send_message ( mesh_model , netkey_index_dest , dest , ( mesh_pdu_t * ) transport_pdu ) ;
}
static void config_node_identity_get_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
uint16_t netkey_index = mesh_access_parser_get_u16 ( & parser ) ;
2019-06-03 14:59:07 +02:00
mesh_network_key_t * network_key = mesh_network_key_list_get ( netkey_index ) ;
uint8_t status = MESH_FOUNDATION_STATUS_SUCCESS ;
2019-06-03 16:36:31 +02:00
mesh_node_identity_state_t node_identity_state = MESH_NODE_IDENTITY_STATE_ADVERTISING_NOT_SUPPORTED ;
2019-06-03 14:59:07 +02:00
if ( network_key = = NULL ) {
status = MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX ;
} else {
# ifdef ENABLE_MESH_PROXY_SERVER
if ( network_key - > node_id_advertisement_running = = 0 ) {
2019-06-03 16:36:31 +02:00
node_identity_state = MESH_NODE_IDENTITY_STATE_ADVERTISING_STOPPED ;
2019-06-03 14:59:07 +02:00
} else {
2019-06-03 16:36:31 +02:00
node_identity_state = MESH_NODE_IDENTITY_STATE_ADVERTISING_RUNNING ;
2019-06-03 14:59:07 +02:00
}
# endif
}
config_node_identity_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , status , netkey_index , node_identity_state ) ;
2019-06-03 11:22:34 +02:00
mesh_access_message_processed ( pdu ) ;
}
static void config_node_identity_set_handler ( mesh_model_t * mesh_model , mesh_pdu_t * pdu ) {
2019-06-03 14:59:07 +02:00
mesh_access_parser_state_t parser ;
mesh_access_parser_init ( & parser , ( mesh_pdu_t * ) pdu ) ;
uint16_t netkey_index = mesh_access_parser_get_u16 ( & parser ) ;
2019-06-03 16:36:31 +02:00
mesh_node_identity_state_t node_identity_state = ( mesh_node_identity_state_t ) mesh_access_parser_get_u8 ( & parser ) ;
2019-06-03 14:59:07 +02:00
uint8_t status = MESH_FOUNDATION_STATUS_FEATURE_NOT_SUPPORTED ;
mesh_network_key_t * network_key = mesh_network_key_list_get ( netkey_index ) ;
if ( network_key = = NULL ) {
status = MESH_FOUNDATION_STATUS_INVALID_NETKEY_INDEX ;
} else {
# ifdef ENABLE_MESH_PROXY_SERVER
switch ( node_identity_state ) {
2019-06-03 16:36:31 +02:00
case MESH_NODE_IDENTITY_STATE_ADVERTISING_STOPPED :
2019-06-03 14:59:07 +02:00
network_key - > node_id_advertisement_running = 0 ;
status = MESH_FOUNDATION_STATUS_SUCCESS ;
break ;
2019-06-03 16:36:31 +02:00
case MESH_NODE_IDENTITY_STATE_ADVERTISING_RUNNING :
2019-06-03 14:59:07 +02:00
network_key - > node_id_advertisement_running = 1 ;
status = MESH_FOUNDATION_STATUS_SUCCESS ;
break ;
default :
break ;
}
# endif
}
config_node_identity_status ( mesh_model , mesh_pdu_netkey_index ( pdu ) , mesh_pdu_src ( pdu ) , status , netkey_index , node_identity_state ) ;
mesh_access_message_processed ( pdu ) ;
2019-06-03 11:22:34 +02:00
}
2019-04-12 21:59:57 +02:00
//
2019-04-12 20:54:29 +02:00
2019-04-12 21:59:57 +02:00
static mesh_operation_t mesh_configuration_server_model_operations [ ] = {
2019-06-03 17:30:01 +02:00
{ MESH_FOUNDATION_OPERATION_APPKEY_ADD , 19 , config_appkey_add_handler } ,
2019-04-26 21:40:12 +02:00
{ MESH_FOUNDATION_OPERATION_APPKEY_DELETE , 3 , config_appkey_delete_handler } ,
2019-04-26 22:46:26 +02:00
{ MESH_FOUNDATION_OPERATION_APPKEY_GET , 2 , config_appkey_get_handler } ,
2019-04-26 23:55:38 +02:00
{ MESH_FOUNDATION_OPERATION_APPKEY_UPDATE , 19 , config_appkey_update_handler } ,
2019-04-23 19:18:33 +02:00
{ MESH_FOUNDATION_OPERATION_NETKEY_ADD , 18 , config_netkey_add_handler } ,
2019-04-23 19:29:25 +02:00
{ MESH_FOUNDATION_OPERATION_NETKEY_UPDATE , 18 , config_netkey_update_handler } ,
2019-04-24 09:40:42 +02:00
{ MESH_FOUNDATION_OPERATION_NETKEY_DELETE , 2 , config_netkey_delete_handler } ,
2019-04-23 19:18:33 +02:00
{ MESH_FOUNDATION_OPERATION_NETKEY_GET , 0 , config_netkey_get_handler } ,
2019-04-12 21:59:57 +02:00
{ MESH_FOUNDATION_OPERATION_COMPOSITION_DATA_GET , 1 , config_composition_data_get_handler } ,
2019-06-03 17:30:01 +02:00
{ MESH_FOUNDATION_OPERATION_BEACON_GET , 0 , config_beacon_get_handler } ,
{ MESH_FOUNDATION_OPERATION_BEACON_SET , 1 , config_beacon_set_handler } ,
{ MESH_FOUNDATION_OPERATION_DEFAULT_TTL_GET , 0 , config_default_ttl_get_handler } ,
{ MESH_FOUNDATION_OPERATION_DEFAULT_TTL_SET , 1 , config_default_ttl_set_handler } ,
{ MESH_FOUNDATION_OPERATION_FRIEND_GET , 0 , config_friend_get_handler } ,
{ MESH_FOUNDATION_OPERATION_FRIEND_SET , 1 , config_friend_set_handler } ,
{ MESH_FOUNDATION_OPERATION_NETWORK_TRANSMIT_GET , 0 , config_model_network_transmit_get_handler } ,
{ MESH_FOUNDATION_OPERATION_NETWORK_TRANSMIT_SET , 1 , config_model_network_transmit_set_handler } ,
{ MESH_FOUNDATION_OPERATION_GATT_PROXY_GET , 0 , config_gatt_proxy_get_handler } ,
{ MESH_FOUNDATION_OPERATION_GATT_PROXY_SET , 1 , config_gatt_proxy_set_handler } ,
{ MESH_FOUNDATION_OPERATION_RELAY_GET , 0 , config_relay_get_handler } ,
{ MESH_FOUNDATION_OPERATION_RELAY_SET , 1 , config_relay_set_handler } ,
{ MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_ADD , 6 , config_model_subscription_add_handler } ,
{ MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_ADD , 20 , config_model_subscription_virtual_address_add_handler } ,
2019-06-04 10:59:13 +02:00
{ MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_DELETE , 6 , config_model_subscription_delete_handler } ,
2019-06-07 11:10:42 +02:00
{ MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_DELETE , 20 , config_model_subscription_virtual_address_delete_handler } ,
2019-06-07 11:00:01 +02:00
{ MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_OVERWRITE , 6 , config_model_subscription_overwrite_handler } ,
2019-06-07 14:54:42 +02:00
{ MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_VIRTUAL_ADDRESS_OVERWRITE , 20 , config_model_subscription_virtual_address_overwrite_handler } ,
2019-06-06 14:53:19 +02:00
{ MESH_FOUNDATION_OPERATION_MODEL_SUBSCRIPTION_DELETE_ALL , 4 , config_model_subscription_delete_all_handler } ,
2019-06-07 10:26:17 +02:00
{ MESH_FOUNDATION_OPERATION_SIG_MODEL_SUBSCRIPTION_GET , 4 , config_model_subscription_get_handler } ,
{ MESH_FOUNDATION_OPERATION_VENDOR_MODEL_SUBSCRIPTION_GET , 6 , config_model_subscription_get_handler } ,
2019-06-03 17:30:01 +02:00
{ MESH_FOUNDATION_OPERATION_SIG_MODEL_APP_GET , 4 , config_sig_model_app_get_handler } ,
{ MESH_FOUNDATION_OPERATION_VENDOR_MODEL_APP_GET , 6 , config_vendor_model_app_get_handler } ,
{ MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_SET , 11 , config_model_publication_set_handler } ,
{ MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_VIRTUAL_ADDRESS_SET , 25 , config_model_publication_virtual_address_set_handler } ,
{ MESH_FOUNDATION_OPERATION_MODEL_PUBLICATION_GET , 4 , config_model_publication_get_handler } ,
{ MESH_FOUNDATION_OPERATION_MODEL_APP_BIND , 6 , config_model_app_bind_handler } ,
{ MESH_FOUNDATION_OPERATION_MODEL_APP_UNBIND , 6 , config_model_app_unbind_handler } ,
{ MESH_FOUNDATION_OPERATION_HEARTBEAT_PUBLICATION_GET , 0 , config_heartbeat_publication_get_handler } ,
{ MESH_FOUNDATION_OPERATION_HEARTBEAT_PUBLICATION_SET , 9 , config_heartbeat_publication_set_handler } ,
2019-06-07 15:54:55 +02:00
{ MESH_FOUNDATION_OPERATION_HEARTBEAT_SUBSCRIPTION_GET , 0 , config_heartbeat_subscription_get_handler } ,
{ MESH_FOUNDATION_OPERATION_HEARTBEAT_SUBSCRIPTION_SET , 5 , config_heartbeat_subscription_set_handler } ,
2019-06-03 17:30:01 +02:00
{ MESH_FOUNDATION_OPERATION_KEY_REFRESH_PHASE_GET , 2 , config_key_refresh_phase_get_handler } ,
{ MESH_FOUNDATION_OPERATION_KEY_REFRESH_PHASE_SET , 3 , config_key_refresh_phase_set_handler } ,
{ MESH_FOUNDATION_OPERATION_NODE_RESET , 0 , config_node_reset_handler } ,
{ MESH_FOUNDATION_OPERATION_LOW_POWER_NODE_POLL_TIMEOUT_GET , 2 , config_low_power_node_poll_timeout_get_handler } ,
2019-06-03 11:22:34 +02:00
{ MESH_FOUNDATION_OPERATION_NODE_IDENTITY_GET , 2 , config_node_identity_get_handler } ,
2019-06-03 14:59:07 +02:00
{ MESH_FOUNDATION_OPERATION_NODE_IDENTITY_SET , 3 , config_node_identity_set_handler } ,
2019-06-03 17:30:01 +02:00
{ 0 , 0 , NULL }
2019-04-12 21:59:57 +02:00
} ;
2019-06-10 18:29:12 +02:00
static mesh_operation_t * mesh_model_lookup_operation ( mesh_model_t * model , mesh_pdu_t * pdu ) {
uint32_t opcode = 0 ;
uint16_t opcode_size = 0 ;
int ok = mesh_access_pdu_get_opcode ( pdu , & opcode , & opcode_size ) ;
if ( ! ok ) return NULL ;
uint16_t len = mesh_pdu_len ( pdu ) ;
// find opcode in table
mesh_operation_t * operation = model - > operations ;
if ( operation = = NULL ) return NULL ;
for ( ; operation - > handler ! = NULL ; operation + + ) {
if ( operation - > opcode ! = opcode ) continue ;
if ( ( opcode_size + operation - > minimum_length ) > len ) continue ;
return operation ;
}
return NULL ;
}
2019-04-22 23:21:44 +02:00
static void mesh_access_message_process_handler ( mesh_pdu_t * pdu ) {
2019-04-12 21:59:57 +02:00
// get opcode and size
2019-04-12 20:54:29 +02:00
uint32_t opcode = 0 ;
2019-04-12 21:59:57 +02:00
uint16_t opcode_size = 0 ;
2019-04-18 18:41:16 +02:00
2019-04-21 23:14:36 +02:00
int ok = mesh_access_pdu_get_opcode ( pdu , & opcode , & opcode_size ) ;
2019-04-22 23:21:44 +02:00
if ( ! ok ) {
mesh_access_message_processed ( pdu ) ;
return ;
}
2019-04-12 21:59:57 +02:00
2019-04-21 23:14:36 +02:00
uint16_t len = mesh_pdu_len ( pdu ) ;
2019-04-16 17:02:14 +02:00
printf ( " MESH Access Message, Opcode = %x: " , opcode ) ;
2019-04-21 23:14:36 +02:00
switch ( pdu - > pdu_type ) {
case MESH_PDU_TYPE_NETWORK :
printf_hexdump ( & ( ( mesh_network_pdu_t * ) pdu ) - > data [ 10 ] , len ) ;
break ;
case MESH_PDU_TYPE_TRANSPORT :
printf_hexdump ( ( ( mesh_transport_pdu_t * ) pdu ) - > data , len ) ;
break ;
default :
break ;
}
2019-04-12 21:59:57 +02:00
2019-06-10 18:29:12 +02:00
// TODO: check if used AppKey is bound to particular model
uint16_t dst = mesh_pdu_dst ( pdu ) ;
if ( mesh_network_address_unicast ( dst ) ) {
// loookup element by unicast address
mesh_element_t * element = mesh_element_for_unicast_address ( dst ) ;
if ( element ! = NULL ) {
// iterate over models, look for operation
mesh_model_iterator_t model_it ;
mesh_model_iterator_init ( & model_it , element ) ;
while ( mesh_model_iterator_has_next ( & model_it ) ) {
2019-06-10 20:05:39 +02:00
mesh_model_t * model = mesh_model_iterator_next ( & model_it ) ;
2019-06-10 18:29:12 +02:00
// find opcode in table
mesh_operation_t * operation = mesh_model_lookup_operation ( model , pdu ) ;
if ( operation = = NULL ) break ;
operation - > handler ( model , pdu ) ;
return ;
}
}
} else {
// iterate over all elements / models, check subscription list
2019-06-10 20:05:39 +02:00
mesh_element_iterator_t it ;
mesh_element_iterator_init ( & it ) ;
while ( mesh_element_iterator_has_next ( & it ) ) {
mesh_element_t * element = ( mesh_element_t * ) mesh_element_iterator_next ( & it ) ;
2019-06-10 18:29:12 +02:00
mesh_model_iterator_t model_it ;
mesh_model_iterator_init ( & model_it , element ) ;
while ( mesh_model_iterator_has_next ( & model_it ) ) {
2019-06-10 20:05:39 +02:00
mesh_model_t * model = mesh_model_iterator_next ( & model_it ) ;
2019-06-10 18:29:12 +02:00
if ( mesh_model_contains_subscription ( model , dst ) ) {
// find opcode in table
mesh_operation_t * operation = mesh_model_lookup_operation ( model , pdu ) ;
if ( operation = = NULL ) break ;
operation - > handler ( model , pdu ) ;
return ;
}
}
}
2019-04-18 18:41:16 +02:00
}
2019-04-22 23:21:44 +02:00
// operation not found -> done
printf ( " Message not handled \n " ) ;
mesh_access_message_processed ( pdu ) ;
2019-04-21 23:14:36 +02:00
}
2019-04-18 18:41:16 +02:00
static btstack_crypto_aes128_cmac_t salt_request ;
static uint8_t label_uuid [ 16 ] ;
static uint8_t salt_hash [ 16 ] ;
static uint16_t virtual_address_hash ;
2019-04-23 17:13:07 +02:00
static mesh_network_key_t test_network_key ;
2019-04-18 18:41:16 +02:00
static void salt_complete ( void * arg ) {
int i ;
printf ( " uint8_t salt[16] = { " ) ;
for ( i = 0 ; i < 16 ; i + + ) {
printf ( " 0x%02x, " , salt_hash [ i ] ) ;
2019-04-10 18:02:21 +02:00
}
2019-04-18 18:41:16 +02:00
printf ( " }; \n " ) ;
}
static uint8_t mesh_salt_vtad [ ] = { 0xce , 0xf7 , 0xfa , 0x9d , 0xc4 , 0x7b , 0xaf , 0x5d , 0xaa , 0xee , 0xd1 , 0x94 , 0x06 , 0x09 , 0x4f , 0x37 , } ;
static void virtual_address_complete ( void * arg ) {
printf ( " Label UUID: " ) ;
printf_hexdump ( label_uuid , 16 ) ;
printf ( " Virtual Address %04x \n " , virtual_address_hash ) ;
2019-01-24 17:05:13 +01:00
}
2019-04-23 17:13:07 +02:00
static void key_derived ( void * arg ) {
}
2019-05-23 18:16:18 +02:00
static void mesh_proxy_packet_handler_beacon ( uint8_t packet_type , uint16_t channel , uint8_t * packet , uint16_t size ) {
2019-05-08 17:38:18 +02:00
switch ( packet_type ) {
case MESH_PROXY_DATA_PACKET :
printf ( " Received beacon \n " ) ;
printf_hexdump ( packet , size ) ;
break ;
case HCI_EVENT_PACKET :
switch ( hci_event_packet_get_type ( packet ) ) {
case HCI_EVENT_MESH_META :
switch ( hci_event_mesh_meta_get_subevent_code ( packet ) ) {
case MESH_SUBEVENT_CAN_SEND_NOW :
gatt_bearer_send_mesh_beacon ( mesh_secure_network_beacon , sizeof ( mesh_secure_network_beacon ) ) ;
break ;
default :
break ;
}
break ;
default :
break ;
}
break ;
default :
break ;
}
}
2019-05-23 18:16:18 +02:00
static void mesh_proxy_packet_handler_network_pdu ( uint8_t packet_type , uint16_t channel , uint8_t * packet , uint16_t size ) {
2019-05-08 17:38:18 +02:00
switch ( packet_type ) {
case MESH_PROXY_DATA_PACKET :
2019-05-28 11:54:11 +02:00
printf ( " mesh: Received network PDU (proxy) \n " ) ;
2019-05-08 17:38:18 +02:00
printf_hexdump ( packet , size ) ;
2019-05-23 14:40:34 +02:00
mesh_network_received_message ( packet , size ) ;
2019-05-08 17:38:18 +02:00
break ;
case HCI_EVENT_PACKET :
switch ( hci_event_packet_get_type ( packet ) ) {
case HCI_EVENT_MESH_META :
switch ( hci_event_mesh_meta_get_subevent_code ( packet ) ) {
2019-05-28 11:54:11 +02:00
case MESH_SUBEVENT_CAN_SEND_NOW :
mesh_gatt_handle_event ( packet_type , channel , packet , size ) ;
break ;
case MESH_SUBEVENT_MESSAGE_SENT :
mesh_gatt_handle_event ( packet_type , channel , packet , size ) ;
break ;
2019-06-03 11:30:28 +02:00
case MESH_SUBEVENT_PROXY_CONNECTED :
2019-05-28 11:54:11 +02:00
printf ( " mesh: MESH_PROXY_CONNECTED \n " ) ;
2019-05-08 17:38:18 +02:00
printf ( " + Setup Secure Network Beacon \n " ) ;
mesh_secure_network_beacon [ 0 ] = BEACON_TYPE_SECURE_NETWORK ;
mesh_secure_network_beacon [ 1 ] = mesh_flags ;
memcpy ( & mesh_secure_network_beacon [ 2 ] , network_id , 8 ) ;
big_endian_store_32 ( mesh_secure_network_beacon , 10 , mesh_get_iv_index ( ) ) ;
btstack_crypto_aes128_cmac_message ( & mesh_cmac_request , beacon_key , 13 ,
& mesh_secure_network_beacon [ 1 ] , mesh_secure_network_beacon_auth_value , & mesh_secure_network_beacon_auth_value_calculated , NULL ) ;
break ;
default :
break ;
}
break ;
default :
break ;
}
break ;
default :
break ;
}
}
static mesh_network_pdu_t * encrypted_proxy_configuration_ready_to_send ;
static void request_can_send_now_proxy_configuration_callback_handler ( mesh_network_pdu_t * network_pdu ) {
encrypted_proxy_configuration_ready_to_send = network_pdu ;
gatt_bearer_request_can_send_now_for_mesh_proxy_configuration ( ) ;
}
static void packet_handler_for_mesh_proxy_configuration ( uint8_t packet_type , uint16_t channel , uint8_t * packet , uint16_t size ) {
printf ( " packet_handler_for_mesh_proxy_configuration \n " ) ;
switch ( packet_type ) {
case MESH_PROXY_DATA_PACKET :
printf ( " Received proxy configuration \n " ) ;
printf_hexdump ( packet , size ) ;
mesh_network_process_proxy_message ( packet , size ) ;
break ;
case HCI_EVENT_PACKET :
switch ( hci_event_packet_get_type ( packet ) ) {
case HCI_EVENT_MESH_META :
switch ( hci_event_mesh_meta_get_subevent_code ( packet ) ) {
case MESH_SUBEVENT_CAN_SEND_NOW :
printf ( " MESH_SUBEVENT_CAN_SEND_NOW packet_handler_for_mesh_proxy_configuration len %d \n " , encrypted_proxy_configuration_ready_to_send - > len ) ;
printf_hexdump ( encrypted_proxy_configuration_ready_to_send - > data , encrypted_proxy_configuration_ready_to_send - > len ) ;
gatt_bearer_send_mesh_proxy_configuration ( encrypted_proxy_configuration_ready_to_send - > data , encrypted_proxy_configuration_ready_to_send - > len ) ;
break ;
default :
break ;
}
break ;
default :
break ;
}
break ;
default :
break ;
}
}
typedef enum {
MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_SET_FILTER_TYPE = 0 ,
MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_ADD_ADDRESSES ,
MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_REMOVE_ADDRESSES ,
MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_FILTER_STATUS
} mesh_proxy_configuration_message_opcode_t ;
typedef enum {
MESH_PROXY_CONFIGURATION_FILTER_TYPE_SET_WHITE_LIST = 0 ,
MESH_PROXY_CONFIGURATION_FILTER_TYPE_BLACK_LIST
} mesh_proxy_configuration_filter_type_t ;
// Used to answer configutation request
static uint16_t proxy_configuration_filter_list_len ;
static mesh_proxy_configuration_filter_type_t proxy_configuration_filter_type ;
static uint16_t primary_element_address ;
void proxy_configuration_message_handler ( mesh_network_callback_type_t callback_type , mesh_network_pdu_t * received_network_pdu ) {
mesh_proxy_configuration_message_opcode_t opcode ;
uint8_t data [ 4 ] ;
mesh_network_pdu_t * network_pdu ;
uint8_t * network_pdu_data ;
uint8_t network_pdu_len ;
switch ( callback_type ) {
case MESH_NETWORK_PDU_RECEIVED :
printf ( " proxy_configuration_message_handler: MESH_PROXY_PDU_RECEIVED \n " ) ;
network_pdu_len = mesh_network_pdu_len ( received_network_pdu ) ;
network_pdu_data = mesh_network_pdu_data ( received_network_pdu ) ;
// printf_hexdump(network_pdu_data, network_pdu_len);
opcode = network_pdu_data [ 0 ] ;
switch ( opcode ) {
case MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_SET_FILTER_TYPE : {
switch ( network_pdu_data [ 1 ] ) {
case MESH_PROXY_CONFIGURATION_FILTER_TYPE_SET_WHITE_LIST :
case MESH_PROXY_CONFIGURATION_FILTER_TYPE_BLACK_LIST :
proxy_configuration_filter_type = network_pdu_data [ 1 ] ;
break ;
}
uint8_t ctl = 1 ;
uint8_t ttl = 0 ;
uint16_t src = primary_element_address ;
uint16_t dest = 0 ; // unassigned address
uint32_t seq = mesh_lower_transport_next_seq ( ) ;
uint8_t nid = mesh_network_nid ( received_network_pdu ) ;
uint16_t netkey_index = received_network_pdu - > netkey_index ;
printf ( " netkey index 0x%02x \n " , netkey_index ) ;
network_pdu = btstack_memory_mesh_network_pdu_get ( ) ;
int pos = 0 ;
data [ pos + + ] = MESH_PROXY_CONFIGURATION_MESSAGE_OPCODE_FILTER_STATUS ;
data [ pos + + ] = proxy_configuration_filter_type ;
big_endian_store_16 ( data , pos , proxy_configuration_filter_list_len ) ;
mesh_network_setup_pdu ( network_pdu , netkey_index , nid , ctl , ttl , seq , src , dest , data , sizeof ( data ) ) ;
mesh_network_encrypt_proxy_message ( network_pdu , & request_can_send_now_proxy_configuration_callback_handler ) ;
// received_network_pdu is processed
btstack_memory_mesh_network_pdu_free ( received_network_pdu ) ;
break ;
}
default :
printf ( " proxy config not implemented, opcode %d \n " , opcode ) ;
break ;
}
break ;
case MESH_NETWORK_PDU_SENT :
// printf("test MESH_PROXY_PDU_SENT\n");
// mesh_lower_transport_received_mesage(MESH_NETWORK_PDU_SENT, network_pdu);
break ;
default :
break ;
}
}
2019-06-06 11:33:26 +02:00
// Test configuration
static mesh_model_t mesh_configuration_server_model ;
static mesh_model_t mesh_health_server_model ;
static mesh_model_t mesh_vendor_model ;
2019-06-06 12:45:19 +02:00
static mesh_model_t mesh_generic_on_off_server_model ;
2019-06-06 11:33:26 +02:00
2018-10-05 15:13:34 +02:00
int btstack_main ( void ) ;
int btstack_main ( void )
{
// register for HCI events
hci_event_callback_registration . callback = & packet_handler ;
hci_add_event_handler ( & hci_event_callback_registration ) ;
// console
btstack_stdin_setup ( stdin_process ) ;
// crypto
btstack_crypto_init ( ) ;
2019-05-08 16:23:08 +02:00
// l2cap
l2cap_init ( ) ;
// setup le device db
le_device_db_init ( ) ;
2018-10-05 15:13:34 +02:00
//
sm_init ( ) ;
// mesh
adv_bearer_init ( ) ;
2019-06-03 17:06:43 +02:00
// setup connectable advertisments
bd_addr_t null_addr ;
memset ( null_addr , 0 , 6 ) ;
uint8_t adv_type = 0 ; // AFV_IND
uint16_t adv_int_min = 0x0030 ;
uint16_t adv_int_max = 0x0030 ;
adv_bearer_advertisements_set_params ( adv_int_min , adv_int_max , adv_type , 0 , null_addr , 0x07 , 0x00 ) ;
2019-05-08 16:23:08 +02:00
// setup ATT server
att_server_init ( profile_data , NULL , NULL ) ;
2019-05-08 17:38:18 +02:00
// Setup GATT bearer
gatt_bearer_init ( ) ;
2019-05-23 18:16:18 +02:00
gatt_bearer_register_for_mesh_network_pdu ( & mesh_proxy_packet_handler_network_pdu ) ;
gatt_bearer_register_for_mesh_beacon ( & mesh_proxy_packet_handler_beacon ) ;
2019-05-08 17:38:18 +02:00
gatt_bearer_register_for_mesh_proxy_configuration ( & packet_handler_for_mesh_proxy_configuration ) ;
mesh_network_set_proxy_message_handler ( proxy_configuration_message_handler ) ;
2019-05-08 18:31:29 +02:00
# ifdef ENABLE_MESH_ADV_BEARER
2019-05-08 17:38:18 +02:00
// Setup Unprovisioned Device Beacon
2019-03-27 21:23:47 +01:00
beacon_init ( ) ;
2018-10-05 15:13:34 +02:00
beacon_register_for_unprovisioned_device_beacons ( & mesh_unprovisioned_beacon_handler ) ;
2019-05-08 18:31:29 +02:00
# endif
2018-10-05 15:13:34 +02:00
// Provisioning in device role
provisioning_device_init ( device_uuid ) ;
2019-05-23 18:16:18 +02:00
provisioning_device_register_packet_handler ( & mesh_provisioning_message_handler ) ;
2018-10-05 15:13:34 +02:00
2018-11-02 15:50:26 +01:00
// Network layer
mesh_network_init ( ) ;
2018-12-04 11:03:09 +01:00
// Transport layers (lower + upper))
mesh_transport_init ( ) ;
2019-04-22 19:44:56 +02:00
mesh_upper_transport_register_access_message_handler ( & mesh_access_message_process_handler ) ;
2018-11-16 10:12:06 +01:00
2019-06-10 20:05:39 +02:00
// Access layer
mesh_access_init ( ) ;
2019-01-15 17:22:12 +01:00
// PTS Virtual Address Label UUID - without Config Model, PTS uses our device uuid
btstack_parse_hex ( " 001BDC0810210B0E0A0C000B0E0A0C00 " , 16 , label_uuid ) ;
pts_proxy_dst = mesh_virtual_address_register ( label_uuid , 0x9779 ) ;
2019-06-06 11:33:26 +02:00
// Access layer - add Primary Element to list of elements - should be hid in e.g mesh_access_init()
mesh_element_add ( mesh_primary_element ( ) ) ;
// Setup Primary Element
mesh_element_t * primary_element = mesh_primary_element ( ) ;
// Loc - bottom - https://www.bluetooth.com/specifications/assigned-numbers/gatt-namespace-descriptors
primary_element - > loc = 0x0103 ;
2019-01-15 17:22:12 +01:00
2019-06-06 11:33:26 +02:00
// Setup models
mesh_configuration_server_model . model_identifier = mesh_model_get_model_identifier_bluetooth_sig ( MESH_SIG_MODEL_ID_CONFIGURATION_SERVER ) ;
2019-04-28 09:33:29 +02:00
mesh_model_reset_appkeys ( & mesh_configuration_server_model ) ;
2019-06-10 17:56:58 +02:00
mesh_configuration_server_model . operations = mesh_configuration_server_model_operations ;
2019-06-06 11:33:26 +02:00
mesh_element_add_model ( primary_element , & mesh_configuration_server_model ) ;
2019-04-28 09:33:29 +02:00
2019-06-06 12:17:37 +02:00
mesh_health_server_model . model_identifier = mesh_model_get_model_identifier_bluetooth_sig ( MESH_SIG_MODEL_ID_HEALTH_SERVER ) ;
2019-04-28 21:59:26 +02:00
mesh_model_reset_appkeys ( & mesh_health_server_model ) ;
2019-06-06 11:33:26 +02:00
mesh_element_add_model ( primary_element , & mesh_health_server_model ) ;
2019-04-28 21:59:26 +02:00
2019-06-06 12:45:19 +02:00
mesh_generic_on_off_server_model . model_identifier = mesh_model_get_model_identifier_bluetooth_sig ( MESH_SIG_MODEL_ID_GENERIC_ON_OFF_SERVER ) ;
mesh_model_reset_appkeys ( & mesh_generic_on_off_server_model ) ;
mesh_element_add_model ( primary_element , & mesh_generic_on_off_server_model ) ;
2019-06-06 12:17:37 +02:00
mesh_vendor_model . model_identifier = mesh_model_get_model_identifier ( BLUETOOTH_COMPANY_ID_BLUEKITCHEN_GMBH , MESH_BLUEKITCHEN_MODEL_ID_TEST_SERVER ) ;
2019-04-28 21:59:26 +02:00
mesh_model_reset_appkeys ( & mesh_vendor_model ) ;
2019-06-06 11:33:26 +02:00
mesh_element_add_model ( primary_element , & mesh_vendor_model ) ;
2019-04-28 21:59:26 +02:00
// calc s1('vtad')7
2019-04-18 18:41:16 +02:00
// btstack_crypto_aes128_cmac_zero(&salt_request, 4, (const uint8_t *) "vtad", salt_hash, salt_complete, NULL);
// calc virtual address hash
// mesh_virtual_address(&salt_request, label_uuid, &virtual_address_hash, virtual_address_complete, NULL);
2018-11-06 21:25:15 +01:00
2019-04-23 17:13:07 +02:00
// calc network key derivative
2019-04-24 10:40:15 +02:00
// btstack_parse_hex("7dd7364cd842ad18c17c2b820c84c3d6", 16, test_network_key.net_key); // spec sample data
// btstack_parse_hex("B72892443F28F28FD61F4B63FF86F695", 16, test_network_key.net_key);
2019-04-23 17:13:07 +02:00
// printf("NetKey: ");
// printf_hexdump(test_network_key.net_key, 16);
// mesh_network_key_derive(&salt_request, &test_network_key, key_derived, NULL);
2018-10-05 15:13:34 +02:00
btstack_parse_hex ( pts_device_uuid_string , 16 , pts_device_uuid ) ;
btstack_print_hex ( pts_device_uuid , 16 , 0 ) ;
// turn on!
hci_power_control ( HCI_POWER_ON ) ;
return 0 ;
}
/* EXAMPLE_END */