From 6940067caab72fb1539b7ab2fb82f4884e1a8547 Mon Sep 17 00:00:00 2001 From: Piotr Narajowski Date: Fri, 25 Jul 2025 13:25:37 +0200 Subject: [PATCH 1/2] nimble/host: add support for Characteristic Extended Properties descriptor Add support for Characteristic Extended Properties descriptor. For each characteristic that has reliable/auxiliary write flags set an instance of Extended Properties descriptor will be registred. --- nimble/host/include/host/ble_gatt.h | 8 +++ nimble/host/src/ble_gatt_priv.h | 9 +++ nimble/host/src/ble_gatts.c | 90 +++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) diff --git a/nimble/host/include/host/ble_gatt.h b/nimble/host/include/host/ble_gatt.h index 229d99dda3..a9d763258b 100644 --- a/nimble/host/include/host/ble_gatt.h +++ b/nimble/host/include/host/ble_gatt.h @@ -65,6 +65,9 @@ struct ble_hs_cfg; /** GATT Client Characteristic Configuration descriptor 16-bit UUID. */ #define BLE_GATT_DSC_CLT_CFG_UUID16 0x2902 +/** GATT Characteristic Extended Porperties descriptor 16-bit UUID. */ +#define BLE_GATT_DSC_EXT_PROP_UUID16 0x2900 + /** @} */ /** @@ -246,6 +249,11 @@ struct ble_gatt_dsc { ble_uuid_any_t uuid; }; +/** Represents a Characteristic Extended Properties descriptor */ +struct ble_gatt_cep_dsc { + /** Characteristic Extended properties **/ + uint16_t properties; +}; /** Represents a handle-value tuple for multiple handle notifications. */ struct ble_gatt_notif { diff --git a/nimble/host/src/ble_gatt_priv.h b/nimble/host/src/ble_gatt_priv.h index 50e0a75b91..111a540b3b 100644 --- a/nimble/host/src/ble_gatt_priv.h +++ b/nimble/host/src/ble_gatt_priv.h @@ -159,6 +159,9 @@ int ble_gattc_init(void); #define BLE_GATTS_INC_SVC_LEN_NO_UUID 4 #define BLE_GATTS_INC_SVC_LEN_UUID 6 +#define BLE_GATTS_CEP_F_RELIABLE_WRITE 0x0001 +#define BLE_GATTS_CEP_F_AUX_WRITE 0x0002 + /** * Contains counts of resources required by the GATT server. The contents of * this struct are generally used to populate a configuration struct before @@ -183,6 +186,12 @@ struct ble_gatt_resources { */ uint16_t cccds; + /** + * Number of characteristic extended properties descriptors. Each of + * these also contributes to the total descriptor count. + */ + uint16_t ceps; + /** Total number of ATT attributes. */ uint16_t attrs; }; diff --git a/nimble/host/src/ble_gatts.c b/nimble/host/src/ble_gatts.c index ee6a8a3c65..f0df15c714 100644 --- a/nimble/host/src/ble_gatts.c +++ b/nimble/host/src/ble_gatts.c @@ -39,6 +39,7 @@ static const ble_uuid_t *uuid_chr = BLE_UUID16_DECLARE(BLE_ATT_UUID_CHARACTERISTIC); 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); static const struct ble_gatt_svc_def **ble_gatts_svc_defs; static int ble_gatts_num_svc_defs; @@ -154,6 +155,22 @@ ble_gatts_chr_clt_cfg_allowed(const struct ble_gatt_chr_def *chr) return flags; } +static uint16_t +ble_gatts_chr_ext_prop_allowed(const struct ble_gatt_chr_def *chr) +{ + uint16_t flags; + + flags = 0; + if (chr->flags & BLE_GATT_CHR_F_RELIABLE_WRITE) { + flags |= BLE_GATTS_CEP_F_RELIABLE_WRITE; + } + if (chr->flags & BLE_GATT_CHR_F_AUX_WRITE) { + flags |= BLE_GATTS_CEP_F_AUX_WRITE; + } + + return flags; +} + static uint8_t ble_gatts_att_flags_from_chr_flags(ble_gatt_chr_flags chr_flags) { @@ -804,6 +821,55 @@ ble_gatts_register_clt_cfg_dsc(uint16_t *att_handle) return 0; } +static int +ble_gatts_cep_access(uint16_t conn_handle, uint16_t attr_handle, uint8_t att_op, + uint16_t offset, struct os_mbuf **om, void *arg) +{ + uint16_t prop = POINTER_TO_UINT(arg); + uint8_t *buf; + + ble_gatts_dsc_inc_stat(ble_gatts_dsc_op(att_op)); + + if (att_op != BLE_ATT_ACCESS_OP_READ) { + return BLE_ATT_ERR_WRITE_NOT_PERMITTED; + } + + buf = os_mbuf_extend(*om, sizeof(prop)); + if (buf == NULL) { + return BLE_ATT_ERR_INSUFFICIENT_RES; + } + put_le16(buf, prop); + + return 0; +} + +static int +ble_gatts_register_cep_dsc(uint16_t *att_handle, ble_gatt_chr_flags flags) +{ + struct ble_gatt_cep_dsc cep; + int rc; + + cep.properties = 0x0000; + if (flags & BLE_GATT_CHR_F_RELIABLE_WRITE) { + cep.properties |= BLE_GATTS_CEP_F_RELIABLE_WRITE; + } + if (flags & BLE_GATT_CHR_F_AUX_WRITE) { + /* TODO: Implement Characteristic User Description + * (Core specification 6.0, vol 3, part G, section 3.3.3.2)*/ + cep.properties |= BLE_GATTS_CEP_F_AUX_WRITE; + } + + rc = ble_att_svr_register(uuid_cep, BLE_ATT_F_READ, 0, att_handle, + ble_gatts_cep_access, UINT_TO_POINTER(cep.properties)); + if (rc != 0) { + return rc; + } + + STATS_INC(ble_gatts_stats, dscs); + + return 0; +} + static int ble_gatts_register_chr(const struct ble_gatt_svc_def *svc, const struct ble_gatt_chr_def *chr, @@ -814,6 +880,7 @@ ble_gatts_register_chr(const struct ble_gatt_svc_def *svc, uint16_t def_handle; uint16_t val_handle; uint16_t dsc_handle; + uint16_t cep_handle; uint8_t att_flags; int rc; @@ -870,6 +937,14 @@ ble_gatts_register_chr(const struct ble_gatt_svc_def *svc, BLE_HS_DBG_ASSERT(dsc_handle == def_handle + 2); } + if (ble_gatts_chr_ext_prop_allowed(chr) != 0) { + rc = ble_gatts_register_cep_dsc(&cep_handle, chr->flags); + if (rc != 0) { + return rc; + } + BLE_HS_DBG_ASSERT(cep_handle == def_handle + 3); + } + /* Register each descriptor. */ if (chr->descriptors != NULL) { for (dsc = chr->descriptors; dsc->uuid != NULL; dsc++) { @@ -2172,6 +2247,21 @@ ble_gatts_count_resources(const struct ble_gatt_svc_def *svcs, res->attrs++; } + /* If the characteristic permits reliable writes or auxiliary + * writes, it has an Extended Properties descriptor. + */ + if (chr->flags & BLE_GATT_CHR_F_AUX_WRITE || + chr->flags & BLE_GATT_CHR_F_RELIABLE_WRITE) { + + /* Each CEP requires: + * o 1 descriptor + * o 1 attribute + */ + res->dscs++; + res->ceps++; + res->attrs++; + } + if (chr->descriptors != NULL) { for (d = 0; chr->descriptors[d].uuid != NULL; d++) { if (!ble_gatts_dsc_is_sane(chr->descriptors + d)) { From 530fc9e842fa72694c5a4cc3cc20d6d43184941d Mon Sep 17 00:00:00 2001 From: Piotr Narajowski Date: Wed, 3 Sep 2025 11:55:48 +0200 Subject: [PATCH 2/2] nimble/host: fix coding style Fix coding style --- nimble/host/include/host/ble_gatt.h | 4 ++-- nimble/host/src/ble_gatt_priv.h | 12 ++++++------ nimble/host/src/ble_gatts.c | 15 +++++---------- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/nimble/host/include/host/ble_gatt.h b/nimble/host/include/host/ble_gatt.h index a9d763258b..4f6b9a2457 100644 --- a/nimble/host/include/host/ble_gatt.h +++ b/nimble/host/include/host/ble_gatt.h @@ -60,10 +60,10 @@ struct ble_hs_cfg; */ /** GATT service 16-bit UUID. */ -#define BLE_GATT_SVC_UUID16 0x1801 +#define BLE_GATT_SVC_UUID16 0x1801 /** GATT Client Characteristic Configuration descriptor 16-bit UUID. */ -#define BLE_GATT_DSC_CLT_CFG_UUID16 0x2902 +#define BLE_GATT_DSC_CLT_CFG_UUID16 0x2902 /** GATT Characteristic Extended Porperties descriptor 16-bit UUID. */ #define BLE_GATT_DSC_EXT_PROP_UUID16 0x2900 diff --git a/nimble/host/src/ble_gatt_priv.h b/nimble/host/src/ble_gatt_priv.h index 111a540b3b..50e9a7d826 100644 --- a/nimble/host/src/ble_gatt_priv.h +++ b/nimble/host/src/ble_gatt_priv.h @@ -151,13 +151,13 @@ int ble_gattc_any_jobs(void); int ble_gattc_init(void); /*** @server. */ -#define BLE_GATTS_CLT_CFG_F_NOTIFY 0x0001 -#define BLE_GATTS_CLT_CFG_F_INDICATE 0x0002 -#define BLE_GATTS_CLT_CFG_F_MODIFIED 0x0080 /* Internal only. */ -#define BLE_GATTS_CLT_CFG_F_RESERVED 0xfffc +#define BLE_GATTS_CLT_CFG_F_NOTIFY 0x0001 +#define BLE_GATTS_CLT_CFG_F_INDICATE 0x0002 +#define BLE_GATTS_CLT_CFG_F_MODIFIED 0x0080 /* Internal only. */ +#define BLE_GATTS_CLT_CFG_F_RESERVED 0xfffc -#define BLE_GATTS_INC_SVC_LEN_NO_UUID 4 -#define BLE_GATTS_INC_SVC_LEN_UUID 6 +#define BLE_GATTS_INC_SVC_LEN_NO_UUID 4 +#define BLE_GATTS_INC_SVC_LEN_UUID 6 #define BLE_GATTS_CEP_F_RELIABLE_WRITE 0x0001 #define BLE_GATTS_CEP_F_AUX_WRITE 0x0002 diff --git a/nimble/host/src/ble_gatts.c b/nimble/host/src/ble_gatts.c index f0df15c714..26cdea45d9 100644 --- a/nimble/host/src/ble_gatts.c +++ b/nimble/host/src/ble_gatts.c @@ -29,16 +29,11 @@ #define BLE_GATTS_INCLUDE_SZ 6 #define BLE_GATTS_CHR_MAX_SZ 19 -static const ble_uuid_t *uuid_pri = - BLE_UUID16_DECLARE(BLE_ATT_UUID_PRIMARY_SERVICE); -static const ble_uuid_t *uuid_sec = - BLE_UUID16_DECLARE(BLE_ATT_UUID_SECONDARY_SERVICE); -static const ble_uuid_t *uuid_inc = - BLE_UUID16_DECLARE(BLE_ATT_UUID_INCLUDE); -static const ble_uuid_t *uuid_chr = - BLE_UUID16_DECLARE(BLE_ATT_UUID_CHARACTERISTIC); -static const ble_uuid_t *uuid_ccc = - BLE_UUID16_DECLARE(BLE_GATT_DSC_CLT_CFG_UUID16); +static const ble_uuid_t *uuid_pri = BLE_UUID16_DECLARE(BLE_ATT_UUID_PRIMARY_SERVICE); +static const ble_uuid_t *uuid_sec = BLE_UUID16_DECLARE(BLE_ATT_UUID_SECONDARY_SERVICE); +static const ble_uuid_t *uuid_inc = BLE_UUID16_DECLARE(BLE_ATT_UUID_INCLUDE); +static const ble_uuid_t *uuid_chr = BLE_UUID16_DECLARE(BLE_ATT_UUID_CHARACTERISTIC); +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); static const struct ble_gatt_svc_def **ble_gatts_svc_defs;