HL-PDJ-1/components/ble/peer_manager/peer_manager_handler.c
xiaozhengsheng 6df0f7d96e 初始版本
2025-08-19 09:49:41 +08:00

687 lines
24 KiB
C

/**
* Copyright (c) 2018 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* 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, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, 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 Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
#include "peer_manager_handler.h"
#include <stdint.h>
#include <string.h>
#include "sdk_errors.h"
#include "app_error.h"
#include "peer_manager.h"
#include "ble_gap.h"
#include "ble_gattc.h"
#include "ble_conn_state.h"
#include "fds.h"
#include "nrf_strerror.h"
#include "sdk_config.h"
#if PM_HANDLER_SEC_DELAY_MS > 0
#include "app_timer.h"
#endif
#define NRF_LOG_MODULE_NAME peer_manager_handler
#if PM_LOG_ENABLED
#define NRF_LOG_LEVEL PM_LOG_LEVEL
#define NRF_LOG_INFO_COLOR PM_LOG_INFO_COLOR
#define NRF_LOG_DEBUG_COLOR PM_LOG_DEBUG_COLOR
#else
#define NRF_LOG_LEVEL 0
#endif // PM_LOG_ENABLED
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
NRF_LOG_MODULE_REGISTER();
#include "nrf_strerror.h"
static const char * m_roles_str[] =
{
"Invalid Role",
"Peripheral",
"Central",
};
static const char * m_sec_procedure_str[] =
{
"Encryption",
"Bonding",
"Pairing",
};
#define PM_EVT_STR(_name) [_name] = STRINGIFY(_name)
static const char * m_event_str[] =
{
PM_EVT_STR(PM_EVT_BONDED_PEER_CONNECTED),
PM_EVT_STR(PM_EVT_CONN_SEC_START),
PM_EVT_STR(PM_EVT_CONN_SEC_SUCCEEDED),
PM_EVT_STR(PM_EVT_CONN_SEC_FAILED),
PM_EVT_STR(PM_EVT_CONN_SEC_CONFIG_REQ),
PM_EVT_STR(PM_EVT_CONN_SEC_PARAMS_REQ),
PM_EVT_STR(PM_EVT_STORAGE_FULL),
PM_EVT_STR(PM_EVT_ERROR_UNEXPECTED),
PM_EVT_STR(PM_EVT_PEER_DATA_UPDATE_SUCCEEDED),
PM_EVT_STR(PM_EVT_PEER_DATA_UPDATE_FAILED),
PM_EVT_STR(PM_EVT_PEER_DELETE_SUCCEEDED),
PM_EVT_STR(PM_EVT_PEER_DELETE_FAILED),
PM_EVT_STR(PM_EVT_PEERS_DELETE_SUCCEEDED),
PM_EVT_STR(PM_EVT_PEERS_DELETE_FAILED),
PM_EVT_STR(PM_EVT_LOCAL_DB_CACHE_APPLIED),
PM_EVT_STR(PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED),
PM_EVT_STR(PM_EVT_SERVICE_CHANGED_IND_SENT),
PM_EVT_STR(PM_EVT_SERVICE_CHANGED_IND_CONFIRMED),
PM_EVT_STR(PM_EVT_SLAVE_SECURITY_REQ),
PM_EVT_STR(PM_EVT_FLASH_GARBAGE_COLLECTED),
PM_EVT_STR(PM_EVT_FLASH_GARBAGE_COLLECTION_FAILED),
};
static const char * m_data_id_str[] =
{
"Outdated (0)",
"Service changed pending flag",
"Outdated (2)",
"Outdated (3)",
"Application data",
"Remote database",
"Peer rank",
"Bonding data",
"Local database",
"Central address resolution",
};
static const char * m_data_action_str[] =
{
"Update",
"Delete"
};
#define PM_SEC_ERR_STR(_name) {.error = _name, .error_str = #_name}
typedef struct
{
pm_sec_error_code_t error;
const char * error_str;
} sec_err_str_t;
static const sec_err_str_t m_pm_sec_error_str[] =
{
PM_SEC_ERR_STR(PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING),
PM_SEC_ERR_STR(PM_CONN_SEC_ERROR_MIC_FAILURE),
PM_SEC_ERR_STR(PM_CONN_SEC_ERROR_DISCONNECT),
PM_SEC_ERR_STR(PM_CONN_SEC_ERROR_SMP_TIMEOUT),
};
static const char * sec_err_string_get(pm_sec_error_code_t error)
{
static char errstr[30];
for (uint32_t i = 0; i < (sizeof(m_pm_sec_error_str)/sizeof(sec_err_str_t)); i++)
{
if (m_pm_sec_error_str[i].error == error)
{
return m_pm_sec_error_str[i].error_str;
}
}
int len = snprintf(errstr, sizeof(errstr), "%s 0x%hx", (error < PM_CONN_SEC_ERROR_BASE)
? "BLE_GAP_SEC_STATUS"
:"PM_CONN_SEC_ERROR", error);
UNUSED_VARIABLE(len);
return errstr;
}
static void _conn_secure(uint16_t conn_handle, bool force)
{
ret_code_t err_code;
if (!force)
{
pm_conn_sec_status_t status;
err_code = pm_conn_sec_status_get(conn_handle, &status);
if (err_code != BLE_ERROR_INVALID_CONN_HANDLE)
{
APP_ERROR_CHECK(err_code);
}
// If the link is already secured, don't initiate security procedure.
if (status.encrypted)
{
NRF_LOG_DEBUG("Already encrypted, skipping security.");
return;
}
}
err_code = pm_conn_secure(conn_handle, false);
if ((err_code == NRF_SUCCESS) || (err_code == NRF_ERROR_BUSY))
{
// Success.
}
else if (err_code == NRF_ERROR_TIMEOUT)
{
NRF_LOG_WARNING("pm_conn_secure() failed because an SMP timeout is preventing security on "\
"the link. Disconnecting conn_handle %d.",
conn_handle);
err_code = sd_ble_gap_disconnect(conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_WARNING("sd_ble_gap_disconnect() returned %s on conn_handle %d.",
nrf_strerror_get(err_code),
conn_handle);
}
}
else if (err_code == NRF_ERROR_INVALID_DATA)
{
NRF_LOG_WARNING("pm_conn_secure() failed because the stored data for conn_handle %d does "\
"not have a valid key.",
conn_handle);
}
else if (err_code == BLE_ERROR_INVALID_CONN_HANDLE)
{
NRF_LOG_WARNING("pm_conn_secure() failed because conn_handle %d is not a valid connection.",
conn_handle);
}
else
{
NRF_LOG_ERROR("Asserting. pm_conn_secure() returned %s on conn_handle %d.",
nrf_strerror_get(err_code),
conn_handle);
APP_ERROR_CHECK(err_code);
}
}
#if PM_HANDLER_SEC_DELAY_MS > 0
APP_TIMER_DEF(secure_delay_timer);
typedef union
{
struct
{
uint16_t conn_handle;
bool force;
} values;
void * p_void;
} conn_secure_context_t;
STATIC_ASSERT(sizeof(conn_secure_context_t) <= sizeof(void *), "conn_secure_context_t is too large.");
static void _conn_secure(uint16_t conn_handle, bool force);
static void delayed_conn_secure(void * context)
{
conn_secure_context_t sec_context = {.p_void = context};
_conn_secure(sec_context.values.conn_handle, sec_context.values.force);
}
static void conn_secure(uint16_t conn_handle, bool force)
{
ret_code_t err_code;
static bool created = false;
if (!created)
{
err_code = app_timer_create(&secure_delay_timer,
APP_TIMER_MODE_SINGLE_SHOT,
delayed_conn_secure);
APP_ERROR_CHECK(err_code);
created = true;
}
conn_secure_context_t sec_context = {0};
sec_context.values.conn_handle = conn_handle;
sec_context.values.force = force;
err_code = app_timer_start(secure_delay_timer,
APP_TIMER_TICKS(PM_HANDLER_SEC_DELAY_MS),
sec_context.p_void);
APP_ERROR_CHECK(err_code);
}
#else
static void conn_secure(uint16_t conn_handle, bool force)
{
_conn_secure(conn_handle, force);
}
#endif
void pm_handler_on_pm_evt(pm_evt_t const * p_pm_evt)
{
pm_handler_pm_evt_log(p_pm_evt);
if (p_pm_evt->evt_id == PM_EVT_BONDED_PEER_CONNECTED)
{
conn_secure(p_pm_evt->conn_handle, false);
}
else if (p_pm_evt->evt_id == PM_EVT_ERROR_UNEXPECTED)
{
NRF_LOG_ERROR("Asserting.");
APP_ERROR_CHECK(p_pm_evt->params.error_unexpected.error);
}
}
void pm_handler_flash_clean_on_return(void)
{
// Trigger the mechanism to make more room in flash.
pm_evt_t storage_full_evt = {.evt_id = PM_EVT_STORAGE_FULL};
pm_handler_flash_clean(&storage_full_evt);
}
static void rank_highest(pm_peer_id_t peer_id)
{
// Trigger a pm_peer_rank_highest() with internal bookkeeping.
pm_evt_t connected_evt = {.evt_id = PM_EVT_BONDED_PEER_CONNECTED, .peer_id = peer_id};
pm_handler_flash_clean(&connected_evt);
}
void pm_handler_flash_clean(pm_evt_t const * p_pm_evt)
{
ret_code_t err_code;
static bool flash_cleaning = false; // Indicates whether garbage collection is currently being run.
static bool flash_write_after_gc = true; // Indicates whether a successful write happened after the last garbage
// collection. If this is false when flash is full, it means just a
// garbage collection won't work, so some data should be deleted.
#define RANK_QUEUE_SIZE 8 // Size of rank_queue.
#define RANK_QUEUE_INIT() PM_PEER_ID_INVALID, // Initial value of rank_queue.
//lint -save -e40 -e26 -esym(628,MACRO_REPEAT_8)
static pm_peer_id_t rank_queue[8] = {MACRO_REPEAT(RANK_QUEUE_SIZE, RANK_QUEUE_INIT)}; // Queue of rank_highest calls that
// failed because of full flash.
//lint -restore
static int rank_queue_wr = 0; // Write pointer for rank_queue.
switch (p_pm_evt->evt_id)
{
case PM_EVT_BONDED_PEER_CONNECTED:
err_code = pm_peer_rank_highest(p_pm_evt->peer_id);
if ((err_code == NRF_ERROR_STORAGE_FULL) ||
(err_code == NRF_ERROR_BUSY))
{
// Queue pm_peer_rank_highest() call and attempt to clean flash.
rank_queue[rank_queue_wr] = p_pm_evt->peer_id;
rank_queue_wr = (rank_queue_wr + 1) % RANK_QUEUE_SIZE;
pm_handler_flash_clean_on_return();
}
else if ((err_code != NRF_ERROR_NOT_SUPPORTED) &&
(err_code != NRF_ERROR_INVALID_PARAM) &&
(err_code != NRF_ERROR_RESOURCES))
{
APP_ERROR_CHECK(err_code);
}
else
{
NRF_LOG_DEBUG("pm_peer_rank_highest() returned %s for peer id %d",
nrf_strerror_get(err_code),
p_pm_evt->peer_id);
}
break;
case PM_EVT_CONN_SEC_START:
break;
case PM_EVT_CONN_SEC_SUCCEEDED:
if ( (p_pm_evt->params.conn_sec_succeeded.procedure == PM_CONN_SEC_PROCEDURE_BONDING)
|| (p_pm_evt->params.conn_sec_succeeded.procedure == PM_CONN_SEC_PROCEDURE_ENCRYPTION))
// PM_CONN_SEC_PROCEDURE_ENCRYPTION in case peer was not recognized at connection time.
{
rank_highest(p_pm_evt->peer_id);
}
break;
case PM_EVT_CONN_SEC_FAILED:
case PM_EVT_CONN_SEC_CONFIG_REQ:
case PM_EVT_CONN_SEC_PARAMS_REQ:
break;
case PM_EVT_STORAGE_FULL:
if (!flash_cleaning)
{
err_code = NRF_SUCCESS;
NRF_LOG_INFO("Attempting to clean flash.");
if (!flash_write_after_gc)
{
// Check whether another user of FDS has deleted a record that can be GCed.
fds_stat_t fds_stats;
err_code = fds_stat(&fds_stats);
APP_ERROR_CHECK(err_code);
flash_write_after_gc = (fds_stats.dirty_records > 0);
}
if (!flash_write_after_gc)
{
pm_peer_id_t peer_id_to_delete;
err_code = pm_peer_ranks_get(NULL, NULL, &peer_id_to_delete, NULL);
if (err_code == NRF_SUCCESS)
{
NRF_LOG_INFO("Deleting lowest ranked peer (peer_id: %d)", peer_id_to_delete);
err_code = pm_peer_delete(peer_id_to_delete);
APP_ERROR_CHECK(err_code);
flash_write_after_gc = true;
}
if (err_code == NRF_ERROR_NOT_FOUND)
{
NRF_LOG_ERROR("There are no peers to delete.");
}
else if (err_code == NRF_ERROR_NOT_SUPPORTED)
{
NRF_LOG_WARNING("Peer ranks functionality is disabled, so no peers are deleted.");
}
else
{
APP_ERROR_CHECK(err_code);
}
}
if (err_code == NRF_SUCCESS)
{
err_code = fds_gc();
if (err_code == NRF_SUCCESS)
{
NRF_LOG_DEBUG("Running flash garbage collection.");
flash_cleaning = true;
}
else if (err_code != FDS_ERR_NO_SPACE_IN_QUEUES)
{
APP_ERROR_CHECK(err_code);
}
}
}
break;
case PM_EVT_ERROR_UNEXPECTED:
break;
case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
flash_write_after_gc = true;
break;
case PM_EVT_PEER_DATA_UPDATE_FAILED:
break;
case PM_EVT_PEER_DELETE_SUCCEEDED:
flash_write_after_gc = true;
break;
case PM_EVT_PEER_DELETE_FAILED:
case PM_EVT_PEERS_DELETE_SUCCEEDED:
case PM_EVT_PEERS_DELETE_FAILED:
case PM_EVT_LOCAL_DB_CACHE_APPLIED:
case PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED:
case PM_EVT_SERVICE_CHANGED_IND_SENT:
case PM_EVT_SERVICE_CHANGED_IND_CONFIRMED:
case PM_EVT_SLAVE_SECURITY_REQ:
break;
case PM_EVT_FLASH_GARBAGE_COLLECTED:
flash_cleaning = false;
flash_write_after_gc = false;
{
// Reattempt queued pm_peer_rank_highest() calls.
int rank_queue_rd = rank_queue_wr;
for (int i = 0; i < RANK_QUEUE_SIZE; i++)
{
pm_peer_id_t peer_id = rank_queue[(i + rank_queue_rd) % RANK_QUEUE_SIZE];
if (peer_id != PM_PEER_ID_INVALID)
{
rank_queue[(i + rank_queue_rd) % RANK_QUEUE_SIZE] = PM_PEER_ID_INVALID;
rank_highest(peer_id);
}
}
}
break;
case PM_EVT_FLASH_GARBAGE_COLLECTION_FAILED:
flash_cleaning = false;
if (p_pm_evt->params.garbage_collection_failed.error == FDS_ERR_BUSY
|| p_pm_evt->params.garbage_collection_failed.error == FDS_ERR_OPERATION_TIMEOUT)
{
// Retry immediately if error is transient.
pm_handler_flash_clean_on_return();
}
break;
default:
break;
}
}
void pm_handler_pm_evt_log(pm_evt_t const * p_pm_evt)
{
NRF_LOG_DEBUG("Event %s", m_event_str[p_pm_evt->evt_id]);
switch (p_pm_evt->evt_id)
{
case PM_EVT_BONDED_PEER_CONNECTED:
NRF_LOG_DEBUG("Previously bonded peer connected: role: %s, conn_handle: %d, peer_id: %d",
m_roles_str[ble_conn_state_role(p_pm_evt->conn_handle)],
p_pm_evt->conn_handle,
p_pm_evt->peer_id);
break;
case PM_EVT_CONN_SEC_START:
NRF_LOG_DEBUG("Connection security procedure started: role: %s, conn_handle: %d, procedure: %s",
m_roles_str[ble_conn_state_role(p_pm_evt->conn_handle)],
p_pm_evt->conn_handle,
m_sec_procedure_str[p_pm_evt->params.conn_sec_start.procedure]);
break;
case PM_EVT_CONN_SEC_SUCCEEDED:
NRF_LOG_INFO("Connection secured: role: %s, conn_handle: %d, procedure: %s",
m_roles_str[ble_conn_state_role(p_pm_evt->conn_handle)],
p_pm_evt->conn_handle,
m_sec_procedure_str[p_pm_evt->params.conn_sec_start.procedure]);
break;
case PM_EVT_CONN_SEC_FAILED:
NRF_LOG_INFO("Connection security failed: role: %s, conn_handle: 0x%x, procedure: %s, error: %d",
m_roles_str[ble_conn_state_role(p_pm_evt->conn_handle)],
p_pm_evt->conn_handle,
m_sec_procedure_str[p_pm_evt->params.conn_sec_start.procedure],
p_pm_evt->params.conn_sec_failed.error);
NRF_LOG_DEBUG("Error (decoded): %s",
sec_err_string_get(p_pm_evt->params.conn_sec_failed.error));
break;
case PM_EVT_CONN_SEC_CONFIG_REQ:
NRF_LOG_DEBUG("Security configuration request");
break;
case PM_EVT_CONN_SEC_PARAMS_REQ:
NRF_LOG_DEBUG("Security parameter request");
break;
case PM_EVT_STORAGE_FULL:
NRF_LOG_WARNING("Flash storage is full");
break;
case PM_EVT_ERROR_UNEXPECTED:
NRF_LOG_ERROR("Unexpected fatal error occurred: error: %s",
nrf_strerror_get(p_pm_evt->params.error_unexpected.error));
break;
case PM_EVT_PEER_DATA_UPDATE_SUCCEEDED:
NRF_LOG_INFO("Peer data updated in flash: peer_id: %d, data_id: %s, action: %s%s",
p_pm_evt->peer_id,
m_data_id_str[p_pm_evt->params.peer_data_update_succeeded.data_id],
m_data_action_str[p_pm_evt->params.peer_data_update_succeeded.action],
p_pm_evt->params.peer_data_update_succeeded.flash_changed ? "" : ", no change");
break;
case PM_EVT_PEER_DATA_UPDATE_FAILED:
// This can happen if the SoftDevice is too busy with BLE operations.
NRF_LOG_WARNING("Peer data updated failed: peer_id: %d, data_id: %s, action: %s, error: %s",
p_pm_evt->peer_id,
m_data_id_str[p_pm_evt->params.peer_data_update_failed.data_id],
m_data_action_str[p_pm_evt->params.peer_data_update_succeeded.action],
nrf_strerror_get(p_pm_evt->params.peer_data_update_failed.error));
break;
case PM_EVT_PEER_DELETE_SUCCEEDED:
NRF_LOG_ERROR("Peer deleted successfully: peer_id: %d", p_pm_evt->peer_id);
break;
case PM_EVT_PEER_DELETE_FAILED:
NRF_LOG_ERROR("Peer deletion failed: peer_id: %d, error: %s",
p_pm_evt->peer_id,
nrf_strerror_get(p_pm_evt->params.peer_delete_failed.error));
break;
case PM_EVT_PEERS_DELETE_SUCCEEDED:
NRF_LOG_INFO("All peers deleted.");
break;
case PM_EVT_PEERS_DELETE_FAILED:
NRF_LOG_ERROR("All peer deletion failed: error: %s",
nrf_strerror_get(p_pm_evt->params.peers_delete_failed_evt.error));
break;
case PM_EVT_LOCAL_DB_CACHE_APPLIED:
NRF_LOG_DEBUG("Previously stored local DB applied: conn_handle: %d, peer_id: %d",
p_pm_evt->conn_handle,
p_pm_evt->peer_id);
break;
case PM_EVT_LOCAL_DB_CACHE_APPLY_FAILED:
// This can happen when the local DB has changed.
NRF_LOG_WARNING("Local DB could not be applied: conn_handle: %d, peer_id: %d",
p_pm_evt->conn_handle,
p_pm_evt->peer_id);
break;
case PM_EVT_SERVICE_CHANGED_IND_SENT:
NRF_LOG_DEBUG("Sending Service Changed indication.");
break;
case PM_EVT_SERVICE_CHANGED_IND_CONFIRMED:
NRF_LOG_DEBUG("Service Changed indication confirmed.");
break;
case PM_EVT_SLAVE_SECURITY_REQ:
NRF_LOG_DEBUG("Security Request received from peer.");
break;
case PM_EVT_FLASH_GARBAGE_COLLECTED:
NRF_LOG_DEBUG("Flash garbage collection complete.");
break;
case PM_EVT_FLASH_GARBAGE_COLLECTION_FAILED:
NRF_LOG_WARNING("Flash garbage collection failed with error %s.",
nrf_strerror_get(p_pm_evt->params.garbage_collection_failed.error));
break;
default:
NRF_LOG_WARNING("Unexpected PM event ID: 0x%x.", p_pm_evt->evt_id);
break;
}
}
void pm_handler_disconnect_on_sec_failure(pm_evt_t const * p_pm_evt)
{
ret_code_t err_code;
if (p_pm_evt->evt_id == PM_EVT_CONN_SEC_FAILED)
{
NRF_LOG_WARNING("Disconnecting conn_handle %d.", p_pm_evt->conn_handle);
err_code = sd_ble_gap_disconnect(p_pm_evt->conn_handle,
BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
if ((err_code != NRF_ERROR_INVALID_STATE) && (err_code != BLE_ERROR_INVALID_CONN_HANDLE))
{
APP_ERROR_CHECK(err_code);
}
}
}
void pm_handler_disconnect_on_insufficient_sec(pm_evt_t const * p_pm_evt,
pm_conn_sec_status_t * p_min_conn_sec)
{
if (p_pm_evt->evt_id == PM_EVT_CONN_SEC_SUCCEEDED)
{
if (!pm_sec_is_sufficient(p_pm_evt->conn_handle, p_min_conn_sec))
{
NRF_LOG_WARNING("Connection security is insufficient, disconnecting.");
ret_code_t err_code = sd_ble_gap_disconnect(p_pm_evt->conn_handle,
BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
APP_ERROR_CHECK(err_code);
}
}
}
void pm_handler_secure_on_connection(ble_evt_t const * p_ble_evt)
{
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
NRF_LOG_DEBUG("Connected, securing connection. conn_handle: %d", p_ble_evt->evt.gap_evt.conn_handle);
conn_secure(p_ble_evt->evt.gap_evt.conn_handle, false);
break;
#if PM_HANDLER_SEC_DELAY_MS > 0
case BLE_GAP_EVT_DISCONNECTED:
{
ret_code_t err_code = app_timer_stop(secure_delay_timer);
APP_ERROR_CHECK(err_code);
} break;
#endif
default:
break;
}
}
void pm_handler_secure_on_error(ble_evt_t const * p_ble_evt)
{
if ((p_ble_evt->header.evt_id >= BLE_GATTC_EVT_BASE) && (p_ble_evt->header.evt_id <= BLE_GATTC_EVT_LAST))
{
if ((p_ble_evt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_ATTERR_INSUF_ENCRYPTION) ||
(p_ble_evt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_ATTERR_INSUF_AUTHENTICATION))
{
NRF_LOG_INFO("GATTC procedure (evt id 0x%x) failed because it needs encryption. Bonding: conn_handle=%d",
p_ble_evt->header.evt_id,
p_ble_evt->evt.gattc_evt.conn_handle);
conn_secure(p_ble_evt->evt.gattc_evt.conn_handle, true);
}
}
}