mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-02-04 15:39:59 +00:00
mesh: move security beacon handling to mesh
This commit is contained in:
parent
670cd995ca
commit
8639e30d7e
123
src/mesh/mesh.c
123
src/mesh/mesh.c
@ -818,6 +818,126 @@ static void mesh_persist_iv_index_and_sequence_number(void){
|
||||
}
|
||||
}
|
||||
|
||||
static void mesh_access_secure_network_beacon_handler(uint8_t packet_type, uint16_t channel, uint8_t * packet, uint16_t size){
|
||||
UNUSED(channel);
|
||||
UNUSED(size);
|
||||
|
||||
if (packet_type != MESH_BEACON_PACKET) return;
|
||||
|
||||
// lookup subnet and netkey by network id
|
||||
uint8_t * beacon_network_id = &packet[2];
|
||||
mesh_subnet_iterator_t it;
|
||||
mesh_subnet_iterator_init(&it);
|
||||
mesh_subnet_t * subnet = NULL;
|
||||
uint8_t new_key = 0;
|
||||
while (mesh_subnet_iterator_has_more(&it)){
|
||||
mesh_subnet_t * item = mesh_subnet_iterator_get_next(&it);
|
||||
if (memcmp(item->old_key->network_id, beacon_network_id, 8) == 0 ) {
|
||||
subnet = item;
|
||||
}
|
||||
if (item->new_key != NULL && memcmp(item->new_key->network_id, beacon_network_id, 8) == 0 ) {
|
||||
subnet = item;
|
||||
new_key = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (subnet == NULL) return;
|
||||
|
||||
uint8_t flags = packet[1];
|
||||
|
||||
// Key refresh via secure network beacons that are authenticated with new netkey
|
||||
if (new_key){
|
||||
// either first or second phase (in phase 0, new key is not set)
|
||||
int key_refresh_flag = flags & 1;
|
||||
if (key_refresh_flag){
|
||||
// transition to phase 3 from either phase 1 or 2
|
||||
switch (subnet->key_refresh){
|
||||
case MESH_KEY_REFRESH_FIRST_PHASE:
|
||||
case MESH_KEY_REFRESH_SECOND_PHASE:
|
||||
mesh_access_key_refresh_revoke_keys(subnet);
|
||||
subnet->key_refresh = MESH_KEY_REFRESH_NOT_ACTIVE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// transition to phase 2 from either phase 1
|
||||
switch (subnet->key_refresh){
|
||||
case MESH_KEY_REFRESH_FIRST_PHASE:
|
||||
// -- update state
|
||||
subnet->key_refresh = MESH_KEY_REFRESH_SECOND_PHASE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IV Update
|
||||
|
||||
int beacon_iv_update_active = flags & 2;
|
||||
int local_iv_update_active = mesh_iv_update_active();
|
||||
uint32_t beacon_iv_index = big_endian_read_32(packet, 10);
|
||||
uint32_t local_iv_index = mesh_get_iv_index();
|
||||
|
||||
int32_t iv_index_delta = (int32_t)(beacon_iv_index - local_iv_index);
|
||||
|
||||
// "If a node in Normal Operation receives a Secure Network beacon with an IV index less than the last known IV Index or greater than
|
||||
// the last known IV Index + 42, the Secure Network beacon shall be ignored."
|
||||
if (iv_index_delta < 0 || iv_index_delta > 42){
|
||||
return;
|
||||
}
|
||||
|
||||
// "If a node in Normal Operation receives a Secure Network beacon with an IV index equal to the last known IV index+1 and
|
||||
// the IV Update Flag set to 0, the node may update its IV without going to the IV Update in Progress state, or it may initiate
|
||||
// an IV Index Recovery procedure (Section 3.10.6), or it may ignore the Secure Network beacon. The node makes the choice depending
|
||||
// on the time since last IV update and the likelihood that the node has missed the Secure Network beacons with the IV update Flag set to 1.""
|
||||
if (local_iv_update_active == 0 && beacon_iv_update_active == 0 && iv_index_delta == 1){
|
||||
// instant iv update
|
||||
mesh_set_iv_index( beacon_iv_index );
|
||||
// store updated iv index
|
||||
mesh_store_iv_index_and_sequence_number();
|
||||
return;
|
||||
}
|
||||
|
||||
// "If this node is a member of a primary subnet and receives a Secure Network beacon on a secondary subnet with an IV Index greater than
|
||||
// the last known IV Index of the primary subnet, the Secure Network beacon shall be ignored."
|
||||
int member_of_primary_subnet = mesh_subnet_get_by_netkey_index(0) != NULL;
|
||||
int beacon_on_secondary_subnet = subnet->netkey_index != 0;
|
||||
if (member_of_primary_subnet && beacon_on_secondary_subnet && iv_index_delta > 0){
|
||||
return;
|
||||
}
|
||||
|
||||
// "If a node in Normal Operation receives a Secure Network beacon with an IV index greater than the last known IV Index + 1..."
|
||||
// "... it may initiate an IV Index Recovery procedure, see Section 3.10.6."
|
||||
if (local_iv_update_active == 0 && iv_index_delta > 1){
|
||||
// "Upon receiving and successfully authenticating a Secure Network beacon for a primary subnet... "
|
||||
int beacon_on_primary_subnet = subnet->netkey_index == 0;
|
||||
if (!beacon_on_primary_subnet) return;
|
||||
// "... whose IV Index is 1 or more higher than the current known IV Index, the node shall "
|
||||
// " set its current IV Index and its current IV Update procedure state from the values in this Secure Network beacon."
|
||||
mesh_iv_index_recovered(beacon_iv_update_active, beacon_iv_index);
|
||||
// store updated iv index if in normal mode
|
||||
if (beacon_iv_update_active == 0){
|
||||
mesh_store_iv_index_and_sequence_number();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (local_iv_update_active == 0){
|
||||
if (beacon_iv_update_active){
|
||||
mesh_trigger_iv_update();
|
||||
}
|
||||
} else {
|
||||
if (beacon_iv_update_active == 0){
|
||||
// " At the point of transition, the node shall reset the sequence number to 0x000000."
|
||||
mesh_sequence_number_set(0);
|
||||
mesh_iv_update_completed();
|
||||
// store updated iv index
|
||||
mesh_store_iv_index_and_sequence_number();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t mesh_tag_for_prov_data(void){
|
||||
return ((uint32_t) 'P' << 24) | ((uint32_t) 'R' << 16) | ((uint32_t) 'O' << 8) | (uint32_t)'V';
|
||||
@ -1009,6 +1129,9 @@ void mesh_init(void){
|
||||
// Add mandatory models: Config Server and Health Server
|
||||
mesh_node_setup_default_models();
|
||||
|
||||
// register for secure network beacons
|
||||
beacon_register_for_secure_network_beacons(&mesh_access_secure_network_beacon_handler);
|
||||
|
||||
// register for seq number updates
|
||||
mesh_sequence_number_set_update_callback(&mesh_persist_iv_index_and_sequence_number);
|
||||
}
|
||||
|
@ -58,7 +58,6 @@
|
||||
#define MEST_TRANSACTION_TIMEOUT_MS 6000
|
||||
|
||||
static void mesh_access_message_process_handler(mesh_pdu_t * pdu);
|
||||
static void mesh_access_secure_network_beacon_handler(uint8_t packet_type, uint16_t channel, uint8_t * packet, uint16_t size);
|
||||
static void mesh_access_upper_transport_handler(mesh_transport_callback_type_t callback_type, mesh_transport_status_t status, mesh_pdu_t * pdu);
|
||||
static const mesh_operation_t * mesh_model_lookup_operation_by_opcode(mesh_model_t * model, uint32_t opcode);
|
||||
|
||||
@ -76,9 +75,6 @@ void mesh_access_init(void){
|
||||
// register with upper transport
|
||||
mesh_upper_transport_register_access_message_handler(&mesh_access_message_process_handler);
|
||||
mesh_upper_transport_set_higher_layer_handler(&mesh_access_upper_transport_handler);
|
||||
|
||||
// register for secure network beacons
|
||||
beacon_register_for_secure_network_beacons(&mesh_access_secure_network_beacon_handler);
|
||||
}
|
||||
|
||||
void mesh_access_emit_state_update_bool(btstack_packet_handler_t event_handler, uint8_t element_index, uint32_t model_identifier,
|
||||
@ -1067,123 +1063,3 @@ void mesh_access_state_changed(mesh_model_t * mesh_model){
|
||||
mesh_model_publication_run(NULL);
|
||||
}
|
||||
|
||||
static void mesh_access_secure_network_beacon_handler(uint8_t packet_type, uint16_t channel, uint8_t * packet, uint16_t size){
|
||||
UNUSED(channel);
|
||||
UNUSED(size);
|
||||
|
||||
if (packet_type != MESH_BEACON_PACKET) return;
|
||||
|
||||
// lookup subnet and netkey by network id
|
||||
uint8_t * beacon_network_id = &packet[2];
|
||||
mesh_subnet_iterator_t it;
|
||||
mesh_subnet_iterator_init(&it);
|
||||
mesh_subnet_t * subnet = NULL;
|
||||
uint8_t new_key = 0;
|
||||
while (mesh_subnet_iterator_has_more(&it)){
|
||||
mesh_subnet_t * item = mesh_subnet_iterator_get_next(&it);
|
||||
if (memcmp(item->old_key->network_id, beacon_network_id, 8) == 0 ) {
|
||||
subnet = item;
|
||||
}
|
||||
if (item->new_key != NULL && memcmp(item->new_key->network_id, beacon_network_id, 8) == 0 ) {
|
||||
subnet = item;
|
||||
new_key = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (subnet == NULL) return;
|
||||
|
||||
uint8_t flags = packet[1];
|
||||
|
||||
// Key refresh via secure network beacons that are authenticated with new netkey
|
||||
if (new_key){
|
||||
// either first or second phase (in phase 0, new key is not set)
|
||||
int key_refresh_flag = flags & 1;
|
||||
if (key_refresh_flag){
|
||||
// transition to phase 3 from either phase 1 or 2
|
||||
switch (subnet->key_refresh){
|
||||
case MESH_KEY_REFRESH_FIRST_PHASE:
|
||||
case MESH_KEY_REFRESH_SECOND_PHASE:
|
||||
mesh_access_key_refresh_revoke_keys(subnet);
|
||||
subnet->key_refresh = MESH_KEY_REFRESH_NOT_ACTIVE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// transition to phase 2 from either phase 1
|
||||
switch (subnet->key_refresh){
|
||||
case MESH_KEY_REFRESH_FIRST_PHASE:
|
||||
// -- update state
|
||||
subnet->key_refresh = MESH_KEY_REFRESH_SECOND_PHASE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IV Update
|
||||
|
||||
int beacon_iv_update_active = flags & 2;
|
||||
int local_iv_update_active = mesh_iv_update_active();
|
||||
uint32_t beacon_iv_index = big_endian_read_32(packet, 10);
|
||||
uint32_t local_iv_index = mesh_get_iv_index();
|
||||
|
||||
int32_t iv_index_delta = (int32_t)(beacon_iv_index - local_iv_index);
|
||||
|
||||
// "If a node in Normal Operation receives a Secure Network beacon with an IV index less than the last known IV Index or greater than
|
||||
// the last known IV Index + 42, the Secure Network beacon shall be ignored."
|
||||
if (iv_index_delta < 0 || iv_index_delta > 42){
|
||||
return;
|
||||
}
|
||||
|
||||
// "If a node in Normal Operation receives a Secure Network beacon with an IV index equal to the last known IV index+1 and
|
||||
// the IV Update Flag set to 0, the node may update its IV without going to the IV Update in Progress state, or it may initiate
|
||||
// an IV Index Recovery procedure (Section 3.10.6), or it may ignore the Secure Network beacon. The node makes the choice depending
|
||||
// on the time since last IV update and the likelihood that the node has missed the Secure Network beacons with the IV update Flag set to 1.""
|
||||
if (local_iv_update_active == 0 && beacon_iv_update_active == 0 && iv_index_delta == 1){
|
||||
// instant iv update
|
||||
mesh_set_iv_index( beacon_iv_index );
|
||||
// store updated iv index
|
||||
mesh_store_iv_index_and_sequence_number();
|
||||
return;
|
||||
}
|
||||
|
||||
// "If this node is a member of a primary subnet and receives a Secure Network beacon on a secondary subnet with an IV Index greater than
|
||||
// the last known IV Index of the primary subnet, the Secure Network beacon shall be ignored."
|
||||
int member_of_primary_subnet = mesh_subnet_get_by_netkey_index(0) != NULL;
|
||||
int beacon_on_secondary_subnet = subnet->netkey_index != 0;
|
||||
if (member_of_primary_subnet && beacon_on_secondary_subnet && iv_index_delta > 0){
|
||||
return;
|
||||
}
|
||||
|
||||
// "If a node in Normal Operation receives a Secure Network beacon with an IV index greater than the last known IV Index + 1..."
|
||||
// "... it may initiate an IV Index Recovery procedure, see Section 3.10.6."
|
||||
if (local_iv_update_active == 0 && iv_index_delta > 1){
|
||||
// "Upon receiving and successfully authenticating a Secure Network beacon for a primary subnet... "
|
||||
int beacon_on_primary_subnet = subnet->netkey_index == 0;
|
||||
if (!beacon_on_primary_subnet) return;
|
||||
// "... whose IV Index is 1 or more higher than the current known IV Index, the node shall "
|
||||
// " set its current IV Index and its current IV Update procedure state from the values in this Secure Network beacon."
|
||||
mesh_iv_index_recovered(beacon_iv_update_active, beacon_iv_index);
|
||||
// store updated iv index if in normal mode
|
||||
if (beacon_iv_update_active == 0){
|
||||
mesh_store_iv_index_and_sequence_number();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (local_iv_update_active == 0){
|
||||
if (beacon_iv_update_active){
|
||||
mesh_trigger_iv_update();
|
||||
}
|
||||
} else {
|
||||
if (beacon_iv_update_active == 0){
|
||||
// " At the point of transition, the node shall reset the sequence number to 0x000000."
|
||||
mesh_sequence_number_set(0);
|
||||
mesh_iv_update_completed();
|
||||
// store updated iv index
|
||||
mesh_store_iv_index_and_sequence_number();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user