fix(nimble): Add changes for nimble-1.9.0-idf migration

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Rahul Tank
2026-08-14 12:19:31 +05:30
co-authored by Cursor
parent 086a35f9e4
commit 79316193f9
111 changed files with 3493 additions and 1810 deletions
+12
View File
@@ -4,12 +4,24 @@ repos
# Non-source files
RELEASE_NOTES.md
.gitignore
**/README.md
Doxyfile
.clang-format
.mailmap
.clang-format-ignore
**/requirements.txt
README.md
pts-gap.txt
pts-gatt.txt
pts-l2cap.txt
pts-sm.txt
94654-20170317-085122560.tpg
94654-20170317-085441153.pts
uncrustify.cfg
.style_ignored_dirs
.mailmap
requirements.txt
# Ignore documentation folder
docs
+2 -2
View File
@@ -124,6 +124,6 @@ Finds an available (idle) EATT channel for the given connection. If an EATT chan
.. code-block:: c
void ble_eatt_release_chan(uint16_t conn_handle, uint8_t op)
void ble_eatt_release_chan(uint16_t conn_handle, uint16_t cid)
Releases a previously claimed EATT channel, marking it as idle and available for new transactions.
Releases a previously claimed EATT channel identified by ``cid``, marking it as idle and available for new transactions.
+2 -1
View File
@@ -1365,6 +1365,7 @@ ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
ble_phy_mode_apply(g_ble_phy_data.phy_mode_rx);
#endif
assert(ble_rf_is_enabled());
ble_phy_rx();
/* Store LLT value at RX start, we'll need this to set wfr */
@@ -1658,7 +1659,7 @@ ble_phy_encrypt_disable(void)
#endif
static int8_t
phy_txpower_round(int8_t dbm)
phy_txpower_round(int dbm)
{
static const int8_t supported_pwr_levels[] = {-18, -12, -8, -6, -3, -2,
-1, 0, 1, 2, 3, 4, 5, 6 };
+2 -4
View File
@@ -112,14 +112,12 @@ struct os_mbuf;
#define BLE_ATT_ERR_DB_OUT_OF_SYNC 0x12
#define BLE_ATT_ERR_VALUE_NOT_ALLOWED 0x13
/**Requested value is not allowed. */
#define BLE_ATT_ERR_VALUE_NOT_ALLOWED 0x13
/**Write Request Rejected. */
#define BLE_ATT_ERR_WRITE_REQ_REJECTED 0xFC
/**Client Characteristic Configuration Descriptor Improperly Configured. */
#define BLE_ATT_ERR_CCCD_IMPORER_CONF 0xFD
#define BLE_ATT_ERR_CCCD_IMPROPER_CONF 0xFD
/**Procedure Already in Progress. */
#define BLE_ATT_ERR_PROC_IN_PROGRESS 0xFE
+2
View File
@@ -338,6 +338,7 @@ int ble_gap_config_ext_scan_adi_filter(uint8_t enable, uint8_t did_filter, uint8
int
ble_gap_dev_authorization(uint16_t conn_handle, bool authorized);
#if MYNEWT_VAL(BLE_HCI_VS)
/**
* Sets the vendor-specific event mask for BLE host.
*
@@ -351,6 +352,7 @@ ble_gap_dev_authorization(uint16_t conn_handle, bool authorized);
*/
int
ble_hs_send_vs_event_mask(uint32_t event_mask);
#endif
void ble_gap_rx_test_evt(const void *buf, uint8_t len);
void ble_gap_tx_test_evt(const void *buf, uint8_t len);
+2 -2
View File
@@ -21,7 +21,7 @@ void ble_hs_deinit(void);
/**
* Initializes the Bluetooth advertising list and associated mutex lock.
*/
void ble_adv_list_init(void);
int ble_adv_list_init(void);
/**
* Deinitializes the Bluetooth advertising list, releasing allocated memory and resources.
@@ -31,7 +31,7 @@ void ble_adv_list_deinit(void);
/**
* Adds a Bluetooth advertising packet to the list.
*/
void ble_adv_list_add_packet(void *data);
bool ble_adv_list_add_packet(void *data);
/**
* Returns the count of Bluetooth advertising packets in the list.
+12 -1
View File
@@ -1653,6 +1653,14 @@ struct ble_gap_event {
uint8_t length;
} unhandled_hci;
#endif
#else
/* Legacy 1.6.0-idf field name; layout intentionally identical. */
struct {
bool is_le_meta;
bool is_vs;
const void *ev;
uint8_t length;
} vs_hci;
#endif
/**
@@ -4081,7 +4089,7 @@ int ble_gap_read_le_phy(uint16_t conn_handle, uint8_t *tx_phy, uint8_t *rx_phy);
#define BLE_GAP_LE_PHY_CODED_MASK 0x04
/** Bitmask for any PHY. */
#define BLE_GAP_LE_PHY_ANY_MASK 0x0F
#define BLE_GAP_LE_PHY_ANY_MASK 0x07
/** @} */
@@ -4595,6 +4603,8 @@ int ble_gap_rd_local_resolv_addr(uint8_t peer_addr_type, const ble_addr_t *peer_
uint8_t *out_addr);
#endif
#if MYNEWT_VAL(BLE_HS_PVCY)
/**
* Read local IRK command
*
@@ -4604,6 +4614,7 @@ int ble_gap_rd_local_resolv_addr(uint8_t peer_addr_type, const ble_addr_t *peer_
*
*/
int ble_gap_read_local_irk(uint8_t * out_irk);
#endif
#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING)
/**
+1 -32
View File
@@ -415,16 +415,6 @@ struct ble_hs_cfg;
/** @} */
/*** @server. */
/** Represents one notification tuple in a multi notification PDU */
struct ble_gatt_notif_entry {
/** The attribute handle on which to notify. */
uint16_t handle;
/** The notification value. */
struct os_mbuf *value;
};
/*** @client. */
/** Represents a GATT error. */
struct ble_gatt_error {
@@ -784,10 +774,6 @@ int ble_gattc_read_mult(uint16_t conn_handle, const uint16_t *handles,
uint8_t num_handles, ble_gatt_attr_fn *cb,
void *cb_arg);
int ble_gattc_read_mult_var(uint16_t conn_handle, const uint16_t *handles,
uint8_t num_handles, ble_gatt_attr_mult_fn *cb,
void *cb_arg);
/**
* Initiates GATT procedure: Read Multiple Variable Length Characteristic Values.
*
@@ -980,22 +966,6 @@ int ble_gatts_notify_multiple_custom(uint16_t conn_handle,
size_t chr_count,
struct ble_gatt_notif *tuples);
/**
* Sends multiple characteristic notifications on the specified
* attribute handles. This function consumes the mbuf of the
* notification value after sending notification.
*
* @param conn_handle The connection over which to execute the
* procedure.
* @param tuples The list of attribute handles and notification
* value tuples.
* @param num_tuples The number of notifications to send.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gatts_multi_notify_custom(uint16_t conn_handle,
struct ble_gatt_notif_entry *tuples, uint16_t num_tuples);
/**
* @deprecated Should not be used. Use ble_gatts_notify_custom instead.
*
@@ -1006,9 +976,8 @@ int ble_gatts_multi_notify_custom(uint16_t conn_handle,
* @param om The value to write to the characteristic.
*
* @return 0 on success; nonzero on failure.
* @deprecated Use ble_gatts_notify_custom() instead.
*/
int ble_gattc_notify_custom(uint16_t conn_handle, uint16_t att_handle,
struct os_mbuf *om);
/**
* Sends a characteristic notification. The content of the message is read
+2
View File
@@ -43,7 +43,9 @@
#include "host/ble_sm.h"
#include "host/ble_store.h"
#include "host/ble_uuid.h"
#if MYNEWT_VAL(BLE_ISO)
#include "host/ble_iso.h"
#endif
#include "nimble/nimble_npl.h"
#include "host/ble_esp_hs.h"
-2
View File
@@ -16,8 +16,6 @@
extern "C" {
#endif
int ble_iso_init(void);
int ble_hs_hci_set_iso_buf_sz(uint16_t pktlen, uint8_t max_pkts);
void ble_hs_hci_get_iso_buf_size(uint16_t *pktlen, uint8_t *max_pkts);
+4 -5
View File
@@ -48,13 +48,13 @@
#include "logcfg/logcfg.h"
#endif
#ifndef ESP_PLATFORM
#if !defined(ESP_PLATFORM) && !MYNEWT_VAL(NEWT_FEATURE_LOGCFG)
#ifndef BLE_NPL_LOG_MODULE
/** Defines the logging module for NimBLE Porting Layer (NPL). */
#define BLE_NPL_LOG_MODULE BLE_HS_LOG
#endif
#include <nimble/nimble_npl_log.h>
#endif /* !ESP_PLATFORM */
#endif /* !ESP_PLATFORM && !NEWT_FEATURE_LOGCFG */
#ifdef __cplusplus
extern "C" {
@@ -71,8 +71,7 @@ struct os_mbuf;
* @param lvl The log level of the message.
* @param ... The format string and additional arguments for the log message.
*/
#ifdef ESP_PLATFORM
/* Use logcfg BLE_HS_LOG_<LVL> macros — avoids conflict with BLE_NPL_LOG_IMPL. */
#if defined(ESP_PLATFORM) || MYNEWT_VAL(NEWT_FEATURE_LOGCFG)
#define BLE_HS_LOG(lvl, ...) \
BLE_HS_LOG_ ## lvl(__VA_ARGS__)
#else
@@ -89,7 +88,7 @@ struct os_mbuf;
* @param lvl The log level of the message.
* @param addr The Bluetooth address to be logged.
*/
#ifdef ESP_PLATFORM
#if defined(ESP_PLATFORM) || MYNEWT_VAL(NEWT_FEATURE_LOGCFG)
#define BLE_HS_LOG_ADDR(lvl, addr) \
BLE_HS_LOG_ ## lvl("%02x:%02x:%02x:%02x:%02x:%02x", \
(addr)[5], (addr)[4], (addr)[3], \
+1 -1
View File
@@ -177,7 +177,7 @@ struct ble_iso_event {
* o BLE_ISO_EVENT_BIG_SYNC_TERMINATED
*/
struct {
uint16_t big_handle;
uint8_t big_handle;
uint8_t reason;
} big_terminated;
+12
View File
@@ -174,6 +174,18 @@ extern "C" {
#define BT_GAP_ADV_SLOW_INT_MIN 0x0640 /* 1 s */
#define BT_GAP_ADV_SLOW_INT_MAX 0x0780 /* 1.2 s */
#if defined(ESP_PLATFORM) && !defined(BLE_NPL_LOG)
#ifndef BLE_NPL_LOG_MODULE
#define BLE_NPL_LOG_MODULE BLE_MESH_LOG
#endif
#ifndef _BLE_NPL_LOG_CAT
#define _BLE_NPL_LOG_CAT(a, ...) _BLE_NPL_LOG_PRIMITIVE_CAT(a, __VA_ARGS__)
#define _BLE_NPL_LOG_PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
#endif
#define BLE_NPL_LOG(lvl, ...) \
_BLE_NPL_LOG_CAT(BLE_NPL_LOG_MODULE, _BLE_NPL_LOG_CAT(_, lvl))(__VA_ARGS__)
#endif
#define BT_DBG(fmt, ...) BLE_NPL_LOG(DEBUG, "%s: " fmt "\n", __func__, ## __VA_ARGS__);
#define BT_INFO(fmt, ...) BLE_NPL_LOG(INFO, "%s: " fmt "\n", __func__, ## __VA_ARGS__);
#define BT_WARN(fmt, ...) BLE_NPL_LOG(WARN, "%s: " fmt "\n", __func__, ## __VA_ARGS__);
+3
View File
@@ -6,6 +6,9 @@
* SPDX-License-Identifier: Apache-2.0
*/
#define BLE_NPL_LOG_MODULE BLE_MESH_MODEL_LOG
#include <nimble/nimble_npl_log.h>
#include "mesh/mesh.h"
void bt_mesh_model_msg_init(struct os_mbuf *msg, uint32_t opcode)
+10 -1
View File
@@ -51,6 +51,8 @@ typedef struct {
uint8_t _ble_svc_ans_alert_not_ctrl_pt[2];
uint8_t _ble_svc_ans_new_alert_cnt[BLE_SVC_ANS_CAT_NUM];
uint8_t _ble_svc_ans_unr_alert_cnt[BLE_SVC_ANS_CAT_NUM];
uint8_t _ble_svc_ans_new_alert_notif_state;
uint8_t _ble_svc_ans_unr_alert_notif_state;
uint16_t _ble_svc_ans_conn_handle;
} ble_svc_ans_ctx_t;
@@ -64,6 +66,8 @@ static ble_svc_ans_ctx_t * ble_svc_ans_ctx;
#define ble_svc_ans_alert_not_ctrl_pt (ble_svc_ans_ctx->_ble_svc_ans_alert_not_ctrl_pt)
#define ble_svc_ans_new_alert_cnt (ble_svc_ans_ctx->_ble_svc_ans_new_alert_cnt)
#define ble_svc_ans_unr_alert_cnt (ble_svc_ans_ctx->_ble_svc_ans_unr_alert_cnt)
#define ble_svc_ans_new_alert_notif_state (ble_svc_ans_ctx->_ble_svc_ans_new_alert_notif_state)
#define ble_svc_ans_unr_alert_notif_state (ble_svc_ans_ctx->_ble_svc_ans_unr_alert_notif_state)
#define ble_svc_ans_conn_handle (ble_svc_ans_ctx->_ble_svc_ans_conn_handle)
#else /* MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC) */
@@ -306,18 +310,21 @@ ble_svc_ans_access(uint16_t conn_handle, uint16_t attr_handle,
case BLE_SVC_ANS_CHR_UUID16_ALERT_NOT_CTRL_PT:
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
ble_hs_lock();
rc = ble_svc_ans_chr_write(ctxt->om,
sizeof ble_svc_ans_alert_not_ctrl_pt,
sizeof ble_svc_ans_alert_not_ctrl_pt,
&ble_svc_ans_alert_not_ctrl_pt,
NULL);
if (rc != 0) {
ble_hs_unlock();
return rc;
}
/* Get command ID and category ID */
/* Get command ID and category ID while still holding lock */
cmd_id = ble_svc_ans_alert_not_ctrl_pt[0];
cat_id = ble_svc_ans_alert_not_ctrl_pt[1];
ble_hs_unlock();
/* Set cat_bit_mask to the appropriate bitmask based on cat_id */
@@ -428,6 +435,8 @@ ble_svc_ans_on_gap_connect(uint16_t conn_handle)
ble_hs_lock();
ble_svc_ans_conn_handle = conn_handle;
ble_svc_ans_new_alert_notif_state = 0;
ble_svc_ans_unr_alert_notif_state = 0;
ble_hs_unlock();
}
+9 -5
View File
@@ -37,6 +37,7 @@ static uint16_t ble_svc_bas_battery_handle;
/* Battery level */
static uint8_t ble_svc_bas_battery_level;
static bool ble_svc_bas_initialized;
static bool ble_svc_bas_counted;
/* Access function */
static int
@@ -138,6 +139,7 @@ ble_svc_bas_deinit(void)
{
ble_gatts_free_svcs();
ble_svc_bas_initialized = false;
ble_svc_bas_counted = false;
}
/**
@@ -154,10 +156,13 @@ ble_svc_bas_init(void)
ble_svc_bas_battery_level = 0;
rc = ble_gatts_count_cfg(ble_svc_bas_defs);
if (rc != 0) {
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, rc);
return;
if (!ble_svc_bas_counted) {
rc = ble_gatts_count_cfg(ble_svc_bas_defs);
if (rc != 0) {
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, rc);
return;
}
ble_svc_bas_counted = true;
}
rc = ble_gatts_add_svcs(ble_svc_bas_defs);
@@ -166,7 +171,6 @@ ble_svc_bas_init(void)
return;
}
ble_svc_bas_battery_level = 0;
ble_svc_bas_initialized = true;
}
#endif
@@ -36,6 +36,7 @@ struct ble_hs_cfg;
void ble_svc_cte_init(void);
void ble_svc_cte_deinit(void);
#ifdef __cplusplus
}
+67 -13
View File
@@ -18,6 +18,7 @@
*/
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include "sysinit/sysinit.h"
#include "syscfg/syscfg.h"
@@ -335,6 +336,21 @@ ble_svc_cte_two_octet_chr_write(struct os_mbuf *om,
}
static void
ble_svc_cte_rollback_aoa_state(uint16_t conn_handle, bool aoa_enabled_now,
bool aoa_disabled_now, uint8_t *cte_enable)
{
if (aoa_enabled_now) {
if (ble_gap_conn_cte_rsp_enable(conn_handle, false) != 0) {
*cte_enable |= CTE_ENABLE_AOA_CONNECTION;
}
} else if (aoa_disabled_now) {
if (ble_gap_conn_cte_rsp_enable(conn_handle, true) != 0) {
*cte_enable &= ~CTE_ENABLE_AOA_CONNECTION;
}
}
}
/**
* @brief Access callback for Constant Tone Extension Service cte enable
*
@@ -377,6 +393,8 @@ static int ble_svc_cte_enable_access(uint16_t conn_handle, uint16_t attr_handle,
&config->cte_enable, NULL);
if (rc == 0) {
bool aoa_enabled_now = false;
bool aoa_disabled_now = false;
if(((config->cte_enable & CTE_ENABLE_AOA_CONNECTION) == CTE_ENABLE_AOA_CONNECTION) &&
((old_enable & CTE_ENABLE_AOA_CONNECTION) != CTE_ENABLE_AOA_CONNECTION)) {
/* 0->1 transition: enable AoA CTE response on this connection */
@@ -391,6 +409,7 @@ static int ble_svc_cte_enable_access(uint16_t conn_handle, uint16_t attr_handle,
rc = 0xFC;
break;
}
aoa_enabled_now = true;
} else if (((old_enable & CTE_ENABLE_AOA_CONNECTION) == CTE_ENABLE_AOA_CONNECTION) &&
((config->cte_enable & CTE_ENABLE_AOA_CONNECTION) != CTE_ENABLE_AOA_CONNECTION)) {
/* 1->0 transition only: disable AoA CTE response.
@@ -402,26 +421,40 @@ static int ble_svc_cte_enable_access(uint16_t conn_handle, uint16_t attr_handle,
rc = 0xFC;
break;
}
aoa_disabled_now = true;
}
if(((config->cte_enable & CTE_ENABLE_AOD_ADVERTISING) == CTE_ENABLE_AOD_ADVERTISING) &&
((old_enable & CTE_ENABLE_AOD_ADVERTISING) != CTE_ENABLE_AOD_ADVERTISING)) {
if (adv_cte_config.cte_phy != CTE_PHY_MIN_VALUE) {
/* CTE PHY range check: valid values are CTE_PHY_MIN_VALUE (LE 1M)
* through CTE_PHY_MAX_VALUE (LE 2M). Both are valid per CTE spec. */
if (adv_cte_config.cte_phy > CTE_PHY_MAX_VALUE) {
ble_svc_cte_rollback_aoa_state(conn_handle,
aoa_enabled_now,
aoa_disabled_now,
&old_enable);
config->cte_enable = old_enable;
rc = SERVICE_ERROR_WRITE_REQUEST_REJECTED;
break;
}
/* Apply the current advertising CTE parameters to the controller
* using advertising instance 0 (default periodic advertising set). */
/* Map GATT PHY characteristic to HCI AoD CTE_Type:
* LE 1M PHY (0) -> AoD 1us slots (0x01)
* LE 2M PHY (1) -> AoD 2us slots (0x02)
* The +1 offset converts the PHY value to the AoD type. */
uint8_t ant_ids[] = {0, 1};
struct ble_gap_periodic_adv_cte_params cte_params = {
.cte_length = adv_cte_config.cte_min_length,
.cte_type = adv_cte_config.cte_phy,
.cte_type = (uint8_t)(adv_cte_config.cte_phy + 1),
.cte_count = adv_cte_config.cte_min_transmit_count,
.switching_pattern_length = 0,
.antenna_ids = NULL,
.switching_pattern_length = 2,
.antenna_ids = ant_ids,
};
if (ble_gap_set_connless_cte_transmit_params(0, &cte_params) != 0 ||
ble_gap_set_connless_cte_transmit_enable(0, 1) != 0) {
ble_svc_cte_rollback_aoa_state(conn_handle,
aoa_enabled_now,
aoa_disabled_now,
&old_enable);
config->cte_enable = old_enable;
rc = SERVICE_ERROR_WRITE_REQUEST_REJECTED;
break;
@@ -429,7 +462,16 @@ static int ble_svc_cte_enable_access(uint16_t conn_handle, uint16_t attr_handle,
} else if (((old_enable & CTE_ENABLE_AOD_ADVERTISING) == CTE_ENABLE_AOD_ADVERTISING) &&
((config->cte_enable & CTE_ENABLE_AOD_ADVERTISING) != CTE_ENABLE_AOD_ADVERTISING)) {
/* 1->0 transition: disable connless CTE transmission */
ble_gap_set_connless_cte_transmit_enable(0, 0);
rc = ble_gap_set_connless_cte_transmit_enable(0, 0);
if (rc != 0) {
ble_svc_cte_rollback_aoa_state(conn_handle,
aoa_enabled_now,
aoa_disabled_now,
&old_enable);
config->cte_enable = old_enable;
rc = SERVICE_ERROR_WRITE_REQUEST_REJECTED;
break;
}
}
}
}
@@ -624,18 +666,30 @@ static void cte_init_config(void) {
/**
* @brief Initialize the Constant Tone Extension Service
*/
static int ble_svc_cte_initialized = 0;
void
ble_svc_cte_deinit(void)
{
if (ble_svc_cte_initialized) {
ble_gap_event_listener_unregister(&cte_gap_listener);
}
ble_svc_cte_initialized = 0;
}
void
ble_svc_cte_init(void)
{
int rc;
/* Guard against repeated calls: ble_gatts_count_cfg and ble_gatts_add_svcs
* are additive, so calling them more than once inflates resource counters
* and inserts duplicate GATT service entries. */
static int initialized = 0;
if (initialized) {
/* Guard against repeated calls within the same init cycle:
* ble_gatts_count_cfg and ble_gatts_add_svcs are additive, so calling
* them more than once inflates resource counters and inserts duplicate
* GATT service entries. ble_svc_cte_deinit() resets this on stack deinit
* so that a subsequent nimble_port_init() cycle re-registers correctly. */
if (ble_svc_cte_initialized) {
return;
}
initialized = 1;
ble_svc_cte_initialized = 1;
cte_init_config();
ble_gap_event_listener_register(&cte_gap_listener, cte_gap_event, NULL);
+7 -2
View File
@@ -169,9 +169,14 @@ ble_svc_cts_access(uint16_t conn_handle, uint16_t attr_handle,
rc = os_mbuf_append(ctxt->om, &current_local_time_val,
sizeof current_local_time_val);
if (rc == 0) {
current_local_time_val.adjust_reason = 0;
/* Clear adjust_reason only on direct client reads, not when
* the stack reads the value to build notifications. */
if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
current_local_time_val.adjust_reason = 0;
}
return 0;
}
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
return BLE_ATT_ERR_INSUFFICIENT_RES;
case BLE_GATT_ACCESS_OP_WRITE_CHR:
rc = ble_svc_cts_chr_write(ctxt->om, sizeof(curr_time), sizeof(curr_time), &curr_time, NULL);
+7 -2
View File
@@ -293,8 +293,12 @@ ble_svc_dis_access(uint16_t conn_handle, uint16_t attr_handle,
{
uint8_t sysid[8] = {0};
if (info != NULL) {
/* System ID is 8 bytes binary */
memcpy(sysid, info, 8);
/* System ID is 8 bytes binary; cap copy length defensively */
size_t len = strlen(info);
if (len > 8) {
len = 8;
}
memcpy(sysid, info, len);
}
int rc = os_mbuf_append(ctxt->om, sysid, 8);
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
@@ -570,6 +574,7 @@ ble_svc_dis_init_dynamic(void)
void
ble_svc_dis_deinit(void)
{
ble_gatts_free_svcs();
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (ble_svc_dis_data_ptr != NULL) {
nimble_platform_mem_free(ble_svc_dis_data_ptr);
+46 -13
View File
@@ -237,19 +237,26 @@ ble_svc_gap_device_name_write_access(struct ble_gatt_access_ctxt *ctxt)
ble_hs_unlock();
return BLE_ATT_ERR_UNLIKELY;
}
// Free old name if already allocated
if (ble_hs_gap_svc_ctx->svc_gap_name) {
nimble_platform_mem_free(ble_hs_gap_svc_ctx->svc_gap_name);
ble_hs_gap_svc_ctx->svc_gap_name = NULL;
char *new_name = nimble_platform_mem_calloc(1, om_len + 1);
if (!new_name) {
ble_hs_unlock();
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_ATT_ERR_INSUFFICIENT_RES);
return BLE_ATT_ERR_INSUFFICIENT_RES;
}
ble_hs_gap_svc_ctx->svc_gap_name = nimble_platform_mem_calloc(1, om_len + 1);
if (!ble_hs_gap_svc_ctx->svc_gap_name) {
rc = ble_hs_mbuf_to_flat(ctxt->om, new_name, om_len, NULL);
if (rc != 0) {
nimble_platform_mem_free(new_name);
ble_hs_unlock();
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_ENOMEM);
return BLE_HS_ENOMEM;
return BLE_ATT_ERR_UNLIKELY;
}
#endif
if (ble_hs_gap_svc_ctx->svc_gap_name) {
nimble_platform_mem_free(ble_hs_gap_svc_ctx->svc_gap_name);
}
ble_hs_gap_svc_ctx->svc_gap_name = new_name;
#else
rc = ble_hs_mbuf_to_flat(ctxt->om, ble_svc_gap_name, om_len, NULL);
@@ -257,6 +264,7 @@ ble_svc_gap_device_name_write_access(struct ble_gatt_access_ctxt *ctxt)
ble_hs_unlock();
return BLE_ATT_ERR_UNLIKELY;
}
#endif
ble_svc_gap_name[om_len] = '\0';
@@ -276,6 +284,12 @@ ble_svc_gap_appearance_read_access(struct ble_gatt_access_ctxt *ctxt)
int rc;
ble_hs_lock();
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (!ble_hs_gap_svc_ctx) {
ble_hs_unlock();
return BLE_ATT_ERR_UNLIKELY;
}
#endif
appearance = htole16(ble_svc_gap_appearance);
ble_hs_unlock();
@@ -300,6 +314,12 @@ ble_svc_gap_appearance_write_access(struct ble_gatt_access_ctxt *ctxt)
}
ble_hs_lock();
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (!ble_hs_gap_svc_ctx) {
ble_hs_unlock();
return BLE_ATT_ERR_UNLIKELY;
}
#endif
rc = ble_hs_mbuf_to_flat(ctxt->om, &ble_svc_gap_appearance, om_len, NULL);
if (rc != 0) {
ble_hs_unlock();
@@ -411,15 +431,28 @@ ble_svc_gap_access(uint16_t conn_handle, uint16_t attr_handle,
#endif
#if MYNEWT_VAL(ENC_ADV_DATA)
case BLE_SVC_GAP_CHR_UUID16_KEY_MATERIAL:
case BLE_SVC_GAP_CHR_UUID16_KEY_MATERIAL: {
uint8_t local_session_key[sizeof(ble_svc_gap_km.session_key)];
uint8_t local_iv[sizeof(ble_svc_gap_km.iv)];
assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
rc = os_mbuf_append(ctxt->om, &(ble_svc_gap_km.session_key), sizeof(ble_svc_gap_km.session_key));
/* Snapshot key material under the host lock to avoid a torn read
* concurrent with ble_svc_gap_device_key_material_set().
*/
ble_hs_lock();
memcpy(local_session_key, ble_svc_gap_km.session_key,
sizeof(local_session_key));
memcpy(local_iv, ble_svc_gap_km.iv, sizeof(local_iv));
ble_hs_unlock();
rc = os_mbuf_append(ctxt->om, local_session_key, sizeof(local_session_key));
if (rc != 0) {
return BLE_ATT_ERR_INSUFFICIENT_RES;
}
rc = os_mbuf_append(ctxt->om, &(ble_svc_gap_km.iv), sizeof(ble_svc_gap_km.iv));
rc = os_mbuf_append(ctxt->om, local_iv, sizeof(local_iv));
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
}
#endif
#if MYNEWT_VAL(BLE_SVC_GAP_GATT_SECURITY_LEVEL)
@@ -569,8 +602,8 @@ ble_svc_gap_device_key_material_set(uint8_t *session_key, uint8_t *iv)
memcpy(&ble_svc_gap_km.session_key, session_key, BLE_EAD_KEY_SIZE);
memcpy(&ble_svc_gap_km.iv, iv, BLE_EAD_IV_SIZE);
ble_gatts_chr_updated(ble_svc_gap_enc_adv_data_handle);
ble_hs_unlock();
ble_gatts_chr_updated(ble_svc_gap_enc_adv_data_handle);
return 0;
}
#endif
@@ -32,6 +32,7 @@
#include "host/ble_gap.h"
#include "host/ble_gatt.h"
#include "services/hid/ble_svc_hid.h"
#include "../../../src/ble_hs_priv.h"
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
#include "esp_nimble_mem.h"
#endif
@@ -335,6 +336,7 @@ fill_boot_mouse_inp(uint16_t instance)
chr = ble_svc_hid_get_chr_block();
if (!chr) {
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_ENOMEM);
return BLE_HS_ENOMEM;
}
memcpy(chr, &demo_chr, sizeof(struct ble_gatt_chr_def));
@@ -915,9 +917,12 @@ ble_svc_hid_init(void)
/* Ensure this function only gets called by sysinit. */
SYSINIT_ASSERT_ACTIVE();
ble_hs_lock();
if (!ble_gatts_mutable()) {
ble_hs_unlock();
return;
}
ble_hs_unlock();
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (ble_svc_hid_static_vars == NULL) {
+7 -5
View File
@@ -50,10 +50,12 @@ static uint16_t ble_svc_htp_temp_type_val_handle;
static uint16_t ble_svc_htp_intr_temp_val_handle;
static uint16_t ble_svc_htp_msr_itvl_val_handle;
#if !MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
static struct {
uint16_t conn_handle;
struct chr_subscribe chr_subs;
} conn_chr_subs[MYNEWT_VAL(BLE_MAX_CONNECTIONS) + 1];
#endif
#define BLE_SVC_HTP_TEMP_MSR_MIN_ITVL 0x0001
#define BLE_SVC_HTP_TEMP_MSR_MAX_ITVL 0xffff
@@ -82,7 +84,7 @@ ble_svc_htp_conn_slot(uint16_t conn_handle, int allocate)
sizeof(conn_chr_subs[free_slot].chr_subs));
}
return free_slot;
return allocate ? free_slot : -1;
}
static uint32_t
@@ -98,10 +100,10 @@ ble_svc_htp_temp_to_ieee11073(float temp)
mantissa = (int32_t)(temp * 100.0f - 0.5f);
}
if (mantissa > 0x7fffff) {
mantissa = 0x7fffff;
} else if (mantissa < -0x800000) {
mantissa = -0x800000;
if (mantissa > 0x7ffffb) {
mantissa = 0x7ffffb;
} else if (mantissa < -0x7ffffd) {
mantissa = -0x7ffffd;
}
return ((uint32_t)exponent << 24) | ((uint32_t)mantissa & 0x00ffffff);
+7 -6
View File
@@ -141,8 +141,9 @@ ble_svc_lls_access(uint16_t conn_handle, uint16_t attr_handle,
* function when a BLE_GAP_EVENT_DISCONNECT event is received and
* pass the disconnect reason into this function.
*
* Here, we then check if the disconnect reason is due to a timout, and if
* so, we call the ble_svc_lls_event_fn callback with the current
* Here, we check if the disconnect reason indicates an unintentional link
* loss (not an explicit termination by the local host or remote user),
* and if so, call the ble_svc_lls_event_fn callback with the current
* alert level. The actual alert implementation is left up to the
* developer.
*
@@ -152,10 +153,10 @@ ble_svc_lls_access(uint16_t conn_handle, uint16_t attr_handle,
void
ble_svc_lls_on_gap_disconnect(int reason)
{
if (reason == BLE_HS_HCI_ERR(BLE_ERR_CONN_SPVN_TMO) ||
reason == BLE_HS_HCI_ERR(BLE_ERR_LMP_LL_RSP_TMO) ||
reason == BLE_HS_HCI_ERR(BLE_ERR_INSTANT_PASSED) ||
reason == BLE_HS_HCI_ERR(BLE_ERR_CONN_TERM_MIC)) {
if (reason != BLE_HS_HCI_ERR(BLE_ERR_REM_USER_CONN_TERM) &&
reason != BLE_HS_HCI_ERR(BLE_ERR_RD_CONN_TERM_RESRCS) &&
reason != BLE_HS_HCI_ERR(BLE_ERR_RD_CONN_TERM_PWROFF) &&
reason != BLE_HS_HCI_ERR(BLE_ERR_CONN_TERM_LOCAL)) {
if (ble_svc_lls_cb_fn != NULL) {
ble_svc_lls_cb_fn(ble_svc_lls_alert_level);
}
+15 -9
View File
@@ -19,6 +19,11 @@
#if MYNEWT_VAL(BLE_GATTS) && CONFIG_BT_NIMBLE_PROX_SERVICE
#define BLE_SVC_PROX_ALERT_NONE 0
#define BLE_SVC_PROX_ALERT_MILD 1
#define BLE_SVC_PROX_ALERT_HIGH 2
#define BLE_SVC_PROX_CONN_HANDLE_NONE 0xffff
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
typedef struct {
@@ -43,11 +48,6 @@ static ble_svc_prox_ctx_t * ble_svc_prox_ctx = NULL;
static uint8_t ble_svc_prox_alert;
static int8_t ble_svc_prox_tx_pwr_lvl;
#define BLE_SVC_PROX_ALERT_NONE 0
#define BLE_SVC_PROX_ALERT_MILD 1
#define BLE_SVC_PROX_ALERT_HIGH 2
#define BLE_SVC_PROX_CONN_HANDLE_NONE 0xffff
#endif /* MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC) */
/* Characteristic value handles */
@@ -140,7 +140,7 @@ ble_svc_prox_conn_slot(uint16_t conn_handle, int allocate)
ble_svc_prox_conn[free_slot].immediate_alert = false;
}
return free_slot;
return allocate ? free_slot : -1;
}
static const struct ble_gatt_svc_def ble_svc_prox_defs[] = {
@@ -457,14 +457,20 @@ ble_svc_prox_init(void)
ble_svc_prox_conn[i].immediate_alert = false;
}
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (ble_svc_prox_ctx->_ble_prox_task_handle == NULL) {
BaseType_t ret = xTaskCreate(ble_prox_prph_task, "ble_prox_prph_task",
4096, NULL, 10,
&ble_svc_prox_ctx->_ble_prox_task_handle);
SYSINIT_PANIC_ASSERT(ret == pdPASS);
}
#else
static TaskHandle_t ble_prox_task_handle;
if (ble_prox_task_handle == NULL) {
BaseType_t ret = xTaskCreate(ble_prox_prph_task, "ble_prox_prph_task",
4096, NULL, 10, &ble_prox_task_handle);
SYSINIT_PANIC_ASSERT(ret == pdPASS);
}
BaseType_t ret = xTaskCreate(ble_prox_prph_task, "ble_prox_prph_task", 4096, NULL, 10, &ble_prox_task_handle);
SYSINIT_PANIC_ASSERT(ret == pdPASS);
#endif
}
#endif
+9 -6
View File
@@ -425,22 +425,21 @@ static int gatt_svr_chr_access_ras_val(uint16_t conn_handle, uint16_t attr_handl
ble_svc_ras_od_rd_seg_len = 0;
}
/* Reset the ranging buffers */
ble_svc_ras_cp_val[0]= 0x02;
ble_svc_ras_cp_val[0] = RASCP_RSP_OPCODE_RSP_CODE;
/*Table 3.12. Response Code Values associated with Op Code 0x02*/
ble_svc_ras_cp_val[1]=0x01; // Success
ble_svc_ras_cp_val[2]=0x00; /* Clear stale 3rd byte */
ble_svc_ras_cp_val[1]=0x01; /* RASCP_OPCODE_ACK_RD (Request Op Code) */
ble_svc_ras_cp_val[2]=0x01; /* Success */
ble_gatts_chr_updated(ble_svc_ras_cp_val_handle);
MODLOG_DFLT(INFO, "Successfully completed the Ranging procedure\n");
for (int i = 0; i < BLE_RAS_MAX_SUBEVENTS_PER_PROCEDURE; i++) {
if (ranging_buffers[i].conn == conn_handle && ranging_buffers[i].isacked == false) {
if (ranging_buffers[i].conn == conn_handle) {
ranging_buffers[i].conn = -1; /* Release buffer */
ranging_buffers[i].isacked = false;
ranging_buffers[i].isbusy = false;
ranging_buffers[i].isready = false;
ranging_buffers[i].ranging_counter = 0;
ranging_buffers[i].subevent_cursor = 0;
break;
}
}
@@ -523,7 +522,11 @@ void ble_gatts_store_ranging_data(struct ble_cs_event ranging_subevent) {
buf->ranging_data.ranging_header.ranging_counter = ranging_subevent.subev_result.procedure_counter;
// buf->ranging_data.ranging_header.selected_tx_power = ranging_subevent.subev_result.selected_tx_power;
uint8_t num_paths = ranging_subevent.subev_result.num_antenna_paths;
buf->ranging_data.ranging_header.antenna_paths_mask = (num_paths > 0) ? ((1 << num_paths) - 1) : 0;
if (num_paths > 4) {
MODLOG_DFLT(WARN, "Unexpected num_antenna_paths: %d, capping to 4\n", num_paths);
num_paths = 4;
}
buf->ranging_data.ranging_header.antenna_paths_mask = (num_paths > 0) ? ((1u << num_paths) - 1) : 0;
uint16_t max_subevent_data = BLE_RAS_PROCEDURE_MEM - sizeof(struct ranging_header);
+8 -5
View File
@@ -70,6 +70,8 @@ static int
ble_svc_tps_access(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
struct ble_hci_cb_read_tx_pwr_cp cmd;
struct ble_hci_cb_read_tx_pwr_rp rsp;
int8_t tx_power_level;
int rc;
@@ -77,14 +79,15 @@ ble_svc_tps_access(uint16_t conn_handle, uint16_t attr_handle,
switch (ctxt->op) {
case BLE_GATT_ACCESS_OP_READ_CHR:
/* Returns advertising TX power as an approximation of the connection
* TX power level. A spec-compliant implementation would use
* HCI_Read_Transmit_Power_Level with conn_handle, which requires an
* async HCI exchange not possible inside a synchronous GATT callback. */
rc = ble_hs_hci_util_read_adv_tx_pwr(&tx_power_level);
cmd.conn_handle = htole16(conn_handle);
cmd.type = 0x01;
rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND,
BLE_HCI_OCF_CB_READ_TX_PWR),
&cmd, sizeof(cmd), &rsp, sizeof(rsp));
if (rc != 0) {
return BLE_ATT_ERR_UNLIKELY;
}
tx_power_level = rsp.tx_level;
rc = os_mbuf_append(ctxt->om, &tx_power_level,
sizeof tx_power_level);
+18 -4
View File
@@ -138,6 +138,17 @@ ble_aes_ccm_encrypt_be(const uint8_t *key, const uint8_t *plaintext, uint8_t *en
#else
#include <tinycrypt/aes.h>
#include <tinycrypt/constants.h>
static void
ble_aes_ccm_secure_zero(void *buf, size_t len)
{
volatile uint8_t *p = buf;
while (len--) {
*p++ = 0;
}
}
int
ble_aes_ccm_encrypt_be(const uint8_t *key, const uint8_t *plaintext, uint8_t *enc_data)
{
@@ -158,7 +169,7 @@ ble_aes_ccm_encrypt_be(const uint8_t *key, const uint8_t *plaintext, uint8_t *en
done:
/* Securely erase sensitive key material from stack */
memset(&s, 0, sizeof(s));
ble_aes_ccm_secure_zero(&s, sizeof(s));
return rc;
}
#endif
@@ -375,9 +386,12 @@ int ble_aes_ccm_decrypt(const uint8_t key[16], uint8_t nonce[13], const uint8_t
return rc;
}
/* Compare calculated MIC with received MIC */
if (memcmp(mic, enc_msg + msg_len, mic_size) != 0) {
/* Zero out the decrypted plaintext on authentication failure */
/* Compare calculated MIC with received MIC in constant time. */
uint8_t diff = 0;
for (size_t i = 0; i < mic_size; i++) {
diff |= mic[i] ^ enc_msg[msg_len + i];
}
if (diff != 0) {
memset(out_msg, 0, msg_len);
return BLE_HS_EAUTHEN;
}
+22 -3
View File
@@ -37,6 +37,9 @@
#define max(a, b) ((a) > (b) ? (a) : (b))
#endif
/* Core Spec Vol 3 Part G 5.3.1: minimum ATT_MTU for Enhanced ATT bearers */
#define BLE_ATT_EATT_MIN_MTU 64
static uint16_t ble_att_preferred_mtu_val;
/** Dispatch table for incoming ATT requests. */
@@ -551,7 +554,7 @@ ble_att_chan_mtu(const struct ble_l2cap_chan *chan)
* MTU field values of the two devices. Reference:
* Core v5.4 Vol 3 Part G 5.3.1 ATT_MTU */
return max(min(chan->coc_tx.mtu, chan->coc_rx.mtu), 64);
return max(min(chan->coc_tx.mtu, chan->coc_rx.mtu), BLE_ATT_EATT_MIN_MTU);
}
#endif
@@ -592,8 +595,24 @@ ble_att_rx_handle_unknown_request(uint8_t op, uint16_t conn_handle,
return;
}
if (op == BLE_ATT_OP_NOTIFY_REQ || op == BLE_ATT_OP_INDICATE_REQ ||
op == BLE_ATT_OP_NOTIFY_MULTI_REQ) {
if (op == BLE_ATT_OP_INDICATE_REQ) {
struct os_mbuf *txom;
os_mbuf_free_chain(*om);
*om = NULL;
txom = ble_hs_mbuf_l2cap_pkt();
if (txom == NULL) {
return;
}
if (ble_att_cmd_prepare(BLE_ATT_OP_INDICATE_RSP, 0, txom) == NULL) {
return;
}
ble_att_tx(conn_handle, cid, txom);
return;
}
if (op == BLE_ATT_OP_NOTIFY_REQ || op == BLE_ATT_OP_NOTIFY_MULTI_REQ) {
return;
}
+10 -11
View File
@@ -83,6 +83,7 @@ ble_att_clt_tx_mtu(uint16_t conn_handle, uint16_t mtu)
} else if (chan->flags & BLE_L2CAP_CHAN_F_TXED_MTU) {
rc = BLE_HS_EALREADY;
} else {
chan->flags |= BLE_L2CAP_CHAN_F_TXED_MTU;
rc = 0;
}
ble_hs_unlock();
@@ -105,13 +106,6 @@ ble_att_clt_tx_mtu(uint16_t conn_handle, uint16_t mtu)
req->bamc_mtu = htole16(mtu);
ble_hs_lock();
rc = ble_att_conn_chan_find(conn_handle, BLE_L2CAP_CID_ATT, &conn, &chan);
if (rc == 0) {
chan->flags |= BLE_L2CAP_CHAN_F_TXED_MTU;
}
ble_hs_unlock();
rc = ble_att_tx(conn_handle, BLE_L2CAP_CID_ATT, txom);
if (rc != 0) {
/* Rollback the flag so future MTU exchanges are not blocked */
@@ -620,10 +614,10 @@ ble_att_clt_tx_read_mult(uint16_t conn_handle, uint16_t cid,
req->handles[i] = htole16(handles[i]);
}
if (OS_MBUF_PKTLEN(txom) > ble_att_mtu_by_cid(conn_handle, cid)) {
os_mbuf_free_chain(txom);
return BLE_HS_EMSGSIZE;
}
/* MTU was already validated before allocation above; a second check here
* would only race with a concurrent MTU exchange and reject a packet that
* has already passed validation.
*/
return ble_att_tx(conn_handle, cid, txom);
}
@@ -905,6 +899,11 @@ ble_att_clt_tx_signed_write_cmd(uint16_t conn_handle, uint16_t cid, uint16_t han
goto err;
}
if (counter == UINT32_MAX) {
rc = BLE_HS_EINVAL;
goto err;
}
/** Copying sign counter */
counter_le = htole32(counter);
memcpy(&message[BLE_ATT_SIGNED_WRITE_DATA_OFFSET + payload_len],
+76 -18
View File
@@ -27,6 +27,10 @@
#include "host/ble_hs_log.h"
#if NIMBLE_BLE_CONNECT
/**
* Prepares an ATT command for transmission. On failure, the txom mbuf is
* freed and NULL is returned.
*/
void *
ble_att_cmd_prepare(uint8_t opcode, size_t len, struct os_mbuf *txom)
{
@@ -246,7 +250,10 @@ ble_att_mtu_req_parse(const void *payload, int len,
src = ble_att_init_parse(BLE_ATT_OP_MTU_REQ, payload, BLE_ATT_MTU_CMD_SZ,
len);
if (src == NULL) { return; }
if (src == NULL) {
memset(dst, 0, sizeof *dst);
return;
}
dst->bamc_mtu = le16toh(src->bamc_mtu);
}
@@ -258,7 +265,10 @@ ble_att_mtu_rsp_parse(const void *payload, int len,
src = ble_att_init_parse(BLE_ATT_OP_MTU_RSP, payload, BLE_ATT_MTU_CMD_SZ,
len);
if (src == NULL) { return; }
if (src == NULL) {
memset(dst, 0, sizeof *dst);
return;
}
dst->bamc_mtu = le16toh(src->bamc_mtu);
}
@@ -294,7 +304,10 @@ ble_att_find_info_req_parse(const void *payload, int len,
src = ble_att_init_parse(BLE_ATT_OP_FIND_INFO_REQ, payload,
BLE_ATT_FIND_INFO_REQ_SZ, len);
if (src == NULL) { return; }
if (src == NULL) {
memset(dst, 0, sizeof *dst);
return;
}
dst->bafq_start_handle = le16toh(src->bafq_start_handle);
dst->bafq_end_handle = le16toh(src->bafq_end_handle);
}
@@ -320,7 +333,10 @@ ble_att_find_info_rsp_parse(const void *payload, int len,
src = ble_att_init_parse(BLE_ATT_OP_FIND_INFO_RSP, payload,
BLE_ATT_FIND_INFO_RSP_BASE_SZ, len);
if (src == NULL) { return; }
if (src == NULL) {
memset(dst, 0, sizeof *dst);
return;
}
dst->bafp_format = src->bafp_format;
}
@@ -344,7 +360,10 @@ ble_att_find_type_value_req_parse(const void *payload, int len,
src = ble_att_init_parse(BLE_ATT_OP_FIND_TYPE_VALUE_REQ, payload,
BLE_ATT_FIND_TYPE_VALUE_REQ_BASE_SZ, len);
if (src == NULL) { return; }
if (src == NULL) {
memset(dst, 0, sizeof *dst);
return;
}
dst->bavq_start_handle = le16toh(src->bavq_start_handle);
dst->bavq_end_handle = le16toh(src->bavq_end_handle);
dst->bavq_attr_type = le16toh(src->bavq_attr_type);
@@ -372,7 +391,10 @@ ble_att_read_type_req_parse(const void *payload, int len,
src = ble_att_init_parse(BLE_ATT_OP_READ_TYPE_REQ, payload,
BLE_ATT_READ_TYPE_REQ_BASE_SZ, len);
if (src == NULL) { return; }
if (src == NULL) {
memset(dst, 0, sizeof *dst);
return;
}
dst->batq_start_handle = le16toh(src->batq_start_handle);
dst->batq_end_handle = le16toh(src->batq_end_handle);
}
@@ -398,7 +420,10 @@ ble_att_read_type_rsp_parse(const void *payload, int len,
src = ble_att_init_parse(BLE_ATT_OP_READ_TYPE_RSP, payload,
BLE_ATT_READ_TYPE_RSP_BASE_SZ, len);
if (src == NULL) { return; }
if (src == NULL) {
memset(dst, 0, sizeof *dst);
return;
}
dst->batp_length = src->batp_length;
}
@@ -422,7 +447,10 @@ ble_att_read_req_parse(const void *payload, int len,
src = ble_att_init_parse(BLE_ATT_OP_READ_REQ, payload,
BLE_ATT_READ_REQ_SZ, len);
if (src == NULL) { return; }
if (src == NULL) {
memset(dst, 0, sizeof *dst);
return;
}
dst->barq_handle = le16toh(src->barq_handle);
}
@@ -446,7 +474,10 @@ ble_att_read_blob_req_parse(const void *payload, int len,
src = ble_att_init_parse(BLE_ATT_OP_READ_BLOB_REQ, payload,
BLE_ATT_READ_BLOB_REQ_SZ, len);
if (src == NULL) { return; }
if (src == NULL) {
memset(dst, 0, sizeof *dst);
return;
}
dst->babq_handle = le16toh(src->babq_handle);
dst->babq_offset = le16toh(src->babq_offset);
}
@@ -500,7 +531,10 @@ ble_att_read_group_type_req_parse(const void *payload, int len,
src = ble_att_init_parse(BLE_ATT_OP_READ_GROUP_TYPE_REQ, payload,
BLE_ATT_READ_GROUP_TYPE_REQ_BASE_SZ, len);
if (src == NULL) { return; }
if (src == NULL) {
memset(dst, 0, sizeof *dst);
return;
}
dst->bagq_start_handle = le16toh(src->bagq_start_handle);
dst->bagq_end_handle = le16toh(src->bagq_end_handle);
}
@@ -526,7 +560,10 @@ ble_att_read_group_type_rsp_parse(const void *payload, int len,
src = ble_att_init_parse(BLE_ATT_OP_READ_GROUP_TYPE_RSP, payload,
BLE_ATT_READ_GROUP_TYPE_RSP_BASE_SZ, len);
if (src == NULL) { return; }
if (src == NULL) {
memset(dst, 0, sizeof *dst);
return;
}
dst->bagp_length = src->bagp_length;
}
@@ -550,7 +587,10 @@ ble_att_write_req_parse(const void *payload, int len,
src = ble_att_init_parse(BLE_ATT_OP_WRITE_REQ, payload,
BLE_ATT_WRITE_REQ_BASE_SZ, len);
if (src == NULL) { return; }
if (src == NULL) {
memset(dst, 0, sizeof *dst);
return;
}
dst->bawq_handle = le16toh(src->bawq_handle);
}
@@ -562,7 +602,10 @@ ble_att_write_cmd_parse(const void *payload, int len,
src = ble_att_init_parse(BLE_ATT_OP_WRITE_CMD, payload,
BLE_ATT_WRITE_REQ_BASE_SZ, len);
if (src == NULL) { return; }
if (src == NULL) {
memset(dst, 0, sizeof *dst);
return;
}
dst->bawq_handle = le16toh(src->bawq_handle);
}
@@ -598,7 +641,10 @@ ble_att_prep_write_req_parse(const void *payload, int len,
src = ble_att_init_parse(BLE_ATT_OP_PREP_WRITE_REQ, payload,
BLE_ATT_PREP_WRITE_CMD_BASE_SZ, len);
if (src == NULL) { return; }
if (src == NULL) {
memset(dst, 0, sizeof *dst);
return;
}
dst->bapc_handle = le16toh(src->bapc_handle);
dst->bapc_offset = le16toh(src->bapc_offset);
}
@@ -624,7 +670,10 @@ ble_att_prep_write_rsp_parse(const void *payload, int len,
src = ble_att_init_parse(BLE_ATT_OP_PREP_WRITE_RSP, payload,
BLE_ATT_PREP_WRITE_CMD_BASE_SZ, len);
if (src == NULL) { return; }
if (src == NULL) {
memset(dst, 0, sizeof *dst);
return;
}
dst->bapc_handle = le16toh(src->bapc_handle);
dst->bapc_offset = le16toh(src->bapc_offset);
}
@@ -650,7 +699,10 @@ ble_att_exec_write_req_parse(const void *payload, int len,
src = ble_att_init_parse(BLE_ATT_OP_EXEC_WRITE_REQ, payload,
BLE_ATT_EXEC_WRITE_REQ_SZ, len);
if (src == NULL) { return; }
if (src == NULL) {
memset(dst, 0, sizeof *dst);
return;
}
dst->baeq_flags = src->baeq_flags;
}
@@ -688,7 +740,10 @@ ble_att_notify_req_parse(const void *payload, int len,
src = ble_att_init_parse(BLE_ATT_OP_NOTIFY_REQ, payload,
BLE_ATT_NOTIFY_REQ_BASE_SZ, len);
if (src == NULL) { return; }
if (src == NULL) {
memset(dst, 0, sizeof *dst);
return;
}
dst->banq_handle = le16toh(src->banq_handle);
}
@@ -712,7 +767,10 @@ ble_att_indicate_req_parse(const void *payload, int len,
src = ble_att_init_parse(BLE_ATT_OP_INDICATE_REQ, payload,
BLE_ATT_INDICATE_REQ_BASE_SZ, len);
if (src == NULL) { return; }
if (src == NULL) {
memset(dst, 0, sizeof *dst);
return;
}
dst->baiq_handle = le16toh(src->baiq_handle);
}
+32 -30
View File
@@ -1205,7 +1205,6 @@ ble_att_svr_fill_type_value(uint16_t conn_handle,
struct ble_att_svr_entry *ha;
uint8_t buf[16];
uint16_t attr_len;
uint16_t req_val_len;
uint16_t first;
uint16_t prev;
int any_entries;
@@ -1214,11 +1213,6 @@ ble_att_svr_fill_type_value(uint16_t conn_handle,
first = 0;
prev = 0;
rc = 0;
attr_om = NULL;
/* Length of the attribute value in the request. */
req_val_len = OS_MBUF_PKTLEN(rxom) -
sizeof(struct ble_att_find_type_value_req);
/* Iterate through the attribute list, keeping track of the current
* matching group. For each attribute entry, determine if data needs to be
@@ -1290,8 +1284,6 @@ ble_att_svr_fill_type_value(uint16_t conn_handle,
}
done:
os_mbuf_free_chain(attr_om);
any_entries = OS_MBUF_PKTHDR(txom)->omp_len >
BLE_ATT_FIND_TYPE_VALUE_RSP_BASE_SZ;
if (rc == 0 && !any_entries) {
@@ -1413,6 +1405,9 @@ static void ble_att_svr_make_conn_aware(uint16_t conn_handle) {
conn->bhc_gatt_svr.half_aware = 1;
ble_hs_conn_addrs(conn, &addrs);
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (ble_gatts_conn_aware_states != NULL)
#endif
for(i = 0; i < MYNEWT_VAL(BLE_STORE_MAX_BONDS); i++) {
if(memcmp(ble_gatts_conn_aware_states[i].peer_id_addr,
addrs.peer_id_addr.val, sizeof addrs.peer_id_addr.val) == 0) {
@@ -1435,6 +1430,9 @@ static bool ble_att_svr_check_conn_aware(uint16_t conn_handle) {
conn->bhc_gatt_svr.aware_state = true;
ble_hs_conn_addrs(conn, &addrs);
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (ble_gatts_conn_aware_states != NULL)
#endif
for(int i = 0; i < MYNEWT_VAL(BLE_STORE_MAX_BONDS); i++) {
if(memcmp(ble_gatts_conn_aware_states[i].peer_id_addr,
addrs.peer_id_addr.val, sizeof addrs.peer_id_addr.val) == 0) {
@@ -1467,10 +1465,9 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle, uint16_t cid,
struct ble_att_read_type_rsp *rsp;
struct ble_att_svr_entry *entry;
struct os_mbuf *txom;
struct os_mbuf *attr_om;
uint16_t attr_len;
uint16_t max_attr_len;
uint16_t mtu;
uint8_t buf[19];
int entry_written;
int txomlen;
int prev_attr_len;
@@ -1501,12 +1498,6 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle, uint16_t cid,
mtu = ble_att_mtu_by_cid(conn_handle, cid);
/* Per Core Spec: max attribute value length is min(ATT_MTU - 4, 253). */
max_attr_len = mtu - 4;
if (max_attr_len > 253) {
max_attr_len = 253;
}
/* Find all matching attributes, writing a record for each. */
entry = NULL;
while (1) {
@@ -1524,9 +1515,8 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle, uint16_t cid,
goto done;
}
attr_len = OS_MBUF_PKTLEN(attr_om);
if (attr_len > max_attr_len) {
attr_len = max_attr_len;
if (attr_len > mtu - 4) {
attr_len = mtu - 4;
}
if (prev_attr_len == 0) {
@@ -1549,14 +1539,12 @@ ble_att_svr_build_read_type_rsp(uint16_t conn_handle, uint16_t cid,
}
data->handle = htole16(entry->ha_handle_id);
os_mbuf_copydata(attr_om, 0, attr_len, data->value);
memcpy(data->value, buf, attr_len);
entry_written = 1;
}
}
done:
os_mbuf_free_chain(attr_om);
if (!entry_written) {
/* No matching attributes. */
if (*att_err == 0) {
@@ -1649,6 +1637,9 @@ ble_att_svr_rx_read_type(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rx
conn->bhc_gatt_svr.half_aware = 0;
ble_hs_conn_addrs(conn, &addrs);
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (ble_gatts_conn_aware_states != NULL)
#endif
for(i = 0; i < MYNEWT_VAL(BLE_STORE_MAX_BONDS); i++) {
if(memcmp(ble_gatts_conn_aware_states[i].peer_id_addr,
addrs.peer_id_addr.val, sizeof addrs.peer_id_addr.val) == 0) {
@@ -1734,6 +1725,7 @@ ble_att_svr_rx_read(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rxom)
if (ble_att_cmd_prepare(BLE_ATT_OP_READ_RSP, 0, txom) == NULL) {
att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
rc = BLE_HS_ENOMEM;
txom = NULL;
goto done;
}
@@ -1799,6 +1791,7 @@ ble_att_svr_rx_read_blob(uint16_t conn_handle, uint16_t cid, struct os_mbuf **rx
if (ble_att_cmd_prepare(BLE_ATT_OP_READ_BLOB_RSP, 0, txom) == NULL) {
att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
rc = BLE_HS_ENOMEM;
txom = NULL;
goto done;
}
@@ -1840,6 +1833,7 @@ ble_att_svr_build_read_mult_rsp(uint16_t conn_handle, uint16_t cid,
*att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
*err_handle = 0;
rc = BLE_HS_ENOMEM;
txom = NULL;
goto done;
}
@@ -1946,6 +1940,7 @@ ble_att_svr_build_read_mult_rsp_var(uint16_t conn_handle, uint16_t cid,
*att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
*err_handle = 0;
rc = BLE_HS_ENOMEM;
txom = NULL;
goto done;
}
@@ -1989,13 +1984,17 @@ ble_att_svr_build_read_mult_rsp_var(uint16_t conn_handle, uint16_t cid,
uint16_t le_len = htole16(tuple_len);
rc = os_mbuf_append(txom, &le_len, sizeof(le_len));
if (rc != 0) {
*att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
*err_handle = handle;
rc = BLE_HS_ENOMEM;
goto done;
}
if (tuple_len != 0) {
rc = os_mbuf_appendfrom(txom, tmp, 0, tuple_len);
if (rc != 0) {
*att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
*err_handle = handle;
rc = BLE_HS_ENOMEM;
goto done;
}
if (tuple_len != 0) {
@@ -2598,8 +2597,12 @@ ble_att_svr_rx_signed_write(uint16_t conn_handle, uint16_t cid, struct os_mbuf *
/* Strip the signature from the end of the mbuf. */
os_mbuf_adj(*rxom, -(BLE_ATT_SIGNED_WRITE_CMD_BASE_SZ - BLE_ATT_SIGNED_WRITE_DATA_OFFSET));
/* Extract received sign counter from the signature bytes */
uint32_t received_sign_counter;
memcpy(&received_sign_counter, sign, sizeof(received_sign_counter));
/* Authentication procedure */
len = OS_MBUF_PKTLEN(*rxom) + sizeof(value_sec.sign_counter) + 1;
len = OS_MBUF_PKTLEN(*rxom) + sizeof(received_sign_counter) + 1;
message = nimble_platform_mem_calloc(1,len);
if (message == NULL) {
rc = BLE_HS_ENOMEM;
@@ -2608,7 +2611,7 @@ ble_att_svr_rx_signed_write(uint16_t conn_handle, uint16_t cid, struct os_mbuf *
message[0] = BLE_ATT_OP_SIGNED_WRITE_CMD;
os_mbuf_copydata(*rxom, 0, OS_MBUF_PKTLEN(*rxom), &message[1]);
memcpy(&message[1 + OS_MBUF_PKTLEN(*rxom)], &value_sec.sign_counter, sizeof(value_sec.sign_counter));
memcpy(&message[1 + OS_MBUF_PKTLEN(*rxom)], &received_sign_counter, sizeof(received_sign_counter));
/* Converting message into little endian format */
swap_in_place(message, len);
@@ -2626,12 +2629,10 @@ ble_att_svr_rx_signed_write(uint16_t conn_handle, uint16_t cid, struct os_mbuf *
/* Converting cmac to little endian */
swap_in_place(cmac, sizeof cmac);
/* Extract received sign counter from the signature bytes */
uint32_t received_sign_counter;
memcpy(&received_sign_counter, sign, sizeof(received_sign_counter));
/* Comparing sign counter — received must be > stored to prevent replay attacks */
if (received_sign_counter <= value_sec.sign_counter) {
/* Comparing sign counter — received must be > stored to prevent replay
* attacks. UINT32_MAX means no signed message received yet. */
if (value_sec.sign_counter != UINT32_MAX &&
received_sign_counter <= value_sec.sign_counter) {
rc = BLE_HS_EAUTHEN;
goto err;
}
@@ -3089,6 +3090,7 @@ ble_att_svr_rx_exec_write(uint16_t conn_handle, uint16_t cid, struct os_mbuf **r
if (ble_att_cmd_prepare(BLE_ATT_OP_EXEC_WRITE_RSP, 0, txom) == NULL) {
att_err = BLE_ATT_ERR_INSUFFICIENT_RES;
rc = BLE_HS_ENOMEM;
txom = NULL;
goto done;
}
+20 -13
View File
@@ -370,7 +370,9 @@ ble_cs_wr_cached_rem_supp_cap(const struct ble_cs_wr_cached_rem_supp_cap_cp *cmd
BLE_HCI_OCF_LE_CS_WR_CACHED_REM_SUPP_CAP),
&cp, sizeof(cp), &rp, sizeof(rp));
rsp->conn_handle = le16toh(rp.conn_handle);
if (rc == 0) {
rsp->conn_handle = le16toh(rp.conn_handle);
}
return rc;
}
@@ -571,7 +573,8 @@ ble_hs_hci_evt_le_cs_rd_rem_supp_cap_complete(uint8_t subevent, const void *data
if (ev->status) {
BLE_HS_LOG(ERROR, "%s status error=%d\n", __func__, ev->status);
ble_cs_call_procedure_complete_cb(le16toh(ev->conn_handle), ev->status);
ble_cs_call_procedure_complete_cb(le16toh(ev->conn_handle),
BLE_HS_HCI_ERR(ev->status));
return BLE_HS_ECONTROLLER;
}
@@ -714,7 +717,8 @@ ble_hs_hci_evt_le_cs_rd_rem_fae_complete(uint8_t subevent, const void *data,
BLE_HS_LOG(INFO, "Remote has No_FAE, continuing to config");
} else if (ev->status) {
BLE_HS_LOG(ERROR, "FAE read failed with status 0x%02x, aborting", ev->status);
ble_cs_call_procedure_complete_cb(le16toh(ev->conn_handle), BLE_HS_ECONTROLLER);
ble_cs_call_procedure_complete_cb(le16toh(ev->conn_handle),
BLE_HS_HCI_ERR(ev->status));
return BLE_HS_ECONTROLLER;
}
@@ -749,6 +753,7 @@ ble_hs_hci_evt_le_cs_rd_rem_fae_complete(uint8_t subevent, const void *data,
rc = ble_gap_conn_find(cmd.conn_handle, &desc);
if (rc != 0) {
ble_cs_call_procedure_complete_cb(cmd.conn_handle, rc);
return rc;
}
@@ -780,7 +785,8 @@ ble_hs_hci_evt_le_cs_rd_rem_fae_complete(uint8_t subevent, const void *data,
if (desc.role == BLE_GAP_ROLE_MASTER) {
rc = ble_cs_create_config(&cmd);
if (rc) {
BLE_HS_LOG(INFO, "Failed to create CS config");
BLE_HS_LOG(ERROR, "Failed to create CS config, rc=%d", rc);
ble_cs_call_procedure_complete_cb(cmd.conn_handle, rc);
}
}
return rc;
@@ -804,7 +810,7 @@ ble_hs_hci_evt_le_cs_sec_enable_complete(uint8_t subevent, const void *data,
if (ev->status) {
BLE_HS_LOG(INFO, "Failed to enable CS security status=%d", ev->status);
ble_cs_call_procedure_complete_cb(le16toh(ev->conn_handle), ev->status);
ble_cs_call_procedure_complete_cb(le16toh(ev->conn_handle), BLE_HS_HCI_ERR(ev->status));
return BLE_HS_ECONTROLLER;
}
@@ -895,10 +901,15 @@ ble_hs_hci_evt_le_cs_config_complete(uint8_t subevent, const void *data,
if (ev->status) {
BLE_HS_LOG(ERROR, "%s status error=%d\n", __func__, ev->status);
ble_cs_call_procedure_complete_cb(le16toh(ev->conn_handle), ev->status);
ble_cs_call_procedure_complete_cb(le16toh(ev->conn_handle), BLE_HS_HCI_ERR(ev->status));
return BLE_HS_ECONTROLLER;
}
if (ev->action != 0x01) {
BLE_HS_LOG(DEBUG, "CS config removed or invalid action, skipping security enable");
return 0;
}
cmd.conn_handle = le16toh(ev->conn_handle);
/* Exchange CS security keys */
@@ -909,17 +920,13 @@ ble_hs_hci_evt_le_cs_config_complete(uint8_t subevent, const void *data,
return rc;
}
if (ev->action != 0x01) {
BLE_HS_LOG(DEBUG, "CS config removed or invalid action, skipping security enable");
return 0;
}
if (desc.role == BLE_GAP_ROLE_MASTER) {
rc = ble_cs_sec_enable(&cmd);
if (rc) {
BLE_HS_LOG(DEBUG, "Failed to enable CS security");
ble_cs_call_procedure_complete_cb(le16toh(ev->conn_handle), BLE_ERR_UNSPECIFIED);
ble_cs_call_procedure_complete_cb(le16toh(ev->conn_handle),
BLE_HS_HCI_ERR(BLE_ERR_UNSPECIFIED));
return rc;
}
}
@@ -940,7 +947,7 @@ ble_hs_hci_evt_le_cs_proc_enable_complete(uint8_t subevent, const void *data,
if (ev->status) {
BLE_HS_LOG(ERROR, "%s status error=%d\n", __func__, ev->status);
ble_cs_call_procedure_complete_cb(le16toh(ev->conn_handle), ev->status);
ble_cs_call_procedure_complete_cb(le16toh(ev->conn_handle), BLE_HS_HCI_ERR(ev->status));
return BLE_HS_ECONTROLLER;
}
+5 -5
View File
@@ -119,8 +119,8 @@ int ble_ead_encrypt(const uint8_t session_key[BLE_EAD_KEY_SIZE], const uint8_t i
}
if (payload_size == 0) {
BLE_HS_LOG(DEBUG, "payload_size is set to 0. The encrypted result will only contain the "
"Randomizer and the MIC.");
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_EINVAL);
return BLE_HS_EINVAL;
}
/* Ensure payload_size isn't too large to wrap around when adding overhead */
@@ -140,7 +140,7 @@ static int ead_decrypt(const uint8_t session_key[BLE_EAD_KEY_SIZE], const uint8_
uint8_t nonce[BLE_EAD_NONCE_SIZE];
/* Defense-in-depth: Validate size to prevent underflow (size_t is unsigned) */
if (encrypted_payload_size < BLE_EAD_RANDOMIZER_SIZE + BLE_EAD_MIC_SIZE) {
if (encrypted_payload_size < BLE_EAD_RANDOMIZER_SIZE + BLE_EAD_MIC_SIZE + 1) {
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_EINVAL);
return BLE_HS_EINVAL;
}
@@ -196,8 +196,8 @@ int ble_ead_decrypt(const uint8_t session_key[BLE_EAD_KEY_SIZE], const uint8_t i
return BLE_HS_EINVAL;
}
/* The underlying ead_decrypt already validates minimum size (Randomizer + MIC).
* BT spec allows empty AD structure sequences, so we don't enforce +2 bytes. */
/* The underlying ead_decrypt already validates minimum size (Randomizer + MIC + 1).
* 1 is added because BT spec mandates that the plaintext shall consist of one or more AD structures. (CSS Part A Section 1.23.2) */
return ead_decrypt(session_key, iv, encrypted_payload, encrypted_payload_size, payload);
}
+54 -29
View File
@@ -195,7 +195,10 @@ ble_eatt_wakeup_cb(struct ble_npl_event *ev)
struct os_mbuf *txom;
struct os_mbuf_pkthdr *omp;
struct ble_l2cap_chan_info info;
int rc;
struct ble_l2cap_chan *chan;
uint16_t conn_handle;
uint16_t cid;
int rc = 0;
eatt = ble_npl_event_get_arg(ev);
assert(eatt);
@@ -211,17 +214,36 @@ ble_eatt_wakeup_cb(struct ble_npl_event *ev)
txom = OS_MBUF_PKTHDR_TO_MBUF(omp);
ble_l2cap_get_chan_info(eatt->chan, &info);
/* We need to unlock before calling ble_eatt_tx because it might lock again or trigger callbacks */
chan = eatt->chan;
conn_handle = eatt->conn_handle;
cid = info.scid;
ble_hs_unlock();
rc = ble_eatt_tx(eatt->conn_handle, info.scid, txom);
rc = ble_l2cap_send(chan, txom);
ble_hs_lock();
/* Break if channel is stalled or busy - both will reschedule wakeup */
if (rc == BLE_HS_ESTALLED || rc == BLE_HS_EBUSY) {
/* Re-validate channel after lock drop: disconnect handler may have freed eatt */
eatt = ble_eatt_find(conn_handle, cid);
if (eatt == NULL) {
if (rc == BLE_HS_EBUSY || (rc != 0 && rc != BLE_HS_ESTALLED)) {
os_mbuf_free_chain(txom);
}
break;
}
/* On success (0) or other errors: continue to next packet */
if (rc == BLE_HS_EBUSY) {
STAILQ_INSERT_HEAD(&eatt->eatt_tx_q, OS_MBUF_PKTHDR(txom), omp_next);
ble_npl_eventq_put(ble_hs_evq_get(), &eatt->wakeup_ev);
break;
}
if (rc == BLE_HS_ESTALLED) {
break;
}
if (rc != 0) {
os_mbuf_free_chain(txom);
}
}
ble_hs_unlock();
}
@@ -258,7 +280,9 @@ ble_eatt_free_nolock(struct ble_eatt *eatt)
struct os_mbuf_pkthdr *omp;
ble_npl_eventq_remove(ble_hs_evq_get(), &eatt->setup_ev);
ble_npl_event_deinit(&eatt->setup_ev);
ble_npl_eventq_remove(ble_hs_evq_get(), &eatt->wakeup_ev);
ble_npl_event_deinit(&eatt->wakeup_ev);
while ((omp = STAILQ_FIRST(&eatt->eatt_tx_q)) != NULL) {
STAILQ_REMOVE_HEAD(&eatt->eatt_tx_q, omp_next);
@@ -272,9 +296,9 @@ ble_eatt_free_nolock(struct ble_eatt *eatt)
static void
ble_eatt_free(struct ble_eatt *eatt)
{
ble_hs_lock();
ble_hs_lock_nested();
ble_eatt_free_nolock(eatt);
ble_hs_unlock();
ble_hs_unlock_nested();
}
static int
@@ -410,14 +434,6 @@ ble_eatt_setup_cb(struct ble_npl_event *ev)
if (rc) {
BLE_EATT_LOG_ERROR("eatt: Failed to connect EATT on conn_handle 0x%04x (status=%d)\n",
eatt->conn_handle, rc);
/* ble_l2cap_enhanced_connect only frees the mbuf if it was consumed.
* If rc is non-zero, it means it failed before consuming it in most cases,
* but we need to be careful about double-free.
* The bug report says it double-frees because ble_l2cap_enhanced_connect
* already frees it on many error paths. */
if (om) {
os_mbuf_free_chain(om);
}
ble_eatt_free(eatt);
}
}
@@ -593,10 +609,13 @@ ble_eatt_get_available_chan_cid(uint16_t conn_handle, uint8_t op)
default_cid = ble_att_get_default_bearer_cid(conn_handle);
if (default_cid) {
eatt = ble_eatt_find(conn_handle, default_cid);
if (eatt && eatt->client_op) {
eatt = ble_eatt_find_not_busy(conn_handle);
}
} else {
eatt = ble_eatt_find_not_busy(conn_handle);
}
if (!eatt || eatt->client_op != 0) {
if (!eatt) {
cid = BLE_L2CAP_CID_ATT;
goto done;
}
@@ -646,28 +665,32 @@ ble_eatt_tx(uint16_t conn_handle, uint16_t cid, struct os_mbuf *txom)
}
ble_att_truncate_to_mtu(eatt->chan, txom);
rc = ble_l2cap_send(eatt->chan, txom);
struct ble_l2cap_chan *chan = eatt->chan;
ble_hs_unlock();
rc = ble_l2cap_send(chan, txom);
if (rc == 0) {
ble_hs_unlock();
goto done;
}
if (rc == BLE_HS_ESTALLED) {
BLE_EATT_LOG_DEBUG("ble_eatt_tx: Eatt stalled");
/* L2CAP owns the mbuf; COC_TX_UNSTALLED event will fire when ready */
/* Do NOT re-queue - this would cause use-after-free */
ble_hs_unlock();
return rc;
} else if (rc == BLE_HS_EBUSY) {
BLE_EATT_LOG_DEBUG("ble_eatt_tx: Message queued");
STAILQ_INSERT_HEAD(&eatt->eatt_tx_q, OS_MBUF_PKTHDR(txom), omp_next);
ble_npl_eventq_put(ble_hs_evq_get(), &eatt->wakeup_ev);
ble_hs_unlock();
return 0;
ble_hs_lock();
eatt = ble_eatt_find(conn_handle, cid);
if (eatt) {
STAILQ_INSERT_HEAD(&eatt->eatt_tx_q, OS_MBUF_PKTHDR(txom), omp_next);
ble_npl_eventq_put(ble_hs_evq_get(), &eatt->wakeup_ev);
ble_hs_unlock();
return 0;
} else {
os_mbuf_free_chain(txom);
ble_hs_unlock();
return BLE_HS_ENOENT;
}
} else {
BLE_EATT_LOG_ERROR("eatt: %s, ERROR %d ", __func__, rc);
/* Free mbuf and return error gracefully instead of crashing */
ble_hs_unlock();
os_mbuf_free_chain(txom);
return rc;
}
@@ -836,6 +859,8 @@ err:
nimble_platform_mem_free(ble_eatt_conn_mem);
ble_eatt_conn_mem = NULL;
#endif
os_mempool_unregister(&ble_eatt_sdu_mbuf_mempool);
os_mempool_unregister(&ble_eatt_conn_pool);
nimble_platform_mem_free(ble_eatt_ctx);
ble_eatt_ctx = NULL;
#endif
+31 -17
View File
@@ -116,11 +116,16 @@ ble_eddystone_set_svc_data_base(uint8_t frame_type)
*/
static int
ble_eddystone_set_adv_data_gen(struct ble_hs_adv_fields *adv_fields,
const uint8_t *svc_data,
uint8_t svc_data_len)
{
struct ble_hs_adv_fields fields;
ble_uuid16_t uuids16[BLE_EDDYSTONE_MAX_UUIDS16 + 1];
int rc;
if (adv_fields->num_uuids16 > BLE_EDDYSTONE_MAX_UUIDS16) {
fields = *adv_fields;
if (fields.num_uuids16 > BLE_EDDYSTONE_MAX_UUIDS16) {
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_EINVAL);
return BLE_HS_EINVAL;
}
@@ -128,36 +133,35 @@ ble_eddystone_set_adv_data_gen(struct ble_hs_adv_fields *adv_fields,
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_EINVAL);
return BLE_HS_EINVAL;
}
if (adv_fields->num_uuids16 > 0 && !adv_fields->uuids16_is_complete) {
if (fields.num_uuids16 > 0 && !fields.uuids16_is_complete) {
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_EINVAL);
return BLE_HS_EINVAL;
}
if (adv_fields->svc_data_uuid16_len != 0) {
if (fields.svc_data_uuid16_len != 0) {
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_EINVAL);
return BLE_HS_EINVAL;
}
ble_eddystone_uuids16[0] =
(ble_uuid16_t) BLE_UUID16_INIT(BLE_EDDYSTONE_SERVICE_UUID);
uuids16[0] = (ble_uuid16_t) BLE_UUID16_INIT(BLE_EDDYSTONE_SERVICE_UUID);
/* Only copy if there are UUIDs and the pointer is valid */
if (adv_fields->num_uuids16 > 0) {
if (adv_fields->uuids16 == NULL) {
if (fields.num_uuids16 > 0) {
if (fields.uuids16 == NULL) {
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_EINVAL);
return BLE_HS_EINVAL;
}
memmove(ble_eddystone_uuids16 + 1, adv_fields->uuids16,
adv_fields->num_uuids16 * sizeof(ble_uuid16_t));
memmove(uuids16 + 1, fields.uuids16,
fields.num_uuids16 * sizeof(ble_uuid16_t));
}
adv_fields->uuids16 = ble_eddystone_uuids16;
adv_fields->num_uuids16++;
adv_fields->uuids16_is_complete = 1;
fields.uuids16 = uuids16;
fields.num_uuids16++;
fields.uuids16_is_complete = 1;
adv_fields->svc_data_uuid16 = ble_eddystone_svc_data;
adv_fields->svc_data_uuid16_len = svc_data_len +
fields.svc_data_uuid16 = svc_data;
fields.svc_data_uuid16_len = svc_data_len +
BLE_EDDYSTONE_SVC_DATA_BASE_SZ;
rc = ble_gap_adv_set_fields(adv_fields);
rc = ble_gap_adv_set_fields(&fields);
if (rc != 0) {
return rc;
}
@@ -169,6 +173,7 @@ int
ble_eddystone_set_adv_data_uid(struct ble_hs_adv_fields *adv_fields,
const void *uid, int8_t measured_power)
{
uint8_t svc_data_copy[BLE_EDDYSTONE_MAX_SVC_DATA_LEN];
uint8_t *svc_data;
int rc;
@@ -208,9 +213,13 @@ ble_eddystone_set_adv_data_uid(struct ble_hs_adv_fields *adv_fields,
svc_data[1 + BLE_EDDYSTONE_UID_LEN] = 0x00;
svc_data[1 + BLE_EDDYSTONE_UID_LEN + 1] = 0x00;
memcpy(svc_data_copy, ble_eddystone_svc_data,
BLE_EDDYSTONE_UID_SVC_DATA_LEN + BLE_EDDYSTONE_SVC_DATA_BASE_SZ);
ble_hs_unlock();
rc = ble_eddystone_set_adv_data_gen(adv_fields, BLE_EDDYSTONE_UID_SVC_DATA_LEN);
rc = ble_eddystone_set_adv_data_gen(adv_fields, svc_data_copy,
BLE_EDDYSTONE_UID_SVC_DATA_LEN);
return rc;
}
@@ -221,6 +230,7 @@ ble_eddystone_set_adv_data_url(struct ble_hs_adv_fields *adv_fields,
uint8_t url_body_len, uint8_t url_suffix,
int8_t measured_power)
{
uint8_t svc_data_copy[BLE_EDDYSTONE_MAX_SVC_DATA_LEN];
uint8_t *svc_data;
int url_len;
int rc;
@@ -278,9 +288,13 @@ ble_eddystone_set_adv_data_url(struct ble_hs_adv_fields *adv_fields,
svc_data[2 + url_body_len] = url_suffix;
}
memcpy(svc_data_copy, ble_eddystone_svc_data,
url_len + 2 + BLE_EDDYSTONE_SVC_DATA_BASE_SZ);
ble_hs_unlock();
rc = ble_eddystone_set_adv_data_gen(adv_fields, url_len + 2);
rc = ble_eddystone_set_adv_data_gen(adv_fields, svc_data_copy,
url_len + 2);
return rc;
}
+506 -275
View File
File diff suppressed because it is too large Load Diff
+4 -2
View File
@@ -84,10 +84,12 @@ void ble_gap_rx_le_scan_timeout(void);
void ble_gap_rx_ext_adv_report(struct ble_gap_ext_disc_desc *desc);
void ble_gap_rx_adv_set_terminated(const struct ble_hci_ev_le_subev_adv_set_terminated *ev);
#if MYNEWT_VAL(BLE_PERIODIC_ADV)
void ble_gap_rx_peroidic_adv_sync_estab(const struct ble_hci_ev_le_subev_periodic_adv_sync_estab *ev);
void ble_gap_rx_peroidic_adv_sync_estab(const struct ble_hci_ev_le_subev_periodic_adv_sync_estab *ev, uint8_t subevent);
void ble_gap_rx_periodic_adv_rpt(const struct ble_hci_ev_le_subev_periodic_adv_rpt *ev);
void ble_gap_rx_periodic_adv_sync_lost(const struct ble_hci_ev_le_subev_periodic_adv_sync_lost *ev);
void ble_gap_rx_periodic_adv_sync_transfer(const struct ble_hci_ev_le_subev_periodic_adv_sync_transfer *ev);
void ble_gap_rx_periodic_adv_sync_transfer(
const struct ble_hci_ev_le_subev_periodic_adv_sync_transfer *ev,
uint8_t subevent);
#endif
#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_BIGINFO_REPORTS) && !MYNEWT_VAL(BLE_ISO)
void ble_gap_rx_biginfo_adv_rpt(const struct ble_hci_ev_le_subev_biginfo_adv_report *ev);
+2 -1
View File
@@ -205,12 +205,13 @@ struct ble_gatt_resources {
*/
uint16_t cccds;
#if MYNEWT_VAL(BLE_CPFD_CAFD)
/**
* Number of characteristic extended properties descriptors. Each of
* these also contributes to the total descriptor count.
*/
uint16_t ceps;
#if MYNEWT_VAL(BLE_CPFD_CAFD)
/**
* Number of client presentation format descriptors. Each of
* these also contributes to the total descriptor count.
+209 -359
View File
@@ -244,10 +244,11 @@ struct ble_gattc_proc {
};
STAILQ_HEAD(ble_gattc_proc_list, ble_gattc_proc);
#if MYNEWT_VAL(BLE_GATTC_PROC_PREEMPTION_PROTECT)
static struct ble_gattc_proc_list temp_proc_list;
#endif
STAILQ_HEAD(ble_gattc_proc_list, ble_gattc_proc);
/**
* Error functions - these handle an incoming ATT error response and apply it
@@ -925,7 +926,9 @@ ble_gattc_proc_free(struct ble_gattc_proc *proc)
static void
ble_gattc_proc_insert(struct ble_gattc_proc *proc, bool insert_head)
{
#if !MYNEWT_VAL(BLE_GATTC_PROC_PREEMPTION_PROTECT)
ble_gattc_dbg_assert_proc_not_inserted(proc);
#endif
ble_hs_lock();
{
@@ -947,6 +950,7 @@ ble_gattc_proc_insert(struct ble_gattc_proc *proc, bool insert_head)
}
#endif
}
if (insert_head) {
STAILQ_INSERT_HEAD(&ble_gattc_procs, proc, next);
} else {
@@ -955,6 +959,37 @@ ble_gattc_proc_insert(struct ble_gattc_proc *proc, bool insert_head)
ble_hs_unlock();
}
#if MYNEWT_VAL(BLE_GATTC_PROC_PREEMPTION_PROTECT)
static bool
ble_gattc_proc_remove_preempted(struct ble_gattc_proc *proc)
{
struct ble_gattc_proc *cur;
bool removed = false;
ble_hs_lock();
STAILQ_FOREACH(cur, &temp_proc_list, next) {
if (cur == proc) {
STAILQ_REMOVE(&temp_proc_list, proc, ble_gattc_proc, next);
removed = true;
break;
}
}
if (!removed) {
STAILQ_FOREACH(cur, &ble_gattc_procs, next) {
if (cur == proc) {
STAILQ_REMOVE(&ble_gattc_procs, proc, ble_gattc_proc, next);
removed = true;
break;
}
}
}
ble_hs_unlock();
return removed;
}
#endif
static void
ble_gattc_proc_set_exp_timer(struct ble_gattc_proc *proc)
{
@@ -1040,6 +1075,11 @@ static ble_gattc_err_fn *
ble_gattc_err_dispatch_get(uint8_t op)
{
BLE_HS_DBG_ASSERT(op < BLE_GATT_OP_CNT);
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (ble_gattc_ctx == NULL || ble_gattc_err_dispatch == NULL) {
return NULL;
}
#endif
return ble_gattc_err_dispatch[op];
}
@@ -1471,7 +1511,6 @@ ble_gattc_resume_procs(void)
{
struct ble_gattc_proc_list stall_list;
struct ble_gattc_proc *proc;
struct ble_gattc_proc *proc_next;
ble_gattc_resume_fn *resume_cb;
int rc;
@@ -1489,9 +1528,8 @@ ble_gattc_resume_procs(void)
proc->flags &= ~BLE_GATTC_PROC_F_STALLED;
rc = resume_cb(proc);
ble_gattc_process_status(proc, rc, false);
proc = proc_next;
}
}
static int32_t
@@ -2055,9 +2093,9 @@ done:
STATS_INC(ble_gattc_stats, disc_all_svcs_fail);
#if MYNEWT_VAL(BLE_GATTC_PROC_PREEMPTION_PROTECT)
if (proc != NULL) {
ble_hs_lock();
STAILQ_REMOVE(&temp_proc_list,proc,ble_gattc_proc, next);
ble_hs_unlock();
if (!ble_gattc_proc_remove_preempted(proc)) {
proc = NULL;
}
}
#endif
}
@@ -2471,9 +2509,16 @@ ble_gattc_find_inc_svcs_rx_read_rsp(struct ble_gattc_proc *proc, int status,
/* Proceed to the next service. */
proc->find_inc_svcs.cur_start = 0;
proc->find_inc_svcs.cur_end = 0;
/* Check if we've exhausted the handle range before resuming */
if (proc->find_inc_svcs.prev_handle >= proc->find_inc_svcs.end_handle) {
ble_gattc_find_inc_svcs_cb(proc, BLE_HS_EDONE, 0, NULL);
return BLE_HS_EDONE;
}
rc = ble_gattc_find_inc_svcs_resume(proc);
if (rc != 0) {
goto err;
return BLE_HS_EDONE;
}
return 0;
@@ -2650,9 +2695,9 @@ done:
STATS_INC(ble_gattc_stats, find_inc_svcs_fail);
#if MYNEWT_VAL(BLE_GATTC_PROC_PREEMPTION_PROTECT)
if (proc != NULL) {
ble_hs_lock();
STAILQ_REMOVE(&temp_proc_list, proc, ble_gattc_proc, next);
ble_hs_unlock();
if (!ble_gattc_proc_remove_preempted(proc)) {
proc = NULL;
}
}
#endif
}
@@ -2841,10 +2886,12 @@ ble_gattc_disc_all_chrs_rx_complete(struct ble_gattc_proc *proc, int status)
return BLE_HS_EDONE;
}
/* We can stop discovery if there are less than 2 attributes left since
* complete characteristic requires at least 2 handles.
/* Per Core Spec, discovery should continue until Attribute Not Found
* or until the next request would start beyond end_handle. The previous
* `+ 1 >= end_handle` short-circuit skipped the final spec-mandated
* READ_BY_TYPE when prev_handle == end_handle - 1.
*/
if (proc->disc_all_chrs.prev_handle + 1 >= proc->disc_all_chrs.end_handle) {
if (proc->disc_all_chrs.prev_handle >= proc->disc_all_chrs.end_handle) {
/* Characteristic discovery complete. */
ble_gattc_disc_all_chrs_cb(proc, BLE_HS_EDONE, 0, NULL);
return BLE_HS_EDONE;
@@ -2904,15 +2951,14 @@ ble_gattc_disc_all_chrs(uint16_t conn_handle, uint16_t start_handle,
}
done:
#if MYNEWT_VAL(BLE_GATTC_PROC_PREEMPTION_PROTECT)
if (proc != NULL) {
ble_hs_lock();
STAILQ_REMOVE(&temp_proc_list,proc,ble_gattc_proc, next);
ble_hs_unlock();
}
#endif
if (rc != 0) {
#if MYNEWT_VAL(BLE_GATTC_PROC_PREEMPTION_PROTECT)
if (proc != NULL) {
if (!ble_gattc_proc_remove_preempted(proc)) {
proc = NULL;
}
}
#endif
STATS_INC(ble_gattc_stats, disc_all_chrs_fail);
}
@@ -3134,6 +3180,9 @@ ble_gattc_disc_chrs_by_uuid(uint16_t conn_handle, uint16_t start_handle,
struct ble_gattc_proc *proc;
int rc;
#if MYNEWT_VAL(BLE_GATTC_PROC_PREEMPTION_PROTECT)
bool in_temp_list = false;
#endif
#if MYNEWT_VAL(BLE_GATT_CACHING)
rc = ble_gattc_cache_conn_search_chrs_by_uuid(conn_handle, start_handle, end_handle, uuid, cb, cb_arg);
@@ -3163,6 +3212,7 @@ ble_gattc_disc_chrs_by_uuid(uint16_t conn_handle, uint16_t start_handle,
#if MYNEWT_VAL(BLE_GATTC_PROC_PREEMPTION_PROTECT)
ble_hs_lock();
STAILQ_INSERT_TAIL(&temp_proc_list, proc, next);
in_temp_list = true;
ble_hs_unlock();
#endif
ble_gattc_log_disc_chr_uuid(proc);
@@ -3176,10 +3226,10 @@ done:
if (rc != 0) {
STATS_INC(ble_gattc_stats, disc_chrs_uuid_fail);
#if MYNEWT_VAL(BLE_GATTC_PROC_PREEMPTION_PROTECT)
if (proc != NULL) {
ble_hs_lock();
STAILQ_REMOVE(&temp_proc_list, proc, ble_gattc_proc, next);
ble_hs_unlock();
if (proc != NULL && in_temp_list) {
if (!ble_gattc_proc_remove_preempted(proc)) {
proc = NULL;
}
}
#endif
}
@@ -3303,8 +3353,8 @@ ble_gattc_disc_all_dscs_rx_idata(struct ble_gattc_proc *proc,
ble_gattc_dbg_assert_proc_not_inserted(proc);
if (idata->attr_handle <= proc->disc_all_dscs.prev_handle ||
idata->attr_handle > proc->disc_all_dscs.end_handle ||
idata->attr_handle < proc->disc_all_dscs.chr_val_handle) {
idata->attr_handle > proc->disc_all_dscs.end_handle) {
/* Peer sent descriptors out of order or out of range; terminate. */
rc = BLE_HS_EBADDATA;
goto done;
@@ -3405,18 +3455,17 @@ ble_gattc_disc_all_dscs(uint16_t conn_handle, uint16_t start_handle,
}
done:
/* One ble_gattc_proc cannot be part of multiple linked lists.
* Hence it needs to be removed before going into ble_gattc_process_status.
*/
#if MYNEWT_VAL(BLE_GATTC_PROC_PREEMPTION_PROTECT)
if (proc != NULL) {
ble_hs_lock();
STAILQ_REMOVE(&temp_proc_list,proc,ble_gattc_proc, next);
ble_hs_unlock();
}
#endif
if (rc != 0) {
/* One ble_gattc_proc cannot be part of multiple linked lists.
* Hence it needs to be removed before going into ble_gattc_process_status.
*/
#if MYNEWT_VAL(BLE_GATTC_PROC_PREEMPTION_PROTECT)
if (proc != NULL) {
if (!ble_gattc_proc_remove_preempted(proc)) {
proc = NULL;
}
}
#endif
STATS_INC(ble_gattc_stats, disc_all_dscs_fail);
}
@@ -3430,7 +3479,8 @@ int ble_gattc_check_valid_param(uint16_t num, uint16_t offset)
if (num == 0) {
return BLE_HS_ATT_ERR(BLE_ATT_ERR_ATTR_NOT_FOUND);
} else if (offset >= num) {
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_ATT_ERR_INVALID_OFFSET);
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__,
BLE_HS_ATT_ERR(BLE_ATT_ERR_INVALID_OFFSET));
return BLE_HS_ATT_ERR(BLE_ATT_ERR_INVALID_OFFSET);
}
@@ -3475,7 +3525,7 @@ static void ble_gattc_fill_gatt_db_conversion(uint16_t *count, uint16_t num, esp
}
break;
}
case BLE_GATT_DB_INCLUDED_SERVICE: {
case ESP_BLE_GATT_DB_INCLUDED_SERVICE: {
ble_gattc_included_svc_elem_t *incl_result = (ble_gattc_included_svc_elem_t *)result;
for (int i = 0; i < db_size; i++) {
incl_result->handle = db[offset + i].handle;
@@ -3825,10 +3875,6 @@ int ble_gattc_get_attr_count(uint16_t conn_handle, esp_ble_gatt_db_attr_type_t t
if (count == NULL) {
return BLE_HS_EINVAL;
}
if (ble_gattc_cache_conn_find(conn_handle) == NULL) {
*count = 0;
return BLE_HS_ENOTCONN;
}
if (type == ESP_BLE_GATT_DB_ALL) {
ble_gattc_get_db_size(conn_handle, start_handle, end_handle, count);
@@ -3845,13 +3891,12 @@ int ble_gattc_get_db(uint16_t conn_handle,
uint16_t num = 0;
ble_gattc_db_elem_t *db = NULL;
/* Not valid (issue-137): null check here is correct; downstream BLE_ATT_ERR_ATTR_NOT_FOUND conflation is pre-existing, not introduced by this MR */
if (count == NULL || result == NULL) {
return BLE_HS_EINVAL;
}
ble_hs_lock();
ble_gattc_get_cached_gatt_db(conn_handle, start_handle, end_handle, &db, &num, count);
ble_hs_unlock();
if (num == 0) {
return BLE_ATT_ERR_ATTR_NOT_FOUND;
@@ -4086,7 +4131,7 @@ ble_gattc_read_uuid_rx_adata(struct ble_gattc_proc *proc,
attr.om = ble_hs_mbuf_from_flat(adata->value, adata->value_len);
if (attr.om == NULL) {
rc = BLE_HS_ENOMEM;
ble_gattc_read_uuid_cb(proc, rc, adata->att_handle, NULL);
rc = ble_gattc_read_uuid_cb(proc, rc, adata->att_handle, NULL);
} else {
rc = 0;
rc = ble_gattc_read_uuid_cb(proc, rc, adata->att_handle, &attr);
@@ -4143,6 +4188,9 @@ ble_gattc_read_by_uuid(uint16_t conn_handle, uint16_t start_handle,
struct ble_gattc_proc *proc;
int rc;
#if MYNEWT_VAL(BLE_GATTC_PROC_PREEMPTION_PROTECT)
bool in_temp_list = false;
#endif
STATS_INC(ble_gattc_stats, read_uuid);
@@ -4166,6 +4214,7 @@ ble_gattc_read_by_uuid(uint16_t conn_handle, uint16_t start_handle,
#if MYNEWT_VAL(BLE_GATTC_PROC_PREEMPTION_PROTECT)
ble_hs_lock();
STAILQ_INSERT_TAIL(&temp_proc_list, proc, next);
in_temp_list = true;
ble_hs_unlock();
#endif
ble_gattc_log_read_uuid(start_handle, end_handle, uuid);
@@ -4178,10 +4227,10 @@ done:
if (rc != 0) {
STATS_INC(ble_gattc_stats, read_uuid_fail);
#if MYNEWT_VAL(BLE_GATTC_PROC_PREEMPTION_PROTECT)
if (proc != NULL) {
ble_hs_lock();
STAILQ_REMOVE(&temp_proc_list, proc, ble_gattc_proc, next);
ble_hs_unlock();
if (proc != NULL && in_temp_list) {
if (!ble_gattc_proc_remove_preempted(proc)) {
proc = NULL;
}
}
#endif
}
@@ -4392,9 +4441,9 @@ done:
STATS_INC(ble_gattc_stats, read_long_fail);
#if MYNEWT_VAL(BLE_GATTC_PROC_PREEMPTION_PROTECT)
if (proc != NULL) {
ble_hs_lock();
STAILQ_REMOVE(&temp_proc_list, proc, ble_gattc_proc, next);
ble_hs_unlock();
if (!ble_gattc_proc_remove_preempted(proc)) {
proc = NULL;
}
}
#endif
}
@@ -4448,32 +4497,39 @@ ble_gattc_read_mult_cb_var(struct ble_gattc_proc *proc, int status,
attr_len = get_le16((*om)->om_data);
os_mbuf_adj(*om, 2);
if (attr_len > BLE_ATT_ATTR_MAX_LEN || attr_len > OS_MBUF_PKTLEN(*om)) {
if (attr_len > BLE_ATT_ATTR_MAX_LEN) {
status = BLE_HS_EBADDATA;
break;
}
attr[i].om = os_msys_get_pkthdr(attr_len, 0);
if (!attr[i].om) {
status = BLE_HS_ENOMEM;
break;
}
{
uint16_t copy_len = attr_len;
rc = os_mbuf_appendfrom(attr[i].om, *om, 0, attr_len);
if (rc) {
status = BLE_HS_ENOMEM;
break;
}
/* failed to correctly parse response,
* cleanup any partial data and set status if not set already
*/
if (i < proc->read_mult.num_handles || OS_MBUF_PKTLEN(*om) != 0) {
for (i = 0; i < proc->read_mult.num_handles; i++) {
os_mbuf_free_chain(attr[i].om);
attr[i].om = NULL;
if (copy_len > OS_MBUF_PKTLEN(*om)) {
copy_len = OS_MBUF_PKTLEN(*om);
}
attr[i].om = os_msys_get_pkthdr(copy_len, 0);
if (!attr[i].om) {
status = BLE_HS_ENOMEM;
break;
}
rc = os_mbuf_appendfrom(attr[i].om, *om, 0, copy_len);
if (rc) {
status = BLE_HS_ENOMEM;
break;
}
os_mbuf_adj(*om, copy_len);
if (copy_len < attr_len) {
i++;
break;
}
}
}
proc->read_mult.cb_mult(proc->conn_handle,
ble_gattc_error(status, att_handle), &attr[0],
proc->read_mult.num_handles, proc->read_mult.cb_arg);
@@ -4716,7 +4772,7 @@ ble_gattc_write_no_rsp(uint16_t conn_handle, uint16_t attr_handle,
cid = ble_eatt_get_available_chan_cid(conn_handle, BLE_GATT_OP_DUMMY);
rc = ble_att_clt_tx_write_cmd(conn_handle, cid, attr_handle, txom);
if (rc != 0) {
STATS_INC(ble_gattc_stats, write);
STATS_INC(ble_gattc_stats, write_no_rsp_fail);
}
ble_eatt_release_chan(conn_handle, cid);
@@ -4762,7 +4818,6 @@ ble_gattc_signed_write(uint16_t conn_handle, uint16_t attr_handle,
}
int rc;
uint16_t cid;
struct ble_store_value_sec value_sec;
struct ble_store_key_sec key_sec;
struct ble_gap_conn_desc desc;
@@ -4797,11 +4852,11 @@ ble_gattc_signed_write(uint16_t conn_handle, uint16_t attr_handle,
/* Converting the csrk to little endian */
swap_buf(csrk, value_sec.csrk, 16);
cid = ble_eatt_get_available_chan_cid(conn_handle, BLE_GATT_OP_DUMMY);
rc = ble_att_clt_tx_signed_write_cmd(conn_handle, cid, attr_handle,
rc = ble_att_clt_tx_signed_write_cmd(conn_handle, BLE_L2CAP_CID_ATT, attr_handle,
csrk, value_sec.sign_counter, txom);
txom = NULL;
ble_eatt_release_chan(conn_handle, cid);
if (rc == 0) {
txom = NULL;
}
if (rc != 0) {
goto err;
}
@@ -5201,7 +5256,7 @@ ble_gattc_write_long_rx_exec(struct ble_gattc_proc *proc, int status)
* response.
*/
ble_gattc_write_long_cb(proc, BLE_HS_EBADDATA, 0);
return BLE_HS_EBADDATA;
return BLE_HS_EDONE;
}
ble_gattc_write_long_cb(proc, status, 0);
@@ -5328,7 +5383,8 @@ ble_gattc_write_reliable_tx(struct ble_gattc_proc *proc)
{
struct ble_gatt_attr *attr;
struct os_mbuf *om;
int16_t max_sz;
uint16_t max_sz;
uint16_t mtu;
int attr_idx;
int rc;
@@ -5346,12 +5402,12 @@ ble_gattc_write_reliable_tx(struct ble_gattc_proc *proc)
attr = proc->write_reliable.attrs + attr_idx;
max_sz = ble_att_mtu_by_cid(proc->conn_handle, proc->cid) - BLE_ATT_PREP_WRITE_CMD_BASE_SZ;
if (max_sz <= 0) {
/* Not connected. */
mtu = ble_att_mtu_by_cid(proc->conn_handle, proc->cid);
if (mtu <= BLE_ATT_PREP_WRITE_CMD_BASE_SZ) {
rc = BLE_HS_ENOTCONN;
goto done;
}
max_sz = mtu - BLE_ATT_PREP_WRITE_CMD_BASE_SZ;
proc->write_reliable.length =
min(max_sz, OS_MBUF_PKTLEN(attr->om) - attr->offset);
@@ -5390,7 +5446,10 @@ ble_gattc_write_reliable_resume(struct ble_gattc_proc *proc)
status = ble_gattc_write_reliable_tx(proc);
rc = ble_gattc_process_resume_status(proc, status);
if (rc != 0) {
ble_gattc_write_reliable_cb(proc, rc, 0);
/* Fire error callback here so ble_gattc_resume_procs (which calls
* ble_gattc_process_status with call_cb=false) does not silently
* drop the proc without notifying the application. */
ble_gattc_write_reliable_err(proc, rc, 0);
return rc;
}
@@ -5410,8 +5469,14 @@ ble_gattc_write_reliable_err(struct ble_gattc_proc *proc, int status,
/* If we have successfully queued any data, and the failure occurred before
* we could send the execute write command, then erase all queued data
* BEFORE invoking the application callback to keep peer state consistent.
* cur_attr is incremented only after an attribute is fully queued; offset
* is advanced only after a verified Prepare Write Response. BLE_HS_EBADDATA
* means the peer queued data but local verification failed — cancel anyway.
*/
if (proc->write_reliable.cur_attr < proc->write_reliable.num_attrs) {
if ((proc->write_reliable.cur_attr > 0 ||
proc->write_reliable.attrs[proc->write_reliable.cur_attr].offset > 0 ||
status == BLE_HS_EBADDATA) &&
proc->write_reliable.cur_attr < proc->write_reliable.num_attrs) {
ble_att_clt_tx_exec_write(proc->conn_handle, proc->cid,
BLE_ATT_EXEC_WRITE_F_CANCEL);
@@ -5477,6 +5542,8 @@ ble_gattc_write_reliable_rx_prep(struct ble_gattc_proc *proc,
}
rc = ble_gattc_write_reliable_resume(proc);
if (rc != 0) {
/* resume() already called ble_gattc_write_reliable_err(); skip err:
* label to avoid firing the application callback a second time. */
return BLE_HS_EDONE;
}
@@ -5556,9 +5623,11 @@ done:
}
/* Free supplied mbufs in case something failed. */
for (i = 0; i < num_attrs; i++) {
os_mbuf_free_chain(attrs[i].om);
attrs[i].om = NULL;
if (attrs != NULL) {
for (i = 0; i < num_attrs; i++) {
os_mbuf_free_chain(attrs[i].om);
attrs[i].om = NULL;
}
}
ble_gattc_process_status(proc, rc, false);
@@ -5626,10 +5695,8 @@ ble_gatts_notify_custom(uint16_t conn_handle, uint16_t chr_val_handle,
rc = BLE_HS_ENOMEM;
goto done;
}
ble_hs_lock();
rc = ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE,
chr_val_handle, 0, &txom, NULL);
ble_hs_unlock();
if (rc != 0) {
/* Fatal error; application disallowed attribute read. */
rc = BLE_HS_EAPP;
@@ -5656,7 +5723,6 @@ done:
return rc;
}
int
ble_gatts_notify_multiple_custom(uint16_t conn_handle,
size_t chr_count,
@@ -5674,7 +5740,6 @@ ble_gatts_notify_multiple_custom(uint16_t conn_handle,
uint16_t mtu = ble_att_mtu(conn_handle) - 1;
struct os_mbuf *txom;
struct ble_hs_conn *conn;
bool free_unused_tuples = false;
txom = ble_hs_mbuf_att_pkt();
if (txom == NULL) {
@@ -5710,7 +5775,6 @@ ble_gatts_notify_multiple_custom(uint16_t conn_handle,
rc = ble_att_svr_read_local(tuples[i].handle, &tuples[i].value);
if (rc != 0) {
BLE_HS_LOG(ERROR, "Attribute read failed (err=0x%02x)", rc);
free_unused_tuples = true;
goto done;
}
}
@@ -5733,7 +5797,13 @@ ble_gatts_notify_multiple_custom(uint16_t conn_handle,
if (OS_MBUF_PKTLEN(txom) + OS_MBUF_PKTLEN(tuples[i].value) > mtu && cur_chr_cnt < 2) {
/* Flush any previously buffered characteristic first to maintain ordering */
if (cur_chr_cnt == 1) {
rc = ble_att_clt_tx_multi_notify(conn_handle, txom);
/* Strip the 4-byte handle+length header and send as a standard
* single-value notification: the spec requires at least two
* handle-value pairs in ATT_MULTIPLE_HANDLE_VALUE_NTF. */
os_mbuf_adj(txom, 4);
rc = ble_att_clt_tx_notify(conn_handle,
tuples[last_appended_idx].handle,
txom);
txom = NULL;
if (rc != 0) {
goto done;
@@ -5767,11 +5837,19 @@ ble_gatts_notify_multiple_custom(uint16_t conn_handle,
}
/* Handle */
os_mbuf_append(txom, &tuples[i].handle, sizeof(uint16_t));
rc = os_mbuf_append(txom, &tuples[i].handle, sizeof(uint16_t));
if (rc != 0) {
rc = BLE_HS_ENOMEM;
goto done;
}
/* Length */
os_mbuf_append(txom, &OS_MBUF_PKTLEN(tuples[i].value),
sizeof(uint16_t));
rc = os_mbuf_append(txom, &OS_MBUF_PKTLEN(tuples[i].value),
sizeof(uint16_t));
if (rc != 0) {
rc = BLE_HS_ENOMEM;
goto done;
}
/* Value */
os_mbuf_concat(txom, tuples[i].value);
@@ -5786,7 +5864,7 @@ ble_gatts_notify_multiple_custom(uint16_t conn_handle,
rc = ble_att_clt_tx_notify(conn_handle, tuples[last_appended_idx].handle,
txom);
txom = NULL;
} else {
} else if (cur_chr_cnt >= 2) {
rc = ble_att_clt_tx_multi_notify(conn_handle, txom);
txom = NULL;
}
@@ -5799,13 +5877,6 @@ done:
tuples[i].value = NULL;
}
STATS_INC(ble_gattc_stats, multi_notify_fail);
if (free_unused_tuples) {
for (i = 0; i < chr_count; i++) {
if (tuples[i].value != NULL) {
os_mbuf_free_chain(tuples[i].value);
}
}
}
}
os_mbuf_free_chain(txom);
@@ -5848,6 +5919,13 @@ ble_gattc_cccd_write_complete_cb(uint16_t conn_handle,
"status=%d conn_handle=%d attr_handle=%d",
error->status, conn_handle, attr->handle);
ble_hs_lock();
gatt_proc_active = false;
ble_hs_unlock();
if (arg != NULL) {
nimble_platform_mem_free(arg);
}
return 0;
}
@@ -5860,7 +5938,9 @@ static int ble_gattc_cccd_register_cb(uint16_t conn_handle, const struct ble_gat
if (error->status == BLE_HS_EDONE) {
/* GATT procedure completed reset active flag */
ble_hs_lock();
gatt_proc_active = false;
ble_hs_unlock();
if (cccd_reg_flag) {
nimble_platform_mem_free(cccd_reg_flag);
}
@@ -5876,15 +5956,22 @@ static int ble_gattc_cccd_register_cb(uint16_t conn_handle, const struct ble_gat
rc = ble_gattc_write_flat(conn_handle,
dsc->handle,
cccd_val, sizeof(cccd_val),
ble_gattc_cccd_write_complete_cb, NULL);
ble_gattc_cccd_write_complete_cb, cccd_reg_flag);
if (rc != 0) {
BLE_HS_LOG(WARN, "Failed to Register for Notification, status = %d", rc);
ble_hs_lock();
gatt_proc_active = false;
ble_hs_unlock();
nimble_platform_mem_free(cccd_reg_flag);
return rc;
}
return BLE_HS_EDONE;
}
} else {
BLE_HS_LOG(WARN, "GATT descriptor discovery failed with status = %d", error->status);
ble_hs_lock();
gatt_proc_active = false;
ble_hs_unlock();
if (cccd_reg_flag) {
nimble_platform_mem_free(cccd_reg_flag);
}
@@ -5920,7 +6007,9 @@ int ble_gattc_register_for_notification(uint16_t conn_handle, uint16_t char_val_
int rc = ble_gattc_disc_all_dscs(conn_handle, char_val_handle, 0xffff,
ble_gattc_cccd_register_cb, cccd_reg_flag);
if (rc != 0) {
ble_hs_lock();
gatt_proc_active = false;
ble_hs_unlock();
nimble_platform_mem_free(cccd_reg_flag);
}
@@ -5936,7 +6025,9 @@ static int ble_gattc_cccd_unregister_cb(uint16_t conn_handle, const struct ble_g
if (error->status == BLE_HS_EDONE) {
/* GATT procedure completed reset active flag */
ble_hs_lock();
gatt_proc_active = false;
ble_hs_unlock();
if (cccd_unreg_flag) {
nimble_platform_mem_free(cccd_unreg_flag);
}
@@ -5952,15 +6043,22 @@ static int ble_gattc_cccd_unregister_cb(uint16_t conn_handle, const struct ble_g
rc = ble_gattc_write_flat(conn_handle,
dsc->handle,
cccd_val, sizeof(cccd_val),
ble_gattc_cccd_write_complete_cb, NULL);
ble_gattc_cccd_write_complete_cb, cccd_unreg_flag);
if (rc != 0) {
BLE_HS_LOG(WARN, "Failed to Unregister for Notification, status = %d", rc);
ble_hs_lock();
gatt_proc_active = false;
ble_hs_unlock();
nimble_platform_mem_free(cccd_unreg_flag);
return rc;
}
return BLE_HS_EDONE;
}
} else {
BLE_HS_LOG(WARN, "GATT descriptor discovery failed with status = %d", error->status);
ble_hs_lock();
gatt_proc_active = false;
ble_hs_unlock();
if (cccd_unreg_flag) {
nimble_platform_mem_free(cccd_unreg_flag);
}
@@ -6009,252 +6107,6 @@ int ble_gattc_unregister_for_notification(uint16_t conn_handle, uint16_t char_va
#endif //MYNEWT_VAL(BLE_STORE_MAX_CCCDS)
#endif //MYNEWT_VAL(BLE_GATTC)
#if MYNEWT_VAL(BLE_GATTS)
int
ble_gatts_notify_multiple_custom(uint16_t conn_handle,
size_t chr_count,
struct ble_gatt_notif *tuples)
{
#if !MYNEWT_VAL(BLE_GATT_NOTIFY)
return BLE_HS_ENOTSUP;
#endif
int rc;
size_t i = 0;
uint16_t cur_chr_cnt = 0;
/* mtu = MTU - 1 octet (OP code) */
uint16_t mtu = ble_att_mtu(conn_handle) - 1;
struct os_mbuf *txom;
struct ble_hs_conn *conn;
txom = ble_hs_mbuf_att_pkt();
if (txom == NULL) {
return BLE_HS_ENOMEM;
}
conn = ble_hs_conn_find(conn_handle);
if (conn == NULL) {
return BLE_HS_ENOTCONN;
}
/* Read missing values */
for (i = 0; i < chr_count; i++) {
if (tuples->handle == 0) {
rc = BLE_HS_EINVAL;
goto done;
}
if (tuples[i].value == NULL) {
rc = ble_att_svr_read_local(tuples[i].handle, &tuples[i].value);
if (rc != 0) {
goto done;
}
}
}
/* If peer does not support fall back to multiple single value
* Notifications */
if ((conn->bhc_gatt_svr.peer_cl_sup_feat[0] & 0x04) == 0) {
for (i = 0; i < chr_count; i++) {
rc = ble_att_clt_tx_notify(conn_handle, tuples[chr_count].handle,
tuples[chr_count].value);
if (rc != 0) {
goto done;
}
}
}
for (i = 0; i < chr_count; i++) {
if (txom->om_len + tuples[i].value->om_len > mtu && cur_chr_cnt < 2) {
rc = ble_att_clt_tx_notify(conn_handle, tuples[i].handle,
tuples[i].value);
if (rc != 0) {
goto done;
}
continue;
} else if (txom->om_len + tuples[i].value->om_len > mtu) {
rc = ble_att_clt_tx_notify_mult(conn_handle, txom);
if (rc != 0) {
goto done;
}
cur_chr_cnt = 0;
/* buffer was consumed, allocate new one */
txom = ble_hs_mbuf_att_pkt();
if (txom == NULL) {
return BLE_HS_ENOMEM;
}
}
os_mbuf_append(txom, &tuples[i].handle, sizeof(uint16_t));
os_mbuf_append(txom, &tuples[i].value->om_len,
sizeof(uint16_t));
os_mbuf_concat(txom, tuples[i].value);
cur_chr_cnt++;
}
if (cur_chr_cnt == 1) {
rc = ble_att_clt_tx_notify(conn_handle, tuples[chr_count].handle,
tuples[chr_count].value);
} else {
rc = ble_att_clt_tx_notify_mult(conn_handle, txom);
}
done:
return rc;
}
int
ble_gatts_notify_multiple(uint16_t conn_handle,
size_t num_handles,
const uint16_t *chr_val_handles)
{
#if !MYNEWT_VAL(BLE_GATT_NOTIFY_MULTIPLE)
return BLE_HS_ENOTSUP;
#endif
int rc;
size_t i;
struct ble_gatt_notif tuples[num_handles];
struct ble_hs_conn *conn;
BLE_HS_LOG_DEBUG("conn_handle %d\n", conn_handle);
conn = ble_hs_conn_find(conn_handle);
if (conn == NULL) {
return BLE_HS_ENOTCONN;
}
/** Skip sending to client that doesn't support this feature */
BLE_HS_LOG_DEBUG("ble_gatts_notify_multiple: peer_cl_sup_feat %d\n",
conn->bhc_gatt_svr.peer_cl_sup_feat[0]);
if ((conn->bhc_gatt_svr.peer_cl_sup_feat[0] & 0x04) == 0) {
for (i = 0; i < num_handles; i++) {
rc = ble_gatts_notify(conn_handle, chr_val_handles[i]);
if (rc != 0) {
return rc;
}
}
return 0;
}
for (i = 0; i < num_handles; i++) {
tuples[i].handle = chr_val_handles[i];
tuples[i].value = NULL;
BLE_HS_LOG(DEBUG, "handle 0x%02x\n", tuples[i].handle);
}
rc = ble_gatts_notify_multiple_custom(conn_handle, num_handles, tuples);
return rc;
}
int
ble_gatts_multi_notify_custom(uint16_t conn_handle,
struct ble_gatt_notif_entry * tuples, uint16_t num_tuples)
{
#if !MYNEWT_VAL(BLE_GATT_MULTI_NOTIFY)
return BLE_HS_ENOTSUP;
#endif
int i;
int rc;
uint16_t mtu;
uint16_t pdu_size;
int split_at;
struct os_mbuf *om = NULL;
STATS_INC(ble_gattc_stats, multi_notify);
ble_gattc_log_multi_notify(tuples, num_tuples);
for (i = 0; i < num_tuples; i++) {
if (tuples[i].value == NULL) {
tuples[i].value = ble_hs_mbuf_att_pkt();
if (tuples[i].value == NULL) {
rc = BLE_HS_ENOMEM;
goto done;
}
rc = ble_att_svr_read_handle(BLE_HS_CONN_HANDLE_NONE,
tuples[i].handle, 0, tuples[i].value, NULL);
if (rc != 0) {
BLE_HS_LOG(ERROR, "Attribute read failed (err=0x%02x), rc");
goto done;
}
}
}
mtu = ble_att_mtu(conn_handle);
pdu_size = sizeof(uint8_t);
split_at = 0;
for (i = 0; i < num_tuples; i++) {
pdu_size += (2 * sizeof(uint16_t)) + OS_MBUF_PKTLEN(tuples[i].value);
if (pdu_size > mtu) {
if (i == split_at) {
rc = BLE_HS_ENOMEM;
goto done;
}
split_at = i;
i--;
pdu_size = sizeof(uint8_t);
}
}
pdu_size = sizeof(uint8_t);
split_at = 0;
om = ble_hs_mbuf_att_pkt();
if (om == NULL) {
rc = BLE_HS_ENOMEM;
goto done;
}
for (i = 0; i < num_tuples; i++) {
pdu_size += (2 * sizeof(uint16_t)) + OS_MBUF_PKTLEN(tuples[i].value);
if (pdu_size > mtu) {
rc = ble_att_clt_tx_multi_notify(conn_handle, om);
if (rc != 0) {
goto done;
}
split_at = i;
i--;
pdu_size = sizeof(uint8_t);
om = ble_hs_mbuf_att_pkt();
if (om == NULL) {
rc = BLE_HS_ENOMEM;
goto done;
}
continue;
}
rc = os_mbuf_copyinto(om, OS_MBUF_PKTLEN(om),
&tuples[i].handle, sizeof tuples[i].handle);
if (rc != 0) {
rc = BLE_HS_ENOMEM;
os_mbuf_free_chain(om);
goto done;
}
rc = os_mbuf_copyinto(om, OS_MBUF_PKTLEN(om),
&(OS_MBUF_PKTLEN(tuples[i].value)),
sizeof(OS_MBUF_PKTLEN(tuples[i].value)));
if (rc != 0) {
rc = BLE_HS_ENOMEM;
os_mbuf_free_chain(om);
goto done;
}
rc = os_mbuf_appendfrom(om, tuples[i].value,
0, OS_MBUF_PKTLEN(tuples[i].value));
if (rc != 0) {
rc = BLE_HS_ENOMEM;
os_mbuf_free_chain(om);
goto done;
}
}
rc = ble_att_clt_tx_multi_notify(conn_handle, om);
done:
if (rc != 0) {
STATS_INC(ble_gattc_stats, multi_notify_fail);
}
for (i = 0; i < num_tuples; i++) {
ble_gap_notify_tx_event(rc, conn_handle, tuples[i].handle, 0);
os_mbuf_free_chain(tuples[i].value);
}
return rc;
}
int
ble_gatts_notify_multiple(uint16_t conn_handle,
size_t num_handles,
@@ -6678,7 +6530,7 @@ ble_gattc_rx_find_type_value_complete(uint16_t conn_handle, uint16_t cid, int st
BLE_GATT_OP_DISC_SVC_UUID);
if (proc != NULL) {
rc = ble_gattc_disc_svc_uuid_rx_complete(proc, status);
ble_gattc_process_status(proc, rc, true);
ble_gattc_process_status(proc, rc, false);
}
}
@@ -6708,7 +6560,7 @@ ble_gattc_rx_read_type_adata(uint16_t conn_handle, uint16_t cid,
*/
ble_gattc_process_status(proc, rc, true);
} else {
rc = -1;
rc = BLE_HS_ENOENT;
}
return rc;
@@ -7305,5 +7157,3 @@ ble_gattc_deinit(void)
#endif
}
#endif
#endif
+13 -2
View File
@@ -39,7 +39,7 @@
#define MAX_ADDR_LIST_CACHE_BUF 4096
#if MYNEWT_VAL(BLE_GATT_CACHING)
static const char *cache_key = "key";
static const char *cache_key = "k";
static const char *cache_addr = "cache_addr_tab";
static uint8_t ble_gattc_cache_find_addr(ble_addr_t addr);
static uint8_t ble_gattc_cache_find_hash(uint8_t * hash_key);
@@ -101,7 +101,7 @@ print_addr(ble_addr_t addr)
}
}
/* Increased buffer size to safely hold "key" + 12 hex chars + null + margin */
/* Buffer size to safely hold "k" + 14 hex chars + null */
#define GATT_CACHE_KEY_NAME_MAX_LEN 20
/* Thread-local storage for key name to avoid static buffer thread safety issues */
@@ -360,7 +360,11 @@ void ble_gattc_cache_get_addr_list(ble_addr_t *addr_list, uint8_t *out_num)
return;
}
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (ble_gattc_cache_static_vars == NULL || cache_env == NULL) {
#else
if (cache_env == NULL) {
#endif
*out_num = 0;
return;
}
@@ -549,6 +553,7 @@ ble_gattc_cache_addr_save(uint8_t *out_index, ble_addr_t addr, uint8_t * hash_ke
} else {
if (cache_env->num_addr >= MAX_DEVICE_IN_CACHE) {
nimble_platform_mem_free(p_buf);
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_ENOMEM);
return BLE_HS_ENOMEM;
}
insert_ind = cache_env->num_addr;
@@ -849,6 +854,12 @@ ble_gattc_cache_find_source(struct ble_gattc_cache_conn *cache_conn, uint8_t *da
uint8_t num;
cache_addr_info_t *addr_info;
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (ble_gattc_cache_static_vars == NULL) {
ble_gap_assoc_event(cache_conn->conn_handle, ESP_FAIL, cache_conn->cache_state);
return ESP_FAIL;
}
#endif
if (cache_env == NULL) {
ble_gap_assoc_event(cache_conn->conn_handle, ESP_FAIL, cache_conn->cache_state);
return ESP_FAIL;
+236 -138
View File
@@ -223,13 +223,7 @@ ble_gattc_cache_conn_find(uint16_t conn_handle)
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (ble_gattc_cache_conn_static_vars == NULL) {
if (ble_gattc_cache_conn_static_vars_init() == NULL) {
return NULL;
}
SLIST_INIT(&ble_gattc_cache_conn_static_vars->_ble_gattc_cache_conns);
}
else if (SLIST_FIRST(&ble_gattc_cache_conns) == NULL) {
SLIST_INIT(&ble_gattc_cache_conns);
return NULL;
}
#endif
SLIST_FOREACH(ble_gattc_cache_conn, &ble_gattc_cache_conns, next) {
@@ -245,10 +239,11 @@ struct ble_gattc_cache_conn *
ble_gattc_cache_conn_find_by_addr(ble_addr_t peer_addr)
{
struct ble_gattc_cache_conn *ble_gattc_cache_conn;
/* TODO(issue-2): When BLE_STATIC_TO_DYNAMIC is enabled this function
* accesses ble_gattc_cache_conns via macro without first checking/
* initialising ble_gattc_cache_conn_static_vars, unlike find(). Add the
* same NULL-guard and lazy-init call that find() performs. */
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (ble_gattc_cache_conn_static_vars == NULL) {
return NULL;
}
#endif
SLIST_FOREACH(ble_gattc_cache_conn, &ble_gattc_cache_conns, next) {
if (memcmp(&ble_gattc_cache_conn->ble_gattc_cache_conn_addr, &peer_addr, sizeof(peer_addr)) == 0) {
return ble_gattc_cache_conn;
@@ -704,6 +699,24 @@ ble_gattc_cache_conn_incl_svc_find(const struct ble_gattc_cache_conn_svc *svc, u
#endif
#if MYNEWT_VAL(BLE_GATT_CACHING_INCLUDE_SERVICES)
static void
ble_gattc_cache_conn_undo_new_svc(struct ble_gattc_cache_conn *peer,
struct ble_gattc_cache_conn_svc *svc,
struct ble_gattc_cache_conn_svc *prev,
bool svc_new)
{
if (!svc_new) {
return;
}
if (prev == NULL) {
SLIST_REMOVE_HEAD(&peer->svcs, next);
} else {
SLIST_REMOVE_AFTER(prev, next);
}
os_memblock_put(&ble_gattc_cache_conn_svc_pool, svc);
}
int
ble_gattc_cache_conn_inc_add(ble_addr_t peer_addr, const struct ble_gatt_incl_svc *gatt_svc)
#else
@@ -716,6 +729,7 @@ ble_gattc_cache_conn_inc_add(ble_addr_t peer_addr, const struct ble_gatt_svc *ga
struct ble_gattc_cache_conn *peer;
#if MYNEWT_VAL(BLE_GATT_CACHING_INCLUDE_SERVICES)
bool svc_new;
struct ble_gattc_cache_conn_incl_svc *incl_svc;
struct ble_gattc_cache_conn_incl_svc *incl_svc_prev;
struct ble_gattc_cache_conn_svc *cur_svc;
@@ -727,6 +741,9 @@ ble_gattc_cache_conn_inc_add(ble_addr_t peer_addr, const struct ble_gatt_svc *ga
return BLE_HS_EUNKNOWN;
}
#if MYNEWT_VAL(BLE_GATT_CACHING_INCLUDE_SERVICES)
svc_new = false;
#endif
svc = ble_gattc_cache_conn_svc_find(peer, gatt_svc->start_handle, &prev);
if (!svc) {
@@ -754,6 +771,9 @@ ble_gattc_cache_conn_inc_add(ble_addr_t peer_addr, const struct ble_gatt_svc *ga
} else {
SLIST_INSERT_AFTER(prev, svc, next);
}
#if MYNEWT_VAL(BLE_GATT_CACHING_INCLUDE_SERVICES)
svc_new = true;
#endif
BLE_HS_LOG(DEBUG, "Secondary Svc added with start_handle = %d , end_handle = %d",
gatt_svc->start_handle, gatt_svc->end_handle);
@@ -767,18 +787,21 @@ ble_gattc_cache_conn_inc_add(ble_addr_t peer_addr, const struct ble_gatt_svc *ga
/* Handle provided by remote device falls outside known service ranges;
* return error gracefully to avoid remote-triggered crash. */
BLE_HS_LOG(ERROR, "No service found for inc_svc handle=%d, %s", gatt_svc->handle, __func__);
ble_gattc_cache_conn_undo_new_svc(peer, svc, prev, svc_new);
return BLE_HS_EUNKNOWN;
}
incl_svc = ble_gattc_cache_conn_incl_svc_find(cur_svc, gatt_svc->handle, &incl_svc_prev);
if (incl_svc != NULL) {
/* Already discovered */
ble_gattc_cache_conn_undo_new_svc(peer, svc, prev, svc_new);
return 0;
}
incl_svc = os_memblock_get(&ble_gattc_cache_conn_incl_svc_pool);
if (incl_svc == NULL) {
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_ENOMEM);
ble_gattc_cache_conn_undo_new_svc(peer, svc, prev, svc_new);
return BLE_HS_ENOMEM;
}
@@ -941,16 +964,18 @@ ble_gattc_get_db_size_with_handle(struct ble_gattc_cache_conn *peer, uint16_t st
}
#endif
SLIST_FOREACH(chr, &svc->chrs, next) {
/* Use def_handle (declaration) for range check so descriptors
* beyond a characteristic whose val_handle is below start_handle
* are still evaluated. */
if (chr->chr.def_handle < start_handle) {
continue;
}
/* Stop when the characteristic declaration is beyond the range;
* its value handle and descriptors cannot be in range either. */
if (chr->chr.def_handle > end_handle) {
return db_size;
}
db_size++;
/* Count the characteristic only when its value handle is within
* [start_handle, end_handle]. Always enter the descriptor loop so
* descriptors of a characteristic whose val_handle is just below
* start_handle are still evaluated. */
if (chr->chr.val_handle >= start_handle && chr->chr.val_handle <= end_handle) {
db_size++;
}
SLIST_FOREACH(dsc, &chr->dscs, next) {
if (dsc->dsc.handle < start_handle) {
@@ -993,7 +1018,7 @@ ble_gattc_get_db_size_with_type(struct ble_gattc_cache_conn *peer, uint8_t type,
switch (type) {
case BLE_GATT_DB_PRIMARY_SERVICE:
/* Count if the service declaration handle falls in range;
* requiring end_handle <= end_handle wrongly excludes
* requiring svc->svc.end_handle <= end_handle wrongly excludes
* services that extend beyond the queried range. */
if (svc->type == BLE_GATT_SVC_TYPE_PRIMARY &&
svc->svc.start_handle >= start_handle &&
@@ -1064,9 +1089,6 @@ void ble_gattc_fill_gatt_db_el(ble_gattc_db_elem_t *attr,
attr->uuid = uuid;
}
/* TODO(issue-5/6): wrap entire body of this function with ble_hs_lock() /
* ble_hs_unlock() to prevent race conditions with the host task modifying the
* service list between the count and fill passes (heap overflow risk). */
void ble_gattc_get_service_with_uuid(uint16_t conn_handle,
ble_uuid_t *svc_uuid,
ble_gattc_db_elem_t **svc_db,
@@ -1076,12 +1098,14 @@ void ble_gattc_get_service_with_uuid(uint16_t conn_handle,
struct ble_gattc_cache_conn *cache_conn;
struct ble_gattc_cache_conn_svc *svc;
ble_hs_lock();
// Find the connection in the cache
cache_conn = ble_gattc_cache_conn_find(conn_handle);
if (cache_conn == NULL || SLIST_EMPTY(&cache_conn->svcs)) {
BLE_HS_LOG(WARN, "%s(), no service.", __func__);
*count = 0;
*svc_db = NULL;
ble_hs_unlock();
return;
}
@@ -1096,15 +1120,18 @@ void ble_gattc_get_service_with_uuid(uint16_t conn_handle,
BLE_HS_LOG(DEBUG, "the db size is 0.");
*count = 0;
*svc_db = NULL;
ble_hs_unlock();
return;
}
// Allocate memory for the GATT database
size_t allocated_size = db_size;
void *buffer = nimble_platform_mem_malloc(db_size * sizeof(ble_gattc_db_elem_t));
if (!buffer) {
BLE_HS_LOG(WARN, "%s(), no resource.", __func__);
*count = 0;
*svc_db = NULL;
ble_hs_unlock();
return;
}
ble_gattc_db_elem_t *curr_db_attr = buffer;
@@ -1113,6 +1140,9 @@ void ble_gattc_get_service_with_uuid(uint16_t conn_handle,
// Iterate through services in the cache
SLIST_FOREACH(svc, &cache_conn->svcs, next) {
if (svc_uuid == NULL || ble_uuid_cmp(&svc->svc.uuid.u, svc_uuid) == 0) {
if (db_size >= allocated_size) {
break;
}
ble_gattc_fill_gatt_db_el(curr_db_attr,
svc->type == BLE_GATT_SVC_TYPE_PRIMARY ? /* attr type */
BLE_GATT_DB_PRIMARY_SERVICE:BLE_GATT_DB_SECONDARY_SERVICE,
@@ -1128,11 +1158,9 @@ void ble_gattc_get_service_with_uuid(uint16_t conn_handle,
*svc_db = buffer;
*count = db_size;
ble_hs_unlock();
}
/* TODO(issue-5/6): wrap entire body with ble_hs_lock() / ble_hs_unlock(); the
* two-pass size-then-fill pattern is not safe against concurrent host task
* modifications (heap overflow / use-after-free). */
void ble_gattc_get_db_with_operation(uint16_t conn_handle,
ble_gatt_get_db_op_t op,
uint16_t char_handle,
@@ -1152,12 +1180,15 @@ void ble_gattc_get_db_with_operation(uint16_t conn_handle,
struct ble_gattc_cache_conn_chr *chr;
struct ble_gattc_cache_conn_dsc *dsc;
ble_hs_lock();
// Find the connection in the cache
cache_conn = ble_gattc_cache_conn_find(conn_handle);
if (cache_conn == NULL || SLIST_EMPTY(&cache_conn->svcs)) {
BLE_HS_LOG(WARN, "the service cache is empty.");
*count = 0;
*char_db = NULL;
ble_hs_unlock();
return;
}
size_t db_size = ble_gattc_get_db_size_with_handle(cache_conn, start_handle, end_handle);
@@ -1166,6 +1197,7 @@ void ble_gattc_get_db_with_operation(uint16_t conn_handle,
BLE_HS_LOG(DEBUG, "the db size is 0.");
*count = 0;
*char_db = NULL;
ble_hs_unlock();
return;
}
@@ -1175,6 +1207,7 @@ void ble_gattc_get_db_with_operation(uint16_t conn_handle,
BLE_HS_LOG(WARN, "%s(), no resource.", __func__);
*count = 0;
*char_db = NULL;
ble_hs_unlock();
return;
}
size_t allocated_size = db_size;
@@ -1225,19 +1258,17 @@ void ble_gattc_get_db_with_operation(uint16_t conn_handle,
#endif
// Check for characteristics
SLIST_FOREACH(chr, &svc->chrs, next) {
if (chr->chr.def_handle < start_handle) {
continue;
}
if (chr->chr.def_handle > end_handle) {
goto fill_done;
}
if (db_size >= allocated_size) {
goto fill_done;
}
if ((op == BLE_GATT_OP_GET_ALL_CHAR || op == BLE_GATT_OP_GET_CHAR_BY_UUID) &&
(char_uuid == NULL || ble_uuid_cmp(&chr->chr.uuid.u, char_uuid) == 0)) {
if (chr->chr.val_handle >= start_handle &&
chr->chr.val_handle <= end_handle) {
if (db_size >= allocated_size) {
goto fill_done;
}
ble_gattc_fill_gatt_db_el(curr_db_attr,
BLE_GATT_DB_CHARACTERISTIC, /* attr type*/
chr->chr.val_handle, /* handle */
@@ -1247,7 +1278,8 @@ void ble_gattc_get_db_with_operation(uint16_t conn_handle,
chr->chr.uuid); /* uuid */
curr_db_attr++;
db_size++;
continue;
}
continue;
}
if ((op == BLE_GATT_OP_GET_DESC_BY_HANDLE || op == BLE_GATT_OP_GET_ALL_DESC) &&
@@ -1295,8 +1327,9 @@ void ble_gattc_get_db_with_operation(uint16_t conn_handle,
fill_done:
*char_db = buffer;
*count = db_size;
ble_hs_unlock();
return;
}
}
void ble_gattc_get_db_size_with_type_handle(uint16_t conn_handle,
ble_gattc_db_attr_type type,
uint16_t start_handle,
@@ -1305,13 +1338,16 @@ void ble_gattc_get_db_size_with_type_handle(uint16_t conn_handle,
{
struct ble_gattc_cache_conn *cache_conn;
ble_hs_lock();
cache_conn = ble_gattc_cache_conn_find(conn_handle);
if (cache_conn == NULL) {
*count = 0;
return ;
ble_hs_unlock();
return;
}
*count = ble_gattc_get_db_size_with_type(cache_conn, type, start_handle, end_handle, char_handle);
*count = ble_gattc_get_db_size_with_type(cache_conn, type, start_handle, end_handle, char_handle);
ble_hs_unlock();
}
void ble_gattc_get_db_size_handle(uint16_t conn_handle,
@@ -1321,12 +1357,15 @@ void ble_gattc_get_db_size_handle(uint16_t conn_handle,
{
struct ble_gattc_cache_conn *cache_conn;
ble_hs_lock();
cache_conn = ble_gattc_cache_conn_find(conn_handle);
if (cache_conn == NULL) {
*count = 0;
ble_hs_unlock();
return;
}
*count = ble_gattc_get_db_size_with_handle(cache_conn, start_handle, end_handle);
ble_hs_unlock();
}
// Copy the server GATT database into db parameter.
@@ -1380,7 +1419,7 @@ static void ble_gattc_get_gatt_db_impl(struct ble_gattc_cache_conn *peer,
}
if (filled >= db_size) {
*db = buffer;
*count = db_size;
*count = filled;
return;
}
ble_gattc_fill_gatt_db_el(curr_db_attr,
@@ -1403,13 +1442,13 @@ static void ble_gattc_get_gatt_db_impl(struct ble_gattc_cache_conn *peer,
if (included_svc->svc.handle > end_handle) {
*db = buffer;
*count = db_size;
*count = filled;
return;
}
if (filled >= db_size) {
*db = buffer;
*count = db_size;
*count = filled;
return;
}
ble_gattc_fill_gatt_db_el(curr_db_attr,
@@ -1425,29 +1464,30 @@ static void ble_gattc_get_gatt_db_impl(struct ble_gattc_cache_conn *peer,
#endif
// Iterate over characterstic
SLIST_FOREACH(chr, &svc->chrs, next) {
if (chr->chr.def_handle < start_handle) {
continue;
}
if (chr->chr.def_handle > end_handle) {
*db = buffer;
*count = db_size;
*count = filled;
return;
}
if (filled >= db_size) {
*db = buffer;
*count = db_size;
return;
/* Fill characteristic entry only when its value handle is within
* [start_handle, end_handle]. Always iterate descriptors below so
* in-range descriptors of boundary characteristics are not missed. */
if (chr->chr.val_handle >= start_handle && chr->chr.val_handle <= end_handle) {
if (filled >= db_size) {
*db = buffer;
*count = filled;
return;
}
ble_gattc_fill_gatt_db_el(curr_db_attr,
BLE_GATT_DB_CHARACTERISTIC, /* attr type */
chr->chr.val_handle, /* attr handle */
0, /* s_handle */
0, /* e_handle */
chr->chr.properties, /* property */
chr->chr.uuid); /* uuid */
curr_db_attr++;
filled++;
}
ble_gattc_fill_gatt_db_el(curr_db_attr,
BLE_GATT_DB_CHARACTERISTIC, /* attr type */
chr->chr.val_handle, /* attr handle */
0, /* s_handle */
0, /* e_handle */
chr->chr.properties, /* property */
chr->chr.uuid); /* uuid */
curr_db_attr++;
filled++;
// Iterate over descriptors
SLIST_FOREACH(dsc, &chr->dscs, next) {
if (dsc->dsc.handle < start_handle) {
@@ -1456,12 +1496,12 @@ static void ble_gattc_get_gatt_db_impl(struct ble_gattc_cache_conn *peer,
if (dsc->dsc.handle > end_handle) {
*db = buffer;
*count = db_size;
*count = filled;
return;
}
if (filled >= db_size) {
*db = buffer;
*count = db_size;
*count = filled;
return;
}
ble_gattc_fill_gatt_db_el(curr_db_attr,
@@ -1546,8 +1586,12 @@ ble_gattc_cache_conn_broken(uint16_t conn_handle)
/* Remove any pending disc_ev from the queue before freeing conn to
* avoid use-after-free when the event fires after the connection struct
* has been returned to the pool. */
ble_npl_eventq_remove((struct ble_npl_eventq *)ble_hs_evq_get(), &conn->disc_ev);
* has been returned to the pool. Guard ev->event != NULL: conn struct is
* zeroed on creation so disc_ev may never have been initialized. */
if (conn->disc_ev.event && ble_npl_event_is_queued(&conn->disc_ev)) {
ble_npl_eventq_remove((struct ble_npl_eventq *)ble_hs_evq_get(),
&conn->disc_ev);
}
ble_npl_event_deinit(&conn->disc_ev);
while ((svc = SLIST_FIRST(&conn->svcs)) != NULL) {
@@ -1563,8 +1607,9 @@ ble_gattc_cache_conn_bonding_established(uint16_t conn_handle)
{
/* update the address of the peer */
struct ble_hs_conn *conn;
struct ble_hs_conn_addrs addrs;
struct ble_hs_conn_addrs addrs = {0};
struct ble_gattc_cache_conn *peer;
static const uint8_t zero_addr[BLE_DEV_ADDR_LEN];
peer = ble_gattc_cache_conn_find(conn_handle);
if (peer == NULL) {
@@ -1576,10 +1621,11 @@ ble_gattc_cache_conn_bonding_established(uint16_t conn_handle)
conn = ble_hs_conn_find(conn_handle);
BLE_HS_DBG_ASSERT(conn != NULL);
ble_hs_conn_addrs(conn, &addrs);
peer->ble_gattc_cache_conn_addr = conn->bhc_peer_addr;
peer->ble_gattc_cache_conn_addr.type =
ble_hs_misc_peer_addr_type_to_id(conn->bhc_peer_addr.type);
if (memcmp(addrs.peer_id_addr.val, zero_addr, sizeof zero_addr) == 0) {
addrs.peer_id_addr = conn->bhc_peer_addr;
addrs.peer_id_addr.type = ble_hs_misc_peer_addr_type_to_id(conn->bhc_peer_addr.type);
}
peer->ble_gattc_cache_conn_addr = addrs.peer_id_addr;
ble_hs_unlock();
}
@@ -1588,9 +1634,10 @@ void
ble_gattc_cache_conn_bonding_restored(uint16_t conn_handle)
{
struct ble_hs_conn *conn;
struct ble_hs_conn_addrs addrs;
struct ble_hs_conn_addrs addrs = {0};
struct ble_gattc_cache_conn *peer;
int rc;
static const uint8_t zero_addr[BLE_DEV_ADDR_LEN];
peer = ble_gattc_cache_conn_find(conn_handle);
if (peer == NULL) {
@@ -1602,6 +1649,10 @@ ble_gattc_cache_conn_bonding_restored(uint16_t conn_handle)
conn = ble_hs_conn_find(conn_handle);
BLE_HS_DBG_ASSERT(conn != NULL);
ble_hs_conn_addrs(conn, &addrs);
if (memcmp(addrs.peer_id_addr.val, zero_addr, sizeof zero_addr) == 0) {
addrs.peer_id_addr = conn->bhc_peer_addr;
addrs.peer_id_addr.type = ble_hs_misc_peer_addr_type_to_id(conn->bhc_peer_addr.type);
}
/* Use the resolved Identity Address so the cache entry remains valid
* across reconnections where the peer rotates its RPA. */
peer->ble_gattc_cache_conn_addr = addrs.peer_id_addr;
@@ -1710,7 +1761,7 @@ ble_gattc_cache_conn_disc_complete(struct ble_gattc_cache_conn *peer, int rc)
}
break;
case BLE_GATT_OP_DISC_SVC_UUID :
rc = ble_gattc_cache_conn_search_svc_by_uuid(peer->conn_handle, op->uuid, op->cb, op->cb_arg);
rc = ble_gattc_cache_conn_search_svc_by_uuid(peer->conn_handle, &op->uuid.u, op->cb, op->cb_arg);
if (rc != 0) {
BLE_HS_LOG(ERROR, "search service by uuid failed");
}
@@ -1728,7 +1779,7 @@ ble_gattc_cache_conn_disc_complete(struct ble_gattc_cache_conn *peer, int rc)
}
break;
case BLE_GATT_OP_DISC_CHR_UUID :
rc = ble_gattc_cache_conn_search_chrs_by_uuid(peer->conn_handle, op->start_handle, op->end_handle, op->uuid, op->cb, op->cb_arg);
rc = ble_gattc_cache_conn_search_chrs_by_uuid(peer->conn_handle, op->start_handle, op->end_handle, &op->uuid.u, op->cb, op->cb_arg);
if (rc != 0) {
BLE_HS_LOG(ERROR, "search chars by uuid failed");
}
@@ -1851,7 +1902,8 @@ ble_gattc_cache_conn_disc(struct ble_gattc_cache_conn *peer)
{
int rc;
if (peer->cache_state == SVC_DISC_IN_PROGRESS) {
if (peer->cache_state >= SVC_DISC_IN_PROGRESS &&
peer->cache_state <= DSC_DISC_IN_PROGRESS) {
return BLE_HS_EALREADY;
}
ble_gattc_cache_conn_undisc_all(peer->ble_gattc_cache_conn_addr);
@@ -1861,6 +1913,9 @@ ble_gattc_cache_conn_disc(struct ble_gattc_cache_conn *peer)
BLE_HS_LOG(INFO, "Initiating Remote Service Discovery");
peer->cache_state = SVC_DISC_IN_PROGRESS;
rc = ble_gattc_disc_all_svcs(peer->conn_handle, ble_gattc_cache_conn_svc_disced, peer);
if (rc != 0) {
peer->cache_state = CACHE_INVALID;
}
return rc;
}
@@ -1873,9 +1928,8 @@ ble_gattc_cache_conn_on_read(uint16_t conn_handle,
uint16_t res;
if (error->status == BLE_HS_EDONE) {
/* Hash characteristic not found; fall back to full discovery. */
res = ble_gattc_cache_conn_disc((struct ble_gattc_cache_conn *)arg);
return res;
/* Ignore Read by UUID follow-up callback. */
return 0;
}
if (error->status != 0) {
@@ -2066,6 +2120,9 @@ ble_gattc_cache_conn_chr_disced(uint16_t conn_handle, const struct ble_gatt_erro
/* All characteristics in this service discovered; start discovering
* characteristics in the next service.
*/
if (peer->cur_svc != NULL) {
peer->cur_svc->chrs_discovered = 1;
}
if (peer->disc_prev_chr_val > 0) {
ble_gattc_cache_conn_disc_chrs(peer);
}
@@ -2094,14 +2151,8 @@ ble_gattc_cache_conn_disc_chrs(struct ble_gattc_cache_conn *peer)
* contains undiscovered characteristics. Then, discover all
* characteristics belonging to that service.
*/
/* TODO(issue-17): Using SLIST_EMPTY(&svc->chrs) to decide whether
* discovery is needed conflates "not yet discovered" with "has no
* characteristics". A service with zero characteristics keeps an empty
* list after discovery completes, causing this loop to restart discovery
* for it on every BLE_HS_EDONE callback (infinite loop). Track
* per-service chr-discovery state with an explicit flag instead. */
SLIST_FOREACH(svc, &peer->svcs, next) {
if (!ble_gattc_cache_conn_svc_is_empty(svc) && SLIST_EMPTY(&svc->chrs)) {
if (!ble_gattc_cache_conn_svc_is_empty(svc) && !svc->chrs_discovered) {
peer->cur_svc = svc;
peer->cache_state = CHR_DISC_IN_PROGRESS;
rc = ble_gattc_disc_all_chrs(peer->conn_handle,
@@ -2213,6 +2264,11 @@ int ble_gattc_cache_refresh(ble_addr_t peer_addr)
return BLE_HS_EUNKNOWN;
}
if (conn->cache_state >= SVC_DISC_IN_PROGRESS &&
conn->cache_state <= DSC_DISC_IN_PROGRESS) {
return BLE_HS_EALREADY;
}
ble_gattc_cacheReset(&peer_addr);
/* Invalidate and restart discovery*/
rc = ble_gattc_cache_conn_disc(conn);
@@ -2268,7 +2324,8 @@ int ble_gattc_cache_assoc(ble_addr_t peer_addr)
BLE_HS_LOG(INFO, "Cache already loaded for conn_handle=%d; "
"cache state=%d. Skipping association.",
cache_conn->conn_handle, cache_conn->cache_state);
ble_gap_assoc_event(cache_conn->conn_handle, 0, cache_conn->cache_state);
ble_gap_assoc_event(cache_conn->conn_handle, 0, CACHE_LOADED);
return 0;
}
if (cache_conn->cache_state == CACHE_INVALID) {
@@ -2301,9 +2358,10 @@ int ble_gattc_cache_clean(ble_addr_t peer_addr)
" %02x:%02x:%02x:%02x:%02x:%02x, Attempting cache clean anyway.",
peer_addr.val[0], peer_addr.val[1], peer_addr.val[2],
peer_addr.val[3], peer_addr.val[4], peer_addr.val[5]);
ble_gattc_cacheReset(&peer_addr);
ble_hs_unlock();
/* Call cacheReset outside lock: it performs blocking NVS flash I/O
* which is inappropriate to hold ble_hs_lock during. */
ble_gattc_cacheReset(&peer_addr);
return 0;
}
@@ -2315,16 +2373,19 @@ int ble_gattc_cache_clean(ble_addr_t peer_addr)
return BLE_HS_EUNKNOWN;
}
// Reset any existing discovery flags/cache markers
ble_gattc_cacheReset(&peer_addr);
/* TODO(issue-13): Before invalidating, iterate conn->svcs and call
* ble_gattc_cache_conn_svc_delete() on each entry to free service,
* characteristic, and descriptor pool blocks. Without this, repeated
* clean+rediscovery cycles exhaust the fixed mempools. */
/* Free in-memory service list under lock, then reset NVS cache
* outside lock to avoid holding ble_hs_lock during blocking flash I/O. */
struct ble_gattc_cache_conn_svc *svc;
while ((svc = SLIST_FIRST(&conn->svcs)) != NULL) {
SLIST_REMOVE_HEAD(&conn->svcs, next);
ble_gattc_cache_conn_svc_delete(svc);
}
conn->cur_svc = NULL;
conn->cache_state = CACHE_INVALID;
ble_hs_unlock();
ble_gattc_cacheReset(&peer_addr);
BLE_HS_LOG(INFO, "GATT cache cleaned for peer: %02x:%02x:%02x:%02x:%02x:%02x",
peer_addr.val[0], peer_addr.val[1], peer_addr.val[2],
peer_addr.val[3], peer_addr.val[4], peer_addr.val[5]);
@@ -2551,6 +2612,9 @@ ble_gattc_cache_conn_init(void)
storage_cb = NULL;
rc = ble_gattc_cache_init(storage_cb);
if (rc != 0) {
goto err;
}
return 0;
err:
@@ -2679,11 +2743,11 @@ static void ble_gattc_cache_conn_fill_op(struct ble_gattc_cache_conn_op *op,
op->cb_type = cb_type;
op->start_handle = start_handle;
op->end_handle = end_handle;
/* TODO(issue-4): storing the uuid pointer directly is unsafe when the
* caller passes a stack-allocated UUID and the operation is deferred.
* The pending_op structure should embed a ble_uuid_any_t and copy the
* UUID here with ble_uuid_copy() to avoid a use-after-return. */
op->uuid = uuid;
if (uuid) {
ble_uuid_copy(&op->uuid, uuid);
} else {
memset(&op->uuid, 0, sizeof(op->uuid));
}
}
int
@@ -2692,7 +2756,6 @@ ble_gattc_cache_conn_search_all_svcs(uint16_t conn_handle,
{
struct ble_gattc_cache_conn *conn;
struct ble_gattc_cache_conn_op *op;
ble_uuid_t uuid = {0};
int rc;
conn = ble_gattc_cache_conn_find(conn_handle);
if (conn == NULL) {
@@ -2708,13 +2771,17 @@ ble_gattc_cache_conn_search_all_svcs(uint16_t conn_handle,
return rc;
}
CHECK_CACHE_CONN_STATE(conn->cache_state, cb, cb_arg, BLE_GATT_OP_DISC_ALL_SVCS,
0, 0, &uuid);
/* Guard against re-init of a disc_ev that is already in the queue;
* re-init would memset the internal event struct and corrupt the queued flag. */
if (ble_npl_event_is_queued(&conn->disc_ev)) {
* re-init would memset the internal event struct and corrupt the queued flag.
* Check ev->event != NULL first: it is NULL when disc_ev was never initialized
* (conn struct is zeroed on creation), and npl_freertos_event_is_queued would
* dereference NULL causing a crash. */
if (conn->disc_ev.event && ble_npl_event_is_queued(&conn->disc_ev)) {
return BLE_HS_EBUSY;
}
CHECK_CACHE_CONN_STATE(conn->cache_state, cb, cb_arg, BLE_GATT_OP_DISC_ALL_SVCS,
0, 0, NULL);
ble_npl_event_init(&conn->disc_ev, ble_gattc_cache_search_all_svcs_cb, &conn->conn_handle);
ble_npl_eventq_put((struct ble_npl_eventq *)ble_hs_evq_get(), &conn->disc_ev);
return 0;
@@ -2743,7 +2810,8 @@ ble_gattc_cache_conn_search_svc_by_uuid_cb(struct ble_npl_event *ev)
dcb = op->cb;
/* Capture before loop: a re-entrant call from dcb may overwrite pending_op. */
void *cb_arg = op->cb_arg;
const ble_uuid_t *uuid = op->uuid;
ble_uuid_any_t uuid_local = op->uuid; /* copy by value to protect against re-entrant overwrite */
const ble_uuid_t *uuid = &uuid_local.u;
SLIST_FOREACH(svc, &conn->svcs, next) {
if (svc->type == BLE_GATT_SVC_TYPE_PRIMARY && ble_uuid_cmp(&svc->svc.uuid.u, uuid) == 0) {
dcb(conn_handle, ble_gattc_cache_error(status, 0), &svc->svc, cb_arg);
@@ -2777,11 +2845,12 @@ ble_gattc_cache_conn_search_svc_by_uuid(uint16_t conn_handle, const ble_uuid_t *
return rc;
}
CHECK_CACHE_CONN_STATE(conn->cache_state, cb, cb_arg, BLE_GATT_OP_DISC_SVC_UUID,
0, 0, uuid);
if (ble_npl_event_is_queued(&conn->disc_ev)) {
if (conn->disc_ev.event && ble_npl_event_is_queued(&conn->disc_ev)) {
return BLE_HS_EBUSY;
}
CHECK_CACHE_CONN_STATE(conn->cache_state, cb, cb_arg, BLE_GATT_OP_DISC_SVC_UUID,
0, 0, uuid);
ble_npl_event_init(&conn->disc_ev, ble_gattc_cache_conn_search_svc_by_uuid_cb, &conn->conn_handle);
ble_npl_eventq_put((struct ble_npl_eventq *)ble_hs_evq_get(), &conn->disc_ev);
return 0;
@@ -2853,7 +2922,6 @@ ble_gattc_cache_conn_search_inc_svcs(uint16_t conn_handle, uint16_t start_handle
{
struct ble_gattc_cache_conn *conn;
struct ble_gattc_cache_conn_op *op;
ble_uuid_t uuid = {0};
int rc;
conn = ble_gattc_cache_conn_find(conn_handle);
@@ -2870,8 +2938,17 @@ ble_gattc_cache_conn_search_inc_svcs(uint16_t conn_handle, uint16_t start_handle
return rc;
}
/* Guard against re-init of a disc_ev that is already in the queue;
* re-init would memset the internal event struct and corrupt the queued flag.
* Check ev->event != NULL first: it is NULL when disc_ev was never initialized
* (conn struct is zeroed on creation), and npl_freertos_event_is_queued would
* dereference NULL causing a crash. */
if (conn->disc_ev.event && ble_npl_event_is_queued(&conn->disc_ev)) {
return BLE_HS_EBUSY;
}
CHECK_CACHE_CONN_STATE(conn->cache_state, cb, cb_arg, BLE_GATT_OP_FIND_INC_SVCS,
start_handle, end_handle, &uuid);
start_handle, end_handle, NULL);
/* put the event in the queue to mimic the gattc behaviour */
ble_npl_event_init(&conn->disc_ev, ble_gattc_cache_conn_search_inc_svcs_cb, &conn->conn_handle);
ble_npl_eventq_put((struct ble_npl_eventq *)ble_hs_evq_get(), &conn->disc_ev);
@@ -2903,19 +2980,25 @@ ble_gattc_cache_conn_search_all_chrs_cb(struct ble_npl_event *ev)
void *cb_arg = op->cb_arg;
uint16_t start_handle = op->start_handle;
uint16_t end_handle = op->end_handle;
svc = ble_gattc_cache_conn_svc_find_range(conn, start_handle);
if (svc == NULL) {
dcb(conn_handle, ble_gattc_cache_error(BLE_HS_EDONE, 0), NULL, cb_arg);
return;
}
/* return all chrs within the requested handle range */
SLIST_FOREACH(chr, &svc->chrs, next) {
if (chr->chr.def_handle < start_handle || chr->chr.def_handle > end_handle) {
SLIST_FOREACH(svc, &conn->svcs, next) {
if (svc->svc.end_handle < start_handle || svc->svc.start_handle > end_handle) {
continue;
}
dcb(conn_handle, ble_gattc_cache_error(status, 0), &chr->chr, cb_arg);
SLIST_FOREACH(chr, &svc->chrs, next) {
int dcb_rc;
if (chr->chr.def_handle < start_handle || chr->chr.def_handle > end_handle) {
continue;
}
dcb_rc = dcb(conn_handle, ble_gattc_cache_error(status, 0),
&chr->chr, cb_arg);
if (dcb_rc != 0) {
return;
}
}
}
status = BLE_HS_EDONE;
dcb(conn_handle, ble_gattc_cache_error(status, 0), NULL, cb_arg);
@@ -2930,7 +3013,6 @@ ble_gattc_cache_conn_search_all_chrs(uint16_t conn_handle, uint16_t start_handle
{
struct ble_gattc_cache_conn *conn;
struct ble_gattc_cache_conn_op *op;
ble_uuid_t uuid = {0};
int rc;
conn = ble_gattc_cache_conn_find(conn_handle);
@@ -2947,11 +3029,12 @@ ble_gattc_cache_conn_search_all_chrs(uint16_t conn_handle, uint16_t start_handle
return rc;
}
CHECK_CACHE_CONN_STATE(conn->cache_state, cb, cb_arg, BLE_GATT_OP_DISC_ALL_CHRS,
start_handle, end_handle, &uuid);
if (ble_npl_event_is_queued(&conn->disc_ev)) {
if (conn->disc_ev.event && ble_npl_event_is_queued(&conn->disc_ev)) {
return BLE_HS_EBUSY;
}
CHECK_CACHE_CONN_STATE(conn->cache_state, cb, cb_arg, BLE_GATT_OP_DISC_ALL_CHRS,
start_handle, end_handle, NULL);
ble_npl_event_init(&conn->disc_ev, ble_gattc_cache_conn_search_all_chrs_cb, &conn->conn_handle);
ble_npl_eventq_put((struct ble_npl_eventq *)ble_hs_evq_get(), &conn->disc_ev);
return 0;
@@ -2980,22 +3063,30 @@ ble_gattc_cache_conn_search_chrs_by_uuid_cb(struct ble_npl_event *ev)
dcb = op->cb;
/* Capture before loop: a re-entrant call from dcb may overwrite pending_op. */
void *cb_arg = op->cb_arg;
const ble_uuid_t *uuid = op->uuid;
ble_uuid_any_t uuid_local = op->uuid; /* copy by value to protect against re-entrant overwrite */
const ble_uuid_t *uuid = &uuid_local.u;
uint16_t start_handle = op->start_handle;
uint16_t end_handle = op->end_handle;
svc = ble_gattc_cache_conn_svc_find_range(conn, start_handle);
if (svc == NULL) {
status = BLE_HS_ENOENT;
dcb(conn_handle, ble_gattc_cache_error(status, 0), NULL, cb_arg);
return;
}
/* return chrs matching UUID within the requested handle range */
SLIST_FOREACH(chr, &svc->chrs, next) {
if (chr->chr.def_handle < start_handle || chr->chr.def_handle > end_handle) {
SLIST_FOREACH(svc, &conn->svcs, next) {
if (svc->svc.end_handle < start_handle || svc->svc.start_handle > end_handle) {
continue;
}
if (ble_uuid_cmp(&chr->chr.uuid.u, uuid) == 0) {
dcb(conn_handle, ble_gattc_cache_error(status, 0), &chr->chr, cb_arg);
SLIST_FOREACH(chr, &svc->chrs, next) {
int dcb_rc;
if (chr->chr.def_handle < start_handle || chr->chr.def_handle > end_handle) {
continue;
}
if (ble_uuid_cmp(&chr->chr.uuid.u, uuid) == 0) {
dcb_rc = dcb(conn_handle, ble_gattc_cache_error(status, 0),
&chr->chr, cb_arg);
if (dcb_rc != 0) {
return;
}
}
}
}
status = BLE_HS_EDONE;
@@ -3027,11 +3118,12 @@ ble_gattc_cache_conn_search_chrs_by_uuid(uint16_t conn_handle, uint16_t start_ha
return rc;
}
CHECK_CACHE_CONN_STATE(conn->cache_state, cb, cb_arg, BLE_GATT_OP_DISC_CHR_UUID,
start_handle, end_handle, uuid);
if (ble_npl_event_is_queued(&conn->disc_ev)) {
if (conn->disc_ev.event && ble_npl_event_is_queued(&conn->disc_ev)) {
return BLE_HS_EBUSY;
}
CHECK_CACHE_CONN_STATE(conn->cache_state, cb, cb_arg, BLE_GATT_OP_DISC_CHR_UUID,
start_handle, end_handle, uuid);
ble_npl_event_init(&conn->disc_ev, ble_gattc_cache_conn_search_chrs_by_uuid_cb, &conn->conn_handle);
ble_npl_eventq_put((struct ble_npl_eventq *)ble_hs_evq_get(), &conn->disc_ev);
return 0;
@@ -3077,10 +3169,16 @@ ble_gattc_cache_conn_search_all_dscs_cb(struct ble_npl_event *ev)
/* return only descriptors within the requested handle range */
SLIST_FOREACH(dsc, &chr->dscs, next) {
int dcb_rc;
if (dsc->dsc.handle < start_handle || dsc->dsc.handle > end_handle) {
continue;
}
dcb(conn_handle, ble_gattc_cache_error(status, 0), chr->chr.val_handle, &dsc->dsc, cb_arg);
dcb_rc = dcb(conn_handle, ble_gattc_cache_error(status, 0),
chr->chr.val_handle, &dsc->dsc, cb_arg);
if (dcb_rc != 0) {
return;
}
}
status = BLE_HS_EDONE;
dcb(conn_handle, ble_gattc_cache_error(status, 0), 0, NULL, cb_arg);
@@ -3096,7 +3194,6 @@ ble_gattc_cache_conn_search_all_dscs(uint16_t conn_handle, uint16_t start_handle
struct ble_gattc_cache_conn *conn;
struct ble_gattc_cache_conn_op *op;
int rc;
ble_uuid_t uuid = {0};
conn = ble_gattc_cache_conn_find(conn_handle);
if (conn == NULL) {
@@ -3112,11 +3209,12 @@ ble_gattc_cache_conn_search_all_dscs(uint16_t conn_handle, uint16_t start_handle
return rc;
}
CHECK_CACHE_CONN_STATE(conn->cache_state, cb, cb_arg, BLE_GATT_OP_DISC_ALL_DSCS,
start_handle, end_handle, &uuid);
if (ble_npl_event_is_queued(&conn->disc_ev)) {
if (conn->disc_ev.event && ble_npl_event_is_queued(&conn->disc_ev)) {
return BLE_HS_EBUSY;
}
CHECK_CACHE_CONN_STATE(conn->cache_state, cb, cb_arg, BLE_GATT_OP_DISC_ALL_DSCS,
start_handle, end_handle, NULL);
ble_npl_event_init(&conn->disc_ev, ble_gattc_cache_conn_search_all_dscs_cb, &conn->conn_handle);
ble_npl_eventq_put((struct ble_npl_eventq *)ble_hs_evq_get(), &conn->disc_ev);
return 0;
+2 -1
View File
@@ -89,6 +89,7 @@ struct ble_gattc_cache_conn_svc {
struct ble_gattc_cache_conn_incl_list incl_svc;
#endif
struct ble_gattc_cache_conn_chr_list chrs;
uint8_t chrs_discovered;
};
SLIST_HEAD(ble_gattc_cache_conn_svc_list, ble_gattc_cache_conn_svc);
@@ -109,7 +110,7 @@ struct ble_gattc_cache_conn_op {
request comes while the cache is building */
uint16_t start_handle;
uint16_t end_handle;
const ble_uuid_t *uuid;
ble_uuid_any_t uuid;
void *cb;
void *cb_arg;
uint8_t cb_type;
+73 -28
View File
@@ -483,8 +483,8 @@ ble_gatts_chr_def_access(uint16_t conn_handle, uint16_t attr_handle,
{
const struct ble_gatt_chr_def *chr;
uint8_t *buf;
uint16_t uuid_len;
uint16_t total_len;
int uuid_len;
STATS_INC(ble_gatts_stats, chr_def_reads);
@@ -492,6 +492,9 @@ ble_gatts_chr_def_access(uint16_t conn_handle, uint16_t attr_handle,
chr = arg;
uuid_len = ble_uuid_length(chr->uuid);
if (uuid_len < 0) {
return BLE_ATT_ERR_UNLIKELY;
}
total_len = 3 + uuid_len; /* properties(1) + handle(2) + uuid */
/* Validate offset */
@@ -599,20 +602,23 @@ ble_gatts_chr_inc_val_stat(uint8_t gatt_op)
bool
ble_gatts_mutable(void)
{
bool mutable;
ble_hs_lock_nested();
/* Ensure no active GAP procedures. */
if (ble_gap_adv_active() ||
ble_gap_disc_active() ||
ble_gap_conn_active()) {
ble_hs_unlock_nested();
return false;
}
/* Ensure no established connections. */
if (ble_hs_conn_first() != NULL) {
return false;
}
mutable = ble_hs_conn_first() == NULL;
ble_hs_unlock_nested();
return true;
return mutable;
}
static int
@@ -1154,6 +1160,10 @@ ble_gatts_read_cccd(uint16_t conn_handle, uint16_t chr_val_handle, uint8_t *cccd
struct ble_gatts_clt_cfg *clt_cfg;
struct ble_hs_conn *conn;
if (cccd_value == NULL) {
return BLE_HS_EINVAL;
}
ble_hs_lock();
conn = ble_hs_conn_find(conn_handle);
@@ -1432,7 +1442,9 @@ ble_gatts_register_chr(const struct ble_gatt_svc_def *svc,
uint16_t def_handle;
uint16_t val_handle;
uint16_t dsc_handle;
#if MYNEWT_VAL(BLE_CPFD_CAFD)
uint16_t cep_handle;
#endif
uint16_t expected_handle;
uint8_t att_flags;
int rc;
@@ -1462,7 +1474,6 @@ ble_gatts_register_chr(const struct ble_gatt_svc_def *svc,
}
expected_handle = def_handle;
(void)expected_handle;
/* Register characteristic value attribute (cast away const on callback
* arg).
@@ -1474,7 +1485,8 @@ ble_gatts_register_chr(const struct ble_gatt_svc_def *svc,
if (rc != 0) {
return rc;
}
BLE_HS_DBG_ASSERT(val_handle == ++expected_handle);
expected_handle++;
BLE_HS_DBG_ASSERT_EVAL(val_handle == expected_handle);
if (chr->val_handle != NULL) {
*chr->val_handle = val_handle;
@@ -1494,7 +1506,8 @@ ble_gatts_register_chr(const struct ble_gatt_svc_def *svc,
if (rc != 0) {
return rc;
}
BLE_HS_DBG_ASSERT(dsc_handle == ++expected_handle);
expected_handle++;
BLE_HS_DBG_ASSERT_EVAL(dsc_handle == expected_handle);
}
#if MYNEWT_VAL(BLE_CPFD_CAFD)
@@ -1503,8 +1516,12 @@ ble_gatts_register_chr(const struct ble_gatt_svc_def *svc,
if (rc != 0) {
return rc;
}
BLE_HS_DBG_ASSERT(cep_handle == ++expected_handle);
expected_handle++;
BLE_HS_DBG_ASSERT_EVAL(cep_handle == expected_handle);
}
#endif
#if MYNEWT_VAL(BLE_CPFD_CAFD)
/* Register each Client Presentation Format Descriptor. */
rc = ble_gatts_register_cpfds(chr->cpfd);
if (rc != 0) {
@@ -3299,22 +3316,37 @@ static int ble_gatts_update_conn_clt_cfg(struct ble_hs_conn *conn, void *arg) {
clt_cfg_arg = arg;
switch (clt_cfg_arg->action) {
case CONN_CLT_CFG_ADD:
case CONN_CLT_CFG_ADD: {
/* added */
int add_rc;
allowed_flags = clt_cfg_arg->allowed_flags;
clt_cfg_arg->rc = ble_gatts_add_clt_cfg(&conn->bhc_gatt_svr.clt_cfgs,
clt_cfg_arg->chr_val_handle, allowed_flags, 0);
if (clt_cfg_arg->rc != 0) {
return clt_cfg_arg->rc;
add_rc = ble_gatts_add_clt_cfg(&conn->bhc_gatt_svr.clt_cfgs,
clt_cfg_arg->chr_val_handle, allowed_flags, 0);
if (add_rc != 0 && clt_cfg_arg->rc == 0) {
/* Only record the first failure; return 0 so iteration continues
* for remaining connections. Caller checks arg.rc after the loop.
*/
clt_cfg_arg->rc = add_rc;
}
if (add_rc != 0) {
return 0;
}
(conn->bhc_gatt_svr.num_clt_cfgs)++;
return 0;
}
case CONN_CLT_CFG_REMOVE:
/* removed */
clt_cfg_arg->rc = ble_gatts_remove_clt_cfg(&conn->bhc_gatt_svr.clt_cfgs,
clt_cfg_arg->chr_val_handle);
if (clt_cfg_arg->rc == 0) {
(conn->bhc_gatt_svr.num_clt_cfgs)--;
{
int remove_rc;
remove_rc = ble_gatts_remove_clt_cfg(&conn->bhc_gatt_svr.clt_cfgs,
clt_cfg_arg->chr_val_handle);
if (remove_rc != 0 && clt_cfg_arg->rc == 0) {
clt_cfg_arg->rc = remove_rc;
}
if (remove_rc == 0) {
(conn->bhc_gatt_svr.num_clt_cfgs)--;
}
}
return 0;
@@ -3465,6 +3497,7 @@ ble_gatts_remove_svc_entry(const ble_uuid_t *uuid)
int ble_gatts_delete_svc(const ble_uuid_t *uuid) {
int rc;
int deregister_rc = BLE_HS_EUNKNOWN;
struct ble_gatts_svc_entry * entry;
int chr_val_handle;
struct ble_gatt_chr_def *chr;
@@ -3502,6 +3535,10 @@ int ble_gatts_delete_svc(const ble_uuid_t *uuid) {
arg.allowed_flags = 0;
arg.rc = 0;
ble_hs_conn_foreach(ble_gatts_update_conn_clt_cfg, &arg);
if (arg.rc != 0) {
BLE_HS_LOG(ERROR, "Failed to remove clt cfg from all connections; rc=%d\n",
arg.rc);
}
}
}
/* keep the start handle and end handle before deleting the service */
@@ -3509,11 +3546,15 @@ int ble_gatts_delete_svc(const ble_uuid_t *uuid) {
start_handle = entry->handle;
end_handle = entry->end_group_handle;
/* deregister service now */
rc = ble_gatts_deregister_svc(uuid);
deregister_rc = ble_gatts_deregister_svc(uuid);
rc = deregister_rc;
done:
if (rc == 0) {
rc = ble_gatts_remove_svc_entry(uuid);
if (deregister_rc == 0) {
int remove_rc;
remove_rc = ble_gatts_remove_svc_entry(uuid);
(void)remove_rc;
#if MYNEWT_VAL(BLE_GATT_CACHING)
/* make all bonded connections them unaware */
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
@@ -3529,17 +3570,15 @@ done:
ble_hs_conn_foreach(ble_gatts_conn_unaware, NULL);
#endif
/* send service change indication */
// ble_svc_gatt_changed(start_handle, end_handle);
}
ble_hs_unlock();
if (rc == 0) {
if (deregister_rc == 0) {
/* send service change indication */
ble_svc_gatt_changed(start_handle, end_handle);
}
return rc;
return deregister_rc == BLE_HS_EUNKNOWN ? rc : deregister_rc;
}
#endif
@@ -3589,7 +3628,13 @@ ble_gatts_free_svcs(void)
if (ble_gatts_svc_defs != NULL) {
nimble_platform_mem_free(ble_gatts_svc_defs);
ble_gatts_svc_defs = NULL;
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (ble_gatts_static_vars != NULL) {
#endif
ble_gatts_num_svc_defs = 0;
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
}
#endif
}
ble_hs_unlock();
@@ -3714,6 +3759,7 @@ ble_gatts_count_resources(const struct ble_gatt_svc_def *svcs,
res->attrs++;
}
#if MYNEWT_VAL(BLE_CPFD_CAFD)
/* If the characteristic permits reliable writes or auxiliary
* writes, it has an Extended Properties descriptor.
*/
@@ -3725,11 +3771,10 @@ ble_gatts_count_resources(const struct ble_gatt_svc_def *svcs,
* o 1 attribute
*/
res->dscs++;
#if MYNEWT_VAL(BLE_CPFD_CAFD)
res->ceps++;
#endif
res->attrs++;
res->ceps++;
}
#endif
if (chr->descriptors != NULL) {
for (d = 0; chr->descriptors[d].uuid != NULL; d++) {
+2 -2
View File
@@ -29,10 +29,10 @@
#if NIMBLE_BLE_CONNECT
static const ble_uuid_t *uuid_ccc =
BLE_UUID16_DECLARE(BLE_GATT_DSC_CLT_CFG_UUID16);
static const ble_uuid_t *uuid_cep =
BLE_UUID16_DECLARE(BLE_GATT_DSC_EXT_PROP_UUID16);
#if MYNEWT_VAL(BLE_CPFD_CAFD)
static const ble_uuid_t *uuid_cep =
BLE_UUID16_DECLARE(BLE_GATT_DSC_EXT_PROP_UUID16);
static const ble_uuid_t *uuid_cpfd =
BLE_UUID16_DECLARE(BLE_GATT_DSC_CLT_PRE_FMT16);
+68 -37
View File
@@ -45,6 +45,7 @@
#if MYNEWT_VAL(BLE_ISO)
#include "host/ble_hs_iso.h"
#include "host/ble_iso.h"
#endif /* MYNEWT_VAL(BLE_ISO) */
#if MYNEWT_VAL(BLE_GATTS) && CONFIG_BT_NIMBLE_GAP_SERVICE
@@ -187,8 +188,8 @@ extern void ble_hs_flow_init(void);
extern void ble_hs_flow_deinit(void);
extern void ble_monitor_deinit(void);
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
void ble_store_config_deinit(void);
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
extern void ble_hs_hci_ctx_free(void);
#endif
@@ -485,7 +486,7 @@ ble_hs_sync(void)
ble_hs_timer_sched(retry_tmo_ticks);
if (rc == 0) {
#if NIMBLE_BLE_CONNECT
#if NIMBLE_BLE_CONNECT && NIMBLE_BLE_SM
rc = ble_hs_misc_restore_irks();
if (rc != 0) {
BLE_HS_LOG(INFO, "Failed to restore IRKs from store; status=%d\n",
@@ -716,12 +717,14 @@ ble_hs_enqueue_hci_event(uint8_t *hci_evt)
ev = os_memblock_get(&ble_hs_hci_ev_pool);
if (ev && ble_hs_evq->eventq) {
if (ev && ble_hs_evq) {
memset (ev, 0, sizeof *ev);
ble_npl_event_init(ev, ble_hs_event_rx_hci_ev, hci_evt);
ble_npl_eventq_put(ble_hs_evq, ev);
} else {
/* Either ev is NULL or queue doesn't exist */
if (ev) {
os_memblock_put(&ble_hs_hci_ev_pool, ev);
}
#if MYNEWT_VAL(MP_RUNTIME_ALLOC)
ble_transport_free(BLE_HCI_EVT, hci_evt);
#else
@@ -750,9 +753,15 @@ ble_hs_notifications_sched(void)
void
ble_hs_sched_reset(int reason)
{
BLE_HS_DBG_ASSERT(ble_hs_reset_reason == 0);
ble_hs_lock_nested();
if (ble_hs_reset_reason != 0) {
ble_hs_unlock_nested();
return;
}
ble_hs_reset_reason = reason;
ble_hs_unlock_nested();
ble_npl_eventq_put(ble_hs_evq, &ble_hs_ev_reset);
}
@@ -952,7 +961,15 @@ ble_hs_init(void)
ble_npl_event_init(&ble_hs_ev_start_stage2, ble_hs_event_start_stage2,
NULL);
ble_hs_hci_init();
rc = ble_npl_mutex_init(&ble_hs_mutex);
SYSINIT_PANIC_ASSERT(rc == 0);
#if MYNEWT_VAL(BLE_HS_DEBUG)
ble_hs_dbg_mutex_locked = 0;
#endif
rc = ble_hs_hci_init();
SYSINIT_PANIC_ASSERT(rc == 0);
#if NIMBLE_BLE_CONNECT
rc = ble_hs_conn_init();
@@ -964,7 +981,6 @@ ble_hs_init(void)
SYSINIT_PANIC_ASSERT(rc == 0);
#endif
#if NIMBLE_BLE_CONNECT
rc = ble_l2cap_init();
SYSINIT_PANIC_ASSERT(rc == 0);
@@ -1009,13 +1025,6 @@ ble_hs_init(void)
STATS_SIZE_32), STATS_NAME_INIT_PARMS(ble_hs_stats), "ble_hs");
SYSINIT_PANIC_ASSERT(rc == 0);
rc = ble_npl_mutex_init(&ble_hs_mutex);
SYSINIT_PANIC_ASSERT(rc == 0);
#if MYNEWT_VAL(BLE_HS_DEBUG)
ble_hs_dbg_mutex_locked = 0;
#endif
#ifdef MYNEWT
ble_hs_evq_set((struct ble_npl_eventq *)os_eventq_dflt_get());
#else
@@ -1079,18 +1088,26 @@ ble_transport_hs_init(void)
void
ble_hs_deinit(void)
{
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (!ble_hs_ctx) {
return;
}
#endif
ble_hs_flow_deinit();
#if BLE_MONITOR
ble_monitor_deinit();
#endif
ble_npl_mutex_deinit(&ble_hs_mutex);
ble_mqueue_deinit(&ble_hs_rx_q);
ble_hs_stop_deinit();
#if CONFIG_BT_NIMBLE_AOA_AOD
extern void ble_svc_cte_deinit(void);
ble_svc_cte_deinit();
#endif
ble_gap_deinit();
ble_hs_hci_deinit();
@@ -1111,9 +1128,9 @@ ble_hs_deinit(void)
ble_gattc_cache_conn_free_all_mem();
#endif
ble_att_deinit();
ble_l2cap_deinit();
ble_att_deinit();
#endif
#if MYNEWT_VAL(BLE_GATTS)
@@ -1136,29 +1153,18 @@ ble_hs_deinit(void)
#if (MYNEWT_VAL(BLE_HOST_BASED_PRIVACY))
ble_hs_resolv_deinit();
#endif
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (ble_hs_ctx) {
ble_hs_ctx->parent_task = NULL;
if (ble_hs_ctx->hci_os_event_buf) {
nimble_platform_mem_free(ble_hs_ctx->hci_os_event_buf);
ble_hs_ctx->hci_os_event_buf = NULL;
}
os_mempool_unregister(&ble_hs_hci_ev_pool);
nimble_platform_mem_free(ble_hs_ctx);
ble_hs_ctx = NULL;
}
if (ble_hs_state_ctx) {
nimble_platform_mem_free(ble_hs_state_ctx);
ble_hs_state_ctx = NULL;
}
ble_store_config_deinit();
#if MYNEWT_VAL(BLE_PERIODIC_ADV)
ble_hs_periodic_sync_deinit();
#endif
ble_store_config_deinit();
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
/* Must be called before ble_hs_ctx is freed — uses ble_hs_lock() which
* expands to ble_hs_ctx->mutex under BLE_STATIC_TO_DYNAMIC. */
#if MYNEWT_VAL(BLE_GATTS) && CONFIG_BT_NIMBLE_GAP_SERVICE
ble_svc_gap_deinit();
#endif
ble_hs_adv_parse_free();
@@ -1172,8 +1178,33 @@ ble_hs_deinit(void)
ble_uuid_deinit();
#if MYNEWT_VAL(BLE_GATTS) && CONFIG_BT_NIMBLE_GAP_SERVICE
ble_svc_gap_deinit();
if (ble_hs_ctx) {
ble_hs_ctx->parent_task = NULL;
if (ble_hs_ctx->hci_os_event_buf) {
nimble_platform_mem_free(ble_hs_ctx->hci_os_event_buf);
ble_hs_ctx->hci_os_event_buf = NULL;
}
os_mempool_unregister(&ble_hs_hci_ev_pool);
/* ble_hs_mutex expands to ble_hs_ctx->mutex here; deinit before
* freeing the context that contains it. */
ble_npl_mutex_deinit(&ble_hs_mutex);
nimble_platform_mem_free(ble_hs_ctx);
ble_hs_ctx = NULL;
}
if (ble_hs_state_ctx) {
nimble_platform_mem_free(ble_hs_state_ctx);
ble_hs_state_ctx = NULL;
}
#else
/* Non-dynamic build: ble_hs_mutex is a static variable; destroy it last
* once all subsystems that call ble_hs_lock() have been torn down. */
#if MYNEWT_VAL(BLE_HS_PVCY)
ble_hs_pvcy_irk_deinit();
#endif
ble_npl_mutex_deinit(&ble_hs_mutex);
#endif
}
+29 -9
View File
@@ -65,7 +65,7 @@ ble_hs_adv_set_hdr(uint8_t type, uint8_t data_len, uint8_t max_len,
int rc;
if (om ) {
if (data_len > 254) {
if (data_len == 255) { /* uint8_t max; +1 below would wrap to 0 */
return BLE_HS_EMSGSIZE;
}
data_len++;
@@ -97,8 +97,7 @@ ble_hs_adv_set_flat_mbuf(uint8_t type, int data_len, const void *data,
{
int rc;
BLE_HS_DBG_ASSERT(data_len > 0);
if (data_len > 254) {
if (data_len <= 0 || data_len > 254) {
return BLE_HS_EMSGSIZE;
}
@@ -158,7 +157,10 @@ ble_hs_adv_set_array_uuid16(uint8_t type, uint8_t num_elems,
} else {
/* elems is const ble_uuid16_t*; u.type is always BLE_UUID_TYPE_16
* by construction; ble_uuid_flat writes exactly 2 bytes for 16-bit UUIDs */
ble_uuid_flat(&elems[i].u, dst + *dst_len);
rc = ble_uuid_flat(&elems[i].u, dst + *dst_len);
if (rc != 0) {
return rc;
}
*dst_len += 2;
}
}
@@ -233,8 +235,9 @@ ble_hs_adv_set_array_uuid128(uint8_t type, uint8_t num_elems,
return rc;
}
} else {
if (ble_uuid_flat(&elems[i].u, dst + *dst_len) != 0) {
return BLE_HS_EINVAL;
rc = ble_uuid_flat(&elems[i].u, dst + *dst_len);
if (rc != 0) {
return rc;
}
*dst_len += 16;
}
@@ -641,6 +644,17 @@ adv_set_fields(const struct ble_hs_adv_fields *adv_fields,
#endif
#endif
/*** 0x30 - Broadcast name. */
if (adv_fields->broadcast_name != NULL && adv_fields->broadcast_name_len > 0) {
rc = ble_hs_adv_set_flat_mbuf(BLE_HS_ADV_TYPE_BROADCAST_NAME,
adv_fields->broadcast_name_len,
adv_fields->broadcast_name,
dst, &dst_len_local, max_len, om);
if (rc != 0) {
return rc;
}
}
/*** 0xff - Manufacturer specific data. */
if ((adv_fields->mfg_data != NULL) && (adv_fields->mfg_data_len >= 2)) {
rc = ble_hs_adv_set_flat_mbuf(BLE_HS_ADV_TYPE_MFG_DATA,
@@ -802,7 +816,7 @@ ble_hs_adv_parse_uuids128(struct ble_hs_adv_fields *adv_fields,
* type are present in advertising data.
*/
free_slots = (BLE_HS_ADV_MAX_FIELD_SZ / sizeof(ble_uuid128_t)) - adv_fields->num_uuids128;
free_slots = (BLE_HS_ADV_MAX_FIELD_SZ / 16) - adv_fields->num_uuids128;
if (uuid_cnt > free_slots) {
/* not enough space to append */
@@ -1089,10 +1103,11 @@ ble_hs_adv_parse_one_field(struct ble_hs_adv_fields *adv_fields,
break;
case BLE_HS_ADV_TYPE_LE_SUPP_FEAT:
if (data_len != BLE_HS_ADV_LE_SUPP_FEAT_LEN) {
if (data_len < 1 || data_len > BLE_HS_ADV_LE_SUPP_FEAT_LEN) {
return BLE_HS_EBADDATA;
}
memcpy(adv_fields->le_supp_feat, data, BLE_HS_ADV_LE_SUPP_FEAT_LEN);
memset(adv_fields->le_supp_feat, 0, BLE_HS_ADV_LE_SUPP_FEAT_LEN);
memcpy(adv_fields->le_supp_feat, data, data_len);
adv_fields->le_supp_feat_is_present = 1;
break;
@@ -1111,6 +1126,11 @@ ble_hs_adv_parse_one_field(struct ble_hs_adv_fields *adv_fields,
adv_fields->enc_adv_data_len = data_len;
break;
#endif
case BLE_HS_ADV_TYPE_BROADCAST_NAME:
adv_fields->broadcast_name = data;
adv_fields->broadcast_name_len = data_len;
break;
case BLE_HS_ADV_TYPE_MFG_DATA:
adv_fields->mfg_data = data;
adv_fields->mfg_data_len = data_len;
+13 -6
View File
@@ -78,7 +78,7 @@ ble_hs_conn_can_alloc(void)
int result;
ble_hs_lock();
ble_hs_lock_nested();
#if MYNEWT_VAL(BLE_GATTS)
result = ble_hs_conn_pool.mp_num_free >= 1 &&
@@ -89,7 +89,7 @@ ble_hs_conn_can_alloc(void)
ble_l2cap_chan_pool.mp_num_free >= BLE_HS_CONN_MIN_CHANS;
#endif
ble_hs_unlock();
ble_hs_unlock_nested();
return result;
}
@@ -511,13 +511,17 @@ ble_hs_conn_addrs(const struct ble_hs_conn *conn,
addrs->our_id_addr.type == BLE_ADDR_RANDOM) {
our_id_addr_val = conn->bhc_our_rnd_addr;
} else {
ble_hs_lock_nested();
rc = ble_hs_id_addr(addrs->our_id_addr.type, &our_id_addr_val, NULL);
ble_hs_unlock_nested();
if (rc != 0) {
return;
}
}
#else
ble_hs_lock_nested();
rc = ble_hs_id_addr(addrs->our_id_addr.type, &our_id_addr_val, NULL);
ble_hs_unlock_nested();
if (rc != 0) {
return;
}
@@ -542,14 +546,15 @@ ble_hs_conn_addrs(const struct ble_hs_conn *conn,
memcpy(bhc_peer_addr.val, conn->bhc_peer_addr.val, BLE_DEV_ADDR_LEN);
struct ble_hs_resolv_entry *rl = NULL;
ble_hs_lock_nested();
rl = ble_hs_resolv_list_find(bhc_peer_addr.val);
if (rl != NULL) {
memcpy(addrs->peer_id_addr.val, rl->rl_identity_addr, BLE_DEV_ADDR_LEN);
addrs->peer_id_addr.type = rl->rl_addr_type;
if (ble_host_rpa_enabled()) {
uint8_t *local_id = NULL;
rc = ble_hs_id_addr(BLE_ADDR_PUBLIC, (const uint8_t **) &local_id, NULL);
const uint8_t *local_id = NULL;
rc = ble_hs_id_addr(BLE_ADDR_PUBLIC, &local_id, NULL);
/* RL is present: populate our id addr with public ID */
if (rc == 0 && local_id != NULL) {
@@ -561,6 +566,7 @@ ble_hs_conn_addrs(const struct ble_hs_conn *conn,
}
}
}
ble_hs_unlock_nested();
#endif
switch (conn->bhc_peer_addr.type) {
case BLE_ADDR_PUBLIC:
@@ -614,7 +620,7 @@ ble_hs_conn_timer(void)
* passes after a partial packet is received, the connection is
* terminated.
*/
if (conn->rx_len) {
if (conn->rx_frags) {
time_diff = conn->rx_frag_tmo - now;
if (time_diff <= 0) {
@@ -692,11 +698,12 @@ ble_hs_conn_init(void)
ble_hs_conn_elem_mem = NULL;
#endif
os_mempool_unregister(&ble_hs_conn_pool);
memset(&ble_hs_conn_pool, 0, sizeof(ble_hs_conn_pool));
if (ble_hs_conn_ctx) {
nimble_platform_mem_free(ble_hs_conn_ctx);
ble_hs_conn_ctx = NULL;
}
memset(&ble_hs_conn_pool, 0, sizeof(ble_hs_conn_pool));
#endif
return BLE_HS_EOS;
}
+12 -3
View File
@@ -211,6 +211,8 @@ ble_hs_flow_acl_free(struct os_mempool_ext *mpe, void *data, void *arg)
#else
int idx = ble_hs_flow_mbuf_index(om);
if (idx < 0) {
BLE_HS_LOG(INFO, "ACL free: mbuf index not found; "
"flow credit may be lost\n");
return os_memblock_put_from_cb(&mpe->mpe_mp, data);
}
conn_handle = ble_hs_flow_mbuf_conn_handle[idx];
@@ -252,11 +254,11 @@ ble_hs_flow_connection_broken(uint16_t conn_handle)
{
uint16_t snapshot = ble_hs_flow_num_completed_pkts;
int rc = ble_hs_flow_tx_num_comp_pkts();
/* Decrement unconditionally to prevent counter overflow during async reset window */
ble_hs_flow_num_completed_pkts = (ble_hs_flow_num_completed_pkts >= snapshot) ?
ble_hs_flow_num_completed_pkts - snapshot : 0;
if (rc != 0) {
ble_hs_sched_reset(rc);
} else {
ble_hs_flow_num_completed_pkts = (ble_hs_flow_num_completed_pkts >= snapshot) ?
ble_hs_flow_num_completed_pkts - snapshot : 0;
}
}
#else
@@ -391,6 +393,13 @@ ble_hs_flow_deinit(void)
nimble_platform_mem_free(ble_hs_flow_ctx);
ble_hs_flow_ctx = NULL;
#else
ble_npl_eventq_remove(ble_hs_evq_get(), &ble_hs_flow_ev);
ble_npl_callout_stop(&ble_hs_flow_timer);
#if SOC_ESP_NIMBLE_CONTROLLER && CONFIG_BT_CONTROLLER_ENABLED
ble_hci_trans_set_acl_free_cb(NULL, NULL);
#else
ble_transport_register_put_acl_from_ll_cb(NULL);
#endif
ble_npl_event_deinit(&ble_hs_flow_ev);
ble_npl_callout_deinit(&ble_hs_flow_timer);
#endif /* MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC) */
+10 -10
View File
@@ -246,11 +246,6 @@ static void esp_hci_err_to_name(int error_code, uint16_t *opcode)
esp_core_err_to_name(error_code, opcode);
return;
}
else if (error_code - 0x200 < 0) {
/* Converts error code to HCI base */
error_code = BLE_HS_HCI_ERR(error_code);
}
for (int i = 0; i<sizeof(err_code_list) / sizeof(err_code_list[0]); i++) {
if (err_code_list[i].error_code == error_code) {
if (opcode == NULL) {
@@ -610,8 +605,8 @@ ble_hs_hci_cmd_tx(uint16_t opcode, const void *cmd, uint8_t cmd_len,
ble_transport_free((uint8_t *)l_ble_hs_hci_ack);
#endif
l_ble_hs_hci_ack = NULL;
ble_npl_sem_pend(&ble_hs_hci_sem, 0);
}
ble_npl_sem_pend(&ble_hs_hci_sem, 0);
BLE_HS_DBG_ASSERT(l_ble_hs_hci_ack == NULL);
rc = ble_hs_hci_cmd_send_buf(opcode, cmd, cmd_len);
@@ -726,9 +721,9 @@ ble_hs_hci_rx_evt(uint8_t *hci_ev, void *arg)
#if ((BT_HCI_LOG_INCLUDED == TRUE) && SOC_ESP_NIMBLE_CONTROLLER && CONFIG_BT_CONTROLLER_ENABLED)
uint16_t len = hci_ev[1] + 3;
if (host_recv_adv_packet(hci_ev)) {
bt_hci_log_record_hci_adv(HCI_LOG_DATA_TYPE_ADV, &hci_ev[2], hci_ev[1]);
bt_hci_log_record_hci_adv(HCI_LOG_DATA_TYPE_ADV, &hci_ev[1], len - 2);
#if BT_HCI_INSIGHTS_INCLUDED
bt_hci_log_record_insights(HCI_LOG_DATA_TYPE_ADV, &hci_ev[2], hci_ev[1]);
bt_hci_log_record_insights(HCI_LOG_DATA_TYPE_ADV, &hci_ev[1], len - 2);
#endif
} else {
bt_hci_log_record_hci_data(0x04, &hci_ev[0], len - 1);
@@ -1075,7 +1070,7 @@ ble_hs_hci_init(void)
rc = ble_npl_mutex_init(&ble_hs_hci_mutex);
if (rc != 0) {
goto err;
goto err_sem;
}
rc = mem_init_mbuf_pool(ble_hs_hci_frag_data,
@@ -1086,11 +1081,16 @@ ble_hs_hci_init(void)
"ble_hs_hci_frag");
if (rc != 0) {
goto err;
goto err_mutex;
}
return 0;
err_mutex:
os_mempool_unregister(&ble_hs_hci_frag_mempool);
ble_npl_mutex_deinit(&ble_hs_hci_mutex);
err_sem:
ble_npl_sem_deinit(&ble_hs_hci_sem);
err:
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (ble_hs_hci_frag_data) {
+2 -13
View File
@@ -27,15 +27,8 @@
#if (BT_HCI_LOG_INCLUDED == TRUE)
#include "hci_log/bt_hci_log.h"
#endif // (BT_HCI_LOG_INCLUDED == TRUE)
/*
* HCI Command Header
*
* Comprises the following fields
* -> Opcode group field & Opcode command field (2)
* -> Parameter Length (1)
* Length of all the parameters (does not include any part of the hci
* command header
*/
/* Length of the HCI command header (opcode 2 bytes + length 1 byte) */
#define BLE_HCI_CMD_HDR_LEN (3)
static int
@@ -64,10 +57,6 @@ ble_hs_hci_cmd_send(uint16_t opcode, uint8_t len, const void *cmddata)
int rc;
cmd = (struct ble_hci_cmd *)ble_transport_alloc_cmd();
if (cmd == NULL) {
return BLE_HS_ENOMEM_EVT;
}
BLE_HS_DBG_ASSERT(cmd != NULL);
if (cmd == NULL) {
return BLE_HS_ENOMEM;
}
+126 -57
View File
@@ -17,6 +17,7 @@
* under the License.
*/
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
@@ -112,6 +113,8 @@ static uint16_t ble_adv_list_count;
#if MYNEWT_VAL(BLE_QUEUE_CONG_CHECK)
#define BLE_ADV_LIST_MAX_LENGTH 50
#define BLE_ADV_LIST_MAX_COUNT 200
static bool ble_adv_list_ready(void);
#endif
#if MYNEWT_VAL(BLE_CHANNEL_SOUNDING)
@@ -462,16 +465,15 @@ ble_hs_hci_evt_resolve_rpa(ble_addr_t *addr)
}
ble_hs_unlock();
if (rl == NULL && ble_gap_rpa_resolve(addr->val, id_addr, &id_addr_type)) {
if (ble_hs_is_rpa(addr->val, ota_addr_type)) {
ble_hs_lock();
rl = ble_hs_resolv_list_find(id_addr);
if (rl != NULL) {
memcpy(rl->rl_peer_rpa, addr->val, BLE_DEV_ADDR_LEN);
rl->rl_isrpa = 1;
}
ble_hs_unlock();
if (rl == NULL && ble_hs_is_rpa(addr->val, ota_addr_type) &&
ble_gap_rpa_resolve(addr->val, id_addr, &id_addr_type)) {
ble_hs_lock();
rl = ble_hs_resolv_list_find(id_addr);
if (rl != NULL) {
memcpy(rl->rl_peer_rpa, addr->val, BLE_DEV_ADDR_LEN);
rl->rl_isrpa = 1;
}
ble_hs_unlock();
memcpy(addr->val, id_addr, BLE_DEV_ADDR_LEN);
addr->type = id_addr_type;
@@ -529,6 +531,7 @@ ble_hs_hci_evt_disconn_complete(uint8_t event_code, const void *data,
#if MYNEWT_VAL(BLE_ENABLE_CONN_REATTEMPT)
if (conn_found) {
int rc;
uint16_t conn_handle = le16toh(ev->conn_handle);
#if MYNEWT_VAL(BT_NIMBLE_MEM_OPTIMIZATION)
should_reattempt = (!conn_slave && ev->reason == BLE_ERR_CONN_SPVN_TMO);
@@ -542,7 +545,7 @@ ble_hs_hci_evt_disconn_complete(uint8_t event_code, const void *data,
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (ble_hs_hci_ensure_ctx()) {
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_ENOMEM);
return BLE_HS_ENOMEM;
goto skip_reattempt;
}
#endif
@@ -555,11 +558,9 @@ ble_hs_hci_evt_disconn_complete(uint8_t event_code, const void *data,
reattempt_conn.count);
reattempt_conn.count += 1;
/* Post event to interested application; pass raw LE value since
* ble_gap_reattempt_count applies le16toh internally. */
ble_gap_reattempt_count(ev->conn_handle, reattempt_conn.count);
ble_gap_reattempt_count(conn_handle, reattempt_conn.count);
#if MYNEWT_VAL(BLE_ROLE_CENTRAL) || MYNEWT_VAL(BLE_ROLE_OBSERVER)
rc = ble_gap_master_connect_reattempt(ev->conn_handle);
rc = ble_gap_master_connect_reattempt(conn_handle);
if (rc != 0) {
BLE_HS_LOG(INFO, "Master reconnect attempt failed; rc = %d", rc);
}
@@ -579,19 +580,19 @@ ble_hs_hci_evt_disconn_complete(uint8_t event_code, const void *data,
#endif
BLE_HS_LOG(INFO, "Reattempt advertising; reason: 0x%x, status = %x",
ev->reason, ev->status);
ble_l2cap_sig_conn_broken(ev->conn_handle, BLE_ERR_CONN_ESTABLISHMENT);
ble_sm_connection_broken(ev->conn_handle);
ble_l2cap_sig_conn_broken(conn_handle, BLE_ERR_CONN_ESTABLISHMENT);
ble_sm_connection_broken(conn_handle);
#if MYNEWT_VAL(BLE_GATTS)
ble_gatts_connection_broken(ev->conn_handle);
ble_gatts_connection_broken(conn_handle);
#endif
#if MYNEWT_VAL(BLE_GATTC)
ble_gattc_connection_broken(ev->conn_handle);
ble_gattc_connection_broken(conn_handle);
#endif
ble_hs_flow_connection_broken(ev->conn_handle);;
ble_hs_flow_connection_broken(conn_handle);;
#if MYNEWT_VAL(BLE_GATT_CACHING)
ble_gattc_cache_conn_broken(ev->conn_handle);
ble_gattc_cache_conn_broken(conn_handle);
#endif
rc = ble_hs_atomic_conn_delete(ev->conn_handle);
rc = ble_hs_atomic_conn_delete(conn_handle);
if (rc != 0) {
return rc;
}
@@ -608,6 +609,11 @@ ble_hs_hci_evt_disconn_complete(uint8_t event_code, const void *data,
/* Normal disconnect. Reset the structure */
memset(&reattempt_conn, 0x0, sizeof (struct ble_gap_reattempt_ctxt));
}
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
skip_reattempt:
;
#endif
}
#endif
@@ -885,17 +891,29 @@ ble_hs_hci_evt_le_enh_conn_complete(uint8_t subevent, const void *data,
if (evt.status == BLE_ERR_DIR_ADV_TMO ||
evt.role == BLE_HCI_LE_CONN_COMPLETE_ROLE_SLAVE) {
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (ble_hs_hci_ensure_ctx()) {
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_ENOMEM);
return BLE_HS_ENOMEM;
}
/* PAwR slave connections use the V2 subevent (not ENH_CONN_COMPLETE).
* The controller does NOT send LE Advertising Set Terminated for PAwR,
* so we must NOT store them as pending — they would hang indefinitely.
* Fall through to the BLE_PERIODIC_ADV_WITH_RESPONSES handler instead. */
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
if (subevent == BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE)
#endif
/* store this until we get set terminated event with adv handle */
memcpy(&pend_conn_complete, &evt, sizeof(evt));
pend_conn_complete_valid = true;
return 0;
{
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (ble_hs_hci_ensure_ctx()) {
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_ENOMEM);
return BLE_HS_ENOMEM;
}
#endif
/* store this until we get set terminated event with adv handle */
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
evt.adv_handle = 0xFF;
evt.sync_handle = 0xFFFF;
#endif
memcpy(&pend_conn_complete, &evt, sizeof(evt));
pend_conn_complete_valid = true;
return 0;
}
}
#endif
@@ -907,7 +925,7 @@ ble_hs_hci_evt_le_enh_conn_complete(uint8_t subevent, const void *data,
evt.sync_handle = 0xFFFF;
} else {
evt.adv_handle = ev->adv_handle;
evt.sync_handle = ev->sync_handle;
evt.sync_handle = le16toh(ev->sync_handle);
if (evt.adv_handle < BLE_ADV_INSTANCES) {
instance = evt.adv_handle;
}
@@ -1059,12 +1077,15 @@ ble_hs_hci_evt_le_adv_rpt(uint8_t subevent, const void *data, unsigned int len)
/* BLE Queue Congestion check*/
#if MYNEWT_VAL(BLE_QUEUE_CONG_CHECK)
if (ble_get_adv_list_length() > BLE_ADV_LIST_MAX_LENGTH || ble_adv_list_count > BLE_ADV_LIST_MAX_COUNT) {
ble_adv_list_refresh();
}
if (ble_npl_mutex_pend(&adv_list_lock, BLE_NPL_TIME_FOREVER) == BLE_NPL_OK) {
ble_adv_list_count++;
ble_npl_mutex_release(&adv_list_lock);
if (ble_adv_list_ready()) {
if (ble_get_adv_list_length() > BLE_ADV_LIST_MAX_LENGTH ||
ble_adv_list_count > BLE_ADV_LIST_MAX_COUNT) {
ble_adv_list_refresh();
}
if (ble_npl_mutex_pend(&adv_list_lock, BLE_NPL_TIME_FOREVER) == BLE_NPL_OK) {
ble_adv_list_count++;
ble_npl_mutex_release(&adv_list_lock);
}
}
#endif
@@ -1133,7 +1154,6 @@ ble_hs_hci_evt_le_dir_adv_rpt(uint8_t subevent, const void *data, unsigned int l
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
desc.ota_addr = desc.addr;
ble_hs_hci_evt_resolve_rpa(&desc.addr);
ble_hs_hci_evt_resolve_rpa(&desc.direct_addr);
#endif
ble_gap_rx_adv_report(&desc);
}
@@ -1537,8 +1557,8 @@ ble_hs_hci_evt_le_ext_adv_rpt(uint8_t subevent, const void *data,
desc.periodic_adv_itvl = le16toh(report->periodic_itvl);
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
desc.ota_addr = desc.addr;
ble_hs_hci_evt_resolve_rpa(&desc.addr);
ble_hs_hci_evt_resolve_rpa(&desc.direct_addr);
#endif
ble_gap_rx_ext_adv_report(&desc);
@@ -1556,13 +1576,25 @@ ble_hs_hci_evt_le_periodic_adv_sync_estab(uint8_t subevent, const void *data,
unsigned int len)
{
const struct ble_hci_ev_le_subev_periodic_adv_sync_estab *ev = data;
unsigned int min_len;
if (len < sizeof(*ev)) {
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
if (subevent == BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_ESTAB) {
min_len = offsetof(struct ble_hci_ev_le_subev_periodic_adv_sync_estab,
num_subevents);
} else {
min_len = sizeof(*ev);
}
#else
min_len = sizeof(*ev);
#endif
if (len < min_len) {
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_ECONTROLLER);
return BLE_HS_ECONTROLLER;
}
ble_gap_rx_peroidic_adv_sync_estab(ev);
ble_gap_rx_peroidic_adv_sync_estab(ev, subevent);
return 0;
}
@@ -1643,13 +1675,25 @@ ble_hs_hci_evt_le_periodic_adv_sync_transfer(uint8_t subevent, const void *data,
{
#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER)
const struct ble_hci_ev_le_subev_periodic_adv_sync_transfer *ev = data;
unsigned int min_len;
if (len < sizeof(*ev)) {
#if MYNEWT_VAL(BLE_PERIODIC_ADV_WITH_RESPONSES)
if (subevent == BLE_HCI_LE_SUBEV_PERIODIC_ADV_SYNC_TRANSFER) {
min_len = offsetof(struct ble_hci_ev_le_subev_periodic_adv_sync_transfer,
num_subevents);
} else {
min_len = sizeof(*ev);
}
#else
min_len = sizeof(*ev);
#endif
if (len < min_len) {
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_EBADDATA);
return BLE_HS_EBADDATA;
}
ble_gap_rx_periodic_adv_sync_transfer(ev);
ble_gap_rx_periodic_adv_sync_transfer(ev, subevent);
#endif
return 0;
@@ -1864,6 +1908,7 @@ ble_hs_hci_evt_le_periodic_adv_subev_resp_rep(uint8_t subevent, const void *data
struct ble_gap_periodic_adv_response resp;
const uint8_t *payload;
unsigned int payload_len;
uint8_t i;
if (len < sizeof(*ev)) {
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_ECONTROLLER);
@@ -1877,7 +1922,7 @@ ble_hs_hci_evt_le_periodic_adv_subev_resp_rep(uint8_t subevent, const void *data
payload = (const uint8_t *)(ev + 1);
payload_len = len - sizeof(*ev);
for (uint8_t i = 0; i < ev->num_responses; i++) {
for (i = 0; i < ev->num_responses; i++) {
if (payload_len < sizeof(*response)) {
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_ECONTROLLER);
return BLE_HS_ECONTROLLER;
@@ -1892,9 +1937,9 @@ ble_hs_hci_evt_le_periodic_adv_subev_resp_rep(uint8_t subevent, const void *data
resp.rssi = response->rssi;
resp.cte_type = response->cte_type;
resp.response_slot = response->response_slot;
resp.data_status = response->data_status;
resp.data_length = response->data_length;
resp.data = response->data;
resp.data_status = response->data_status;
ble_gap_rx_periodic_adv_response(resp);
@@ -2125,6 +2170,14 @@ ble_hs_hci_evt_process(struct ble_hci_ev *ev)
rc = BLE_HS_ECONTROLLER;
goto done;
}
/* NOP Command Complete events are sent by the controller for flow
* control and have opcode 0; they have no dispatch entry and should
* be silently consumed.
*/
if (opcode == BLE_HCI_OPCODE_NOP) {
rc = 0;
goto done;
}
entry = ble_hs_hci_evt_dispatch_find(opcode);
}
else {
@@ -2236,21 +2289,25 @@ ble_adv_list_ready(void)
return true;
}
void ble_adv_list_init(void)
int ble_adv_list_init(void)
{
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (ble_hs_hci_ensure_ctx()) {
return;
return BLE_HS_ENOMEM;
}
#endif
if (ble_npl_mutex_init(&adv_list_lock) != BLE_NPL_OK) {
BLE_HS_LOG(ERROR, "%s mutex init failed", __func__);
return;
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
ble_hs_hci_ctx_free();
#endif
return BLE_HS_EOS;
}
SLIST_INIT(&ble_adv_list);
ble_adv_list_count = 0;
return 0;
}
void ble_adv_list_deinit(void)
@@ -2258,8 +2315,16 @@ void ble_adv_list_deinit(void)
struct ble_addr_list_entry *device;
struct ble_addr_list_entry *temp;
if (!ble_adv_list_ready() ||
ble_npl_mutex_pend(&adv_list_lock, BLE_NPL_TIME_FOREVER) != BLE_NPL_OK) {
if (!ble_adv_list_ready()) {
return;
}
if (ble_npl_mutex_pend(&adv_list_lock, BLE_NPL_TIME_FOREVER) != BLE_NPL_OK) {
SLIST_FOREACH_SAFE(device, &ble_adv_list, next, temp) {
SLIST_REMOVE(&ble_adv_list, device, ble_addr_list_entry, next);
nimble_platform_mem_free(device);
}
ble_npl_mutex_deinit(&adv_list_lock);
return;
}
@@ -2273,32 +2338,34 @@ void ble_adv_list_deinit(void)
ble_npl_mutex_deinit(&adv_list_lock);
}
void ble_adv_list_add_packet(void *data)
bool ble_adv_list_add_packet(void *data)
{
struct ble_addr_list_entry *device;
struct ble_addr_list_entry *entry;
if (!data) {
BLE_HS_LOG(ERROR, "%s data is NULL", __func__);
return;
return false;
}
if (!ble_adv_list_ready() ||
ble_npl_mutex_pend(&adv_list_lock, BLE_NPL_TIME_FOREVER) != BLE_NPL_OK) {
return;
return false;
}
device = (struct ble_addr_list_entry *)data;
SLIST_FOREACH(entry, &ble_adv_list, next) {
if (entry == device) {
if (entry->addr.type == device->addr.type &&
memcmp(entry->addr.val, device->addr.val, BLE_DEV_ADDR_LEN) == 0) {
ble_npl_mutex_release(&adv_list_lock);
return;
return false;
}
}
SLIST_INSERT_HEAD(&ble_adv_list, device, next);
ble_npl_mutex_release(&adv_list_lock);
return true;
}
uint32_t ble_get_adv_list_length(void)
@@ -2373,7 +2440,9 @@ bool ble_check_adv_list(const uint8_t *addr, uint8_t addr_type)
if (adv_packet) {
adv_packet->addr.type = addr_type;
memcpy(adv_packet->addr.val, addr, BLE_DEV_ADDR_LEN);
ble_adv_list_add_packet(adv_packet);
if (!ble_adv_list_add_packet(adv_packet)) {
nimble_platform_mem_free(adv_packet);
}
} else {
BLE_HS_LOG(ERROR, "%s adv_packet malloc failed", __func__);
}
+6 -6
View File
@@ -317,6 +317,8 @@ ble_hs_id_addr(uint8_t id_addr_type, const uint8_t **out_id_addr,
}
#endif
BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
switch (id_addr_type) {
case BLE_ADDR_PUBLIC:
case BLE_ADDR_PUBLIC_ID:
@@ -372,7 +374,6 @@ static int
ble_hs_id_addr_type_usable(uint8_t own_addr_type)
{
uint8_t id_addr_type;
const uint8_t *id_addr_ptr;
int nrpa;
int rc;
@@ -387,18 +388,17 @@ ble_hs_id_addr_type_usable(uint8_t own_addr_type)
case BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT:
case BLE_OWN_ADDR_RPA_RANDOM_DEFAULT:
#if !MYNEWT_VAL(BLE_HS_PVCY)
return BLE_HS_ENOTSUP;
#endif
id_addr_type = ble_hs_misc_own_addr_type_to_id(own_addr_type);
rc = ble_hs_id_addr(id_addr_type, &id_addr_ptr, &nrpa);
rc = ble_hs_id_addr(id_addr_type, NULL, &nrpa);
if (rc != 0) {
return rc;
}
if (nrpa) {
return BLE_HS_ENOADDR;
}
#if !MYNEWT_VAL(BLE_HS_PVCY)
return BLE_HS_ENOTSUP;
#endif
break;
default:
+23 -10
View File
@@ -50,18 +50,12 @@ static uint8_t ble_hs_iso_max_pkts;
static uint16_t ble_hs_iso_avail_pkts;
#endif /* MYNEWT_VAL(BLE_ISO_STD_FLOW_CTRL) */
int
ble_iso_init(void)
{
return 0;
}
int
ble_hs_hci_set_iso_buf_sz(uint16_t pktlen, uint8_t max_pkts)
{
BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
if (pktlen < BLE_HCI_ISO_DATA_LOAD_HDR_SZ || max_pkts == 0) {
if (pktlen == 0 || max_pkts == 0) {
return BLE_HS_EINVAL;
}
@@ -193,9 +187,25 @@ ble_hs_hci_iso_tx_now(uint16_t conn_handle, const uint8_t *sdu, uint16_t sdu_len
uint8_t dlh_len;
uint8_t *frag;
int rc;
#if MYNEWT_VAL(BLE_ISO_STD_FLOW_CTRL)
uint16_t count;
#endif
#if MYNEWT_VAL(BLE_ISO_STD_FLOW_CTRL)
uint16_t count = ble_hs_hci_iso_buf_needed(sdu_len, ts_flag);
dlh_len = (ts_flag ? BLE_HCI_ISO_DATA_LOAD_TS_SZ : 0) +
BLE_HCI_ISO_DATA_LOAD_HDR_SZ;
count = ble_hs_hci_iso_buf_needed(sdu_len, ts_flag);
if (count == 0) {
return BLE_HS_EINVAL;
}
/* Host does not support fragmentation yet; reject SDUs that don't fit in one buffer. */
if (count > 1) {
BLE_HS_LOG(ERROR, "ISO SDU+hdr too large (%u > %u)",
(unsigned)(sdu_len + dlh_len), (unsigned)ble_hs_iso_buf_sz);
return BLE_HS_EMSGSIZE;
}
/* Make sure the Controller ISO buffer can accommodate the SDU completely */
if (count > ble_hs_iso_avail_pkts) {
@@ -207,10 +217,13 @@ ble_hs_hci_iso_tx_now(uint16_t conn_handle, const uint8_t *sdu, uint16_t sdu_len
BLE_HS_LOG(WARN, "ISO flow control!");
return BLE_HS_EAGAIN;
}
dlh_len = (ts_flag ? BLE_HCI_ISO_DATA_LOAD_TS_SZ : 0) +
BLE_HCI_ISO_DATA_LOAD_HDR_SZ;
#else
dlh_len = (ts_flag ? BLE_HCI_ISO_DATA_LOAD_TS_SZ : 0) +
BLE_HCI_ISO_DATA_LOAD_HDR_SZ;
#endif
dlh_len = (ts_flag ? BLE_HCI_ISO_DATA_LOAD_TS_SZ : 0) + BLE_HCI_ISO_DATA_LOAD_HDR_SZ;
/* Note:
* Here we allocate memory to hold the whole SDU, and in the BLE Controller,
* the SDU will be checked. If it's too large, error will be returned.
+2 -2
View File
@@ -271,7 +271,7 @@ ble_hs_hci_set_cig_params_test(uint8_t cig_id, uint32_t sdu_interval_c_to_p, uin
}
if (rsp_buf == NULL||
rsp_len < sizeof(struct ble_hci_le_set_cig_params_rp) + cis_cnt * 2) {
rsp_len < sizeof(struct ble_hci_le_set_cig_params_test_rp) + cis_cnt * 2) {
return BLE_HS_EINVAL;
}
@@ -311,7 +311,7 @@ ble_hs_hci_set_cig_params_test(uint8_t cig_id, uint32_t sdu_interval_c_to_p, uin
return ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
BLE_HCI_OCF_LE_SET_CIG_PARAMS_TEST),
cmd_buf, cmd_len, rsp_buf,
sizeof(struct ble_hci_le_set_cig_params_rp) +
sizeof(struct ble_hci_le_set_cig_params_test_rp) +
cis_cnt * 2);
}
#endif /* MYNEWT_VAL(BLE_ISO_TEST) */
+31 -26
View File
@@ -81,8 +81,8 @@ ble_hs_pvcy_set_addr_timeout(uint16_t timeout)
struct ble_hci_le_set_rpa_tmo_cp cmd;
if (timeout == 0 || timeout > BLE_MAX_RPA_TIMEOUT_VAL) {
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_HCI_ERR(BLE_ERR_INV_HCI_CMD_PARMS));
return BLE_HS_HCI_ERR(BLE_ERR_INV_HCI_CMD_PARMS);
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_EINVAL);
return BLE_HS_EINVAL;
}
cmd.rpa_timeout = htole16(timeout);
@@ -209,17 +209,19 @@ ble_hs_pvcy_remove_entry(uint8_t addr_type, const uint8_t *addr)
cmd.peer_addr_type = addr_type;
memcpy(cmd.peer_id_addr, addr, BLE_DEV_ADDR_LEN);
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
ble_hs_lock();
rc = ble_hs_resolv_list_rmv(addr_type, &cmd.peer_id_addr[0]);
ble_hs_unlock();
#else
ble_gap_preempt();
ble_hs_lock();
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
rc = ble_hs_resolv_list_rmv(addr_type, &cmd.peer_id_addr[0]);
#else
rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
BLE_HCI_OCF_LE_RMV_RESOLV_LIST),
&cmd, sizeof(cmd), NULL, 0);
#endif
ble_hs_unlock();
ble_gap_preempt_done();
#endif
return rc;
}
@@ -260,7 +262,7 @@ ble_hs_pvcy_add_entry_hci(const uint8_t *addr, uint8_t addr_type,
#endif
if (addr_type > BLE_ADDR_RANDOM) {
return BLE_ERR_INV_HCI_CMD_PARMS;
return BLE_HS_EINVAL;
}
cmd.peer_addr_type = addr_type;
@@ -397,10 +399,10 @@ ble_hs_pvcy_ensure_started(void)
}
#endif
ble_hs_lock();
ble_hs_lock_nested();
if (ble_hs_pvcy_started) {
ble_hs_unlock();
ble_hs_unlock_nested();
return 0;
}
@@ -420,13 +422,13 @@ ble_hs_pvcy_ensure_started(void)
}
if (rc != 0) {
ble_hs_unlock();
ble_hs_unlock_nested();
return rc;
}
ble_hs_pvcy_started = 1;
ble_hs_unlock();
ble_hs_unlock_nested();
return 0;
}
@@ -527,7 +529,7 @@ ble_hs_pvcy_set_our_irk(const uint8_t *irk)
{
uint8_t tmp_addr[6];
uint8_t new_irk[16];
int rc;
int rc = 0;
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (ble_hs_pvcy_ctx == NULL) {
@@ -555,7 +557,7 @@ ble_hs_pvcy_set_our_irk(const uint8_t *irk)
ble_hs_resolv_enable(0);
}
ble_hs_resolv_list_clear_all(false);
ble_hs_resolv_list_clear_all();
if (rpa_state) {
ble_hs_resolv_enable(1);
@@ -580,7 +582,7 @@ ble_hs_pvcy_set_our_irk(const uint8_t *irk)
done:
ble_gap_preempt_done();
if (rc != 0) {
return rc;
goto pvcy_done;
}
#endif
@@ -597,11 +599,20 @@ done:
memset(tmp_addr, 0, 6);
rc = ble_hs_pvcy_add_entry(tmp_addr, 0, zero_irk);
if (rc != 0) {
#if !MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
goto pvcy_done;
#else
return rc;
#endif
}
#endif
return 0;
#if !MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
pvcy_done:
ble_gap_preempt_done();
#endif
return rc;
}
int
@@ -670,17 +681,16 @@ ble_hs_pvcy_rpa_config(uint8_t enable)
{
int rc = 0;
ble_hs_lock();
#if !MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
ble_gap_preempt();
#endif
if (enable != NIMBLE_HOST_DISABLE_PRIVACY) {
rc = ble_hs_pvcy_ensure_started();
if (rc != 0) {
goto done;
return rc;
}
}
ble_hs_lock();
if (enable != NIMBLE_HOST_DISABLE_PRIVACY) {
ble_hs_resolv_enable(true);
/* Configure NRPA address related flags according to input parameter */
@@ -689,12 +699,10 @@ ble_hs_pvcy_rpa_config(uint8_t enable)
} else {
ble_hs_resolv_nrpa_disable();
}
} else {
ble_hs_resolv_enable(false);
}
done:
ble_hs_unlock();
if (rc == 0 && enable != NIMBLE_HOST_DISABLE_PRIVACY) {
@@ -704,9 +712,6 @@ done:
rc = ble_hs_gen_own_private_rnd();
ble_gap_preempt_done();
}
#if !MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
ble_gap_preempt_done();
#endif
return rc;
}
+11 -5
View File
@@ -801,6 +801,8 @@ ble_hs_resolv_list_add(uint8_t *cmdbuf)
const uint8_t *ident_addr;
struct ble_hs_resolv_entry *rl;
struct ble_hs_dev_records *p_dev_rec = NULL;
uint8_t p_dev_idaddr_backup[6];
bool p_dev_idaddr_modified = false;
BLE_HS_DBG_ASSERT(ble_hs_locked_by_cur_task());
@@ -841,6 +843,8 @@ ble_hs_resolv_list_add(uint8_t *cmdbuf)
p_dev_rec = ble_rpa_find_peer_dev_by_irk(rl->rl_peer_irk);
if (p_dev_rec != NULL) {
p_dev_idaddr_modified = true;
memcpy(p_dev_idaddr_backup, p_dev_rec->identity_addr, 6);
memcpy(p_dev_rec->identity_addr, ident_addr, 6);
memcpy(rl->rl_pseudo_id, p_dev_rec->pseudo_addr, 6);
}
@@ -852,8 +856,12 @@ ble_hs_resolv_list_add(uint8_t *cmdbuf)
if (ble_hs_resolv_gen_priv_addr(rl, 1) != 0 ||
ble_hs_resolv_gen_priv_addr(rl, 0) != 0) {
memset(rl, 0, sizeof(*rl));
if (p_dev_idaddr_modified) {
memcpy(p_dev_rec->identity_addr, p_dev_idaddr_backup, 6);
}
return BLE_HS_EUNKNOWN;
}
++(g_ble_hs_resolv_data.rl_cnt);
BLE_HS_LOG(DEBUG, "Device added to RL, Resolving list count = %d\n", g_ble_hs_resolv_data.rl_cnt);
@@ -912,7 +920,7 @@ ble_hs_resolv_list_rmv(uint8_t addr_type, uint8_t *ident_addr)
* Clear the resolving list
*/
void
ble_hs_resolv_list_clear_all(bool preserve_local)
ble_hs_resolv_list_clear_all(void)
{
struct ble_hs_resolv_entry local_entry;
bool restore_local = false;
@@ -930,10 +938,8 @@ ble_hs_resolv_list_clear_all(bool preserve_local)
}
#endif
/* Index 0 is the local identity. Some callers clear only peer state,
* while local IRK replacement must clear it too.
*/
if (preserve_local && g_ble_hs_resolv_data.rl_cnt > 0) {
/* Preserve local device entry at index 0 if it exists */
if (g_ble_hs_resolv_data.rl_cnt > 0) {
memcpy(&local_entry, &g_ble_hs_resolv_list[0], sizeof(local_entry));
restore_local = true;
}
+1 -1
View File
@@ -69,7 +69,7 @@ uint8_t *ble_hs_get_rpa_local(void);
/* Remove a device from the resolving list */
int ble_hs_resolv_list_rmv(uint8_t, uint8_t *);
/* Clear the resolving list and peer dev record */
void ble_hs_resolv_list_clear_all(bool preserve_local);
void ble_hs_resolv_list_clear_all(void);
/* Update the local IRK stored at index 0 (must hold host lock) */
void ble_hs_resolv_update_local_irk(const uint8_t *irk);
+16 -5
View File
@@ -502,8 +502,6 @@ ble_hs_startup_reset_tx(void)
int
ble_hs_startup_go(void)
{
struct ble_store_gen_key gen_key;
int key_rc;
int rc;
rc = ble_hs_startup_reset_tx();
@@ -562,31 +560,44 @@ ble_hs_startup_go(void)
return rc;
}
#if MYNEWT_VAL(BLE_HS_PVCY) && NIMBLE_BLE_SM
struct ble_store_gen_key gen_key;
int key_rc;
if (ble_hs_cfg.store_gen_key_cb) {
memset(&gen_key, 0, sizeof(gen_key));
key_rc = ble_hs_cfg.store_gen_key_cb(BLE_STORE_GEN_KEY_IRK, &gen_key,
BLE_HS_CONN_HANDLE_NONE);
#if MYNEWT_VAL(BLE_HS_PVCY)
if (key_rc == 0) {
rc = ble_hs_pvcy_set_our_irk(gen_key.irk);
if (rc != 0) {
BLE_HS_LOG(WARN, "ble_hs_pvcy_set_our_irk (stored) rc=%d\n", rc);
return rc;
}
}
#endif
} else {
key_rc = -1;
}
#if MYNEWT_VAL(BLE_HS_PVCY)
if (key_rc != 0) {
ble_hs_pvcy_set_default_irk();
rc = ble_hs_pvcy_set_our_irk(NULL);
if (rc != 0) {
BLE_HS_LOG(WARN, "ble_hs_pvcy_set_our_irk (default) rc=%d\n", rc);
return rc;
}
}
#elif MYNEWT_VAL(BLE_HS_PVCY)
/* SM disabled: no bond store or AES for IRK/RPA; skip privacy init. */
#else
if (ble_hs_cfg.store_gen_key_cb) {
struct ble_store_gen_key gen_key;
memset(&gen_key, 0, sizeof(gen_key));
(void)ble_hs_cfg.store_gen_key_cb(BLE_STORE_GEN_KEY_IRK, &gen_key,
BLE_HS_CONN_HANDLE_NONE);
}
#endif
/* If flow control is enabled, configure the controller to use it.
+62 -17
View File
@@ -68,6 +68,10 @@ static uint8_t ble_hs_stop_conn_cnt;
static struct ble_npl_callout ble_hs_stop_terminate_tmo;
#endif
/** List of listeners being notified; guarded by ble_hs_stop_notifying. */
static struct ble_hs_stop_listener_slist ble_hs_stop_notify_list;
static bool ble_hs_stop_notifying;
static int
ble_hs_stop_hci_reset(void)
{
@@ -81,8 +85,9 @@ ble_hs_stop_hci_reset(void)
static void
ble_hs_stop_done(int status)
{
struct ble_hs_stop_listener_slist slist;
struct ble_hs_stop_listener_slist notify_list;
struct ble_hs_stop_listener *listener;
struct ble_hs_stop_listener *l;
int rc;
ble_npl_callout_stop(&ble_hs_stop_terminate_tmo);
@@ -94,28 +99,60 @@ ble_hs_stop_done(int status)
return;
}
slist = ble_hs_stop_listeners;
ble_hs_stop_notify_list = ble_hs_stop_listeners;
SLIST_INIT(&ble_hs_stop_listeners);
ble_hs_enabled_state = BLE_HS_ENABLED_STATE_OFF;
ble_hs_stop_notifying = true;
ble_hs_unlock();
ble_gap_event_listener_unregister(&ble_hs_stop_gap_listener);
/* Reset the controller. */
/* Reset the controller while still in STOPPING state so the HCI ACK is
* not dropped by host_rcv_pkt (which drops packets when state == OFF). */
rc = ble_hs_stop_hci_reset();
if (rc != 0) {
BLE_HS_LOG(ERROR, "ble_hs_stop: failed to reset controller; rc=%d\n", rc);
}
/* Mark host as OFF and absorb any listeners registered during the HCI
* reset before notifying waiters. */
ble_hs_lock();
ble_hs_enabled_state = BLE_HS_ENABLED_STATE_OFF;
while ((listener = SLIST_FIRST(&ble_hs_stop_listeners)) != NULL) {
bool already;
SLIST_REMOVE_HEAD(&ble_hs_stop_listeners, link);
already = false;
SLIST_FOREACH(l, &ble_hs_stop_notify_list, link) {
if (l == listener) {
already = true;
break;
}
}
if (!already) {
SLIST_INSERT_HEAD(&ble_hs_stop_notify_list, listener, link);
}
}
ble_hs_stop_notifying = false;
notify_list = ble_hs_stop_notify_list;
SLIST_INIT(&ble_hs_stop_notify_list);
ble_hs_unlock();
/* Clear advertising, scanning and connection states. */
ble_gap_reset_state(0);
if (status != 0) {
if (status == BLE_HS_ETIMEOUT) {
ble_gap_reset_state(BLE_ERR_CONN_SPVN_TMO);
} else {
ble_gap_reset_state(BLE_ERR_REM_USER_CONN_TERM);
}
} else {
ble_gap_reset_state(0);
}
/* After LL reset the controller loses its random address */
ble_hs_id_reset();
SLIST_FOREACH(listener, &slist, link) {
SLIST_FOREACH(listener, &notify_list, link) {
listener->fn(status, listener->arg);
}
}
@@ -160,13 +197,14 @@ ble_hs_stop_terminate_all_periodic_sync(void)
*
* Also, once the sync is terminated, the psync will be freed and
* removed from the list such that the next iteration yields the next
* psync handle. Continue on errors so all syncs are cleaned up.
* psync handle. Return on errors; the caller (ble_hs_stop) will
* report the failure via ble_hs_stop_done.
*/
rc = ble_gap_periodic_adv_sync_terminate(sync_handle);
if (rc != 0 && rc != BLE_HS_ENOTCONN) {
BLE_HS_LOG(ERROR, "failed to terminate periodic sync=0x%04x, rc=%d\n",
sync_handle, rc);
/* Continue attempting to terminate remaining syncs. */
return rc;
}
}
@@ -249,15 +287,22 @@ ble_hs_stop_register_listener(struct ble_hs_stop_listener *listener,
BLE_HS_DBG_ASSERT(fn != NULL);
listener->fn = fn;
listener->arg = arg;
/* Guard against duplicate registration which would corrupt the list. */
SLIST_FOREACH(l, &ble_hs_stop_listeners, link) {
if (l == listener) {
return;
}
}
listener->fn = fn;
listener->arg = arg;
if (ble_hs_stop_notifying) {
SLIST_FOREACH(l, &ble_hs_stop_notify_list, link) {
if (l == listener) {
return;
}
}
}
SLIST_INSERT_HEAD(&ble_hs_stop_listeners, listener, link);
}
@@ -362,8 +407,6 @@ ble_hs_stop(struct ble_hs_stop_listener *listener,
void
ble_hs_stop_init(void)
{
int rc;
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (!ble_hs_stop_ctx) {
ble_hs_stop_ctx = nimble_platform_mem_calloc(1, sizeof(*ble_hs_stop_ctx));
@@ -375,13 +418,15 @@ ble_hs_stop_init(void)
#endif
#ifdef MYNEWT
rc = ble_npl_callout_init(&ble_hs_stop_terminate_tmo, ble_npl_eventq_dflt_get(),
ble_hs_stop_terminate_timeout_cb, NULL);
ble_npl_callout_init(&ble_hs_stop_terminate_tmo, ble_npl_eventq_dflt_get(),
ble_hs_stop_terminate_timeout_cb, NULL);
#else
int rc;
rc = ble_npl_callout_init(&ble_hs_stop_terminate_tmo, nimble_port_get_dflt_eventq(),
ble_hs_stop_terminate_timeout_cb, NULL);
#endif
SYSINIT_PANIC_ASSERT(rc == 0);
#endif
}
void
+158 -69
View File
@@ -17,9 +17,15 @@
* under the License.
*/
#include <stdint.h>
#include <string.h>
#include "syscfg/syscfg.h"
#if MYNEWT_VAL(BLE_ISO)
_Static_assert(MYNEWT_VAL(BLE_TRANSPORT_ISO_SIZE) > 4,
"BLE_TRANSPORT_ISO_SIZE must be > 4 for ISO SDU header");
#include "os/os_mbuf.h"
#include "host/ble_hs_log.h"
#include "host/ble_hs.h"
@@ -62,7 +68,7 @@ enum ble_iso_conn_type {
struct ble_iso_big {
SLIST_ENTRY(ble_iso_big) next;
uint8_t handle;
uint16_t handle;
uint16_t max_pdu;
uint8_t bis_cnt;
@@ -73,7 +79,7 @@ struct ble_iso_big {
struct ble_iso_conn {
SLIST_ENTRY(ble_iso_conn) next;
enum ble_iso_conn_type type;
uint8_t handle;
uint16_t handle;
struct ble_iso_rx_data_info rx_info;
struct os_mbuf *rx_buf;
@@ -96,6 +102,18 @@ static struct os_mempool ble_iso_bis_pool;
static os_membuf_t ble_iso_bis_mem[
OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_ISO_MAX_BISES), sizeof (struct ble_iso_bis))];
static void
ble_iso_broadcast_code_set(uint8_t *dst, const char *src)
{
size_t code_len;
memset(dst, 0, 16);
if (src != NULL) {
code_len = strnlen(src, 16);
memcpy(dst, src, code_len);
}
}
static void
ble_iso_conn_append(struct ble_iso_conn *conn)
{
@@ -119,7 +137,7 @@ ble_iso_big_handle_set(struct ble_iso_big *big)
uint8_t i;
/* Set next free handle */
for (i = BLE_HCI_ISO_BIG_HANDLE_MIN; i < BLE_HCI_ISO_BIG_HANDLE_MAX; i++) {
for (i = BLE_HCI_ISO_BIG_HANDLE_MIN; i <= BLE_HCI_ISO_BIG_HANDLE_MAX; i++) {
struct ble_iso_big *node = NULL;
if (free_handle > BLE_HCI_ISO_BIG_HANDLE_MAX) {
@@ -134,7 +152,7 @@ ble_iso_big_handle_set(struct ble_iso_big *big)
}
}
if (node == NULL || node->handle != big->handle) {
if (node == NULL) {
return 0;
}
}
@@ -209,12 +227,13 @@ static int
ble_iso_big_free(struct ble_iso_big *big)
{
struct ble_iso_conn *conn;
struct ble_iso_conn *conn_tmp;
struct ble_iso_bis *rem_bis[MYNEWT_VAL(BLE_ISO_MAX_BISES)] = {
[0 ... MYNEWT_VAL(BLE_ISO_MAX_BISES) - 1] = NULL
};
uint8_t i = 0;
SLIST_FOREACH(conn, &ble_iso_conns, next) {
SLIST_FOREACH_SAFE(conn, &ble_iso_conns, next, conn_tmp) {
struct ble_iso_bis *bis;
if (conn->type != BLE_ISO_CONN_BIS) {
@@ -223,6 +242,11 @@ ble_iso_big_free(struct ble_iso_big *big)
bis = CONTAINER_OF(conn, struct ble_iso_bis, conn);
if (bis->big == big) {
if (conn->rx_buf != NULL) {
os_mbuf_free_chain(conn->rx_buf);
conn->rx_buf = NULL;
memset(&conn->rx_info, 0, sizeof(conn->rx_info));
}
SLIST_REMOVE(&ble_iso_conns, conn, ble_iso_conn, next);
rem_bis[i++] = bis;
}
@@ -261,8 +285,7 @@ ble_iso_create_big(const struct ble_iso_create_big_params *create_params,
struct ble_iso_big *big;
int rc;
cp.adv_handle = create_params->adv_handle;
if (create_params->bis_cnt > MYNEWT_VAL(BLE_ISO_MAX_BISES)) {
if (create_params->bis_cnt == 0 || create_params->bis_cnt > MYNEWT_VAL(BLE_ISO_MAX_BISES)) {
return BLE_HS_EINVAL;
}
@@ -285,18 +308,23 @@ ble_iso_create_big(const struct ble_iso_create_big_params *create_params,
}
}
cp.big_handle = big->handle;
cp.adv_handle = create_params->adv_handle;
cp.num_bis = create_params->bis_cnt;
put_le24(cp.sdu_interval, big_params->sdu_interval);
cp.max_sdu = big_params->max_sdu;
cp.max_transport_latency = big_params->max_transport_latency;
cp.max_sdu = htole16(big_params->max_sdu);
cp.max_transport_latency = htole16(big_params->max_transport_latency);
cp.rtn = big_params->rtn;
cp.phy = big_params->phy;
cp.packing = big_params->packing;
cp.framing = big_params->framing;
cp.encryption = big_params->encryption;
if (big_params->encryption) {
memcpy(cp.broadcast_code, big_params->broadcast_code, 16);
if (big_params->broadcast_code == NULL) {
ble_iso_big_free(big);
return BLE_HS_EINVAL;
}
ble_iso_broadcast_code_set(cp.broadcast_code, big_params->broadcast_code);
}
rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
@@ -339,6 +367,8 @@ ble_iso_rx_create_big_complete(const struct ble_hci_ev_le_subev_create_big_compl
{
struct ble_iso_event event;
struct ble_iso_big *big;
ble_iso_event_fn *cb;
void *cb_arg;
big = ble_iso_big_find_by_handle(ev->big_handle);
if (big == NULL) {
@@ -346,9 +376,13 @@ ble_iso_rx_create_big_complete(const struct ble_hci_ev_le_subev_create_big_compl
return;
}
cb = big->cb;
cb_arg = big->cb_arg;
memset(&event, 0, sizeof(event));
event.type = BLE_ISO_EVENT_BIG_CREATE_COMPLETE;
event.big_created.status = ev->status;
event.big_created.desc.big_handle = ev->big_handle;
if (event.big_created.status != 0) {
ble_iso_big_free(big);
@@ -356,14 +390,13 @@ ble_iso_rx_create_big_complete(const struct ble_hci_ev_le_subev_create_big_compl
if (big->bis_cnt != ev->num_bis) {
BLE_HS_LOG_ERROR("Unexpected num_bis=%d != bis_cnt=%d\n",
ev->num_bis, big->bis_cnt);
/* XXX: Should we destroy the group? */
}
ble_iso_big_conn_handles_init(big, ev->conn_handle, ev->num_bis);
ble_iso_big_conn_handles_init(big, ev->conn_handle,
min(big->bis_cnt, ev->num_bis));
big->max_pdu = ev->max_pdu;
big->max_pdu = le16toh(ev->max_pdu);
event.big_created.desc.big_handle = ev->big_handle;
event.big_created.desc.big_sync_delay = get_le24(ev->big_sync_delay);
event.big_created.desc.transport_latency_big =
get_le24(ev->transport_latency_big);
@@ -371,16 +404,18 @@ ble_iso_rx_create_big_complete(const struct ble_hci_ev_le_subev_create_big_compl
event.big_created.desc.bn = ev->bn;
event.big_created.desc.pto = ev->pto;
event.big_created.desc.irc = ev->irc;
event.big_created.desc.max_pdu = ev->max_pdu;
event.big_created.desc.iso_interval = ev->iso_interval;
event.big_created.desc.num_bis = ev->num_bis;
memcpy(event.big_created.desc.conn_handle, ev->conn_handle,
ev->num_bis * sizeof(uint16_t));
event.big_created.desc.max_pdu = le16toh(ev->max_pdu);
event.big_created.desc.iso_interval = le16toh(ev->iso_interval);
event.big_created.desc.num_bis = min(big->bis_cnt, ev->num_bis);
for (uint8_t i = 0; i < event.big_created.desc.num_bis; i++) {
event.big_created.desc.conn_handle[i] =
le16toh(ev->conn_handle[i]);
}
event.big_created.phy = ev->phy;
}
if (big->cb != NULL) {
big->cb(&event, big->cb_arg);
if (cb != NULL) {
cb(&event, cb_arg);
}
}
@@ -396,15 +431,18 @@ ble_iso_rx_terminate_big_complete(const struct ble_hci_ev_le_subev_terminate_big
return;
}
ble_iso_event_fn *cb = big->cb;
void *cb_arg = big->cb_arg;
event.type = BLE_ISO_EVENT_BIG_TERMINATE_COMPLETE;
event.big_terminated.big_handle = ev->big_handle;
event.big_terminated.reason = ev->reason;
if (big->cb != NULL) {
big->cb(&event, big->cb_arg);
}
ble_iso_big_free(big);
if (cb != NULL) {
cb(&event, cb_arg);
}
}
static int
@@ -419,7 +457,10 @@ ble_iso_tx_complete(uint16_t conn_handle, const uint8_t *data,
return BLE_HS_ENOMEM;
}
os_mbuf_extend(om, 8);
if (os_mbuf_extend(om, 8) == NULL) {
os_mbuf_free_chain(om);
return BLE_HS_ENOMEM;
}
/* Connection_Handle, PB_Flag, TS_Flag */
put_le16(&om->om_data[0],
BLE_HCI_ISO_HANDLE(conn_handle, BLE_HCI_ISO_PB_COMPLETE, 0));
@@ -428,11 +469,12 @@ ble_iso_tx_complete(uint16_t conn_handle, const uint8_t *data,
/* Packet_Sequence_Number placeholder */
put_le16(&om->om_data[4], 0);
/* ISO_SDU_Length */
put_le16(&om->om_data[6], data_len);
put_le16(&om->om_data[6], data_len & BLE_HCI_ISO_SDU_LENGTH_MASK);
rc = os_mbuf_append(om, data, data_len);
if (rc) {
return rc;
os_mbuf_free_chain(om);
return BLE_HS_ENOMEM;
}
return ble_transport_to_ll_iso(om);
@@ -450,13 +492,16 @@ ble_iso_tx_segmented(uint16_t conn_handle, const uint8_t *data,
int rc;
while (data_left) {
packet_len = min(MYNEWT_VAL(BLE_TRANSPORT_ISO_SIZE), data_left);
if (data_left == data_len) {
pb = BLE_HCI_ISO_PB_FIRST;
} else if (packet_len == data_left) {
pb = BLE_HCI_ISO_PB_LAST;
packet_len = min(MYNEWT_VAL(BLE_TRANSPORT_ISO_SIZE) - 4, data_left);
} else {
pb = BLE_HCI_ISO_PB_CONTINUATION;
packet_len = min(MYNEWT_VAL(BLE_TRANSPORT_ISO_SIZE), data_left);
if (packet_len == data_left) {
pb = BLE_HCI_ISO_PB_LAST;
} else {
pb = BLE_HCI_ISO_PB_CONTINUATION;
}
}
om = ble_hs_mbuf_bare_pkt();
@@ -464,7 +509,10 @@ ble_iso_tx_segmented(uint16_t conn_handle, const uint8_t *data,
return BLE_HS_ENOMEM;
}
os_mbuf_extend(om, pb == BLE_HCI_ISO_PB_FIRST ? 8: 4);
if (os_mbuf_extend(om, pb == BLE_HCI_ISO_PB_FIRST ? 8 : 4) == NULL) {
os_mbuf_free_chain(om);
return BLE_HS_ENOMEM;
}
/* Connection_Handle, PB_Flag, TS_Flag */
put_le16(&om->om_data[0],
@@ -476,20 +524,24 @@ ble_iso_tx_segmented(uint16_t conn_handle, const uint8_t *data,
put_le16(&om->om_data[2], packet_len + 4);
/* Packet_Sequence_Number placeholder */
put_le16(&om->om_data[8], 0);
put_le16(&om->om_data[4], 0);
/* ISO_SDU_Length */
put_le16(&om->om_data[10], packet_len);
/* ISO_SDU_Length: must be total SDU length, not fragment length (BT Spec 5.4.5) */
put_le16(&om->om_data[6], data_len & BLE_HCI_ISO_SDU_LENGTH_MASK);
} else {
put_le16(&om->om_data[2], packet_len);
}
rc = os_mbuf_append(om, data + offset, packet_len);
if (rc) {
return rc;
os_mbuf_free_chain(om);
return BLE_HS_ENOMEM;
}
ble_transport_to_ll_iso(om);
rc = ble_transport_to_ll_iso(om);
if (rc != 0) {
return rc;
}
offset += packet_len;
data_left -= packet_len;
@@ -503,7 +555,11 @@ ble_iso_tx(uint16_t conn_handle, void *data, uint16_t data_len)
{
int rc;
if (data_len <= MYNEWT_VAL(BLE_TRANSPORT_ISO_SIZE)) {
if (data_len > BLE_HCI_ISO_SDU_LENGTH_MASK) {
return BLE_HS_EINVAL;
}
if (data_len <= MYNEWT_VAL(BLE_TRANSPORT_ISO_SIZE) - 4) {
rc = ble_iso_tx_complete(conn_handle, data, data_len);
} else {
rc = ble_iso_tx_segmented(conn_handle, data, data_len);
@@ -523,6 +579,10 @@ ble_iso_big_sync_create(const struct ble_iso_big_sync_create_params *param,
struct ble_iso_big *big;
int rc;
if (param->bis_cnt == 0 || param->bis_cnt > MYNEWT_VAL(BLE_ISO_MAX_BISES)) {
return BLE_HS_EINVAL;
}
big = ble_iso_big_alloc();
if (big == NULL) {
return BLE_HS_ENOMEM;
@@ -538,7 +598,7 @@ ble_iso_big_sync_create(const struct ble_iso_big_sync_create_params *param,
if (param->broadcast_code != NULL) {
cp->encryption = BLE_HCI_ISO_BIG_ENCRYPTION_ENCRYPTED;
memcpy(cp->broadcast_code, param->broadcast_code, sizeof(cp->broadcast_code));
ble_iso_broadcast_code_set(cp->broadcast_code, param->broadcast_code);
} else {
cp->encryption = BLE_HCI_ISO_BIG_ENCRYPTION_UNENCRYPTED;
memset(cp->broadcast_code, 0, sizeof(cp->broadcast_code));
@@ -632,6 +692,7 @@ ble_iso_rx_big_sync_established(const struct ble_hci_ev_le_subev_big_sync_establ
memset(&event, 0, sizeof(event));
event.type = BLE_ISO_EVENT_BIG_SYNC_ESTABLISHED;
event.big_sync_established.status = ev->status;
event.big_sync_established.desc.big_handle = ev->big_handle;
if (event.big_sync_established.status != 0) {
ble_iso_big_free(big);
@@ -639,12 +700,13 @@ ble_iso_rx_big_sync_established(const struct ble_hci_ev_le_subev_big_sync_establ
if (big->bis_cnt != ev->num_bis) {
BLE_HS_LOG_ERROR("Unexpected num_bis=%d != bis_cnt=%d\n",
ev->num_bis, big->bis_cnt);
/* XXX: Should we destroy the group? */
}
ble_iso_big_conn_handles_init(big, ev->conn_handle, ev->num_bis);
ble_iso_big_conn_handles_init(big, ev->conn_handle,
min(big->bis_cnt, ev->num_bis));
big->max_pdu = le16toh(ev->max_pdu);
event.big_sync_established.desc.big_handle = ev->big_handle;
event.big_sync_established.desc.transport_latency_big =
get_le24(ev->transport_latency_big);
event.big_sync_established.desc.nse = ev->nse;
@@ -653,9 +715,11 @@ ble_iso_rx_big_sync_established(const struct ble_hci_ev_le_subev_big_sync_establ
event.big_sync_established.desc.irc = ev->irc;
event.big_sync_established.desc.max_pdu = le16toh(ev->max_pdu);
event.big_sync_established.desc.iso_interval = le16toh(ev->iso_interval);
event.big_sync_established.desc.num_bis = ev->num_bis;
memcpy(event.big_sync_established.desc.conn_handle, ev->conn_handle,
ev->num_bis * sizeof(uint16_t));
event.big_sync_established.desc.num_bis = min(big->bis_cnt, ev->num_bis);
for (uint8_t i = 0; i < event.big_sync_established.desc.num_bis; i++) {
event.big_sync_established.desc.conn_handle[i] =
le16toh(ev->conn_handle[i]);
}
}
if (cb != NULL) {
@@ -754,6 +818,9 @@ ble_iso_event_iso_rx_emit(struct ble_iso_conn *conn)
if (conn->cb != NULL) {
conn->cb(&event, conn->cb_arg);
} else {
os_mbuf_free_chain(conn->rx_buf);
conn->rx_buf = NULL;
}
}
@@ -849,7 +916,7 @@ ble_iso_rx_data(struct os_mbuf *om, void *arg)
if (conn == NULL) {
BLE_HS_LOG_DEBUG("Unknown handle=%d\n", conn_handle);
os_mbuf_free_chain(om);
return BLE_HS_EMSGSIZE;
return BLE_HS_ENOTCONN;
}
rc = ble_iso_conn_rx_data_load(conn, om, pb_flag, ts_flag > 0, arg);
@@ -882,42 +949,52 @@ ble_iso_data_path_setup(const struct ble_iso_data_path_setup_params *param)
return BLE_HS_EINVAL;
}
cp = (void *)buf;
put_le16(&cp->conn_handle, param->conn_handle);
cp->data_path_dir = 0;
if (param->data_path_dir & BLE_ISO_DATA_DIR_TX) {
/* Input (Host to Controller) */
cp->data_path_dir |= BLE_HCI_ISO_DATA_PATH_DIR_INPUT;
if (param->codec_config_len > UINT8_MAX - sizeof(*cp)) {
return BLE_HS_EINVAL;
}
if (param->data_path_dir & BLE_ISO_DATA_DIR_RX) {
cp = (void *)buf;
put_le16(&cp->conn_handle, param->conn_handle);
cp->data_path_id = param->data_path_id;
if (param->data_path_dir == BLE_ISO_DATA_DIR_TX) {
/* Input (Host to Controller) */
cp->data_path_dir = BLE_HCI_ISO_DATA_PATH_DIR_INPUT;
} else if (param->data_path_dir == BLE_ISO_DATA_DIR_RX) {
/* Output (Controller to Host) */
cp->data_path_dir |= BLE_HCI_ISO_DATA_PATH_DIR_OUTPUT;
cp->data_path_dir = BLE_HCI_ISO_DATA_PATH_DIR_OUTPUT;
if (cp->data_path_id == BLE_HCI_ISO_DATA_PATH_ID_HCI && param->cb == NULL) {
BLE_HS_LOG_ERROR("param->cb is NULL\n");
return BLE_HS_EINVAL;
}
conn->cb = param->cb;
conn->cb_arg = param->cb_arg;
} else {
return BLE_HS_EINVAL;
}
cp->data_path_id = param->data_path_id;
cp->codec_id[0] = param->codec_id.format;
put_le16(&cp->codec_id[1], param->codec_id.company_id);
put_le16(&cp->codec_id[3], param->codec_id.vendor_specific);
if (param->ctrl_delay > 0xFFFFFFUL) {
return BLE_HS_EINVAL;
}
put_le24(cp->controller_delay, param->ctrl_delay);
cp->codec_config_len = param->codec_config_len;
memcpy(cp->codec_config, param->codec_config, cp->codec_config_len);
if (cp->codec_config_len > 0) {
memcpy(cp->codec_config, param->codec_config, cp->codec_config_len);
}
rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
BLE_HCI_OCF_LE_SETUP_ISO_DATA_PATH),
cp, sizeof(*cp) + cp->codec_config_len, &rp,
sizeof(rp));
if (rc == 0 && param->data_path_dir == BLE_ISO_DATA_DIR_RX) {
conn->cb = param->cb;
conn->cb_arg = param->cb_arg;
}
return rc;
}
@@ -937,23 +1014,34 @@ ble_iso_data_path_remove(const struct ble_iso_data_path_remove_params *param)
put_le16(&cp.conn_handle, param->conn_handle);
if (param->data_path_dir & BLE_ISO_DATA_DIR_TX) {
/* Input (Host to Controller) */
cp.data_path_dir |= BLE_HCI_ISO_DATA_PATH_DIR_INPUT;
if (param->data_path_dir == BLE_ISO_DATA_DIR_TX) {
/* Remove Input path (Host to Controller) */
cp.data_path_dir |= BLE_HCI_ISO_REMOVE_DATA_PATH_INPUT;
}
if (param->data_path_dir & BLE_ISO_DATA_DIR_RX) {
/* Output (Controller to Host) */
cp.data_path_dir |= BLE_HCI_ISO_DATA_PATH_DIR_OUTPUT;
if (param->data_path_dir == BLE_ISO_DATA_DIR_RX) {
/* Remove Output path (Controller to Host) */
cp.data_path_dir |= BLE_HCI_ISO_REMOVE_DATA_PATH_OUTPUT;
}
conn->cb = NULL;
conn->cb_arg = NULL;
if (cp.data_path_dir == 0) {
return BLE_HS_EINVAL;
}
rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_LE,
BLE_HCI_OCF_LE_REMOVE_ISO_DATA_PATH),
&cp, sizeof(cp), &rp, sizeof(rp));
if (rc == 0 && (param->data_path_dir == BLE_ISO_DATA_DIR_RX)) {
if (conn->rx_buf != NULL) {
os_mbuf_free_chain(conn->rx_buf);
conn->rx_buf = NULL;
memset(&conn->rx_info, 0, sizeof(conn->rx_info));
}
conn->cb = NULL;
conn->cb_arg = NULL;
}
return rc;
}
@@ -963,6 +1051,7 @@ ble_iso_init(void)
int rc;
SLIST_INIT(&ble_iso_bigs);
SLIST_INIT(&ble_iso_conns);
rc = os_mempool_init(&ble_iso_big_pool,
MYNEWT_VAL(BLE_ISO_MAX_BIGS),
+3
View File
@@ -20,11 +20,13 @@
#ifndef H_BLE_ISO_PRIV_
#define H_BLE_ISO_PRIV_
#include "syscfg/syscfg.h"
#include "nimble/hci_common.h"
#ifdef __cplusplus
extern "C" {
#endif
#if MYNEWT_VAL(BLE_ISO)
void
ble_iso_rx_create_big_complete(const struct ble_hci_ev_le_subev_create_big_complete *ev);
@@ -39,6 +41,7 @@ ble_iso_rx_big_sync_lost(const struct ble_hci_ev_le_subev_big_sync_lost *ev);
int
ble_iso_rx_data(struct os_mbuf *om, void *arg);
#endif /* MYNEWT_VAL(BLE_ISO) */
#ifdef __cplusplus
}
+21 -23
View File
@@ -258,8 +258,8 @@ ble_l2cap_enhanced_connect(uint16_t conn_handle,
ble_hs_unlock();
if (rc != 0) {
/* Ownership of sdu_rx mbufs is not transferred to the stack on failure.
* The caller is responsible for freeing them.
/* Ownership of sdu_rx mbufs is transferred to the stack.
* The stack is responsible for freeing them even on failure.
*/
}
@@ -405,7 +405,6 @@ ble_l2cap_rx(uint16_t conn_handle, uint8_t pb, struct os_mbuf *om)
struct ble_l2cap_chan *chan;
struct ble_l2cap_hdr hdr;
struct os_mbuf *rx_frags;
uint16_t rx_len;
uint16_t rx_cid;
int rc;
@@ -474,8 +473,8 @@ ble_l2cap_rx(uint16_t conn_handle, uint8_t pb, struct os_mbuf *om)
chan = ble_hs_conn_chan_find_by_scid(conn, hdr.cid);
if (chan) {
if (chan->dcid >= BLE_L2CAP_COC_CID_START &&
chan->dcid <= BLE_L2CAP_COC_CID_END && hdr.len > chan->my_coc_mps) {
if (chan->scid >= BLE_L2CAP_COC_CID_START &&
chan->scid <= BLE_L2CAP_COC_CID_END && hdr.len > chan->my_coc_mps) {
ble_l2cap_sig_disconnect_nolock(chan);
ble_l2cap_rx_free(conn);
rc = BLE_HS_EBADDATA;
@@ -483,7 +482,10 @@ ble_l2cap_rx(uint16_t conn_handle, uint8_t pb, struct os_mbuf *om)
}
if (hdr.len > ble_l2cap_get_mtu(chan)) {
ble_l2cap_sig_disconnect_nolock(chan);
if (chan->scid >= BLE_L2CAP_COC_CID_START &&
chan->scid <= BLE_L2CAP_COC_CID_END) {
ble_l2cap_sig_disconnect_nolock(chan);
}
ble_l2cap_rx_free(conn);
rc = BLE_HS_EBADDATA;
goto done;
@@ -501,7 +503,6 @@ ble_l2cap_rx(uint16_t conn_handle, uint8_t pb, struct os_mbuf *om)
}
rx_frags = conn->rx_frags;
rx_len = conn->rx_len;
rx_cid = conn->rx_cid;
conn->rx_frags = NULL;
@@ -523,18 +524,15 @@ ble_l2cap_rx(uint16_t conn_handle, uint8_t pb, struct os_mbuf *om)
return 0;
}
if (chan->dcid >= BLE_L2CAP_COC_CID_START &&
chan->dcid <= BLE_L2CAP_COC_CID_END && rx_len > chan->my_coc_mps) {
#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) != 0
if (chan->scid >= BLE_L2CAP_COC_CID_START &&
chan->scid <= BLE_L2CAP_COC_CID_END &&
chan->coc_rx.sdus[chan->coc_rx.current_sdu_idx] == NULL) {
ble_l2cap_disconnect(chan);
os_mbuf_free_chain(rx_frags);
return BLE_HS_EBADDATA;
}
if (rx_len > ble_l2cap_get_mtu(chan)) {
ble_l2cap_disconnect(chan);
os_mbuf_free_chain(rx_frags);
return BLE_HS_EBADDATA;
return BLE_HS_EINVAL;
}
#endif
rc = chan->rx_fn(chan, &rx_frags);
os_mbuf_free_chain(rx_frags);
@@ -600,14 +598,14 @@ ble_l2cap_init(void)
size_t chan_mem_bytes = OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_L2CAP_MAX_CHANS) +
MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM),
sizeof (struct ble_l2cap_chan)) * sizeof(os_membuf_t);
if (ble_l2cap_chan_mem == NULL) {
if (ble_l2cap_chan_mem == NULL && chan_mem_bytes != 0) {
ble_l2cap_chan_mem = (os_membuf_t *)nimble_platform_mem_calloc(1, chan_mem_bytes);
if (ble_l2cap_chan_mem == NULL) {
nimble_platform_mem_free(ble_l2cap_ctx);
ble_l2cap_ctx = NULL;
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_ENOMEM);
return BLE_HS_ENOMEM;
}
}
if (ble_l2cap_chan_mem == NULL && chan_mem_bytes != 0) {
nimble_platform_mem_free(ble_l2cap_ctx);
ble_l2cap_ctx = NULL;
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_ENOMEM);
return BLE_HS_ENOMEM;
}
#endif
#endif
+30 -32
View File
@@ -66,15 +66,6 @@ static struct os_mempool ble_l2cap_coc_srv_pool;
static struct ble_l2cap_coc_srv_list ble_l2cap_coc_srvs;
#endif
#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
#ifndef max
#define max(a, b) ((a) > (b) ? (a) : (b))
#endif
static struct ble_l2cap_coc_srv *
ble_l2cap_coc_srv_find(uint16_t psm);
@@ -151,6 +142,7 @@ int
ble_l2cap_coc_remove_server_nolock(uint16_t psm)
{
struct ble_l2cap_coc_srv *srv;
int rc;
srv = ble_l2cap_coc_srv_find(psm);
if (!srv) {
@@ -159,7 +151,8 @@ ble_l2cap_coc_remove_server_nolock(uint16_t psm)
STAILQ_REMOVE(&ble_l2cap_coc_srvs, srv, ble_l2cap_coc_srv, next);
os_memblock_put(&ble_l2cap_coc_srv_pool, srv);
rc = os_memblock_put(&ble_l2cap_coc_srv_pool, srv);
BLE_HS_DBG_ASSERT_EVAL(rc == 0);
return 0;
}
@@ -215,6 +208,19 @@ ble_l2cap_coc_get_cid(uint32_t *cid_mask)
return BLE_L2CAP_COC_CID_START + bit;
}
static uint16_t
ble_l2cap_coc_calc_initial_credits(uint16_t mtu, uint16_t mps)
{
uint16_t credits;
credits = mtu / mps;
if (mtu % mps) {
credits++;
}
return credits;
}
static void
ble_l2cap_event_coc_received_data(struct ble_l2cap_chan *chan,
struct os_mbuf *om)
@@ -243,6 +249,11 @@ ble_l2cap_coc_rx_fn(struct ble_l2cap_chan *chan, struct os_mbuf **om)
int rc;
sdu_idx = chan->coc_rx.current_sdu_idx;
if (rx->sdus[sdu_idx] == NULL) {
BLE_HS_LOG(ERROR, "CoC RX with no buffer armed (sdu_idx=%u)\n", sdu_idx);
ble_l2cap_disconnect(chan);
return BLE_HS_EINVAL;
}
BLE_HS_DBG_ASSERT(rx->sdus[sdu_idx] != NULL);
om_total = OS_MBUF_PKTLEN(*om);
@@ -378,10 +389,7 @@ ble_l2cap_coc_set_new_mtu_mps(struct ble_l2cap_chan *chan, uint16_t mtu,
}
chan->my_coc_mps = mps;
chan->coc_rx.mtu = mtu;
chan->initial_credits = mtu / chan->my_coc_mps;
if (mtu % chan->my_coc_mps) {
chan->initial_credits++;
}
chan->initial_credits = ble_l2cap_coc_calc_initial_credits(mtu, mps);
}
struct ble_l2cap_chan *
@@ -425,14 +433,12 @@ ble_l2cap_coc_chan_alloc(struct ble_hs_conn *conn, uint16_t psm, uint16_t mtu,
}
/* Number of credits should allow to send full SDU with on given
* L2CAP MTU
* L2CAP MTU. Keep local credits at initial_credits so that
* recv_ready() during the accept callback does not send a duplicate
* Flow Control Credit indication before the connection response.
*/
chan->coc_rx.credits = mtu / chan->my_coc_mps;
if (mtu % chan->my_coc_mps) {
chan->coc_rx.credits++;
}
chan->initial_credits = chan->coc_rx.credits;
chan->initial_credits = ble_l2cap_coc_calc_initial_credits(mtu, chan->my_coc_mps);
chan->coc_rx.credits = chan->initial_credits;
return chan;
}
@@ -637,7 +643,7 @@ failed:
os_mbuf_free_chain(tx->sdus[0]);
}
tx->sdus[0] = NULL;
if (tx->data_offset > 0) {
if (tx->data_offset > 0 && rc != BLE_HS_ENOTCONN) {
ble_l2cap_sig_disconnect_nolock(chan);
}
tx->data_offset = 0;
@@ -738,18 +744,10 @@ ble_l2cap_coc_recv_ready(struct ble_l2cap_chan *chan, struct os_mbuf *sdu_rx)
ble_hs_unlock();
ble_l2cap_sig_le_credits(cached_conn_handle, cached_scid,
credits_to_send);
ble_hs_lock();
/* Re-validate connection and channel after relock -- they could have
* been freed while the lock was released. Credits were already updated
* before unlocking; no further update needed here. */
conn = ble_hs_conn_find(cached_conn_handle);
if (conn != NULL) {
c = ble_hs_conn_chan_find_by_scid(conn, cached_scid);
}
} else {
ble_hs_unlock();
}
ble_hs_unlock();
return 0;
}
-7
View File
@@ -62,8 +62,6 @@ struct ble_l2cap_coc_srv {
#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) != 0
int ble_l2cap_coc_init(void);
void ble_l2cap_coc_deinit(void);
int ble_l2cap_coc_create_server(uint16_t psm, uint16_t mtu,
ble_l2cap_event_fn *cb, void *cb_arg);
int ble_l2cap_coc_create_server_nolock(uint16_t psm, uint16_t mtu,
ble_l2cap_event_fn *cb, void *cb_arg);
int ble_l2cap_coc_remove_server_nolock(uint16_t psm);
@@ -89,11 +87,6 @@ ble_l2cap_coc_init(void) {
inline void ble_l2cap_coc_deinit (void){
}
static inline int
ble_l2cap_coc_create_server(uint16_t psm, uint16_t mtu,
ble_l2cap_event_fn *cb, void *cb_arg) {
return BLE_HS_ENOTSUP;
}
static inline int
ble_l2cap_coc_create_server_nolock(uint16_t psm, uint16_t mtu,
+40 -25
View File
@@ -285,9 +285,9 @@ ble_l2cap_sig_proc_insert(struct ble_l2cap_sig_proc *proc)
{
ble_l2cap_sig_dbg_assert_proc_not_inserted(proc);
ble_hs_lock();
ble_hs_lock_nested();
STAILQ_INSERT_HEAD(&ble_l2cap_sig_procs, proc, next);
ble_hs_unlock();
ble_hs_unlock_nested();
}
/**
@@ -376,13 +376,6 @@ ble_l2cap_sig_proc_set_timer(struct ble_l2cap_sig_proc *proc)
ble_hs_timer_resched();
}
static void
ble_l2cap_sig_proc_start(struct ble_l2cap_sig_proc *proc)
{
ble_l2cap_sig_proc_set_timer(proc);
ble_l2cap_sig_proc_insert(proc);
}
static void
ble_l2cap_sig_process_status(struct ble_l2cap_sig_proc *proc, int status)
{
@@ -654,6 +647,13 @@ done:
#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) != 0
static void
ble_l2cap_sig_proc_start(struct ble_l2cap_sig_proc *proc)
{
ble_l2cap_sig_proc_set_timer(proc);
ble_l2cap_sig_proc_insert(proc);
}
static int
ble_l2cap_sig_coc_err2ble_hs_err(uint16_t l2cap_coc_err)
{
@@ -1101,6 +1101,11 @@ ble_l2cap_sig_credit_base_con_req_rx(uint16_t conn_handle,
ble_hs_unlock();
rc = ble_l2cap_event_coc_accept(chans[i], le16toh(req->mtu));
if (rc == 0 &&
chans[i]->coc_rx.sdus[chans[i]->coc_rx.current_sdu_idx] == NULL) {
/* ECFC requires a valid receive buffer during accept. */
rc = BLE_HS_ENOMEM;
}
if (rc == 0) {
rsp->dcids[i] = htole16(chans[i]->scid);
chan_created++;
@@ -1544,12 +1549,14 @@ ble_l2cap_sig_ecoc_connect_nolock(uint16_t conn_handle, uint16_t psm, uint16_t m
int i;
if (!sdu_rx || !cb) {
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_EINVAL);
/* Callers transfer ownership of sdu_rx[] mbufs on entry. When cb is
* NULL but sdu_rx is provided, free the mbufs to avoid leaking. */
if (sdu_rx) {
for (i = 0; i < num; i++) {
os_mbuf_free_chain(sdu_rx[i]);
}
}
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_EINVAL);
return BLE_HS_EINVAL;
}
@@ -1570,11 +1577,8 @@ ble_l2cap_sig_ecoc_connect_nolock(uint16_t conn_handle, uint16_t psm, uint16_t m
}
if (num == 0 || num > BLE_L2CAP_MAX_COC_CONN_REQ) {
for (i = 0; i < num; i++) {
os_mbuf_free_chain(sdu_rx[i]);
}
ble_l2cap_sig_proc_free(proc);
return BLE_HS_EINVAL;
rc = BLE_HS_EINVAL;
goto failed;
}
proc->op = BLE_L2CAP_SIG_PROC_OP_CONNECT;
@@ -1584,13 +1588,14 @@ ble_l2cap_sig_ecoc_connect_nolock(uint16_t conn_handle, uint16_t psm, uint16_t m
req = ble_l2cap_sig_cmd_get(BLE_L2CAP_SIG_OP_CREDIT_CONNECT_REQ, proc->id,
sizeof(*req) + num * sizeof(uint16_t), &txom);
if (!req) {
ble_l2cap_sig_proc_free(proc);
return BLE_HS_ENOMEM;
rc = BLE_HS_ENOMEM;
goto failed;
}
for (i = 0; i < num; i++) {
proc->connect.chan[i] =
ble_l2cap_coc_chan_alloc(conn, psm, mtu, sdu_rx[i], cb, cb_arg);
sdu_rx[i] = NULL; /* ownership transferred to chan_alloc (freed on failure) */
if (!proc->connect.chan[i]) {
os_mbuf_free_chain(txom);
rc = BLE_HS_ENOMEM;
@@ -1619,11 +1624,12 @@ ble_l2cap_sig_ecoc_connect_nolock(uint16_t conn_handle, uint16_t psm, uint16_t m
failed:
for (i = 0; i < num; i++) {
if (proc->connect.chan[i]) {
if (i < BLE_L2CAP_MAX_COC_CONN_REQ && proc->connect.chan[i]) {
proc->connect.chan[i]->cb = NULL;
proc->connect.chan[i]->coc_rx.sdus[0] = NULL;
ble_l2cap_chan_free(conn, proc->connect.chan[i]);
proc->connect.chan[i] = NULL;
} else {
os_mbuf_free_chain(sdu_rx[i]);
}
}
@@ -1804,13 +1810,10 @@ ble_l2cap_sig_coc_disconnect_cb(struct ble_l2cap_sig_proc *proc, int status)
chan = ble_hs_conn_chan_find_by_scid(conn, proc->disconnect.scid);
if (chan) {
SLIST_REMOVE(&conn->bhc_channels, chan, ble_l2cap_chan, next);
ble_l2cap_chan_free(conn, chan);
}
}
ble_hs_unlock();
if (chan) {
ble_l2cap_chan_free(conn, chan);
}
}
static int
@@ -1963,7 +1966,7 @@ ble_l2cap_sig_le_credits_rx(uint16_t conn_handle, struct ble_l2cap_sig_hdr *hdr,
}
int
ble_l2cap_sig_le_credits(uint16_t conn_handle, uint16_t scid, uint16_t credits)
ble_l2cap_sig_le_credits_nolock(uint16_t conn_handle, uint16_t scid, uint16_t credits)
{
struct ble_l2cap_sig_le_credits *cmd;
struct os_mbuf *txom;
@@ -1978,7 +1981,19 @@ ble_l2cap_sig_le_credits(uint16_t conn_handle, uint16_t scid, uint16_t credits)
cmd->scid = htole16(scid);
cmd->credits = htole16(credits);
return ble_l2cap_sig_tx(conn_handle, txom);
return ble_l2cap_sig_tx_nolock(conn_handle, txom);
}
int
ble_l2cap_sig_le_credits(uint16_t conn_handle, uint16_t scid, uint16_t credits)
{
int rc;
ble_hs_lock();
rc = ble_l2cap_sig_le_credits_nolock(conn_handle, scid, credits);
ble_hs_unlock();
return rc;
}
#endif
+17
View File
@@ -145,6 +145,10 @@ ble_l2cap_sig_coc_connect(uint16_t conn_handle, uint16_t psm, uint16_t mtu,
struct os_mbuf *sdu_rx, ble_l2cap_event_fn *cb,
void *cb_arg)
{
/* Real implementation takes ownership of sdu_rx on entry; honor the
* same contract in the stub so callers never leak the mbuf chain.
*/
os_mbuf_free_chain(sdu_rx);
return BLE_HS_ENOTSUP;
}
@@ -159,6 +163,7 @@ ble_l2cap_sig_connect_nolock(uint16_t conn_handle, uint16_t psm, uint16_t mtu,
struct os_mbuf *sdu_rx, ble_l2cap_event_fn *cb,
void *cb_arg)
{
os_mbuf_free_chain(sdu_rx);
return BLE_HS_ENOTSUP;
}
@@ -204,6 +209,13 @@ ble_l2cap_sig_ecoc_connect(uint16_t conn_handle, uint16_t psm, uint16_t mtu,
uint8_t num, struct os_mbuf *sdu_rx[],
ble_l2cap_event_fn *cb, void *cb_arg)
{
uint8_t i;
if (sdu_rx != NULL) {
for (i = 0; i < num; i++) {
os_mbuf_free_chain(sdu_rx[i]);
}
}
return BLE_HS_ENOTSUP;
}
@@ -220,6 +232,11 @@ ble_l2cap_sig_ecoc_connect_nolock(uint16_t conn_handle, uint16_t psm, uint16_t m
uint8_t num, struct os_mbuf *sdu_rx[],
ble_l2cap_event_fn *cb, void *cb_arg)
{
if (sdu_rx != NULL) {
for (uint8_t i = 0; i < num; i++) {
os_mbuf_free_chain(sdu_rx[i]);
}
}
return BLE_HS_ENOTSUP;
}
+123 -76
View File
@@ -56,8 +56,7 @@
#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif /* NIMBLE_BLE_SM */
#endif /* NIMBLE_BLE_CONNECT */
#endif /* min */
#ifndef max
#define max(a, b) ((a) > (b) ? (a) : (b))
@@ -172,7 +171,7 @@ static struct os_mempool ble_sm_proc_pool;
static struct ble_sm_proc_list ble_sm_procs;
#endif // BLE_STATIC_TO_DYNAMIC
static void ble_sm_pair_cfg(struct ble_sm_proc *proc);
static int ble_sm_pair_cfg(struct ble_sm_proc *proc);
/*****************************************************************************
@@ -869,16 +868,10 @@ ble_sm_build_authreq(void)
{
uint8_t authreq;
authreq = ble_hs_cfg.sm_bonding << 0 |
ble_hs_cfg.sm_sc << 3 |
ble_hs_cfg.sm_keypress << 4;
if (ble_hs_cfg.sm_mitm &&
(ble_hs_cfg.sm_io_cap != BLE_HS_IO_NO_INPUT_OUTPUT ||
ble_hs_cfg.sm_oob_data_flag)) {
authreq |= 1 << 2;
}
authreq = (ble_hs_cfg.sm_bonding << 0) |
(ble_hs_cfg.sm_mitm << 2) |
(ble_hs_cfg.sm_sc << 3) |
(ble_hs_cfg.sm_keypress << 4);
return authreq;
}
@@ -1205,15 +1198,11 @@ ble_sm_process_result(uint16_t conn_handle, struct ble_sm_result *res,
#endif
if (res->enc_cb &&
res->app_status != BLE_HS_ENOTCONN) {
/* Do not send this event on broken connection */
ble_gap_pairing_complete_event(conn_handle, res->app_status);
}
/* Persist keys if bonding has successfully completed. */
if (res->app_status == 0 &&
rm &&
(proc->flags & BLE_SM_PROC_F_BONDING)) {
ble_sm_persist_keys(proc);
/* Do not send this event on broken connection.
* Use sm_err as fallback when app_status was not explicitly set. */
int status = res->app_status != 0 ? res->app_status
: BLE_HS_SM_US_ERR(res->sm_err);
ble_gap_pairing_complete_event(conn_handle, status);
}
#if MYNEWT_VAL(BLE_DEFER_CONN_EVENTS)
@@ -1232,8 +1221,6 @@ ble_sm_process_result(uint16_t conn_handle, struct ble_sm_result *res,
ble_gap_passkey_event(conn_handle, &res->passkey_params);
}
}
if (rm) {
ble_sm_proc_free(proc);
break;
@@ -1435,6 +1422,7 @@ ble_sm_enc_event_rx(uint16_t conn_handle, uint8_t evt_status, int encrypted)
BLE_HS_DBG_ASSERT(proc->rx_key_flags == 0);
proc->state = BLE_SM_PROC_STATE_NONE;
authenticated = !!(proc->flags & BLE_SM_PROC_F_AUTHENTICATED);
sc = !!(proc->flags & BLE_SM_PROC_F_SC);
bonded = 1;
res.restore = 1;
@@ -1508,8 +1496,8 @@ ble_sm_retrieve_ltk(uint16_t ediv, uint64_t rand, uint8_t peer_addr_type,
key_sec.peer_addr.type = peer_addr_type;
memcpy(key_sec.peer_addr.val, peer_addr, 6);
for (i = 0; ; i++) {
key_sec.idx = i;
for (i = 0; i <= UINT8_MAX; i++) {
key_sec.idx = (uint8_t)i;
rc = ble_store_read_our_sec(&key_sec, value_sec);
if (rc != 0) {
return rc;
@@ -1518,6 +1506,7 @@ ble_sm_retrieve_ltk(uint16_t ediv, uint64_t rand, uint8_t peer_addr_type,
return 0;
}
}
return BLE_HS_ENOENT;
}
static int
@@ -1603,9 +1592,11 @@ ble_sm_ltk_restore_exec(struct ble_sm_proc *proc, struct ble_sm_result *res,
if (value_sec->authenticated) {
proc->flags |= BLE_SM_PROC_F_AUTHENTICATED;
}
if (value_sec->sc) {
proc->flags |= BLE_SM_PROC_F_SC;
}
} else {
/* Notify the app if it provided a key and the procedure failed. */
res->sm_err = BLE_SM_ERR_UNSPECIFIED;
res->enc_cb = 1;
}
} else {
@@ -1616,11 +1607,11 @@ ble_sm_ltk_restore_exec(struct ble_sm_proc *proc, struct ble_sm_result *res,
rc = ble_sm_ltk_req_neg_reply_tx(proc->conn_handle);
if (rc != 0) {
res->app_status = rc;
res->sm_err = BLE_SM_ERR_UNSPECIFIED;
res->enc_cb = 1; /* Notify application of failure, similar to reply branch */
} else {
res->app_status = BLE_HS_ENOENT;
res->app_status = 0;
}
}
if (res->app_status == 0) {
@@ -1697,6 +1688,7 @@ ble_sm_ltk_req_rx(const struct ble_hci_ev_le_subev_lt_key_req *ev)
if (conn == NULL) {
ble_sm_ltk_req_neg_reply_tx(conn_handle);
res.app_status = BLE_HS_ENOTCONN;
res.execute = 0;
if (proc != NULL) {
proc->state = BLE_SM_PROC_STATE_NONE;
}
@@ -1889,7 +1881,7 @@ ble_sm_state_after_pair(struct ble_sm_proc *proc)
}
}
static void
static int
ble_sm_pair_cfg(struct ble_sm_proc *proc)
{
struct ble_sm_pair_cmd *pair_req, *pair_rsp;
@@ -1949,6 +1941,7 @@ ble_sm_pair_cfg(struct ble_sm_proc *proc)
rc = ble_sm_io_action(proc, &ioact);
BLE_HS_DBG_ASSERT_EVAL(rc == 0);
return rc;
}
static void
@@ -2033,7 +2026,13 @@ ble_sm_pair_exec(struct ble_sm_proc *proc, struct ble_sm_result *res,
proc->state = ble_sm_state_after_pair(proc);
rc = ble_sm_io_action(proc, &ioact);
BLE_HS_DBG_ASSERT(rc == 0);
if (rc != 0) {
os_mbuf_free_chain(txom);
res->sm_err = BLE_SM_ERR_INVAL;
res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_INVAL);
res->enc_cb = 1;
return;
}
if (ble_sm_ioact_state(ioact) == proc->state) {
res->passkey_params.action = ioact;
@@ -2087,9 +2086,8 @@ ble_sm_verify_auth_requirements(uint8_t cmd)
/* Fail if security level forces MITM protection and remote does not
* support it. SC-Only mode also requires MITM.
*/
if ((ble_hs_cfg.sm_sc_only || ble_hs_cfg.sm_sec_lvl >= 3) &&
if ((ble_hs_cfg.sm_sec_lvl >= 3 || ble_hs_cfg.sm_sc_only) &&
!(cmd & BLE_SM_PAIR_AUTHREQ_MITM)) {
return false;
}
@@ -2198,11 +2196,10 @@ ble_sm_pair_req_rx(uint16_t conn_handle, struct os_mbuf **om,
} else if (req->max_enc_key_size > BLE_SM_PAIR_KEY_SZ_MAX) {
res->sm_err = BLE_SM_ERR_INVAL;
res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_INVAL);
} else if (!(req->authreq & BLE_SM_PAIR_AUTHREQ_BOND) &&
(req->init_key_dist != 0 || req->resp_key_dist != 0)) {
/* If the Bonding_Flags is set to No Bonding, the Initiator Key
* Distribution and Responder Key Distribution fields shall be set
* to zero.
} else if (req->authreq & 0x02) {
/* Bonding_Flags field uses only the two least significant bits;
* values 10b and 11b are reserved for future use and must be
* rejected (Core Spec Vol 3 Part H Sec 3.5.1).
*/
res->sm_err = BLE_SM_ERR_INVAL;
res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_INVAL);
@@ -2218,6 +2215,7 @@ ble_sm_pair_req_rx(uint16_t conn_handle, struct os_mbuf **om,
} else if (!ble_sm_verify_auth_requirements(req->authreq)) {
res->sm_err = BLE_SM_ERR_AUTHREQ;
res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_AUTHREQ);
res->enc_cb = 1;
} else {
/* The request looks good. Precalculate our pairing response and
* determine some properties of the imminent link. We need this
@@ -2226,11 +2224,16 @@ ble_sm_pair_req_rx(uint16_t conn_handle, struct os_mbuf **om,
* information in a notification to the app.
*/
ble_sm_pair_rsp_fill(proc);
ble_sm_pair_cfg(proc);
proc_flags = proc->flags;
key_size = proc->key_size;
res->execute = 1;
rc = ble_sm_pair_cfg(proc);
if (rc != 0) {
res->sm_err = BLE_SM_ERR_AUTHREQ;
res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_AUTHREQ);
res->enc_cb = 1;
} else {
proc_flags = proc->flags;
key_size = proc->key_size;
res->execute = 1;
}
}
}
@@ -2282,17 +2285,16 @@ ble_sm_pair_rsp_rx(uint16_t conn_handle, struct os_mbuf **om,
if (rsp->max_enc_key_size < BLE_SM_PAIR_KEY_SZ_MIN) {
res->sm_err = BLE_SM_ERR_ENC_KEY_SZ;
res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_ENC_KEY_SZ);
res->enc_cb = 1;
} else if (rsp->max_enc_key_size > BLE_SM_PAIR_KEY_SZ_MAX) {
res->sm_err = BLE_SM_ERR_INVAL;
res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_INVAL);
} else if (!(rsp->authreq & BLE_SM_PAIR_AUTHREQ_BOND) &&
(rsp->init_key_dist != 0 || rsp->resp_key_dist != 0)) {
/* If the Bonding_Flags is set to No Bonding, the Initiator Key
* Distribution and Responder Key Distribution fields shall be set
* to zero.
*/
res->enc_cb = 1;
} else if (rsp->authreq & 0x02) {
/* Reserved Bonding_Flags values 10b/11b must be rejected. */
res->sm_err = BLE_SM_ERR_INVAL;
res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_INVAL);
res->enc_cb = 1;
} else if ((ble_hs_cfg.sm_sc_only || ble_hs_cfg.sm_sec_lvl == 4) &&
(rsp->max_enc_key_size != BLE_SM_PAIR_KEY_SZ_MAX)) {
/* Fail if Secure Connections Only mode or Security Level 4 is on
@@ -2300,9 +2302,11 @@ ble_sm_pair_rsp_rx(uint16_t conn_handle, struct os_mbuf **om,
*/
res->sm_err = BLE_SM_ERR_ENC_KEY_SZ;
res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_ENC_KEY_SZ);
res->enc_cb = 1;
} else if (!ble_sm_verify_auth_requirements(rsp->authreq)) {
res->sm_err = BLE_SM_ERR_AUTHREQ;
res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_AUTHREQ);
res->enc_cb = 1;
} else {
struct ble_sm_pair_cmd *req = (struct ble_sm_pair_cmd *)(proc->pair_req + 1);
if ((rsp->init_key_dist & ~req->init_key_dist) != 0 ||
@@ -2310,10 +2314,12 @@ ble_sm_pair_rsp_rx(uint16_t conn_handle, struct os_mbuf **om,
res->sm_err = BLE_SM_ERR_INVAL;
res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_INVAL);
res->enc_cb = 1;
} else {
ble_sm_pair_cfg(proc);
rc = ble_sm_io_action(proc, &ioact);
rc = ble_sm_pair_cfg(proc);
if (rc == 0) {
rc = ble_sm_io_action(proc, &ioact);
}
if (rc != 0) {
res->sm_err = BLE_SM_ERR_AUTHREQ;
res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_AUTHREQ);
@@ -2363,6 +2369,12 @@ ble_sm_sec_req_exec(struct ble_sm_proc *proc, struct ble_sm_result *res,
}
cmd->authreq = ble_sm_build_authreq();
if (ble_hs_cfg.sm_mitm &&
ble_hs_cfg.sm_io_cap == BLE_HS_IO_NO_INPUT_OUTPUT &&
!ble_hs_cfg.sm_oob_data_flag) {
cmd->authreq &= ~BLE_SM_PAIR_AUTHREQ_MITM;
}
rc = ble_sm_tx(proc->conn_handle, txom);
if (rc != 0) {
res->app_status = rc;
@@ -2781,6 +2793,7 @@ ble_sm_enc_info_rx(uint16_t conn_handle, struct os_mbuf **om,
res->sm_err = BLE_SM_ERR_KEY_REJ;
res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_KEY_REJ);
res->enc_cb = 1;
} else {
proc->rx_key_flags &= ~BLE_SM_KE_F_ENC_INFO;
proc->peer_keys.ltk_valid = 1;
@@ -2962,7 +2975,7 @@ ble_sm_sign_info_rx(uint16_t conn_handle, struct os_mbuf **om,
memcpy(proc->peer_keys.csrk, cmd->sig_key, 16);
proc->peer_keys.csrk_valid = 1;
proc->peer_keys.sign_counter = 0;
proc->peer_keys.sign_counter = UINT32_MAX;
ble_sm_key_rxed(proc, res);
}
@@ -3068,6 +3081,7 @@ ble_sm_update_peer_sign_counter(uint16_t conn_handle, uint32_t sign_counter)
struct ble_store_key_sec key_sec;
struct ble_store_value_sec value_sec;
struct ble_gap_conn_desc desc;
uint32_t orig_sign_counter;
int rc;
rc = ble_gap_conn_find(conn_handle, &desc);
@@ -3085,13 +3099,33 @@ ble_sm_update_peer_sign_counter(uint16_t conn_handle, uint32_t sign_counter)
if (value_sec.csrk_present != 1) {
return BLE_HS_ENOENT;
}
rc = ble_store_delete_peer_sec(&key_sec);
if (rc != 0) {
return rc;
if (sign_counter == UINT32_MAX) {
return BLE_HS_EINVAL;
}
#if MYNEWT_VAL(BLE_HS_PVCY)
if (value_sec.irk_present == 1) {
ble_hs_pvcy_remove_entry(value_sec.peer_addr.type,
value_sec.peer_addr.val);
}
#endif
orig_sign_counter = value_sec.sign_counter;
value_sec.sign_counter = sign_counter;
rc = ble_store_write_peer_sec(&value_sec);
if (rc != 0) {
value_sec.sign_counter = orig_sign_counter;
int recovery_rc = ble_store_write_peer_sec(&value_sec);
(void)recovery_rc;
#if MYNEWT_VAL(BLE_HS_PVCY)
if (recovery_rc != 0 && value_sec.irk_present == 1) {
ble_hs_pvcy_add_entry(value_sec.peer_addr.val,
value_sec.peer_addr.type,
value_sec.irk);
}
#endif
}
return rc;
}
@@ -3101,6 +3135,7 @@ ble_sm_incr_peer_sign_counter(uint16_t conn_handle, uint32_t new_counter)
struct ble_store_key_sec key_sec;
struct ble_store_value_sec value_sec;
struct ble_gap_conn_desc desc;
uint32_t orig_sign_counter;
int rc;
rc = ble_gap_conn_find(conn_handle, &desc);
@@ -3118,14 +3153,8 @@ ble_sm_incr_peer_sign_counter(uint16_t conn_handle, uint32_t new_counter)
if (value_sec.csrk_present != 1) {
return BLE_HS_ENOENT;
}
if (value_sec.sign_counter == (uint32_t)0xffffffff) {
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_ENOMEM);
return BLE_HS_ENOMEM;
}
rc = ble_store_delete_peer_sec(&key_sec);
if (rc != 0) {
return rc;
if (new_counter == UINT32_MAX) {
return BLE_HS_EINVAL;
}
#if MYNEWT_VAL(BLE_HS_PVCY)
@@ -3147,9 +3176,20 @@ ble_sm_incr_peer_sign_counter(uint16_t conn_handle, uint32_t new_counter)
#endif
#endif
orig_sign_counter = value_sec.sign_counter;
value_sec.sign_counter = new_counter;
rc = ble_store_write_peer_sec(&value_sec);
if (rc != 0) {
value_sec.sign_counter = orig_sign_counter;
int recovery_rc = ble_store_write_peer_sec(&value_sec);
(void)recovery_rc;
#if MYNEWT_VAL(BLE_HS_PVCY)
if (recovery_rc != 0 && value_sec.irk_present == 1) {
ble_hs_pvcy_add_entry(value_sec.peer_addr.val,
value_sec.peer_addr.type,
value_sec.irk);
}
#endif
return rc;
}
@@ -3771,16 +3811,13 @@ ble_sm_get_static_passkey_config(uint32_t *passkey, bool *enabled)
}
#endif
#if MYNEWT_VAL(BLE_SM_CSIS_SIRK)
#if MYNEWT_VAL(BLE_SM_CSIS_SIRK) && NIMBLE_BLE_SM
int
ble_sm_csis_decrypt_sirk(const uint8_t *ltk, const uint8_t *enc_sirk, uint8_t *out)
{
int rc;
/* Decrypt SIRK with sdf(K, EncSIRK) */
/* XXX: ble_sm_alg_csis_sdf is currently not implemented in NimBLE.
* This will result in a linker error if this function is called.
*/
rc = ble_sm_alg_csis_sdf(ltk, enc_sirk, out);
return rc;
@@ -3807,14 +3844,15 @@ ble_sm_csis_resolve_rsi(const uint8_t *rsi, const uint8_t *sirk,
rc = ble_store_read_peer_sec(&key_sec, &value_sec);
if (rc != 0) {
return rc;
goto done;
} else if (!value_sec.ltk_present) {
return BLE_HS_ENOENT;
rc = BLE_HS_ENOENT;
goto done;
}
rc = ble_sm_csis_decrypt_sirk(value_sec.ltk, sirk, plaintext_sirk);
if (rc != 0) {
return rc;
goto done;
}
} else {
memcpy(plaintext_sirk, sirk, 16);
@@ -3822,14 +3860,22 @@ ble_sm_csis_resolve_rsi(const uint8_t *rsi, const uint8_t *sirk,
rc = ble_sm_alg_csis_sih(plaintext_sirk, prand, local_hash);
if (rc != 0) {
return rc;
goto done;
}
if (memcmp(local_hash, hash, 3)) {
return BLE_HS_EAUTHEN;
rc = BLE_HS_EAUTHEN;
goto done;
}
return 0;
rc = 0;
done:
memset(plaintext_sirk, 0, sizeof(plaintext_sirk));
memset(&value_sec, 0, sizeof(value_sec));
__asm__ volatile("" : : "r"(plaintext_sirk), "r"(&value_sec) : "memory");
return rc;
}
int
@@ -3875,4 +3921,5 @@ ble_sm_csis_generate_rsi(const uint8_t *sirk, uint8_t *out)
return 0;
}
#endif
#endif /* BLE_SM_CSIS_SIRK */
#endif /* NIMBLE_BLE_CONNECT */
+570 -134
View File
@@ -32,21 +32,71 @@
#include "nimble/ble.h"
#include "ble_hs_priv.h"
#include <mbedtls/aes.h>
#if MYNEWT_VAL(BLE_CRYPTO_STACK_MBEDTLS)
#if CONFIG_MBEDTLS_VER_4_X_SUPPORT
#include "psa/crypto.h"
#else
#include "mbedtls/aes.h"
#include "mbedtls/cipher.h"
#include "mbedtls/entropy.h"
#include "mbedtls/cmac.h"
#include "mbedtls/ecdh.h"
#include "mbedtls/ecp.h"
#include "mbedtls/esp_mbedtls_random.h"
#endif // CONFIG_MBEDTLS_VER_4_X_SUPPORT
#else
#include "tinycrypt/aes.h"
#include "tinycrypt/constants.h"
#include "tinycrypt/utils.h"
#if MYNEWT_VAL(BLE_SM_SC)
#include <mbedtls/cmac.h>
#include <mbedtls/ecp.h>
#include <mbedtls/ecdh.h>
#include "tinycrypt/cmac_mode.h"
#include "tinycrypt/ecc_dh.h"
#if MYNEWT_VAL(TRNG)
#include "trng/trng.h"
#endif
#endif
#endif
#if MYNEWT_VAL(BLE_CRYPTO_STACK_MBEDTLS)
#if !CONFIG_MBEDTLS_VER_4_X_SUPPORT
#if MYNEWT_VAL(BLE_SM_SC)
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
#include "esp_nimble_mem.h"
static mbedtls_ecp_keypair *keypair_ptr __attribute__((unused)) = NULL;
#define keypair (*keypair_ptr)
#else
static mbedtls_ecp_keypair keypair;
#endif /* MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC) */
#endif
#endif /* !CONFIG_MBEDTLS_VER_4_X_SUPPORT */
#else
#if MYNEWT_VAL(BLE_SM_SC) && MYNEWT_VAL(TRNG)
static struct trng_dev *g_trng;
#endif
#endif
#if CONFIG_MBEDTLS_VER_4_X_SUPPORT
#define BLE_PUB_KEY_LEN 65
static const char * const TAG = "ble_sm_alg";
#else
#define BLE_PUB_KEY_LEN 64
#endif // CONFIG_MBEDTLS_VER_4_X_SUPPORT
/**
* Keep forward-compatibility with Mbed TLS 3.x.
*
* Direct access to fields of structures declared in public headers is no longer
* supported. In Mbed TLS 3, the layout of structures is not considered part of
* the stable API, and minor versions (3.1, 3.2, etc.) may add, remove, rename,
* reorder or change the type of structure fields.
*/
#if (MBEDTLS_VERSION_NUMBER < 0x03000000)
#ifndef MBEDTLS_PRIVATE
#define MBEDTLS_PRIVATE(member) member
#endif
#endif
static void
ble_sm_alg_secure_zero(void *buf, size_t len)
@@ -72,24 +122,90 @@ int
ble_sm_alg_encrypt(const uint8_t *key, const uint8_t *plaintext,
uint8_t *enc_data)
{
int ret = 0;
struct mbedtls_aes_context ctx;
uint8_t tmp[16];
int rc = 0;
swap_buf(tmp, key, 16);
mbedtls_aes_init(&ctx);
mbedtls_aes_setkey_enc(&ctx, tmp, 128);
swap_buf(tmp, plaintext, 16);
if (mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, tmp, enc_data)) {
ret = BLE_HS_EUNKNOWN;
} else {
swap_in_place(enc_data, 16);
#if MYNEWT_VAL(BLE_CRYPTO_STACK_MBEDTLS)
#if CONFIG_MBEDTLS_VER_4_X_SUPPORT
psa_status_t status;
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_id_t key_id = 0;
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_ENCRYPT);
psa_set_key_algorithm(&key_attributes, PSA_ALG_ECB_NO_PADDING);
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_AES);
psa_set_key_bits(&key_attributes, 128);
status = psa_import_key(&key_attributes, tmp, 16, &key_id);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Failed to import AES key: %d", status);
BLE_HS_LOG(ERROR, "%s:%d rc=%d\n", __func__, __LINE__, BLE_HS_EUNKNOWN);
rc = BLE_HS_EUNKNOWN;
goto done;
}
mbedtls_aes_free(&ctx);
psa_reset_key_attributes(&key_attributes);
return ret;
swap_buf(tmp, plaintext, 16);
size_t output_len = 0;
status = psa_cipher_encrypt(key_id, PSA_ALG_ECB_NO_PADDING, tmp,
16, enc_data, 16, &output_len);
if (status != PSA_SUCCESS || output_len != 16) {
ESP_LOGE(TAG, "Encryption failed: %d", status);
psa_destroy_key(key_id);
BLE_HS_LOG(ERROR, "%s:%d rc=%d\n", __func__, __LINE__, BLE_HS_EUNKNOWN);
rc = BLE_HS_EUNKNOWN;
goto done;
}
psa_destroy_key(key_id);
#else
mbedtls_aes_context s = {0};
mbedtls_aes_init(&s);
if (mbedtls_aes_setkey_enc(&s, tmp, 128) != 0) {
mbedtls_aes_free(&s);
BLE_HS_LOG(ERROR, "%s:%d rc=%d\n", __func__, __LINE__, BLE_HS_EUNKNOWN);
rc = BLE_HS_EUNKNOWN;
goto done;
}
swap_buf(tmp, plaintext, 16);
if (mbedtls_aes_crypt_ecb(&s, MBEDTLS_AES_ENCRYPT, tmp, enc_data) != 0) {
mbedtls_aes_free(&s);
BLE_HS_LOG(ERROR, "%s:%d rc=%d\n", __func__, __LINE__, BLE_HS_EUNKNOWN);
rc = BLE_HS_EUNKNOWN;
goto done;
}
mbedtls_aes_free(&s);
#endif // CONFIG_MBEDTLS_VER_4_X_SUPPORT
#else
struct tc_aes_key_sched_struct s;
if (tc_aes128_set_encrypt_key(&s, tmp) == TC_CRYPTO_FAIL) {
BLE_HS_LOG(ERROR, "%s:%d rc=%d\n", __func__, __LINE__, BLE_HS_EUNKNOWN);
ble_sm_alg_secure_zero(&s, sizeof(s));
rc = BLE_HS_EUNKNOWN;
goto done;
}
swap_buf(tmp, plaintext, 16);
if (tc_aes_encrypt(enc_data, tmp, &s) == TC_CRYPTO_FAIL) {
BLE_HS_LOG(ERROR, "%s:%d rc=%d\n", __func__, __LINE__, BLE_HS_EUNKNOWN);
ble_sm_alg_secure_zero(&s, sizeof(s));
rc = BLE_HS_EUNKNOWN;
goto done;
}
ble_sm_alg_secure_zero(&s, sizeof(s));
#endif
swap_in_place(enc_data, 16);
done:
ble_sm_alg_secure_zero(tmp, sizeof(tmp));
return rc;
}
int
@@ -206,14 +322,120 @@ done:
* @param len Length of the message in octets.
* @param out Output; message authentication code.
*/
static int
#if MYNEWT_VAL(BLE_CRYPTO_STACK_MBEDTLS)
int
ble_sm_alg_aes_cmac(const uint8_t *key, const uint8_t *in, size_t len,
uint8_t *out)
{
if (mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB),
key, 128, in, len, out)) {
#if CONFIG_MBEDTLS_VER_4_X_SUPPORT
psa_status_t status;
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_id_t key_id = 0;
psa_algorithm_t alg = PSA_ALG_CMAC;
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_SIGN_MESSAGE);
psa_set_key_algorithm(&key_attributes, PSA_ALG_CMAC);
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_AES);
psa_set_key_bits(&key_attributes, 128);
status = psa_import_key(&key_attributes, key, 16, &key_id);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Failed to import key: %d", status);
BLE_HS_LOG(ERROR, "%s:%d rc=%d\n", __func__, __LINE__, BLE_HS_EUNKNOWN);
return BLE_HS_EUNKNOWN;
}
psa_reset_key_attributes(&key_attributes);
psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT;
status = psa_mac_sign_setup(&operation, key_id, alg);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Failed to setup MAC sign operation: %d", status);
psa_destroy_key(key_id);
BLE_HS_LOG(ERROR, "%s:%d rc=%d\n", __func__, __LINE__, BLE_HS_EUNKNOWN);
return BLE_HS_EUNKNOWN;
}
size_t output_len = 0;
status = psa_mac_update(&operation, in, len);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Failed to update MAC operation: %d", status);
psa_mac_abort(&operation);
psa_destroy_key(key_id);
BLE_HS_LOG(ERROR, "%s:%d rc=%d\n", __func__, __LINE__, BLE_HS_EUNKNOWN);
return BLE_HS_EUNKNOWN;
}
status = psa_mac_sign_finish(&operation, out, 16, &output_len);
if (status != PSA_SUCCESS || output_len != 16) {
ESP_LOGE(TAG, "Failed to finish MAC sign operation: %d", status);
psa_mac_abort(&operation);
psa_destroy_key(key_id);
BLE_HS_LOG(ERROR, "%s:%d rc=%d\n", __func__, __LINE__, BLE_HS_EUNKNOWN);
return BLE_HS_EUNKNOWN;
}
psa_destroy_key(key_id);
return 0;
#else
int rc = BLE_HS_EUNKNOWN;
mbedtls_cipher_context_t ctx = {0};
const mbedtls_cipher_info_t *cipher_info;
mbedtls_cipher_init(&ctx);
cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB);
if (cipher_info == NULL) {
goto exit;
}
if (mbedtls_cipher_setup(&ctx, cipher_info) != 0) {
goto exit;
}
rc = mbedtls_cipher_cmac_starts(&ctx, key, 128);
if (rc != 0) {
goto exit;
}
rc = mbedtls_cipher_cmac_update(&ctx, in, len);
if (rc != 0) {
goto exit;
}
rc = mbedtls_cipher_cmac_finish(&ctx, out);
exit:
mbedtls_cipher_free(&ctx);
if (rc != 0) {
rc = BLE_HS_EUNKNOWN;
}
return rc;
#endif // CONFIG_MBEDTLS_VER_4_X_SUPPORT
}
#else
int
ble_sm_alg_aes_cmac(const uint8_t *key, const uint8_t *in, size_t len,
uint8_t *out)
{
struct tc_aes_key_sched_struct sched;
struct tc_cmac_struct state;
int rc = BLE_HS_EUNKNOWN;
if (tc_cmac_setup(&state, key, &sched) == TC_CRYPTO_FAIL) {
BLE_HS_LOG(ERROR, "%s:%d rc=%d\n", __func__, __LINE__, BLE_HS_EUNKNOWN);
goto done;
}
if (tc_cmac_update(&state, in, len) == TC_CRYPTO_FAIL) {
BLE_HS_LOG(ERROR, "%s:%d rc=%d\n", __func__, __LINE__, BLE_HS_EUNKNOWN);
goto done;
}
if (tc_cmac_final(out, &state) == TC_CRYPTO_FAIL) {
BLE_HS_LOG(ERROR, "%s:%d rc=%d\n", __func__, __LINE__, BLE_HS_EUNKNOWN);
goto done;
}
rc = 0;
@@ -222,6 +444,7 @@ done:
ble_sm_alg_secure_zero(&sched, sizeof(sched));
return rc;
}
#endif
#if MYNEWT_VAL(BLE_SM_SC)
@@ -480,18 +703,24 @@ ble_sm_alg_csis_k1(const uint8_t *n, size_t n_len, const uint8_t *salt,
/* T = AES-CMAC_SALT (N) */
rc = ble_sm_alg_aes_cmac(salt_be, n_be, n_len, t);
if (rc != 0) {
return rc;
goto done;
}
/* AES-CMAC_T (P) */
rc = ble_sm_alg_aes_cmac(t, p, p_len, out);
if (rc != 0) {
return rc;
goto done;
}
swap_in_place(out, 16);
return 0;
done:
memset(t, 0, sizeof(t));
memset(salt_be, 0, sizeof(salt_be));
memset(n_be, 0, sizeof(n_be));
__asm__ volatile("" : : "r"(t), "r"(salt_be), "r"(n_be) : "memory");
return rc;
}
int
@@ -583,97 +812,170 @@ ble_sm_alg_csis_sih(const uint8_t *k, const uint8_t *r, uint8_t *out)
rc = ble_sm_alg_encrypt(k, r1, r1);
if (rc != 0) {
ble_sm_alg_secure_zero(r1, sizeof(r1));
return rc;
}
memcpy(out, r1, 3);
ble_sm_alg_secure_zero(r1, sizeof(r1));
return 0;
}
int
ble_sm_alg_rng(void *arg, unsigned char *buf, size_t size)
{
(void)arg;
#if MYNEWT_VAL(SELFTEST)
while (size--) {
buf[size] = 9;
}
return 0;
#elif MYNEWT_VAL(TRNG)
size_t num;
if (!g_trng) {
g_trng = (struct trng_dev *)os_dev_open("trng", OS_WAIT_FOREVER, NULL);
assert(g_trng);
}
while (size) {
num = trng_read(g_trng, buf, size);
buf += num;
size -= num;
}
return 0;
#else
return ble_hs_hci_util_rand(buf, size);
#endif
}
int
ble_sm_alg_gen_dhkey(const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y,
const uint8_t *our_priv_key, uint8_t *out_dhkey)
{
int err;
mbedtls_mpi priv;
mbedtls_mpi shared;
mbedtls_ecp_group group;
mbedtls_ecp_point point;
uint8_t pub_key[65];
uint8_t dh[32];
uint8_t pk[BLE_PUB_KEY_LEN];
uint8_t priv[32];
int rc = BLE_HS_EUNKNOWN;
mbedtls_mpi_init(&priv);
mbedtls_mpi_init(&shared);
mbedtls_ecp_point_init(&point);
mbedtls_ecp_group_init(&group);
swap_buf(priv, our_priv_key, 32);
pub_key[0] = 0x04; /* Uncompressed point identifier */
swap_buf(&pub_key[1], peer_pub_key_x, 32);
swap_buf(&pub_key[33], peer_pub_key_y, 32);
#if MYNEWT_VAL(BLE_CRYPTO_STACK_MBEDTLS)
#if CONFIG_MBEDTLS_VER_4_X_SUPPORT
// PSA/mbedTLS expects 65 bytes: 0x04 prefix + X (32 bytes) + Y (32 bytes)
pk[0] = 0x04; // Uncompressed format for public key
swap_buf(&pk[1], peer_pub_key_x, 32);
swap_buf(&pk[33], peer_pub_key_y, 32);
err = mbedtls_ecp_group_load(&group, MBEDTLS_ECP_DP_SECP256R1);
if (err == 0) {
err = mbedtls_ecp_point_read_binary(&group, &point, pub_key, sizeof(pub_key));
psa_key_id_t key_id = 0;
psa_status_t status;
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
psa_set_key_bits(&key_attributes, 256);
psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDH);
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_DERIVE);
status = psa_import_key(&key_attributes, priv, 32, &key_id);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Failed to import key: %d", status);
goto exit;
}
psa_reset_key_attributes(&key_attributes);
size_t output_len = 0;
status = psa_raw_key_agreement(PSA_ALG_ECDH, key_id, pk, BLE_PUB_KEY_LEN, dh, sizeof(dh), &output_len);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Failed to perform raw key agreement: %d", status);
goto exit;
}
if (err == 0) {
err = mbedtls_ecp_check_pubkey(&group, &point);
if (output_len != 32) {
ESP_LOGE(TAG, "Unexpected output length: %zu", output_len);
goto exit;
}
rc = 0;
exit:
if (key_id != 0) {
psa_destroy_key(key_id);
}
#else
swap_buf(pk, peer_pub_key_x, 32);
swap_buf(&pk[32], peer_pub_key_y, 32);
#if MYNEWT_VAL(BLE_SM_SC) && MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (!keypair_ptr) {
keypair_ptr = nimble_platform_mem_calloc(1, sizeof(mbedtls_ecp_keypair));
if (!keypair_ptr) {
rc = BLE_HS_ENOMEM;
goto exit_cleanup;
}
}
#endif
struct mbedtls_ecp_point pt = {0}, Q = {0};
mbedtls_mpi z = {0}, d = {0};
uint8_t pub[65] = {0};
/* Hardcoded first byte of pub key for MBEDTLS_ECP_PF_UNCOMPRESSED */
pub[0] = 0x04;
memcpy(&pub[1], pk, 64);
/* Initialize the required structures here */
mbedtls_ecp_point_init(&pt);
mbedtls_ecp_point_init(&Q);
mbedtls_mpi_init(&d);
mbedtls_mpi_init(&z);
/* Below 3 steps are to validate public key on curve secp256r1 */
if (mbedtls_ecp_group_load(&keypair.MBEDTLS_PRIVATE(grp), MBEDTLS_ECP_DP_SECP256R1) != 0) {
goto exit;
}
if (err == 0) {
err = mbedtls_mpi_read_binary_le(&priv, our_priv_key, 32);
if (mbedtls_ecp_point_read_binary(&keypair.MBEDTLS_PRIVATE(grp), &pt, pub, 65) != 0) {
goto exit;
}
if (err == 0) {
err = mbedtls_ecdh_compute_shared(&group, &shared, &point, &priv,
ble_sm_alg_rng, NULL);
if (mbedtls_ecp_check_pubkey(&keypair.MBEDTLS_PRIVATE(grp), &pt) != 0) {
goto exit;
}
if (err == 0) {
err = mbedtls_mpi_write_binary_le(&shared, out_dhkey, 32);
/* Prepare point Q from pub key */
if (mbedtls_ecp_point_read_binary(&keypair.MBEDTLS_PRIVATE(grp), &Q, pub, 65) != 0) {
goto exit;
}
mbedtls_ecp_group_free(&group);
mbedtls_ecp_point_free(&point);
mbedtls_mpi_free(&priv);
mbedtls_mpi_free(&shared);
if (err) {
return BLE_HS_EUNKNOWN;
if (mbedtls_mpi_read_binary(&d, priv, 32) != 0) {
goto exit;
}
return 0;
rc = mbedtls_ecdh_compute_shared(&keypair.MBEDTLS_PRIVATE(grp), &z, &Q, &d,
mbedtls_esp_random, NULL);
if (rc != 0) {
goto exit;
}
rc = mbedtls_mpi_write_binary(&z, dh, 32);
if (rc != 0) {
goto exit;
}
exit:
mbedtls_ecp_point_free(&pt);
mbedtls_mpi_free(&z);
mbedtls_mpi_free(&d);
mbedtls_ecp_point_free(&Q);
#endif // CONFIG_MBEDTLS_VER_4_X_SUPPORT
if (rc != 0) {
#if !CONFIG_MBEDTLS_VER_4_X_SUPPORT && MYNEWT_VAL(BLE_SM_SC) && MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (keypair_ptr) {
mbedtls_ecp_keypair_free(&keypair);
nimble_platform_mem_free(keypair_ptr);
keypair_ptr = NULL;
}
#endif
rc = BLE_HS_EUNKNOWN;
goto exit_cleanup;
}
#else
// TinyCrypt/uECC expects 64 bytes: X (32 bytes) + Y (32 bytes), no prefix
swap_buf(pk, peer_pub_key_x, 32);
swap_buf(&pk[32], peer_pub_key_y, 32);
if (uECC_valid_public_key(pk, uECC_secp256r1()) < 0) {
rc = BLE_HS_EUNKNOWN;
goto exit_cleanup;
}
rc = uECC_shared_secret(pk, priv, dh, uECC_secp256r1());
if (rc == TC_CRYPTO_FAIL) {
rc = BLE_HS_EUNKNOWN;
goto exit_cleanup;
}
#endif
swap_buf(out_dhkey, dh, 32);
rc = 0;
exit_cleanup:
/* Zero sensitive key material from stack */
memset(dh, 0, sizeof(dh));
memset(priv, 0, sizeof(priv));
/* Use a memory barrier to prevent compiler from optimizing out the memsets */
__asm__ __volatile__("" : : "r"(dh), "r"(priv) : "memory");
return rc;
}
/* based on Core Specification 4.2 Vol 3. Part H 2.3.5.6.1 */
@@ -696,6 +998,121 @@ static const uint8_t ble_sm_alg_dbg_pub_key[64] = {
};
#endif
#if MYNEWT_VAL(BLE_CRYPTO_STACK_MBEDTLS)
static int
mbedtls_gen_keypair(uint8_t *public_key, uint8_t *private_key)
{
int rc = BLE_HS_EUNKNOWN;
#if CONFIG_MBEDTLS_VER_4_X_SUPPORT
psa_status_t status = PSA_SUCCESS;
psa_key_id_t key_id = 0;
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_algorithm_t alg = PSA_ALG_ECDH;
psa_key_type_t key_type = PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1);
psa_key_usage_t key_usage = PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_EXPORT;
psa_set_key_type(&key_attributes, key_type);
psa_set_key_bits(&key_attributes, 256);
psa_set_key_algorithm(&key_attributes, alg);
psa_set_key_usage_flags(&key_attributes, key_usage);
status = psa_generate_key(&key_attributes, &key_id);
if (status != PSA_SUCCESS) {
ESP_LOGE(TAG, "Failed to generate key: %d", status);
goto exit;
}
psa_reset_key_attributes(&key_attributes);
size_t olen = 0;
status = psa_export_public_key(key_id, public_key, BLE_PUB_KEY_LEN, &olen);
if (status != PSA_SUCCESS || olen != BLE_PUB_KEY_LEN) {
ESP_LOGE(TAG, "Failed to export public key: %d", status);
goto exit;
}
status = psa_export_key(key_id, private_key, 32, &olen);
if (status != PSA_SUCCESS || olen != 32) {
ESP_LOGE(TAG, "Failed to export private key: %d", status);
goto exit;
}
rc = 0;
exit:
if (key_id != 0) {
psa_destroy_key(key_id);
}
if (rc != 0) {
BLE_HS_LOG(ERROR, "%s:%d rc=%d\n", __func__, __LINE__, BLE_HS_EUNKNOWN);
return BLE_HS_EUNKNOWN;
}
#else
#if MYNEWT_VAL(BLE_SM_SC) && MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (!keypair_ptr) {
keypair_ptr = nimble_platform_mem_calloc(1, sizeof(mbedtls_ecp_keypair));
if (!keypair_ptr) {
BLE_HS_LOG(ERROR, "%s rc=%d\n", __func__, BLE_HS_ENOMEM);
return BLE_HS_ENOMEM;
}
}
#endif
/* Free the previously allocate keypair */
mbedtls_ecp_keypair_free(&keypair);
mbedtls_ecp_keypair_init(&keypair);
if ((rc = mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, &keypair,
mbedtls_esp_random, NULL)) != 0) {
goto exit;
}
if (( rc = mbedtls_mpi_write_binary(&keypair.MBEDTLS_PRIVATE(d), private_key, 32)) != 0) {
goto exit;
}
size_t olen = 0;
uint8_t pub[65] = {0};
if ((rc = mbedtls_ecp_point_write_binary(&keypair.MBEDTLS_PRIVATE(grp), &keypair.MBEDTLS_PRIVATE(Q), MBEDTLS_ECP_PF_UNCOMPRESSED,
&olen, pub, 65)) != 0) {
goto exit;
}
memcpy(public_key, &pub[1], 64);
exit:
if (rc != 0) {
mbedtls_ecp_keypair_free(&keypair);
#if MYNEWT_VAL(BLE_SM_SC) && MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (keypair_ptr) {
nimble_platform_mem_free(keypair_ptr);
keypair_ptr = NULL;
}
#endif
rc = BLE_HS_EUNKNOWN;
}
#endif // CONFIG_MBEDTLS_VER_4_X_SUPPORT
return rc;
}
void mbedtls_free_keypair(void)
{
#ifndef CONFIG_MBEDTLS_VER_4_X_SUPPORT
#if MYNEWT_VAL(BLE_SM_SC) && MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (keypair_ptr) {
mbedtls_ecp_keypair_free(&keypair);
nimble_platform_mem_free(keypair_ptr);
keypair_ptr = NULL;
}
#else
mbedtls_ecp_keypair_free(&keypair);
#endif
#endif // CONFIG_MBEDTLS_VER_4_X_SUPPORT
}
#endif
/**
* pub: 64 bytes
* priv: 32 bytes
@@ -709,66 +1126,85 @@ ble_sm_alg_gen_key_pair(uint8_t *pub, uint8_t *priv)
swap_buf(&pub[32], &ble_sm_alg_dbg_pub_key[32], 32);
swap_buf(priv, ble_sm_alg_dbg_priv_key, 32);
#else
uint8_t pub_buf[65];
size_t pub_len = 0;
mbedtls_ecp_keypair keypair;
mbedtls_ecp_group group;
mbedtls_ecp_point point;
mbedtls_mpi d;
int err;
mbedtls_ecp_keypair_init(&keypair);
mbedtls_ecp_group_init(&group);
mbedtls_ecp_point_init(&point);
mbedtls_mpi_init(&d);
uint8_t pk[BLE_PUB_KEY_LEN];
do {
err = mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, &keypair,
ble_sm_alg_rng, NULL);
if (err) {
break;
}
err = mbedtls_ecp_export(&keypair, &group, &d, &point);
if (err) {
break;
#if MYNEWT_VAL(BLE_CRYPTO_STACK_MBEDTLS)
if (mbedtls_gen_keypair(pk, priv) != 0) {
BLE_HS_LOG(ERROR, "%s:%d rc=%d\n", __func__, __LINE__, BLE_HS_EUNKNOWN);
return BLE_HS_EUNKNOWN;
}
#if CONFIG_MBEDTLS_VER_4_X_SUPPORT
// PSA/mbedTLS: pk[0]=0x04, pk[1..32]=X, pk[33..64]=Y
swap_buf(pub, &pk[1], 32); // Extract X (skip 0x04 prefix)
swap_buf(&pub[32], &pk[33], 32); // Extract Y
#else
swap_buf(pub, pk, 32);
swap_buf(&pub[32], &pk[32], 32);
#endif // CONFIG_MBEDTLS_VER_4_X_SUPPORT
#else
if (uECC_make_key(pk, priv, uECC_secp256r1()) != TC_CRYPTO_SUCCESS) {
BLE_HS_LOG(ERROR, "%s:%d rc=%d\n", __func__, __LINE__, BLE_HS_EUNKNOWN);
return BLE_HS_EUNKNOWN;
}
// TinyCrypt/uECC: pk[0..31]=X, pk[32..63]=Y (no prefix)
swap_buf(pub, pk, 32); // Extract X (from start)
swap_buf(&pub[32], &pk[32], 32); // Extract Y
#endif
err = mbedtls_mpi_write_binary_le(&d, priv, 32);
if (err) {
break;
}
/* Make sure generated key isn't debug key. */
} while (memcmp(priv, ble_sm_alg_dbg_priv_key, 32) == 0);
if (err == 0) {
err = mbedtls_ecp_point_write_binary(&group, &point, MBEDTLS_ECP_PF_UNCOMPRESSED,
&pub_len, pub_buf, sizeof(pub_buf));
}
if (err == 0) {
if (pub_len == sizeof(pub_buf)) {
swap_buf(pub, &pub_buf[1], 32);
swap_buf(pub + 32, &pub_buf[33], 32);
} else {
err = BLE_HS_EUNKNOWN;
}
}
mbedtls_ecp_keypair_free(&keypair);
mbedtls_ecp_group_free(&group);
mbedtls_ecp_point_free(&point);
mbedtls_mpi_free(&d);
if (err) {
return BLE_HS_EUNKNOWN;
}
swap_in_place(priv, 32);
#endif
return 0;
}
#if MYNEWT_VAL(SELFTEST)
/* Unit tests rely on custom RNG function not being set */
#define ble_sm_alg_rand NULL
#elif !(MYNEWT_VAL(BLE_CRYPTO_STACK_MBEDTLS))
/* used by uECC to get random data */
static int
ble_sm_alg_rand(uint8_t *dst, unsigned int size)
{
#if MYNEWT_VAL(TRNG)
size_t num;
if (!g_trng) {
g_trng = (struct trng_dev *)os_dev_open("trng", OS_WAIT_FOREVER, NULL);
assert(g_trng);
}
while (size) {
num = trng_read(g_trng, dst, size);
dst += num;
size -= num;
}
#else
if (!ble_hs_is_enabled()) {
return 0;
}
if (ble_hs_hci_util_rand(dst, size)) {
return 0;
}
#endif
return 1;
}
#endif
void
ble_sm_alg_ecc_init(void)
{
#if (!MYNEWT_VAL(BLE_CRYPTO_STACK_MBEDTLS))
uECC_set_rng(ble_sm_alg_rand);
#endif
return;
}
#endif
#endif
#endif
+8 -2
View File
@@ -333,11 +333,14 @@ int ble_sm_alg_gen_dhkey(const uint8_t *peer_pub_key_x,
const uint8_t *peer_pub_key_y,
const uint8_t *our_priv_key, uint8_t *out_dhkey);
int ble_sm_alg_gen_key_pair(uint8_t *pub, uint8_t *priv);
void ble_sm_alg_ecc_init(void);
int ble_sm_csis_generate_rsi(const uint8_t *sirk, uint8_t *out);
int ble_sm_csis_encrypt_sirk(const uint8_t *ltk, const uint8_t *plaintext_sirk,
uint8_t *out);
int ble_sm_csis_decrypt_sirk(const uint8_t *ltk, const uint8_t *enc_sirk, uint8_t *out);
int ble_sm_csis_resolve_rsi(const uint8_t *rsi, const uint8_t *sirk,
const ble_addr_t *ltk_peer_addr);
void ble_sm_enc_change_rx(const struct ble_hci_ev_enrypt_chg *ev);
void ble_sm_enc_key_refresh_rx(const struct ble_hci_ev_enc_key_refresh *ev);
@@ -388,10 +391,13 @@ void ble_sm_sc_deinit(void);
#define ble_sm_sc_random_exec(proc, res)
#define ble_sm_sc_random_rx(proc, res)
#define ble_sm_sc_public_key_exec(proc, res, arg)
#define ble_sm_sc_public_key_rx(conn_handle, op, om, res)
#define ble_sm_sc_public_key_rx(conn_handle, om, res)
#define ble_sm_sc_dhkey_check_exec(proc, res, arg)
#define ble_sm_sc_dhkey_check_rx(conn_handle, op, om, res)
#define ble_sm_sc_dhkey_check_rx(conn_handle, om, res)
#define ble_sm_sc_init()
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
#define ble_sm_sc_deinit()
#endif
#endif
+8 -7
View File
@@ -172,13 +172,6 @@ ble_sm_sc_io_action(struct ble_sm_proc *proc, uint8_t *action)
} else if (pair_req->oob_data_flag == BLE_SM_PAIR_OOB_YES ||
pair_rsp->oob_data_flag == BLE_SM_PAIR_OOB_YES) {
*action = BLE_SM_IOACT_OOB_SC;
#if MYNEWT_VAL(STATIC_PASSKEY)
} else if (ble_hs_cfg.sm_static_passkey) {
*action = BLE_SM_IOACT_STATIC;
proc->pair_alg = BLE_SM_PAIR_ALG_PASSKEY;
proc->flags |= BLE_SM_PROC_F_AUTHENTICATED;
return 0;
#endif
} else if (!(pair_req->authreq & BLE_SM_PAIR_AUTHREQ_MITM) &&
!(pair_rsp->authreq & BLE_SM_PAIR_AUTHREQ_MITM)) {
@@ -193,6 +186,13 @@ ble_sm_sc_io_action(struct ble_sm_proc *proc, uint8_t *action)
*action = ble_sm_sc_resp_ioa[pair_rsp->io_cap][pair_req->io_cap];
}
#if MYNEWT_VAL(STATIC_PASSKEY)
if ((*action == BLE_SM_IOACT_NONE || *action == BLE_SM_IOACT_INPUT ||
*action == BLE_SM_IOACT_DISP) && ble_hs_cfg.sm_static_passkey) {
*action = BLE_SM_IOACT_STATIC;
}
#endif
switch (*action) {
case BLE_SM_IOACT_NONE:
proc->pair_alg = BLE_SM_PAIR_ALG_JW;
@@ -1065,6 +1065,7 @@ ble_sm_sc_oob_generate_data(struct ble_sm_sc_oob_data *oob_data)
void
ble_sm_sc_init(void)
{
ble_sm_alg_ecc_init();
ble_sm_sc_keys_generated = 0;
#if MYNEWT_VAL(BLE_HS_DEBUG)
ble_sm_dbg_sc_keys_set = 0;
+4
View File
@@ -617,6 +617,7 @@ int
ble_store_read_local_irk(const struct ble_store_key_local_irk *key,
struct ble_store_value_local_irk *out_value)
{
#if NIMBLE_BLE_CONNECT
union ble_store_value local_store_value = {0};
union ble_store_key local_store_key = {0};
int rc;
@@ -632,6 +633,9 @@ ble_store_read_local_irk(const struct ble_store_key_local_irk *key,
}
return rc;
#else
return BLE_HS_ENOTSUP;
#endif
}
#endif
@@ -106,6 +106,9 @@ int ble_restore_our_sec_nvs(void)
qsort(temp_our_secs, temp_count, sizeof(struct ble_store_value_sec), ble_store_config_compare_bond_count);
/* Copy sorted order back to global array before assigning sequential bond counts */
memcpy(ble_store_config_our_secs, temp_our_secs, temp_count * sizeof(struct ble_store_value_sec));
ble_store_config_our_bond_count = 0;
for (int i = 0; i < temp_count; i++) {
@@ -128,6 +131,9 @@ int ble_restore_peer_sec_nvs(void)
qsort(temp_peer_secs, temp_count, sizeof(struct ble_store_value_sec), ble_store_config_compare_bond_count);
/* Copy sorted order back to global array before assigning sequential bond counts */
memcpy(ble_store_config_peer_secs, temp_peer_secs, temp_count * sizeof(struct ble_store_value_sec));
ble_store_config_peer_bond_count = 0;
for (int i = 0; i < temp_count; i++) {
@@ -1202,16 +1208,9 @@ ble_store_config_delete(int obj_type, const union ble_store_key *key)
}
}
/* Track initialization state for idempotency */
static bool g_ble_store_config_initialized = false;
void
ble_store_config_init(void)
{
if (g_ble_store_config_initialized) {
return;
}
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (ble_store_config_vars == NULL) {
ble_store_config_vars = nimble_platform_mem_calloc(1, sizeof(ble_store_config_vars_t));
@@ -1240,8 +1239,6 @@ ble_store_config_init(void)
ble_store_config_num_rpa_recs = 0;
ble_store_config_num_local_irks=0;
ble_store_config_conf_init();
g_ble_store_config_initialized = true;
}
void
@@ -1257,7 +1254,4 @@ ble_store_config_deinit(void)
ble_hs_cfg.store_read_cb = NULL;
ble_hs_cfg.store_write_cb = NULL;
ble_hs_cfg.store_delete_cb = NULL;
/* Reset initialization flag to allow re-initialization */
g_ble_store_config_initialized = false;
}
@@ -162,6 +162,7 @@ ble_store_config_conf_set(int argc, char **argv, char *val)
MYNEWT_VAL(BLE_STORE_MAX_BONDS),
&ble_store_config_num_peer_secs);
return rc;
#if MYNEWT_VAL(BLE_STORE_MAX_CCCDS)
} else if (strcmp(argv[0], "cccd") == 0) {
rc = ble_store_config_deserialize_arr(
val,
@@ -170,6 +171,7 @@ ble_store_config_conf_set(int argc, char **argv, char *val)
MYNEWT_VAL(BLE_STORE_MAX_CCCDS),
&ble_store_config_num_cccds);
return rc;
#endif
}
#if MYNEWT_VAL(BLE_STORE_MAX_CSFCS)
else if (strcmp(argv[0], "csfc") == 0) {
@@ -217,9 +219,11 @@ ble_store_config_conf_export(void (*func)(char *name, char *val),
/* Get the largest possible encoding size */
buf_sz = BLE_STORE_CONFIG_SEC_SET_ENCODE_SZ;
#if MYNEWT_VAL(BLE_STORE_MAX_CCCDS)
if (BLE_STORE_CONFIG_CCCD_SET_ENCODE_SZ > buf_sz) {
buf_sz = BLE_STORE_CONFIG_CCCD_SET_ENCODE_SZ;
}
#endif
if (BLE_STORE_CONFIG_RPA_REC_SET_ENCODE_SZ > buf_sz) {
buf_sz = BLE_STORE_CONFIG_RPA_REC_SET_ENCODE_SZ;
}
@@ -253,12 +257,14 @@ ble_store_config_conf_export(void (*func)(char *name, char *val),
buf_sz);
func("ble_hs/peer_sec", buf);
#if MYNEWT_VAL(BLE_STORE_MAX_CCCDS)
ble_store_config_serialize_arr(ble_store_config_cccds,
sizeof *ble_store_config_cccds,
ble_store_config_num_cccds,
buf,
buf_sz);
func("ble_hs/cccd", buf);
#endif
#if MYNEWT_VAL(BLE_STORE_MAX_CSFCS)
ble_store_config_serialize_arr(ble_store_config_csfcs,
sizeof *ble_store_config_csfcs,
@@ -168,9 +168,6 @@ int ble_store_config_persist_eads(void);
int ble_store_config_persist_rpa_recs(void);
int ble_store_config_persist_local_irk(void);
void ble_store_config_conf_init(void);
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
void ble_store_config_deinit(void);
#endif
#else
static inline int ble_store_config_persist_our_secs(void) { return 0; }
@@ -183,11 +180,11 @@ static inline int ble_store_config_persist_eads(void) { return 0; }
static inline int ble_store_config_persist_rpa_recs(void) { return 0; }
static inline int ble_store_config_persist_local_irk(void) { return 0; }
static inline void ble_store_config_conf_init(void) { }
//static inline void ble_store_config_deinit(void) { }
#if MYNEWT_VAL(BLE_HOST_BASED_PRIVACY)
static inline int ble_store_persist_peer_records(void) { return 0; }
#endif
#endif /* MYNEWT_VAL(BLE_STORE_CONFIG_PERSIST) */
void ble_store_config_deinit(void);
#ifdef __cplusplus
}
+76 -6
View File
@@ -942,15 +942,28 @@ int ble_store_config_persist_local_irk(void)
ESP_LOGD(TAG, "Deleting Local IRK, nvs idx = %d", nvs_idx);
return ble_nvs_delete_value(BLE_STORE_OBJ_TYPE_LOCAL_IRK, nvs_idx);
} else {
/* Equal counts - this could be an update, sync all entries */
/* Equal counts - this is a resync/resequence. The previous
* implementation deleted all entries first and then re-wrote them,
* which could leave NVS with fewer entries than RAM on a partial
* write failure. Instead, overwrite slots 1..N in place (newer
* values win), then delete any extras only after every write
* succeeded.
*/
char key_string[NIMBLE_NVS_STR_NAME_MAX_LEN];
ESP_LOGD(TAG, "Syncing Local IRK values to NVS...");
/* Delete existing entries first to avoid duplication/corruption */
for (int i = 1; i <= nvs_count; i++) {
ble_nvs_delete_value(BLE_STORE_OBJ_TYPE_LOCAL_IRK, i);
}
for (int i = 0; i < ble_store_config_num_local_irks; i++) {
val.local_irk = ble_store_config_local_irks[i];
int rc = ble_store_nvs_write(BLE_STORE_OBJ_TYPE_LOCAL_IRK, &val);
get_nvs_key_string(BLE_STORE_OBJ_TYPE_LOCAL_IRK, i + 1, key_string);
int rc = ble_nvs_write_key_value(key_string, &val.local_irk,
sizeof(struct ble_store_value_local_irk));
if (rc != 0) {
return rc;
}
}
/* No extras expected since counts are equal, but be defensive. */
for (int i = ble_store_config_num_local_irks + 1;
i <= get_nvs_max_obj_value(BLE_STORE_OBJ_TYPE_LOCAL_IRK); i++) {
int rc = ble_nvs_delete_value(BLE_STORE_OBJ_TYPE_LOCAL_IRK, i);
if (rc != 0) {
return rc;
}
@@ -985,6 +998,25 @@ int ble_store_config_persist_rpa_recs(void)
}
ESP_LOGD(TAG, "Deleting RPA_REC, nvs idx = %d", nvs_idx);
return ble_nvs_delete_value(BLE_STORE_OBJ_TYPE_PEER_ADDR, nvs_idx);
} else {
char key_string[NIMBLE_NVS_STR_NAME_MAX_LEN];
ESP_LOGD(TAG, "Syncing RPA_RECS values to NVS...");
for (int i = 0; i < ble_store_config_num_rpa_recs; i++) {
val.rpa_rec = ble_store_config_rpa_recs[i];
get_nvs_key_string(BLE_STORE_OBJ_TYPE_PEER_ADDR, i + 1, key_string);
int rc = ble_nvs_write_key_value(key_string, &val.rpa_rec,
sizeof(struct ble_store_value_rpa_rec));
if (rc != 0) {
return rc;
}
}
for (int i = ble_store_config_num_rpa_recs + 1;
i <= get_nvs_max_obj_value(BLE_STORE_OBJ_TYPE_PEER_ADDR); i++) {
int rc = ble_nvs_delete_value(BLE_STORE_OBJ_TYPE_PEER_ADDR, i);
if (rc != 0) {
return rc;
}
}
}
return 0;
@@ -1019,6 +1051,25 @@ int ble_store_config_persist_peer_secs(void)
}
ESP_LOGD(TAG, "Deleting peer sec, nvs idx = %d", nvs_idx);
return ble_nvs_delete_value(BLE_STORE_OBJ_TYPE_PEER_SEC, nvs_idx);
} else {
char key_string[NIMBLE_NVS_STR_NAME_MAX_LEN];
ESP_LOGD(TAG, "Syncing peer sec values to NVS...");
for (int i = 0; i < ble_store_config_num_peer_secs; i++) {
val.sec = ble_store_config_peer_secs[i];
get_nvs_key_string(BLE_STORE_OBJ_TYPE_PEER_SEC, i + 1, key_string);
int rc = ble_nvs_write_key_value(key_string, &val.sec,
sizeof(struct ble_store_value_sec));
if (rc != 0) {
return rc;
}
}
for (int i = ble_store_config_num_peer_secs + 1;
i <= get_nvs_max_obj_value(BLE_STORE_OBJ_TYPE_PEER_SEC); i++) {
int rc = ble_nvs_delete_value(BLE_STORE_OBJ_TYPE_PEER_SEC, i);
if (rc != 0) {
return rc;
}
}
}
return 0;
}
@@ -1052,6 +1103,25 @@ int ble_store_config_persist_our_secs(void)
}
ESP_LOGD(TAG, "Deleting our sec, nvs idx = %d", nvs_idx);
return ble_nvs_delete_value(BLE_STORE_OBJ_TYPE_OUR_SEC, nvs_idx);
} else {
char key_string[NIMBLE_NVS_STR_NAME_MAX_LEN];
ESP_LOGD(TAG, "Syncing our sec values to NVS...");
for (int i = 0; i < ble_store_config_num_our_secs; i++) {
val.sec = ble_store_config_our_secs[i];
get_nvs_key_string(BLE_STORE_OBJ_TYPE_OUR_SEC, i + 1, key_string);
int rc = ble_nvs_write_key_value(key_string, &val.sec,
sizeof(struct ble_store_value_sec));
if (rc != 0) {
return rc;
}
}
for (int i = ble_store_config_num_our_secs + 1;
i <= get_nvs_max_obj_value(BLE_STORE_OBJ_TYPE_OUR_SEC); i++) {
int rc = ble_nvs_delete_value(BLE_STORE_OBJ_TYPE_OUR_SEC, i);
if (rc != 0) {
return rc;
}
}
}
return 0;
}
+3 -2
View File
@@ -265,8 +265,9 @@ ble_gatts_reg_test_misc_verify_entry(uint8_t op, const ble_uuid_t *uuid)
int i;
for (i = 0; i < ble_gatts_reg_test_num_entries; i++) {
entry = ble_gatts_reg_test_entries + i;
if (entry->op == op && ble_uuid_cmp(&entry->uuid.u, uuid) == 0) {
if (ble_gatts_reg_test_entries[i].op == op &&
ble_uuid_cmp(&ble_gatts_reg_test_entries[i].uuid.u, uuid) == 0) {
entry = ble_gatts_reg_test_entries + i;
break;
}
}
+15 -14
View File
@@ -1924,22 +1924,23 @@ ble_hs_test_util_store_read(int obj_type, const union ble_store_key *key,
ble_sm_test_store_key.cccd = key->cccd;
break;
default:
return BLE_HS_ENOTSUP;
break;
}
rc = ble_store_config_read(obj_type, key, value);
switch (ble_sm_test_store_obj_type) {
case BLE_STORE_OBJ_TYPE_PEER_SEC:
case BLE_STORE_OBJ_TYPE_OUR_SEC:
ble_sm_test_store_value.sec = value->sec;
break;
case BLE_STORE_OBJ_TYPE_CCCD:
ble_sm_test_store_value.cccd = value->cccd;
break;
default:
rc = BLE_HS_ENOTSUP;
break;
if (rc == 0) {
switch (ble_sm_test_store_obj_type) {
case BLE_STORE_OBJ_TYPE_PEER_SEC:
case BLE_STORE_OBJ_TYPE_OUR_SEC:
ble_sm_test_store_value.sec = value->sec;
break;
case BLE_STORE_OBJ_TYPE_CCCD:
ble_sm_test_store_value.cccd = value->cccd;
break;
default:
rc = BLE_HS_ENOTSUP;
break;
}
}
return rc;
@@ -1963,7 +1964,7 @@ ble_hs_test_util_store_write(int obj_type, const union ble_store_value *value)
ble_sm_test_store_value.cccd = value->cccd;
break;
default:
rc = BLE_HS_ENOTSUP;
/* For other types, preserve the return code from ble_store_config_write */
break;
}
+1 -1
View File
@@ -430,7 +430,7 @@ TEST_CASE_SELF(ble_sm_test_case_peer_sec_req_inval)
TEST_CASE_SELF(ble_sm_test_case_peer_sec_req_reject)
{
struct ble_sm_sec_req sec_req;
struct ble_sm_sec_req sec_req = {0};
int rc;
struct ble_sm_pair_cmd pair_rsp = {0x04, 0, 0x0D, 10, 0x02, 0x02};
-1
View File
@@ -358,7 +358,6 @@ enum ble_error_codes
* (Corresponds to Resolved Private Address).
*/
#define BLE_ADDR_RANDOM_ID (0x03)
#define BLE_ADDR_ANONYMOUS (0xFF)
/**
* Bluetooth Device Address Type: Anonymous
+6 -3
View File
@@ -2913,7 +2913,7 @@ struct hci_data_hdr
#define BLE_HCI_PB_FIRST_FLUSH 2
#define BLE_HCI_PB_FULL 3
#define BLE_HCI_ISO_CONN_HANDLE_MASK (0x07ff)
#define BLE_HCI_ISO_CONN_HANDLE_MASK (0x0fff)
#define BLE_HCI_ISO_PB_FLAG_MASK (0x3000)
#define BLE_HCI_ISO_TS_FLAG_MASK (0x4000)
#define BLE_HCI_ISO_LENGTH_MASK (0x3fff)
@@ -2938,7 +2938,7 @@ struct hci_data_hdr
#define BLE_HCI_ISO_PKT_STATUS_VALID 0x00
#define BLE_HCI_ISO_PKT_STATUS_INVALID 0x01
#define BLE_HCI_ISO_PKT_STATUS_LOST 0x10
#define BLE_HCI_ISO_PKT_STATUS_LOST 0x02
#define BLE_HCI_ISO_BIG_HANDLE_MIN 0x00
#define BLE_HCI_ISO_BIG_HANDLE_MAX 0xEF
@@ -2948,6 +2948,8 @@ struct hci_data_hdr
#define BLE_HCI_ISO_DATA_PATH_DIR_INPUT 0x00
#define BLE_HCI_ISO_DATA_PATH_DIR_OUTPUT 0x01
#define BLE_HCI_ISO_REMOVE_DATA_PATH_INPUT 0x01
#define BLE_HCI_ISO_REMOVE_DATA_PATH_OUTPUT 0x02
#define BLE_HCI_ISO_DATA_PATH_ID_HCI 0x00
@@ -2961,7 +2963,8 @@ struct ble_hci_iso {
uint8_t data[0];
};
#define BLE_HCI_ISO_HDR_SDU_LENGTH_MASK (0x07ff)
#define BLE_HCI_ISO_HDR_SDU_LENGTH_MASK (0x0fff)
struct ble_hci_iso_data {
uint16_t packet_seq_num;
+4
View File
@@ -302,6 +302,10 @@ cdc_hci_acl_packet_write(struct usb_in_packet *packet, size_t offset)
if (new_offset == 0) {
/* Write H4 ACL type */
new_offset += tud_cdc_n_write_char(cdc_num, HCI_H4_ACL);
if (new_offset == 0) {
/* USB FIFO full; cannot write H4 type byte yet */
return (int)offset;
}
}
for (;;) {
@@ -72,6 +72,9 @@ hci_ipc_alloc(struct hci_ipc_sm *sm)
sm->om = ble_transport_alloc_iso_from_ll();
#endif
break;
default:
assert(0);
break;
}
sm->rem_len = sm->hdr.length;
@@ -122,9 +125,11 @@ hci_ipc_frame(struct hci_ipc_sm *sm)
break;
default:
assert(0);
break;
return;
}
assert(rc == 0);
sm->hdr.type = 0;
sm->hdr.length = 0;
sm->hdr_len = 0;
@@ -247,7 +252,7 @@ hci_ipc_init(volatile struct hci_ipc_shm *shm, struct hci_ipc_sm *sm)
ble_npl_time_delay(1); /* 1 tick delay every 1000 iterations */
}
}
if (timeout == 0) {
if (shm->n2a_num_evt_disc == 0) {
abort(); /* Timeout waiting for host initialization */
}
/* Memory barrier to ensure we see updated values from host */
@@ -23,7 +23,11 @@ ble_transport_dummy_host_recv_cb(hci_driver_data_type_t type, uint8_t *data, uin
} else if (type == HCI_DRIVER_TYPE_ISO) {
free(data);
} else {
#if MYNEWT_VAL(MP_RUNTIME_ALLOC)
ble_transport_free(BLE_HCI_EVT, data);
#else
ble_transport_free(data);
#endif
}
return 0;
}
@@ -51,7 +55,11 @@ ble_transport_host_recv_cb(hci_driver_data_type_t type, uint8_t *data, uint16_t
else if (type == HCI_DRIVER_TYPE_EVT) {
rc = ble_transport_to_hs_evt(data);
} else {
#if MYNEWT_VAL(MP_RUNTIME_ALLOC)
ble_transport_free(BLE_HCI_EVT, data);
#else
ble_transport_free(data);
#endif
}
return rc;
}
@@ -104,8 +112,16 @@ ble_transport_alloc_cmd(void)
return pkt->data;
}
#if MYNEWT_VAL(MP_RUNTIME_ALLOC)
void
ble_transport_free(uint8_t type, void *buf)
{
r_ble_hci_trans_buf_free(buf);
}
#else
void
ble_transport_free(void *buf)
{
r_ble_hci_trans_buf_free(buf);
}
#endif
@@ -122,8 +122,6 @@ nrf5340_ble_hci_trans_rx(int channel, void *user_data)
static void
nrf5340_ble_hci_init(void)
{
os_sr_t sr;
SYSINIT_ASSERT_ACTIVE();
#if MYNEWT_VAL(BLE_TRANSPORT_RX_TASK)
@@ -131,9 +129,7 @@ nrf5340_ble_hci_init(void)
#endif
ipc_nrf5340_recv(IPC_RX_CHANNEL, nrf5340_ble_hci_trans_rx, NULL);
OS_ENTER_CRITICAL(sr);
nrf5340_ble_hci_trans_rx(IPC_RX_CHANNEL, NULL);
OS_EXIT_CRITICAL(sr);
}
#if MYNEWT_VAL(BLE_CONTROLLER)
+16 -4
View File
@@ -193,6 +193,7 @@ ble_hci_sock_acl_tx(struct os_mbuf *om)
int i;
struct os_mbuf *m;
uint8_t ch;
int pktlen;
memset(&msg, 0, sizeof(msg));
memset(iov, 0, sizeof(iov));
@@ -204,6 +205,10 @@ ble_hci_sock_acl_tx(struct os_mbuf *om)
iov[0].iov_base = &ch;
i = 1;
for (m = om; m; m = SLIST_NEXT(m, om_next)) {
if (i >= 8) {
os_mbuf_free_chain(om);
return BLE_ERR_MEM_CAPACITY;
}
iov[i].iov_base = m->om_data;
iov[i].iov_len = m->om_len;
i++;
@@ -213,9 +218,10 @@ ble_hci_sock_acl_tx(struct os_mbuf *om)
STATS_INC(hci_sock_stats, omsg);
STATS_INC(hci_sock_stats, oacl);
STATS_INCN(hci_sock_stats, obytes, OS_MBUF_PKTLEN(om) + 1);
pktlen = OS_MBUF_PKTLEN(om);
i = sendmsg(ble_hci_sock_state.sock, &msg, 0);
os_mbuf_free_chain(om);
if (i != OS_MBUF_PKTLEN(om) + 1) {
if (i != pktlen + 1) {
if (i < 0) {
dprintf(1, "sendmsg() failed : %d\n", errno);
} else {
@@ -289,6 +295,7 @@ ble_hci_sock_iso_tx(struct os_mbuf *om)
int i;
struct os_mbuf *m;
uint8_t ch;
int pktlen;
memset(&msg, 0, sizeof(msg));
memset(iov, 0, sizeof(iov));
@@ -300,6 +307,10 @@ ble_hci_sock_iso_tx(struct os_mbuf *om)
iov[0].iov_base = &ch;
i = 1;
for (m = om; m; m = SLIST_NEXT(m, om_next)) {
if (i >= 8) {
os_mbuf_free_chain(om);
return BLE_ERR_MEM_CAPACITY;
}
iov[i].iov_base = m->om_data;
iov[i].iov_len = m->om_len;
i++;
@@ -310,8 +321,9 @@ ble_hci_sock_iso_tx(struct os_mbuf *om)
STATS_INC(hci_sock_stats, oiso);
STATS_INCN(hci_sock_stats, obytes, OS_MBUF_PKTLEN(om) + 1);
i = sendmsg(ble_hci_sock_state.sock, &msg, 0);
pktlen = OS_MBUF_PKTLEN(om);
os_mbuf_free_chain(om);
if (i != OS_MBUF_PKTLEN(om) + 1) {
if (i != pktlen + 1) {
if (i < 0) {
dprintf(1, "sendmsg() failed : %d\n", errno);
} else {
@@ -606,8 +618,8 @@ ble_hci_sock_rx_msg(void)
if (bhss->rx_off < BLE_HCI_DATA_HDR_SZ) {
return -1;
}
len = 1 + BLE_HCI_DATA_HDR_SZ + (bhss->rx_data[4] << 8) +
bhss->rx_data[3];
len = 1 + BLE_HCI_DATA_HDR_SZ +
(((bhss->rx_data[4] << 8) | bhss->rx_data[3]) & BLE_HCI_ISO_LENGTH_MASK);
if (bhss->rx_off < len) {
return -1;
}
+28 -11
View File
@@ -68,6 +68,25 @@ static struct {
#endif
#if MYNEWT_VAL(BLE_MONITOR_UART)
static int
monitor_uart_available_space(void)
{
int head;
int tail;
int space;
head = tx_ringbuf_head;
tail = tx_ringbuf_tail;
if (head >= tail) {
space = sizeof(tx_ringbuf) - (head - tail) - 1;
} else {
space = tail - head - 1;
}
return space;
}
static inline int
inc_and_wrap(int i, int max)
{
@@ -345,14 +364,19 @@ ble_monitor_deinit(void)
int
ble_monitor_send(uint16_t opcode, const void *data, size_t len)
{
os_sr_t sr;
ble_npl_mutex_pend(&lock, OS_TIMEOUT_NEVER);
OS_ENTER_CRITICAL(sr);
#if MYNEWT_VAL(BLE_MONITOR_UART)
if (monitor_uart_available_space() < (int)(len + 32)) {
ble_npl_mutex_release(&lock);
return BLE_HS_ENOMEM;
}
#endif
monitor_write_header(opcode, len);
monitor_write(data, len);
OS_EXIT_CRITICAL(sr);
ble_npl_mutex_release(&lock);
return 0;
}
@@ -405,11 +429,6 @@ ble_monitor_log(int level, const char *fmt, ...)
static const char id[] = "nimble";
struct ble_monitor_user_logging ulog;
va_list va;
int len;
va_start(va, fmt);
len = vsnprintf(NULL, 0, fmt, va);
va_end(va);
switch (level) {
case LOG_LEVEL_ERROR:
@@ -512,9 +531,7 @@ ble_transport_to_ll_cmd(void *buf)
struct ble_hci_cmd *cmd;
#if !(SOC_ESP_NIMBLE_CONTROLLER) && CONFIG_BT_CONTROLLER_ENABLED
if (cmd_buf[0] == 0x01) {
cmd_buf++;
}
cmd_buf++;
#endif
cmd = (void *)cmd_buf;
+5
View File
@@ -25,6 +25,7 @@
#include <os/os_mbuf.h>
#include <nimble/transport.h>
#include <nimble/nimble_npl.h>
#include <nimble/nimble_port.h>
#if !defined(MYNEWT) || MYNEWT_VAL(BLE_TRANSPORT_RX_TASK_STACK_SIZE)
@@ -80,7 +81,11 @@ ble_transport_rx_register(ble_transport_rx_func_t *func, void *arg)
void
ble_transport_rx(void)
{
#ifdef MYNEWT
ble_npl_eventq_put(&rx_eventq, &rx_event);
#else
ble_npl_eventq_put(nimble_port_get_dflt_eventq(), &rx_event);
#endif
}
#endif
+4
View File
@@ -448,6 +448,10 @@ void ble_buf_free(void)
{
os_msys_buf_free();
#if MYNEWT_VAL(MP_RUNTIME_ALLOC)
return;
#endif
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (ble_trans_ctx == NULL) {
return;
+1 -1
View File
@@ -253,7 +253,7 @@ ble_transport_ll_deinit(void)
{
memset(&hci_uart_h4sm, 0, sizeof(hci_uart_h4sm));
hal_uart_close(MYNEWT_VAL(BLE_TRANSPORT_UART_PORT));
hal_uart_close(MYNEWT_VAL(BLE_TRANSPORT_UART_LL_PORT));
hal_uart_deinit_cbs();
}
@@ -17,18 +17,22 @@
* under the License.
*/
#ifndef __LOG_H__
#define __LOG_H__
#ifndef __CONSOLE_PORT_H__
#define __CONSOLE_PORT_H__
#ifdef __cplusplus
extern "C" {
#endif
struct log {
};
#include "os/os_eventq.h"
#include "nimble/nimble_npl.h"
void console_set_queues(struct os_eventq *avail, struct os_eventq *lines);
void console_set_event_cb(ble_npl_event_fn *cb);
int console_init(void);
#ifdef __cplusplus
}
#endif
#endif /* __LOG_H__ */
#endif /* __CONSOLE_PORT_H__ */
@@ -217,6 +217,7 @@ shell_nlip_input_register(shell_nlip_input_func_t nf, void *arg)
int
shell_nlip_output(struct os_mbuf *m)
{
os_mbuf_free_chain(m);
return 0;
}
#endif
@@ -352,7 +352,12 @@ vnd_model_recv(struct bt_mesh_model *model,
buf->om_len);
bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_3(0x01, CID_VENDOR));
os_mbuf_append(msg, buf->om_data, buf->om_len);
rc = os_mbuf_append(msg, buf->om_data, buf->om_len);
if (rc) {
console_printf("#vendor-model-recv: append failed\n");
os_mbuf_free_chain(msg);
return rc;
}
rc = bt_mesh_model_send(model, ctx, msg, NULL, NULL);
if (rc) {
@@ -102,5 +102,5 @@ main(int argc, char *argv[])
NULL, TASK_DEFAULT_PRIORITY, BLE_NPL_TIME_FOREVER,
TASK_DEFAULT_STACK, TASK_DEFAULT_STACK_SIZE);
pthread_exit(&ret);
pthread_exit(NULL);
}
+36
View File
@@ -0,0 +1,36 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef __LOG_H__
#define __LOG_H__
#ifdef __cplusplus
extern "C" {
#endif
#ifndef ESP_PLATFORM
struct log {
};
#endif
#ifdef __cplusplus
}
#endif
#endif /* __LOG_H__ */
-1
View File
@@ -26,7 +26,6 @@
#ifndef ESP_PLATFORM
#include "log/log.h"
#endif
#include "log_common/log_common.h"
#if CONFIG_BLE_HOST_NIMBLE_COMPRESSED_LOG_ENABLE
#include "nimble_log_index.h"
+2 -1
View File
@@ -239,7 +239,8 @@ mem_init_mbuf_pool(void *mem, struct os_mempool *mempool,
if (num_blocks < 0 || num_blocks > UINT16_MAX) {
return OS_EINVAL;
}
if (block_size < 0 || block_size > UINT16_MAX) {
if (block_size <= 0 || block_size > UINT16_MAX ||
block_size < (int)sizeof(struct os_mbuf)) {
return OS_EINVAL;
}
+61 -12
View File
@@ -56,6 +56,7 @@
#define NIMBLE_PORT_LOG_TAG "BLE_INIT"
extern void os_msys_init(void);
extern void os_msys_buf_free(void);
#if CONFIG_BT_NIMBLE_ENABLED
extern void ble_hs_deinit(void);
@@ -97,9 +98,10 @@ static struct ble_hs_stop_listener stop_listener;
#endif
extern void os_msys_init(void);
extern void os_msys_buf_free(void);
extern void os_mempool_module_init(void);
#if MYNEWT_VAL(MP_RUNTIME_ALLOC)
extern void os_mempool_deinit(bool is_controller);
extern void os_mempool_deinit(void);
#endif
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
@@ -129,6 +131,15 @@ ble_npl_reset_deinit_flag(void)
{
ble_npl_deiniting = false;
}
static void
ble_npl_free_ctx(void)
{
if (ble_npl_ctx != NULL) {
nimble_platform_mem_free(ble_npl_ctx);
ble_npl_ctx = NULL;
}
}
#endif
/**
@@ -170,17 +181,29 @@ esp_err_t esp_nimble_init(void)
/* Initialize the function pointers for OS porting */
rc = npl_freertos_funcs_init();
if (rc != 0) {
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
ble_npl_free_ctx();
#endif
return ESP_ERR_NO_MEM;
}
if (npl_freertos_mempool_init() != 0) {
ESP_LOGE(NIMBLE_PORT_LOG_TAG, "mempool init failed\n");
npl_freertos_funcs_deinit();
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
ble_npl_free_ctx();
#endif
return ESP_FAIL;
}
#if CONFIG_BT_CONTROLLER_ENABLED
if(esp_nimble_hci_init() != ESP_OK) {
ESP_LOGE(NIMBLE_PORT_LOG_TAG, "hci inits failed\n");
npl_freertos_mempool_deinit();
npl_freertos_funcs_deinit();
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
ble_npl_free_ctx();
#endif
return ESP_FAIL;
}
/* Initialize default event queue before ble_hs_init() posts start event. */
@@ -192,6 +215,11 @@ esp_err_t esp_nimble_init(void)
ret = ble_buf_alloc();
if (ret != ESP_OK) {
ble_buf_free();
npl_freertos_mempool_deinit();
npl_freertos_funcs_deinit();
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
ble_npl_free_ctx();
#endif
return ESP_FAIL;
}
ble_transport_init();
@@ -216,7 +244,26 @@ esp_err_t esp_nimble_init(void)
#endif
#if MYNEWT_VAL(BLE_QUEUE_CONG_CHECK)
ble_adv_list_init();
if (ble_adv_list_init() != 0) {
#if !SOC_ESP_NIMBLE_CONTROLLER || !CONFIG_BT_CONTROLLER_ENABLED
#if CONFIG_BT_CONTROLLER_ENABLED
esp_nimble_hci_deinit();
os_msys_buf_free();
#else
ble_transport_deinit();
ble_buf_free();
#endif
ble_npl_eventq_deinit(&g_eventq_dflt);
npl_freertos_mempool_deinit();
npl_freertos_funcs_deinit();
#else
ble_npl_eventq_deinit(&g_eventq_dflt);
#endif
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
ble_npl_free_ctx();
#endif
return ESP_FAIL;
}
#endif
/* Initialize the host */
@@ -251,6 +298,14 @@ esp_err_t esp_nimble_deinit(void)
ble_transport_ll_deinit();
#if (BT_HCI_LOG_INCLUDED == TRUE)
bt_hci_log_deinit();
#endif
#if MYNEWT_VAL(BLE_QUEUE_CONG_CHECK)
ble_adv_list_deinit();
#endif
#if !SOC_ESP_NIMBLE_CONTROLLER || !CONFIG_BT_CONTROLLER_ENABLED
#if CONFIG_BT_CONTROLLER_ENABLED
if(esp_nimble_hci_deinit() != ESP_OK) {
@@ -261,9 +316,6 @@ esp_err_t esp_nimble_deinit(void)
return ESP_FAIL;
}
#else
#if MYNEWT_VAL(BLE_QUEUE_CONG_CHECK)
ble_adv_list_deinit();
#endif
ble_transport_deinit();
ble_buf_free();
#endif
@@ -283,10 +335,7 @@ esp_err_t esp_nimble_deinit(void)
#endif
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
if (ble_npl_ctx) {
nimble_platform_mem_free(ble_npl_ctx);
ble_npl_ctx = NULL;
}
ble_npl_free_ctx();
/* Keep ble_npl_deiniting = true until nimble_port_deinit completes.
* This prevents controller deinit from re-allocating ble_npl_ctx when it
* calls nimble_port_get_dflt_eventq(). The flag will be reset at the START
@@ -304,7 +353,7 @@ esp_err_t esp_nimble_deinit(void)
bt_osal_freertos_funcs_deinit();
#if MYNEWT_VAL(MP_RUNTIME_ALLOC)
os_mempool_deinit(0);
os_mempool_deinit();
#endif
return ret;
@@ -384,7 +433,7 @@ nimble_port_deinit(void)
if(esp_nimble_deinit() != ESP_OK) {
ESP_LOGE(NIMBLE_PORT_LOG_TAG, "nimble host deinit failed\n");
ret = ESP_FAIL;
return ESP_FAIL;
}
#if CONFIG_BT_CONTROLLER_ENABLED
@@ -492,7 +541,7 @@ nimble_port_get_dflt_eventq(void)
/* Normal case: try to allocate context */
if (ble_npl_ensure_ctx()) {
return NULL;
return &g_eventq_shutdown_fallback;
}
#endif
+10 -3
View File
@@ -235,8 +235,8 @@ os_msys_get_pkthdr(uint16_t dsize, uint16_t user_hdr_len)
struct os_mbuf *m;
struct os_mbuf_pool *pool;
if (user_hdr_len > 0xFF00) {
goto err;
if (user_hdr_len > (255 - sizeof(struct os_mbuf_pkthdr))) {
goto err_hdr;
}
total_pkthdr_len = user_hdr_len + sizeof(struct os_mbuf_pkthdr);
@@ -247,6 +247,13 @@ os_msys_get_pkthdr(uint16_t dsize, uint16_t user_hdr_len)
m = os_mbuf_get_pkthdr(pool, user_hdr_len);
return (m);
err_hdr:
log_count++;
if ((log_count % 100) == 0) {
ESP_LOGI("ESP_LOG_INFO", "user_hdr_len too large (%u)\n", user_hdr_len);
log_count = 0;
}
return (NULL);
err:
log_count ++;
if ((log_count % 100) == 0) {
@@ -961,7 +968,7 @@ done:
/* Fix up the packet header, if one is present. */
if (OS_MBUF_IS_PKTHDR(om)) {
OS_MBUF_PKTHDR(om)->omp_len =
max(OS_MBUF_PKTHDR(om)->omp_len, (uint16_t)total_len);
max(OS_MBUF_PKTHDR(om)->omp_len, total_len);
}
return rc;
+135 -21
View File
@@ -88,9 +88,32 @@ os_mempool_poison_check(const struct os_mempool *mp, void *start)
p++;
}
}
static bool
os_mempool_poison_valid(const struct os_mempool *mp, void *start)
{
uint32_t *p;
uint32_t *end;
int sz;
sz = OS_MEM_TRUE_BLOCK_SIZE(mp->mp_block_size);
p = start;
end = p + sz / 4;
p += sizeof(struct os_memblock) / 4;
while (p < end) {
if (*p != os_mem_poison) {
return false;
}
p++;
}
return true;
}
#else
#define os_mempool_poison(mp, start)
#define os_mempool_poison_check(mp, start)
#define os_mempool_poison_valid(mp, start) true
#endif
#if MYNEWT_VAL(OS_MEMPOOL_GUARD)
#define OS_MEMPOOL_GUARD_PATTERN 0xBAFF1ED1
@@ -118,9 +141,26 @@ os_mempool_guard_check(const struct os_mempool *mp, void *start)
assert(*tgt == OS_MEMPOOL_GUARD_PATTERN);
}
}
static bool
os_mempool_guard_valid(const struct os_mempool *mp, void *start)
{
uint32_t *tgt;
if ((mp->mp_flags & OS_MEMPOOL_F_EXT) == 0) {
tgt = (uint32_t *)((uintptr_t)start +
OS_MEM_TRUE_BLOCK_SIZE(mp->mp_block_size));
if (*tgt != OS_MEMPOOL_GUARD_PATTERN) {
return false;
}
}
return true;
}
#else
#define os_mempool_guard(mp, start)
#define os_mempool_guard_check(mp, start)
#define os_mempool_guard_valid(mp, start) true
#endif
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
@@ -143,6 +183,10 @@ os_mempool_init_internal(struct os_mempool *mp, uint16_t blocks,
int i;
uint8_t *block_addr;
struct os_memblock *block_ptr;
#if MYNEWT_VAL(MP_RUNTIME_ALLOC) && MYNEWT_VAL(MP_BLOCK_REUSED)
uint8_t old_flags = 0;
struct os_memblock *old_first = NULL;
#endif
/* Check for valid parameters */
if (!mp || (block_size == 0)) {
@@ -165,6 +209,15 @@ os_mempool_init_internal(struct os_mempool *mp, uint16_t blocks,
}
}
#if MYNEWT_VAL(MP_RUNTIME_ALLOC) && MYNEWT_VAL(MP_BLOCK_REUSED)
if (membuf == NULL && mp != NULL &&
(mp->mp_flags & (OS_MEMPOOL_F_REUSED | OS_MEMPOOL_F_RUNTIME)) ==
(OS_MEMPOOL_F_REUSED | OS_MEMPOOL_F_RUNTIME)) {
old_flags = mp->mp_flags;
old_first = SLIST_FIRST(mp);
}
#endif
/* Initialize the memory pool structure */
mp->mp_block_size = block_size;
mp->mp_num_free = blocks;
@@ -173,11 +226,28 @@ os_mempool_init_internal(struct os_mempool *mp, uint16_t blocks,
mp->mp_num_blocks = blocks;
mp->mp_membuf_addr = (uintptr_t)membuf;
mp->name = name;
SLIST_FIRST(mp) = membuf;
if (blocks > 0) {
SLIST_FIRST(mp) = membuf;
} else {
SLIST_FIRST(mp) = NULL;
}
#if MYNEWT_VAL(MP_RUNTIME_ALLOC)
if (membuf == NULL) {
/* Runtime allocation mode */
#if MYNEWT_VAL(MP_BLOCK_REUSED)
if (old_flags & OS_MEMPOOL_F_REUSED) {
void *temp_ptr;
struct os_memblock *block_ptr;
block_ptr = old_first;
while (block_ptr != NULL) {
temp_ptr = block_ptr;
block_ptr = SLIST_NEXT(block_ptr, mb_next);
nimble_platform_mem_free(temp_ptr);
}
}
#endif
mp->mp_membuf_addr = 0;
mp->mp_flags |= OS_MEMPOOL_F_RUNTIME;
#if MYNEWT_VAL(MP_BLOCK_REUSED)
@@ -259,6 +329,10 @@ os_mempool_ext_init(struct os_mempool_ext *mpe, uint16_t blocks,
{
int rc;
if (mpe == NULL) {
return OS_INVALID_PARM;
}
rc = os_mempool_init_internal(&mpe->mpe_mp, blocks, block_size, membuf,
name, OS_MEMPOOL_F_EXT);
if (rc != 0) {
@@ -388,15 +462,17 @@ os_mempool_ext_clear(struct os_mempool_ext *mpe)
{
int rc;
if (mpe == NULL) {
return OS_INVALID_PARM;
}
/* Clear the mempool first while EXT flag is intact */
rc = os_mempool_clear(&mpe->mpe_mp);
if (rc != OS_OK) {
return rc;
}
/* Then clear the extended flags using bitwise operation to preserve other flags */
#if MYNEWT_VAL(MP_RUNTIME_ALLOC)
mpe->mpe_mp.mp_flags &= ~OS_MEMPOOL_F_EXT;
#else
mpe->mpe_mp.mp_flags &= ~OS_MEMPOOL_F_EXT;
#endif
/* Clear callback pointers; keep OS_MEMPOOL_F_EXT so block stride stays consistent. */
mpe->mpe_put_cb = NULL;
mpe->mpe_put_arg = NULL;
@@ -408,16 +484,21 @@ os_mempool_is_sane(const struct os_mempool *mp)
{
struct os_memblock *block;
if (mp == NULL) {
return false;
}
#if MYNEWT_VAL(MP_RUNTIME_ALLOC)
/* Runtime mode cannot verify sanity */
if (mp->mp_flags & OS_MEMPOOL_F_RUNTIME) {
assert(0);
return false;
}
#endif
/* Verify that each block in the free list belongs to the mempool. */
/* Limit iterations to prevent infinite loops in case of corruption */
uint16_t iterations = 0;
uint32_t iterations = 0;
SLIST_FOREACH(block, mp, mb_next) {
if (++iterations > mp->mp_num_blocks) {
/* Potential cycle detected */
@@ -426,8 +507,12 @@ os_mempool_is_sane(const struct os_mempool *mp)
if (!os_memblock_from(mp, block)) {
return false;
}
os_mempool_poison_check(mp, block);
os_mempool_guard_check(mp, block);
if (!os_mempool_poison_valid(mp, block)) {
return false;
}
if (!os_mempool_guard_valid(mp, block)) {
return false;
}
}
return true;
@@ -444,6 +529,7 @@ os_memblock_from(const struct os_mempool *mp, const void *block_addr)
/* Runtime allocation mode doesn't support from */
if (mp->mp_flags & OS_MEMPOOL_F_RUNTIME) {
assert(0);
return false;
}
#endif
@@ -485,6 +571,7 @@ os_memblock_get(struct os_mempool *mp)
OS_ENTER_CRITICAL(sr);
if (mp->mp_num_free) {
#if MYNEWT_VAL(MP_BLOCK_REUSED)
if (mp->mp_flags & OS_MEMPOOL_F_REUSED) {
if (SLIST_FIRST(mp) != NULL) {
block = SLIST_FIRST(mp);
@@ -493,13 +580,15 @@ os_memblock_get(struct os_mempool *mp)
need_alloc = true;
mp->mp_alloc_blocks++;
} else {
/* apply the changes: pool budget exhausted and free list empty;
* exit without decrementing mp_num_free to prevent permanent
* pool exhaustion when mp_num_free > 0 but no block available */
/* Pool budget exhausted and free list empty; exit without
* decrementing mp_num_free. */
OS_EXIT_CRITICAL(sr);
os_trace_api_ret_u32(OS_TRACE_ID_MEMBLOCK_GET, 0);
return NULL;
}
} else {
} else
#endif
{
need_alloc = true;
}
/* Decrement number free by 1 */
@@ -541,6 +630,7 @@ os_memblock_get(struct os_mempool *mp)
os_mempool_guard_check(mp, block);
}
os_trace_api_ret_u32(OS_TRACE_ID_MEMBLOCK_GET, (uintptr_t)block);
return block;
}
#endif
@@ -580,6 +670,10 @@ os_memblock_put_from_cb(struct os_mempool *mp, void *block_addr)
os_sr_t sr;
struct os_memblock *block;
if (mp == NULL || block_addr == NULL) {
return OS_INVALID_PARM;
}
os_trace_api_u32x2(OS_TRACE_ID_MEMBLOCK_PUT_FROM_CB, (uintptr_t)mp,
(uintptr_t)block_addr);
@@ -587,6 +681,7 @@ os_memblock_put_from_cb(struct os_mempool *mp, void *block_addr)
if (mp->mp_flags & OS_MEMPOOL_F_RUNTIME) {
bool need_free = true;
os_mempool_guard_check(mp, block_addr);
os_mempool_poison(mp, block_addr);
/* Runtime allocation mode - free directly */
OS_ENTER_CRITICAL(sr);
@@ -600,21 +695,28 @@ os_memblock_put_from_cb(struct os_mempool *mp, void *block_addr)
}
}
if (mp->mp_num_free >= mp->mp_num_blocks) {
OS_EXIT_CRITICAL(sr);
return OS_INVALID_PARM;
}
block = (struct os_memblock *)block_addr;
SLIST_NEXT(block, mb_next) = SLIST_FIRST(mp);
SLIST_FIRST(mp) = block;
need_free = false;
}
if (mp->mp_num_free >= mp->mp_num_blocks) {
OS_EXIT_CRITICAL(sr);
return OS_INVALID_PARM;
}
mp->mp_num_free++;
assert(mp->mp_num_blocks >= mp->mp_num_free);
OS_EXIT_CRITICAL(sr);
/* Poison and free outside critical section to minimize lock hold time */
if (!need_free) {
os_mempool_poison(mp, block_addr);
} else {
/* Free outside critical section to minimize lock hold time */
if (need_free) {
nimble_platform_mem_free(block_addr);
}
os_trace_api_ret_u32(OS_TRACE_ID_MEMBLOCK_PUT_FROM_CB, (uint32_t)OS_OK);
return OS_OK;
}
#endif
@@ -723,6 +825,10 @@ os_mempool_info_get_next(struct os_mempool *mp, struct os_mempool_info *omi)
{
struct os_mempool *cur;
if (omi == NULL) {
return NULL;
}
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
os_mempool_list_ensure_init();
#endif
@@ -741,8 +847,12 @@ os_mempool_info_get_next(struct os_mempool *mp, struct os_mempool_info *omi)
omi->omi_num_blocks = cur->mp_num_blocks;
omi->omi_num_free = cur->mp_num_free;
omi->omi_min_free = cur->mp_min_free;
strncpy(omi->omi_name, cur->name, sizeof(omi->omi_name) - 1);
omi->omi_name[sizeof(omi->omi_name) - 1] = '\0';
if (cur->name != NULL) {
strncpy(omi->omi_name, cur->name, sizeof(omi->omi_name) - 1);
omi->omi_name[sizeof(omi->omi_name) - 1] = '\0';
} else {
omi->omi_name[0] = '\0';
}
return (cur);
}
@@ -806,5 +916,9 @@ os_mempool_deinit(void)
}
mp = STAILQ_NEXT(mp, mp_list);
}
#if MYNEWT_VAL(BLE_STATIC_TO_DYNAMIC)
STAILQ_INIT(&g_os_mempool_list);
g_os_mempool_list_inited = false;
#endif
}
#endif

Some files were not shown because too many files have changed in this diff Show More