diff --git a/nimble/host/include/host/ble_gatt.h b/nimble/host/include/host/ble_gatt.h index 8ad0cba52..c2a378c2f 100644 --- a/nimble/host/include/host/ble_gatt.h +++ b/nimble/host/include/host/ble_gatt.h @@ -127,50 +127,58 @@ struct ble_hs_cfg; */ /** GATT Characteristic Flag: Broadcast. */ -#define BLE_GATT_CHR_F_BROADCAST 0x0001 +#define BLE_GATT_CHR_F_BROADCAST 0x00000001 /** GATT Characteristic Flag: Read. */ -#define BLE_GATT_CHR_F_READ 0x0002 +#define BLE_GATT_CHR_F_READ 0x00000002 /** GATT Characteristic Flag: Write without Response. */ -#define BLE_GATT_CHR_F_WRITE_NO_RSP 0x0004 +#define BLE_GATT_CHR_F_WRITE_NO_RSP 0x00000004 /** GATT Characteristic Flag: Write. */ -#define BLE_GATT_CHR_F_WRITE 0x0008 +#define BLE_GATT_CHR_F_WRITE 0x00000008 /** GATT Characteristic Flag: Notify. */ -#define BLE_GATT_CHR_F_NOTIFY 0x0010 +#define BLE_GATT_CHR_F_NOTIFY 0x00000010 /** GATT Characteristic Flag: Indicate. */ -#define BLE_GATT_CHR_F_INDICATE 0x0020 +#define BLE_GATT_CHR_F_INDICATE 0x00000020 /** GATT Characteristic Flag: Authenticated Signed Writes. */ -#define BLE_GATT_CHR_F_AUTH_SIGN_WRITE 0x0040 +#define BLE_GATT_CHR_F_AUTH_SIGN_WRITE 0x00000040 /** GATT Characteristic Flag: Reliable Writes. */ -#define BLE_GATT_CHR_F_RELIABLE_WRITE 0x0080 +#define BLE_GATT_CHR_F_RELIABLE_WRITE 0x00000080 /** GATT Characteristic Flag: Auxiliary Writes. */ -#define BLE_GATT_CHR_F_AUX_WRITE 0x0100 +#define BLE_GATT_CHR_F_AUX_WRITE 0x00000100 /** GATT Characteristic Flag: Read Encrypted. */ -#define BLE_GATT_CHR_F_READ_ENC 0x0200 +#define BLE_GATT_CHR_F_READ_ENC 0x00000200 /** GATT Characteristic Flag: Read Authenticated. */ -#define BLE_GATT_CHR_F_READ_AUTHEN 0x0400 +#define BLE_GATT_CHR_F_READ_AUTHEN 0x00000400 /** GATT Characteristic Flag: Read Authorized. */ -#define BLE_GATT_CHR_F_READ_AUTHOR 0x0800 +#define BLE_GATT_CHR_F_READ_AUTHOR 0x00000800 /** GATT Characteristic Flag: Write Encrypted. */ -#define BLE_GATT_CHR_F_WRITE_ENC 0x1000 +#define BLE_GATT_CHR_F_WRITE_ENC 0x00001000 /** GATT Characteristic Flag: Write Authenticated. */ -#define BLE_GATT_CHR_F_WRITE_AUTHEN 0x2000 +#define BLE_GATT_CHR_F_WRITE_AUTHEN 0x00002000 /** GATT Characteristic Flag: Write Authorized. */ -#define BLE_GATT_CHR_F_WRITE_AUTHOR 0x4000 +#define BLE_GATT_CHR_F_WRITE_AUTHOR 0x00004000 +/** GATT Characteristic Flag: CCCD Write Encrypted */ +#define BLE_GATT_CHR_F_NOTIFY_INDICATE_ENC 0x00008000 + +/** GATT Characteristic Flag: CCCD Write Authenticated */ +#define BLE_GATT_CHR_F_NOTIFY_INDICATE_AUTHEN 0x00010000 + +/** GATT Characteristic Flag: CCCD Write Authorized */ +#define BLE_GATT_CHR_F_NOTIFY_INDICATE_AUTHOR 0x00020000 /** @} */ @@ -996,7 +1004,7 @@ typedef int ble_gatt_access_fn(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg); /** Type definition for GATT characteristic flags. */ -typedef uint16_t ble_gatt_chr_flags; +typedef uint32_t ble_gatt_chr_flags; /** Represents the definition of a GATT characteristic. */ struct ble_gatt_chr_def { @@ -1031,6 +1039,8 @@ struct ble_gatt_chr_def { /** * At registration time, this is filled in with the characteristic's value * attribute handle. + * + * The attribute handle for CCCD is `val_handle + 1` */ uint16_t *val_handle; diff --git a/nimble/host/src/ble_gap.c b/nimble/host/src/ble_gap.c index 072b415b4..642976e6b 100644 --- a/nimble/host/src/ble_gap.c +++ b/nimble/host/src/ble_gap.c @@ -8513,6 +8513,10 @@ ble_gap_enc_event(uint16_t conn_handle, int status, ble_gap_event_listener_call(&event); ble_gap_call_conn_event_cb(&event, conn_handle); +#if MYNEWT_VAL(BLE_GATTC) && MYNEWT_VAL(BLE_GATTC_AUTO_PAIR) + ble_gattc_recover_gatt_proc(conn_handle, status); +#endif + if (status != 0) { return; } diff --git a/nimble/host/src/ble_gatt_priv.h b/nimble/host/src/ble_gatt_priv.h index eda5b85e6..1f2649e0a 100644 --- a/nimble/host/src/ble_gatt_priv.h +++ b/nimble/host/src/ble_gatt_priv.h @@ -161,6 +161,9 @@ int32_t ble_gattc_timer(void); int ble_gattc_any_jobs(void); int ble_gattc_init(void); +#if MYNEWT_VAL(BLE_GATTC) && MYNEWT_VAL(BLE_GATTC_AUTO_PAIR) +void ble_gattc_recover_gatt_proc(uint16_t conn_handle, int enc_status); +#endif /*** @server. */ #define BLE_GATTS_CLT_CFG_F_NOTIFY 0x0001 @@ -224,7 +227,6 @@ int ble_gatts_register_svcs(const struct ble_gatt_svc_def *svcs, int ble_gatts_clt_cfg_access(uint16_t conn_handle, uint16_t attr_handle, uint8_t op, uint16_t offset, struct os_mbuf **om, void *arg); -void ble_gatts_set_clt_cfg_perm_flags(uint8_t flags); #if MYNEWT_VAL(BLE_GATT_CACHING) struct ble_gatts_aware_state { diff --git a/nimble/host/src/ble_gattc.c b/nimble/host/src/ble_gattc.c index 037b5f465..8cb013692 100644 --- a/nimble/host/src/ble_gattc.c +++ b/nimble/host/src/ble_gattc.c @@ -113,6 +113,9 @@ struct ble_gattc_proc { STAILQ_ENTRY(ble_gattc_proc) next; +#if MYNEWT_VAL(BLE_GATTC_AUTO_PAIR) + struct ble_gatt_error error; +#endif uint32_t exp_os_ticks; uint16_t conn_handle; uint16_t cid; @@ -210,6 +213,9 @@ struct ble_gattc_proc { uint16_t att_handle; ble_gatt_attr_fn *cb; void *cb_arg; +#if MYNEWT_VAL(BLE_GATTC_AUTO_PAIR) + struct os_mbuf * om; +#endif } write; struct { @@ -461,6 +467,11 @@ static struct os_mempool ble_gattc_proc_pool; /* The list of active GATT client procedures. */ static struct ble_gattc_proc_list ble_gattc_procs; +#if MYNEWT_VAL(BLE_GATTC_AUTO_PAIR) +/** Retry procedure after encryption response. */ +static struct ble_gattc_proc_list ble_gattc_cached_procs; +#endif + #if MYNEWT_VAL(BLE_GATTC) /* The time when we should attempt to resume stalled procedures, in OS ticks. * A value of 0 indicates no stalled procedures. @@ -780,6 +791,13 @@ ble_gattc_proc_free(struct ble_gattc_proc *proc) ble_gattc_dbg_assert_proc_not_inserted(proc); switch (proc->op) { +#if MYNEWT_VAL(BLE_GATTC_AUTO_PAIR) + case BLE_GATT_OP_WRITE: + if (MYNEWT_VAL(BLE_GATT_WRITE)) { + os_mbuf_free_chain(proc->write.om); + } + break; +#endif case BLE_GATT_OP_WRITE_LONG: if (MYNEWT_VAL(BLE_GATT_WRITE_LONG)) { os_mbuf_free_chain(proc->write_long.attr.om); @@ -1389,6 +1407,94 @@ ble_gattc_error(int status, uint16_t att_handle) return &error; } +#if MYNEWT_VAL(BLE_GATTC_AUTO_PAIR) +void +ble_gattc_recover_gatt_proc(uint16_t conn_handle, int enc_status) +{ + struct ble_gattc_proc * prev; + struct ble_gattc_proc * proc; + struct ble_gattc_proc * next; + struct os_mbuf * om; + struct ble_gatt_attr attrs[MYNEWT_VAL(BLE_GATT_WRITE_MAX_ATTRS)]; + ble_gattc_err_fn *err_cb; + + prev = NULL; + proc = STAILQ_FIRST(&ble_gattc_cached_procs); + while (proc != NULL) { + next = STAILQ_NEXT(proc, next); + + if (proc->conn_handle == conn_handle) { + if (enc_status == 0) { + switch (proc->op) { + case BLE_GATT_OP_READ: + ble_gattc_read(conn_handle, proc->read.handle, + proc->read.cb, proc->read.cb_arg); + break; + case BLE_GATT_OP_READ_UUID: + ble_gattc_read_by_uuid(conn_handle, proc->read_uuid.start_handle, + proc->read_uuid.end_handle, &proc->read_uuid.chr_uuid.u, + proc->read_uuid.cb, proc->read_uuid.cb_arg); + break; + case BLE_GATT_OP_READ_LONG: + ble_gattc_read_long(conn_handle, proc->read_long.handle, + proc->read_long.offset, proc->read_long.cb, + proc->read_long.cb_arg); + break; + case BLE_GATT_OP_READ_MULT: + ble_gattc_read_mult(conn_handle, proc->read_mult.handles, + proc->read_mult.num_handles, proc->read_mult.cb, + proc->read_mult.cb_arg); + break; + case BLE_GATT_OP_READ_MULT_VAR: + ble_gattc_read_mult_var(conn_handle, proc->read_mult.handles, + proc->read_mult.num_handles, proc->read_mult.cb_mult, + proc->read_mult.cb_arg); + break; + case BLE_GATT_OP_WRITE: + /* Mbuf will be consumed by the API. */ + om = os_mbuf_dup(proc->write.om); + ble_gattc_write(conn_handle, proc->write.att_handle, + om, proc->write.cb, proc->write.cb_arg); + break; + case BLE_GATT_OP_WRITE_LONG: + /* Mbuf will be consumed by the API. */ + om = os_mbuf_dup(proc->write_long.attr.om); + ble_gattc_write_long(conn_handle, proc->write_long.attr.handle, + proc->write_long.attr.offset, om, + proc->write_long.cb, proc->write_long.cb_arg); + case BLE_GATT_OP_WRITE_RELIABLE: + for (int i = 0; i < proc->write_reliable.num_attrs; i++) { + attrs[i].handle = proc->write_reliable.attrs[i].handle; + attrs[i].offset = 0; + attrs[i].om = os_mbuf_dup(proc->write_reliable.attrs[i].om); + } + ble_gattc_write_reliable(conn_handle, attrs, + proc->write_reliable.num_attrs, + proc->write_reliable.cb, proc->write_reliable.cb_arg); + } + } else { + err_cb = ble_gattc_err_dispatch_get(proc->op); + if (err_cb != NULL) { + err_cb(proc, BLE_HS_ERR_ATT_BASE + proc->error.status, proc->error.att_handle); + } + } + + if (!prev) { + STAILQ_REMOVE_HEAD(&ble_gattc_cached_procs, next); + } else { + STAILQ_REMOVE_AFTER(&ble_gattc_cached_procs, prev, next); + } + + ble_gattc_proc_free(proc); + proc = prev; + } + + prev = proc; + proc = next; + } +} +#endif /* MYNEWT_VAL(BLE_GATTC_AUTO_PAIR) */ + /***************************************************************************** * $mtu * *****************************************************************************/ @@ -4391,6 +4497,9 @@ ble_gattc_write(uint16_t conn_handle, uint16_t attr_handle, proc->write.att_handle = attr_handle; proc->write.cb = cb; proc->write.cb_arg = cb_arg; +#if MYNEWT_VAL(BLE_GATTC_AUTO_PAIR) + proc->write.om = os_mbuf_dup(txom); +#endif ble_gattc_log_write(attr_handle, OS_MBUF_PKTLEN(txom), 1); @@ -5486,9 +5595,30 @@ ble_gattc_rx_err(uint16_t conn_handle, uint16_t cid, uint16_t handle, uint16_t s { struct ble_gattc_proc *proc; ble_gattc_err_fn *err_cb; +#if MYNEWT_VAL(BLE_GATTC_AUTO_PAIR) + struct ble_gap_conn_desc desc; + int rc; +#endif proc = ble_gattc_extract_first_by_conn_cid_op(conn_handle, cid, BLE_GATT_OP_NONE); +#if MYNEWT_VAL(BLE_GATTC_AUTO_PAIR) + ble_gap_conn_find(conn_handle, &desc); + proc->error.att_handle = handle; + proc->error.status = status; +#endif + if (proc != NULL) { +#if MYNEWT_VAL(BLE_GATTC_AUTO_PAIR) + if (desc.sec_state.encrypted == 0 && + (status == BLE_ATT_ERR_INSUFFICIENT_ENC || + status == BLE_ATT_ERR_INSUFFICIENT_AUTHEN)) { + rc = ble_gap_security_initiate(conn_handle); + if (rc == 0) { + STAILQ_INSERT_TAIL(&ble_gattc_cached_procs, proc, next); + return; + } + } +#endif err_cb = ble_gattc_err_dispatch_get(proc->op); if (err_cb != NULL) { err_cb(proc, BLE_HS_ERR_ATT_BASE + status, handle); @@ -5913,6 +6043,9 @@ ble_gattc_init(void) STAILQ_INIT(&temp_proc_list); #endif STAILQ_INIT(&ble_gattc_procs); +#if MYNEWT_VAL(BLE_GATTC_AUTO_PAIR) + STAILQ_INIT(&ble_gattc_cached_procs); +#endif if (MYNEWT_VAL(BLE_GATT_MAX_PROCS) > 0) { rc = os_mempool_init(&ble_gattc_proc_pool, diff --git a/nimble/host/src/ble_gatts.c b/nimble/host/src/ble_gatts.c index 8c7efa390..b9f30fa9b 100644 --- a/nimble/host/src/ble_gatts.c +++ b/nimble/host/src/ble_gatts.c @@ -28,7 +28,6 @@ #include "esp_nimble_mem.h" #if MYNEWT_VAL(BLE_GATTS) -static uint8_t perm_flags = BLE_ATT_F_READ | BLE_ATT_F_WRITE ; #if MYNEWT_VAL(BLE_DYNAMIC_SERVICE) #include "services/gatt/ble_svc_gatt.h" @@ -179,11 +178,6 @@ ble_gatts_clt_cfg_free(struct ble_gatts_clt_cfg *cfg) } #endif -void ble_gatts_set_clt_cfg_perm_flags(uint8_t flags) -{ - perm_flags = flags ; -} - static int ble_gatts_svc_access(uint16_t conn_handle, uint16_t attr_handle, uint8_t op, uint16_t offset, struct os_mbuf **om, @@ -259,6 +253,26 @@ ble_gatts_chr_clt_cfg_allowed(const struct ble_gatt_chr_def *chr) return flags; } +static uint8_t +ble_gatts_chr_clt_cfg_flags_from_chr_flags(ble_gatt_chr_flags chr_flags) +{ + uint8_t cccd_flags; + + cccd_flags = BLE_ATT_F_READ | BLE_ATT_F_WRITE; + + if (chr_flags & BLE_GATT_CHR_F_NOTIFY_INDICATE_ENC) { + cccd_flags |= BLE_ATT_F_WRITE_ENC; + } + if (chr_flags & BLE_GATT_CHR_F_NOTIFY_INDICATE_AUTHEN) { + cccd_flags |= BLE_ATT_F_WRITE_AUTHEN; + } + if (chr_flags & BLE_GATT_CHR_F_NOTIFY_INDICATE_AUTHOR) { + cccd_flags |= BLE_ATT_F_WRITE_AUTHOR; + } + + return cccd_flags; +} + static uint8_t ble_gatts_att_flags_from_chr_flags(ble_gatt_chr_flags chr_flags) { @@ -1011,10 +1025,10 @@ ble_gatts_clt_cfg_access(uint16_t conn_handle, uint16_t attr_handle, } static int -ble_gatts_register_clt_cfg_dsc(uint16_t *att_handle) +ble_gatts_register_clt_cfg_dsc(uint16_t *att_handle, uint8_t cccd_flags) { int rc; - rc = ble_att_svr_register(uuid_ccc, perm_flags, 0, + rc = ble_att_svr_register(uuid_ccc, cccd_flags, 0, att_handle, ble_gatts_clt_cfg_access, NULL); if (rc != 0) { return rc; @@ -1190,7 +1204,8 @@ ble_gatts_register_chr(const struct ble_gatt_svc_def *svc, } if (ble_gatts_chr_clt_cfg_allowed(chr) != 0) { - rc = ble_gatts_register_clt_cfg_dsc(&dsc_handle); + att_flags = ble_gatts_chr_clt_cfg_flags_from_chr_flags(chr->flags); + rc = ble_gatts_register_clt_cfg_dsc(&dsc_handle, att_flags); if (rc != 0) { return rc; }