diff --git a/nimble/host/include/host/ble_gatt.h b/nimble/host/include/host/ble_gatt.h index 229d99dda3..4f6b9a2457 100644 --- a/nimble/host/include/host/ble_gatt.h +++ b/nimble/host/include/host/ble_gatt.h @@ -60,10 +60,13 @@ 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 /** @} */ @@ -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..50e9a7d826 100644 --- a/nimble/host/src/ble_gatt_priv.h +++ b/nimble/host/src/ble_gatt_priv.h @@ -151,13 +151,16 @@ 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 /** * Contains counts of resources required by the GATT server. The contents of @@ -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..26cdea45d9 100644 --- a/nimble/host/src/ble_gatts.c +++ b/nimble/host/src/ble_gatts.c @@ -29,16 +29,12 @@ #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; static int ble_gatts_num_svc_defs; @@ -154,6 +150,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 +816,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 +875,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 +932,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 +2242,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)) {