Files
EPD-nRF5/components/ble/peer_manager/peer_manager.c
Shuanglei Tao f353d23368 Initial commit
2024-11-11 15:35:36 +08:00

619 lines
19 KiB
C

/* Copyright (C) 2015 Nordic Semiconductor. All Rights Reserved.
*
* The information contained herein is property of Nordic Semiconductor ASA.
* SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
*
* Licensees are granted free, non-transferable use of the information. NO
* WARRANTY of ANY KIND is provided. This heading must NOT be removed from
* the file.
*
*/
#include "peer_manager.h"
#include <string.h>
#include "security_manager.h"
#include "gatt_cache_manager.h"
#include "peer_database.h"
#include "id_manager.h"
#include "ble_conn_state.h"
#define MAX_REGISTRANTS 3 /**< The number of user that can register with the module. */
/**@brief Macro for verifying that the module is initialized. It will cause the function to return
* @ref NRF_ERROR_INVALID_STATE if not.
*/
#define VERIFY_MODULE_INITIALIZED() \
do \
{ \
if (!m_pm.initialized) \
{ \
return NRF_ERROR_INVALID_STATE; \
} \
} while(0)
/**@brief Macro for verifying that the module is initialized. It will cause the function to return
* if not.
*/
#define VERIFY_MODULE_INITIALIZED_VOID()\
do \
{ \
if (!m_pm.initialized) \
{ \
return; \
} \
} while(0)
/**@brief Macro for verifying that the module is initialized. It will cause the function to return
* if not.
*
* @param[in] param The variable to check if is NULL.
*/
#define VERIFY_PARAM_NOT_NULL(param) \
do \
{ \
if (param == NULL) \
{ \
return NRF_ERROR_NULL; \
} \
} while(0)
typedef struct
{
bool initialized;
pm_evt_handler_t evt_handlers[MAX_REGISTRANTS];
uint8_t n_registrants;
ble_conn_state_user_flag_id_t pairing_flag_id;
ble_conn_state_user_flag_id_t bonding_flag_id;
} pm_t;
static pm_t m_pm;
static void evt_send(pm_evt_t * p_event)
{
for (int i = 0; i < m_pm.n_registrants; i++)
{
m_pm.evt_handlers[i](p_event);
}
}
void pdb_evt_handler(pdb_evt_t const * p_evt)
{
bool send_evt = true;
pm_evt_t pm_evt;
memset(&pm_evt, 0, sizeof(pm_evt_t));
pm_evt.peer_id = p_evt->peer_id;
pm_evt.conn_handle = im_conn_handle_get(pm_evt.peer_id);
switch (p_evt->evt_id)
{
case PDB_EVT_WRITE_BUF_STORED:
pm_evt.evt_id = PM_EVT_PEER_DATA_UPDATED;
pm_evt.params.peer_data_updated_evt.data_id = p_evt->data_id;
pm_evt.params.peer_data_updated_evt.action = PM_PEER_DATA_ACTION_UPDATE;
break;
case PDB_EVT_RAW_STORED:
pm_evt.evt_id = PM_EVT_PEER_DATA_UPDATED;
pm_evt.params.peer_data_updated_evt.data_id = p_evt->data_id;
pm_evt.params.peer_data_updated_evt.action = PM_PEER_DATA_ACTION_UPDATE;
break;
case PDB_EVT_RAW_STORE_FAILED:
pm_evt.evt_id = PM_EVT_PEER_DATA_UPDATE_FAILED;
pm_evt.params.peer_data_update_failed_evt.data_id = p_evt->data_id;
pm_evt.params.peer_data_update_failed_evt.action = PM_PEER_DATA_ACTION_UPDATE;
pm_evt.params.peer_data_update_failed_evt.error = NRF_ERROR_INTERNAL;
break;
case PDB_EVT_CLEARED:
pm_evt.evt_id = PM_EVT_PEER_DATA_UPDATED;
pm_evt.params.peer_data_updated_evt.data_id = p_evt->data_id;
pm_evt.params.peer_data_updated_evt.action = PM_PEER_DATA_ACTION_CLEAR;
break;
case PDB_EVT_CLEAR_FAILED:
pm_evt.evt_id = PM_EVT_PEER_DATA_UPDATE_FAILED;
pm_evt.params.peer_data_update_failed_evt.data_id = p_evt->data_id;
pm_evt.params.peer_data_update_failed_evt.action = PM_PEER_DATA_ACTION_CLEAR;
pm_evt.params.peer_data_update_failed_evt.error = NRF_ERROR_INTERNAL;
break;
case PDB_EVT_COMPRESSED:
send_evt = false;
// Do nothing
break;
case PDB_EVT_ERROR_NO_MEM:
pm_evt.evt_id = PM_EVT_STORAGE_FULL;
break;
case PDB_EVT_ERROR_UNEXPECTED:
pm_evt.evt_id = PM_EVT_ERROR_UNEXPECTED;
break;
default:
/* No implementation necessary. */
break;
}
if (send_evt)
{
evt_send(&pm_evt);
}
}
void sm_evt_handler(sm_evt_t const * p_sm_evt)
{
bool find_peer_id = true;
bool send_evt = true;
pm_evt_t pm_evt;
memset(&pm_evt, 0, sizeof(pm_evt_t));
pm_evt.conn_handle = p_sm_evt->conn_handle;
switch (p_sm_evt->evt_id)
{
case SM_EVT_SLAVE_SECURITY_REQ:
find_peer_id = false;
send_evt = false;
break;
case SM_EVT_SEC_PROCEDURE_START:
{
bool pairing = p_sm_evt->params.sec_procedure_start.procedure
!= PM_LINK_SECURED_PROCEDURE_ENCRYPTION;
bool bonding = p_sm_evt->params.sec_procedure_start.procedure
== PM_LINK_SECURED_PROCEDURE_BONDING;
find_peer_id = false;
send_evt = false;
ble_conn_state_user_flag_set(p_sm_evt->conn_handle, m_pm.pairing_flag_id, pairing);
ble_conn_state_user_flag_set(p_sm_evt->conn_handle, m_pm.bonding_flag_id, bonding);
break;
}
case SM_EVT_PAIRING_SUCCESS:
pm_evt.evt_id = PM_EVT_LINK_SECURED;
pm_evt.params.link_secured_evt.procedure =
p_sm_evt->params.pairing_success.bonded
? PM_LINK_SECURED_PROCEDURE_BONDING
: PM_LINK_SECURED_PROCEDURE_PAIRING;
ble_conn_state_user_flag_set(p_sm_evt->conn_handle, m_pm.pairing_flag_id, true);
ble_conn_state_user_flag_set(p_sm_evt->conn_handle,
m_pm.bonding_flag_id,
p_sm_evt->params.pairing_success.bonded
);
break;
case SM_EVT_PAIRING_FAIL:
pm_evt.evt_id = PM_EVT_LINK_SECURE_FAILED;
pm_evt.params.link_secure_failed_evt.procedure =
ble_conn_state_user_flag_get(p_sm_evt->conn_handle, m_pm.bonding_flag_id)
? PM_LINK_SECURED_PROCEDURE_BONDING
: PM_LINK_SECURED_PROCEDURE_PAIRING;
pm_evt.params.link_secure_failed_evt.error.error_type = PM_ERROR_TYPE_SEC_STATUS;
pm_evt.params.link_secure_failed_evt.error.error_src
= p_sm_evt->params.pairing_failed.error_src;
pm_evt.params.link_secure_failed_evt.error.error.sec_status
= p_sm_evt->params.pairing_failed.auth_status;
break;
case SM_EVT_LINK_ENCRYPTION_UPDATE:
if (!ble_conn_state_user_flag_get(p_sm_evt->conn_handle, m_pm.pairing_flag_id))
{
pm_evt.evt_id = PM_EVT_LINK_SECURED;
pm_evt.params.link_secured_evt.procedure = PM_LINK_SECURED_PROCEDURE_ENCRYPTION;
}
else
{
find_peer_id = false;
send_evt = false;
}
break;
case SM_EVT_LINK_ENCRYPTION_FAILED:
pm_evt.evt_id = PM_EVT_LINK_SECURE_FAILED;
pm_evt.params.link_secure_failed_evt.procedure
= PM_LINK_SECURED_PROCEDURE_ENCRYPTION;
pm_evt.params.link_secure_failed_evt.error.error_type
= PM_ERROR_TYPE_PM_SEC_ERROR;
pm_evt.params.link_secure_failed_evt.error.error_src
= p_sm_evt->params.link_encryption_failed.error_src;
pm_evt.params.link_secure_failed_evt.error.error.sec_status
= p_sm_evt->params.link_encryption_failed.error;
break;
case SM_EVT_BONDING_INFO_STORED:
pm_evt.evt_id = PM_EVT_PEER_DATA_UPDATED;
pm_evt.peer_id = p_sm_evt->params.bonding_info_stored.peer_id;
pm_evt.params.peer_data_updated_evt.data_id = PM_PEER_DATA_ID_BONDING;
pm_evt.params.peer_data_updated_evt.action = PM_PEER_DATA_ACTION_UPDATE;
find_peer_id = false;
break;
case SM_EVT_ERROR_BONDING_INFO:
pm_evt.evt_id = PM_EVT_PEER_DATA_UPDATE_FAILED;
pm_evt.peer_id = p_sm_evt->params.error_bonding_info.peer_id;
pm_evt.params.peer_data_update_failed_evt.data_id = PM_PEER_DATA_ID_BONDING;
pm_evt.params.peer_data_update_failed_evt.action = PM_PEER_DATA_ACTION_UPDATE;
pm_evt.params.peer_data_update_failed_evt.error
= p_sm_evt->params.error_bonding_info.error;
find_peer_id = false;
break;
case SM_EVT_ERROR_UNEXPECTED:
pm_evt.evt_id = PM_EVT_ERROR_UNEXPECTED;
pm_evt.params.error_unexpected_evt.error = p_sm_evt->params.error_unexpected.error;
break;
case SM_EVT_ERROR_NO_MEM:
pm_evt.evt_id = PM_EVT_STORAGE_FULL;
break;
case SM_EVT_ERROR_SMP_TIMEOUT:
pm_evt.evt_id = PM_EVT_LINK_SECURE_FAILED;
pm_evt.params.link_secure_failed_evt.procedure
= ble_conn_state_user_flag_get(p_sm_evt->conn_handle, m_pm.bonding_flag_id)
? PM_LINK_SECURED_PROCEDURE_BONDING
: PM_LINK_SECURED_PROCEDURE_PAIRING;
pm_evt.params.link_secure_failed_evt.error.error_type = PM_ERROR_TYPE_PM_SEC_ERROR;
pm_evt.params.link_secure_failed_evt.error.error_src = BLE_GAP_SEC_STATUS_SOURCE_LOCAL;
pm_evt.params.link_secure_failed_evt.error.error.pm_sec_error
= PM_SEC_ERROR_SMP_TIMEOUT;
break;
}
if (find_peer_id)
{
pm_evt.peer_id = im_peer_id_get_by_conn_handle(p_sm_evt->conn_handle);
}
if (send_evt)
{
evt_send(&pm_evt);
}
}
void gcm_evt_handler(gcm_evt_t const * p_evt)
{
bool send_evt = true;
pm_evt_t pm_evt;
memset(&pm_evt, 0, sizeof(pm_evt_t));
pm_evt.peer_id = p_evt->peer_id;
pm_evt.conn_handle = im_conn_handle_get(pm_evt.peer_id);
switch (p_evt->evt_id)
{
case GCM_EVT_LOCAL_DB_CACHE_STORED:
pm_evt.evt_id = PM_EVT_PEER_DATA_UPDATED;
pm_evt.params.peer_data_updated_evt.action = PM_PEER_DATA_ACTION_UPDATE;
pm_evt.params.peer_data_updated_evt.data_id = PM_PEER_DATA_ID_GATT_LOCAL;
break;
case GCM_EVT_LOCAL_DB_CACHE_UPDATED:
pm_evt.evt_id = PM_EVT_PEER_DATA_UPDATED;
pm_evt.params.peer_data_updated_evt.action = PM_PEER_DATA_ACTION_UPDATE;
pm_evt.params.peer_data_updated_evt.data_id = PM_PEER_DATA_ID_GATT_LOCAL;
break;
case GCM_EVT_LOCAL_DB_CACHE_APPLIED:
pm_evt.evt_id = PM_EVT_LOCAL_DB_CACHE_APPLIED;
pm_evt.params.peer_data_updated_evt.action = PM_PEER_DATA_ACTION_UPDATE;
pm_evt.params.peer_data_updated_evt.data_id = PM_PEER_DATA_ID_GATT_LOCAL;
break;
case GCM_EVT_ERROR_LOCAL_DB_CACHE_APPLY:
pm_evt.evt_id = PM_EVT_ERROR_LOCAL_DB_CACHE_APPLY;
pm_evt.params.peer_data_updated_evt.action = PM_PEER_DATA_ACTION_UPDATE;
pm_evt.params.peer_data_updated_evt.data_id = PM_PEER_DATA_ID_GATT_LOCAL;
break;
case GCM_EVT_REMOTE_DB_CACHE_UPDATED:
pm_evt.evt_id = PM_EVT_PEER_DATA_UPDATED;
pm_evt.params.peer_data_updated_evt.action = PM_PEER_DATA_ACTION_UPDATE;
pm_evt.params.peer_data_updated_evt.data_id = PM_PEER_DATA_ID_GATT_REMOTE;
break;
case GCM_EVT_SERVICE_CHANGED_INDICATION_SENT:
pm_evt.evt_id = PM_EVT_SERVICE_CHANGED_INDICATION_SENT;
break;
case GCM_EVT_ERROR_DATA_SIZE:
send_evt = false;
break;
case GCM_EVT_ERROR_STORAGE_FULL:
pm_evt.evt_id = PM_EVT_STORAGE_FULL;
break;
case GCM_EVT_ERROR_UNEXPECTED:
pm_evt.evt_id = PM_EVT_ERROR_UNEXPECTED;
pm_evt.params.error_unexpected_evt.error = p_evt->params.error_unexpected.error;
pm_evt.conn_handle = p_evt->params.error_unexpected.conn_handle;
break;
}
if (send_evt)
{
evt_send(&pm_evt);
}
}
void im_evt_handler(im_evt_t const * p_evt)
{
pm_evt_t pm_evt;
switch (p_evt->evt_id)
{
case IM_EVT_DUPLICATE_ID:
// Delete the duplicate data to free space and avoid finding old data when scanning in the future
pm_peer_delete(p_evt->params.duplicate_id.peer_id_2);
break;
case IM_EVT_BONDED_PEER_CONNECTED:
ble_conn_state_user_flag_set(p_evt->conn_handle, m_pm.bonding_flag_id, true);
memset(&pm_evt, 0, sizeof(pm_evt_t));
pm_evt.conn_handle = p_evt->conn_handle;
pm_evt.peer_id = im_peer_id_get_by_conn_handle(p_evt->conn_handle);
pm_evt.evt_id = PM_EVT_BONDED_PEER_CONNECTED;
evt_send(&pm_evt);
break;
}
}
void pm_ble_evt_handler(ble_evt_t * p_ble_evt)
{
VERIFY_MODULE_INITIALIZED_VOID();
im_ble_evt_handler(p_ble_evt);
sm_ble_evt_handler(p_ble_evt);
gcm_ble_evt_handler(p_ble_evt);
}
ret_code_t pm_init(void)
{
ret_code_t err_code;
err_code = pdb_register(pdb_evt_handler);
if (err_code != NRF_SUCCESS)
{
if (err_code != NRF_ERROR_INVALID_STATE)
{
err_code = NRF_ERROR_INTERNAL;
}
return err_code;
}
err_code = sm_register(sm_evt_handler);
if (err_code != NRF_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
err_code = gcm_init(gcm_evt_handler);
if (err_code != NRF_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
err_code = im_register(im_evt_handler);
if (err_code != NRF_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
m_pm.pairing_flag_id = ble_conn_state_user_flag_acquire();
if (m_pm.pairing_flag_id == BLE_CONN_STATE_USER_FLAG_INVALID)
{
return NRF_ERROR_INTERNAL;
}
m_pm.bonding_flag_id = ble_conn_state_user_flag_acquire();
if (m_pm.bonding_flag_id == BLE_CONN_STATE_USER_FLAG_INVALID)
{
return NRF_ERROR_INTERNAL;
}
m_pm.initialized = true;
return NRF_SUCCESS;
}
ret_code_t pm_register(pm_evt_handler_t event_handler)
{
VERIFY_MODULE_INITIALIZED();
if (m_pm.n_registrants >= MAX_REGISTRANTS)
{
return NRF_ERROR_NO_MEM;
}
m_pm.evt_handlers[m_pm.n_registrants] = event_handler;
m_pm.n_registrants += 1;
return NRF_SUCCESS;
}
ret_code_t pm_sec_params_set(ble_gap_sec_params_t * p_sec_params)
{
VERIFY_MODULE_INITIALIZED();
ret_code_t err_code;
err_code = sm_sec_params_set(p_sec_params);
if (err_code == NRF_ERROR_INVALID_STATE)
{
err_code = NRF_ERROR_INTERNAL;
}
return err_code;
}
ret_code_t pm_link_secure(uint16_t conn_handle, bool force_repairing)
{
VERIFY_MODULE_INITIALIZED();
ret_code_t err_code;
err_code = sm_link_secure(conn_handle, force_repairing);
return err_code;
}
ret_code_t pm_sec_params_reply(uint16_t conn_handle, ble_gap_sec_params_t * p_sec_params)
{
return NRF_SUCCESS;
}
void pm_local_database_has_changed(void)
{
gcm_local_database_has_changed();
}
ret_code_t pm_wlist_create(pm_peer_id_t * p_peer_ids,
uint8_t n_peer_ids,
ble_gap_whitelist_t * p_whitelist)
{
return im_wlist_create(p_peer_ids, n_peer_ids, p_whitelist);
}
ret_code_t pm_wlist_set(ble_gap_whitelist_t * p_whitelist)
{
return im_wlist_set(p_whitelist);
}
ret_code_t pm_link_status_get(uint16_t conn_handle, pm_link_status_t * p_link_status)
{
VERIFY_PARAM_NOT_NULL(p_link_status);
if (conn_handle == BLE_CONN_HANDLE_INVALID)
{
return NRF_ERROR_INVALID_PARAM;
}
// Read the bonded status from the user flag that is maintained by events.
p_link_status->bonded = ble_conn_state_user_flag_get(conn_handle, m_pm.bonding_flag_id);
// Read the connected, encrypted and mitm status from the connection state module.
p_link_status->connected = ble_conn_state_valid(conn_handle);
p_link_status->encrypted = ble_conn_state_encrypted(conn_handle);
p_link_status->mitm_protected = ble_conn_state_mitm_protected(conn_handle);
return NRF_SUCCESS;
}
ret_code_t pm_peer_id_get(uint16_t conn_handle, pm_peer_id_t * p_peer_id)
{
VERIFY_PARAM_NOT_NULL(p_peer_id);
* p_peer_id = im_peer_id_get_by_conn_handle(conn_handle);
return NRF_SUCCESS;
}
ret_code_t pm_conn_handle_get(pm_peer_id_t peer_id, uint16_t * p_conn_handle)
{
VERIFY_PARAM_NOT_NULL(p_conn_handle);
* p_conn_handle = im_conn_handle_get(peer_id);
return NRF_SUCCESS;
}
uint32_t pm_n_peers(void)
{
return pdb_n_peers();
}
pm_peer_id_t pm_next_peer_id_get(pm_peer_id_t prev_peer_id)
{
return pdb_next_peer_id_get(prev_peer_id);
}
ret_code_t pm_peer_data_get(pm_peer_id_t peer_id, pm_peer_data_id_t data_id, pm_peer_data_t * p_peer_data)
{
return pdb_raw_read(peer_id, data_id, p_peer_data);
}
ret_code_t pm_peer_data_store(pm_peer_id_t peer_id,
pm_peer_data_const_t * p_peer_data,
pm_store_token_t * p_token)
{
return pdb_raw_store(peer_id, p_peer_data, p_token);
}
ret_code_t pm_peer_data_clear(pm_peer_id_t peer_id, pm_peer_data_id_t data_id)
{
ret_code_t err_code;
VERIFY_MODULE_INITIALIZED();
if (data_id == PM_PEER_DATA_ID_BONDING || data_id == PM_PEER_DATA_ID_INVALID)
{
return NRF_ERROR_INVALID_PARAM;
}
err_code = pdb_clear(peer_id, data_id);
return err_code;
}
ret_code_t pm_peer_new(pm_peer_data_bonding_t * p_bonding_data,
pm_peer_id_t * p_new_peer_id,
pm_store_token_t * p_token)
{
VERIFY_MODULE_INITIALIZED();
VERIFY_PARAM_NOT_NULL(p_bonding_data);
VERIFY_PARAM_NOT_NULL(p_new_peer_id);
* p_new_peer_id = pdb_peer_allocate();
if (* p_new_peer_id == PM_PEER_ID_INVALID)
{
return NRF_ERROR_NO_MEM;
}
pm_peer_data_const_t peer_data;
memset(&peer_data, 0, sizeof(pm_peer_data_const_t));
peer_data.length_words = PM_BONDING_DATA_N_WORDS();
peer_data.data_type = PM_PEER_DATA_ID_BONDING;
peer_data.data.p_bonding_data = p_bonding_data;
return pm_peer_data_store(*p_new_peer_id, &peer_data, p_token);
}
void pm_peer_delete(pm_peer_id_t peer_id)
{
pdb_peer_free(peer_id);
}
void pm_peer_delete_all(void)
{
pm_peer_id_t current_peer_id = PM_PEER_ID_INVALID;
while (pdb_next_peer_id_get(PM_PEER_ID_INVALID) != PM_PEER_ID_INVALID)
{
current_peer_id = pdb_next_peer_id_get(current_peer_id);
pm_peer_delete(current_peer_id);
}
}