diff --git a/nimble/controller/include/controller/ble_ll_ctrl.h b/nimble/controller/include/controller/ble_ll_ctrl.h index b0da1e736..8432422a8 100644 --- a/nimble/controller/include/controller/ble_ll_ctrl.h +++ b/nimble/controller/include/controller/ble_ll_ctrl.h @@ -39,7 +39,8 @@ extern "C" { #define BLE_LL_CTRL_PROC_LE_PING (7) #define BLE_LL_CTRL_PROC_DATA_LEN_UPD (8) #define BLE_LL_CTRL_PROC_PHY_UPDATE (9) -#define BLE_LL_CTRL_PROC_NUM (10) +#define BLE_LL_CTRL_PROC_SCA_UPDATE (10) +#define BLE_LL_CTRL_PROC_NUM (11) #define BLE_LL_CTRL_PROC_IDLE (255) /* Checks if a particular control procedure is running */ @@ -306,6 +307,11 @@ void ble_ll_hci_ev_send_vendor_err(const char *file, uint32_t line); uint8_t ble_ll_ctrl_phy_tx_transition_get(uint8_t phy_mask); uint8_t ble_ll_ctrl_phy_from_phy_mask(uint8_t phy_mask); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) +void ble_ll_hci_ev_sca_update(struct ble_ll_conn_sm *connsm, + uint8_t status, uint8_t peer_sca); +#endif + #ifdef __cplusplus } #endif diff --git a/nimble/controller/src/ble_ll.c b/nimble/controller/src/ble_ll.c index 996ad9c33..c6eefcf57 100644 --- a/nimble/controller/src/ble_ll.c +++ b/nimble/controller/src/ble_ll.c @@ -1678,6 +1678,9 @@ ble_ll_init(void) features |= BLE_LL_FEAT_SYNC_TRANS_SEND; #endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) + features |= BLE_LL_FEAT_SCA_UPDATE; +#endif /* Initialize random number generation */ ble_ll_rand_init(); diff --git a/nimble/controller/src/ble_ll_conn_hci.c b/nimble/controller/src/ble_ll_conn_hci.c index b84b690be..9936b9d34 100644 --- a/nimble/controller/src/ble_ll_conn_hci.c +++ b/nimble/controller/src/ble_ll_conn_hci.c @@ -1560,6 +1560,34 @@ ltk_key_cmd_complete: } #endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) +int +ble_ll_conn_req_peer_sca(const uint8_t *cmdbuf, uint8_t len, + uint8_t *rspbuf, uint8_t *rsplen) +{ + const struct ble_hci_le_request_peer_sca_cp *params = (const void *)cmdbuf; + struct ble_ll_conn_sm *connsm; + + connsm = ble_ll_conn_find_active_conn(params->conn_handle); + if (!connsm) { + return BLE_ERR_UNK_CONN_ID; + } + + if (!(connsm->remote_features[2] & (BLE_LL_FEAT_SCA_UPDATE >> 24))) { + return BLE_ERR_UNSUPP_REM_FEATURE; + } + + if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_SCA_UPDATE)) { + /* Not really specified what we should return */ + return BLE_ERR_CTLR_BUSY; + } + + ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_SCA_UPDATE); + + return 0; +} +#endif + #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) /** * Read authenticated payload timeout (OGF=3, OCF==0x007B) diff --git a/nimble/controller/src/ble_ll_conn_priv.h b/nimble/controller/src/ble_ll_conn_priv.h index a836bfe40..9891bfaec 100644 --- a/nimble/controller/src/ble_ll_conn_priv.h +++ b/nimble/controller/src/ble_ll_conn_priv.h @@ -196,6 +196,11 @@ int ble_ll_conn_hci_wr_auth_pyld_tmo(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); int ble_ll_conn_hci_rd_auth_pyld_tmo(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen); +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) +int ble_ll_conn_req_peer_sca(const uint8_t *cmdbuf, uint8_t len, + uint8_t *rspbuf, uint8_t *rsplen); +#endif + #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING) void ble_ll_conn_auth_pyld_timer_start(struct ble_ll_conn_sm *connsm); #else diff --git a/nimble/controller/src/ble_ll_ctrl.c b/nimble/controller/src/ble_ll_ctrl.c index ea2ba8349..f6f3b0bc5 100644 --- a/nimble/controller/src/ble_ll_ctrl.c +++ b/nimble/controller/src/ble_ll_ctrl.c @@ -505,6 +505,12 @@ ble_ll_ctrl_proc_unk_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, uint8_t * ble_ll_ctrl_phy_update_cancel(connsm, BLE_ERR_UNSUPP_REM_FEATURE); ctrl_proc = BLE_LL_CTRL_PROC_PHY_UPDATE; break; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) + case BLE_LL_CTRL_CLOCK_ACCURACY_REQ: + ble_ll_hci_ev_sca_update(connsm, BLE_ERR_UNSUPPORTED, 0); + ctrl_proc = BLE_LL_CTRL_PROC_SCA_UPDATE; + break; #endif default: ctrl_proc = BLE_LL_CTRL_PROC_NUM; @@ -836,6 +842,20 @@ ble_ll_ctrl_phy_req_rsp_make(struct ble_ll_conn_sm *connsm, uint8_t *ctrdata) } } +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) +/** + * Create a LL_CLOCK_ACCURACY_REQ or LL_CLOCK_ACCURACY_RSP pdu + * + * @param connsm Pointer to connection state machine + * @param ctrdata: Pointer to where CtrData starts in pdu + */ +static void +ble_ll_ctrl_sca_req_rsp_make(struct ble_ll_conn_sm *connsm, uint8_t *ctrdata) +{ + ctrdata[0] = BLE_LL_SCA_ENUM; +} +#endif + static uint8_t ble_ll_ctrl_rx_phy_req(struct ble_ll_conn_sm *connsm, uint8_t *req, uint8_t *rsp) @@ -1040,7 +1060,44 @@ ble_ll_ctrl_rx_periodic_sync_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr) connsm->sync_transfer_skip, connsm->sync_transfer_sync_timeout); } + return BLE_ERR_MAX; +} +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) +/** + * Called when a BLE_LL_CTRL_CLOCK_ACCURACY_REQ PDU is received + * + * @param connsm + * @param dptr + * @param rsp Pointer to CtrData of BLE_LL_CTRL_CLOCK_ACCURACY_RSP. + * + * @return uint8_t + */ +static uint8_t +ble_ll_ctrl_rx_sca_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, + uint8_t *rsp) +{ + ble_ll_ctrl_sca_req_rsp_make(connsm, rsp); + return BLE_LL_CTRL_CLOCK_ACCURACY_RSP; +} + +/** + * Called when a BLE_LL_CTRL_CLOCK_ACCURACY_RSP PDU is received + * + * @param connsm + * @param dptr + * + * @return uint8_t + */ +static uint8_t +ble_ll_ctrl_rx_sca_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr) +{ + if (connsm->cur_ctrl_proc != BLE_LL_CTRL_PROC_SCA_UPDATE) { + return BLE_LL_CTRL_UNKNOWN_RSP; + } + ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_SCA_UPDATE); + ble_ll_hci_ev_sca_update(connsm, BLE_ERR_SUCCESS, dptr[0]); return BLE_ERR_MAX; } #endif @@ -1676,6 +1733,12 @@ ble_ll_ctrl_rx_reject_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr, */ ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD); break; +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) + case BLE_LL_CTRL_PROC_SCA_UPDATE: + ble_ll_hci_ev_sca_update(connsm, ble_error, 0); + ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_SCA_UPDATE); + break; +#endif default: break; } @@ -2138,6 +2201,12 @@ ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int ctrl_proc) opcode = BLE_LL_CTRL_PHY_REQ; ble_ll_ctrl_phy_req_rsp_make(connsm, ctrdata); break; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) + case BLE_LL_CTRL_PROC_SCA_UPDATE: + opcode = BLE_LL_CTRL_CLOCK_ACCURACY_REQ; + ble_ll_ctrl_sca_req_rsp_make(connsm, ctrdata); + break; #endif default: BLE_LL_ASSERT(0); @@ -2568,6 +2637,14 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om) rsp_opcode = ble_ll_ctrl_rx_phy_update_ind(connsm, dptr); break; #endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) + case BLE_LL_CTRL_CLOCK_ACCURACY_REQ: + rsp_opcode = ble_ll_ctrl_rx_sca_req(connsm, dptr, rspdata); + break; + case BLE_LL_CTRL_CLOCK_ACCURACY_RSP: + rsp_opcode = ble_ll_ctrl_rx_sca_rsp(connsm, dptr); + break; +#endif #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER) case BLE_LL_CTRL_PERIODIC_SYNC_IND: rsp_opcode = ble_ll_ctrl_rx_periodic_sync_ind(connsm, dptr); diff --git a/nimble/controller/src/ble_ll_hci.c b/nimble/controller/src/ble_ll_hci.c index 14f71de1b..39693679f 100644 --- a/nimble/controller/src/ble_ll_hci.c +++ b/nimble/controller/src/ble_ll_hci.c @@ -618,6 +618,9 @@ ble_ll_hci_le_cmd_send_cmd_status(uint16_t ocf) case BLE_HCI_OCF_LE_GEN_DHKEY: case BLE_HCI_OCF_LE_SET_PHY: case BLE_HCI_OCF_LE_PERIODIC_ADV_CREATE_SYNC: +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) + case BLE_HCI_OCF_LE_REQ_PEER_SCA: +#endif rc = 1; break; default: @@ -1153,6 +1156,12 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf, case BLE_HCI_OCF_LE_SET_HOST_FEAT: rc = ble_ll_set_host_feat(cmdbuf, len); break; +#endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) + case BLE_HCI_OCF_LE_REQ_PEER_SCA: + rc = ble_ll_conn_req_peer_sca(cmdbuf, len, + rspbuf, rsplen); + break; #endif default: rc = BLE_ERR_UNKNOWN_HCI_CMD; diff --git a/nimble/controller/src/ble_ll_hci_ev.c b/nimble/controller/src/ble_ll_hci_ev.c index dbc50db98..0d6da9a01 100644 --- a/nimble/controller/src/ble_ll_hci_ev.c +++ b/nimble/controller/src/ble_ll_hci_ev.c @@ -461,6 +461,37 @@ ble_ll_hci_ev_phy_update(struct ble_ll_conn_sm *connsm, uint8_t status) } #endif +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) +void +ble_ll_hci_ev_sca_update(struct ble_ll_conn_sm *connsm, uint8_t status, + uint8_t peer_sca) +{ + struct ble_hci_ev_le_subev_peer_sca_complete *ev; + struct ble_hci_ev *hci_ev; + + if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_REQ_PEER_SCA_COMP)) { + return; + } + + hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI); + if (!hci_ev) { + return; + } + + hci_ev->opcode = BLE_HCI_EVCODE_LE_META; + hci_ev->length = sizeof(*ev); + ev = (void *) hci_ev->data; + + ev->subev_code = BLE_HCI_LE_SUBEV_REQ_PEER_SCA_COMP; + ev->status = status; + ev->conn_handle = htole16(connsm->conn_handle); + ev->sca = peer_sca; + + ble_ll_hci_event_send(hci_ev); +} + +#endif + void ble_ll_hci_ev_send_vendor_err(const char *file, uint32_t line) { diff --git a/nimble/controller/src/ble_ll_supp_cmd.c b/nimble/controller/src/ble_ll_supp_cmd.c index 1285d9182..10943703f 100644 --- a/nimble/controller/src/ble_ll_supp_cmd.c +++ b/nimble/controller/src/ble_ll_supp_cmd.c @@ -410,6 +410,17 @@ BLE_SUPP_CMD_LE_PADV_DEFAULT_SYNC_TRANSFER_PARAMS \ ) +/* Octet 43 */ +#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE) +#define BLE_SUPP_CMD_LE_REQUEST_PEER_SCA (1 << 2) +#else +#define BLE_SUPP_CMD_LE_REQUEST_PEER_SCA (0 << 0) +#endif +#define BLE_LL_SUPP_CMD_OCTET_43 \ +( \ + BLE_SUPP_CMD_LE_REQUEST_PEER_SCA \ +) + /* Octet 44 */ #if MYNEWT_VAL(BLE_VERSION) >= 52 #define BLE_SUPP_CMD_LE_SET_HOST_FEATURE (1 << 0) @@ -467,6 +478,6 @@ const uint8_t g_ble_ll_supp_cmds[BLE_LL_SUPP_CMD_LEN] = BLE_LL_SUPP_CMD_OCTET_40, /* Octet 40 */ BLE_LL_SUPP_CMD_OCTET_41, 0, - 0, + BLE_LL_SUPP_CMD_OCTET_43, BLE_LL_SUPP_CMD_OCTET_44, }; diff --git a/nimble/controller/syscfg.yml b/nimble/controller/syscfg.yml index f864acce5..2327263b1 100644 --- a/nimble/controller/syscfg.yml +++ b/nimble/controller/syscfg.yml @@ -260,6 +260,13 @@ syscfg.defs: Advertising Sync Transfer Feature. value: MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER) + BLE_LL_CFG_FEAT_LL_SCA_UPDATE: + description: > + This option is used to enable/disable support for SCA update procedure + value: 0 + restrictions: + - '(BLE_VERSION >= 52) if 1' + BLE_LL_EXT_ADV_AUX_PTR_CNT: description: > This option configure a max number of scheduled outstanding auxiliary diff --git a/nimble/include/nimble/hci_common.h b/nimble/include/nimble/hci_common.h index 4aaf81c7d..b52dccd99 100644 --- a/nimble/include/nimble/hci_common.h +++ b/nimble/include/nimble/hci_common.h @@ -825,6 +825,11 @@ struct ble_hci_le_set_default_periodic_sync_transfer_params_cp { #define BLE_HCI_OCF_LE_GENERATE_DHKEY_V2 (0x005E) #define BLE_HCI_OCF_LE_MODIFY_SCA (0x005F) +#define BLE_HCI_OCF_LE_REQ_PEER_SCA (0x006d) +struct ble_hci_le_request_peer_sca_cp { + uint16_t conn_handle; +} __attribute__((packed)); + #define BLE_HCI_OCF_LE_SET_HOST_FEAT (0x0074) struct ble_hci_le_set_host_feat_cp { uint8_t bit_num; @@ -1444,6 +1449,14 @@ struct ble_hci_ev_le_subev_periodic_adv_sync_transfer { uint8_t aca; } __attribute__((packed)); +#define BLE_HCI_LE_SUBEV_REQ_PEER_SCA_COMP (0x1F) +struct ble_hci_ev_le_subev_peer_sca_complete { + uint8_t subev_code; + uint8_t status; + uint16_t conn_handle; + uint8_t sca; +} __attribute__((packed)); + /* Data buffer overflow event */ #define BLE_HCI_EVENT_ACL_BUF_OVERFLOW (0x01)