This is an automated email from the ASF dual-hosted git repository.

andk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git


The following commit(s) were added to refs/heads/master by this push:
     new 554e0634 nimble/ll: Fix encryption pause/restart procedure
554e0634 is described below

commit 554e063421f07fe2a9028ea2b389a503e1d24ee0
Author: Andrzej Kaczmarek <[email protected]>
AuthorDate: Thu Jun 13 18:32:24 2024 +0200

    nimble/ll: Fix encryption pause/restart procedure
    
    This fixes 2 issues in encrpytion pause/restart procedure (i.e. key
    refresh) initiated in central role:
    
    1. We transition to "paused" encryption state when LL_PAUSE_ENC_RSP is
       txd, but that is done after we try to enqueue LL_ENC_REQ. This means
       LL_ENC_REQ is put at the end of tx queue. By conicidence this makes
       order of PDUs correct when there's only LL_PAUSE_ENC_RSP on tx queue,
       but it fails if there was an ACL packet already queued. In such case
       LL_ENC_REQ is queued after that ACL packet which means neither will
       be sent - ACL packet cannot be sent because we have no encryption,
       LL_ENC_REQ cannot be sent because there's ACL packet in front.
    2. We do not check if LL_ENC_REQ was properly queued (i.e. if mbuf was
       allocated for PDU) so it may happen that LL_ENC_REQ will never be
       queued.
    
    In both scenarios the connection will timeout eventually since
    encryption restart procedure cannot be completed.
    
    This fix ensures that LL_ENC_REQ is queued properly by using a "pending"
    flag that is evaluated when checking for pending procedures.
---
 nimble/controller/include/controller/ble_ll_conn.h |  1 +
 nimble/controller/src/ble_ll_ctrl.c                | 38 ++++++++++++----------
 2 files changed, 22 insertions(+), 17 deletions(-)

diff --git a/nimble/controller/include/controller/ble_ll_conn.h 
b/nimble/controller/include/controller/ble_ll_conn.h
index 88e7934b..7d6af874 100644
--- a/nimble/controller/include/controller/ble_ll_conn.h
+++ b/nimble/controller/include/controller/ble_ll_conn.h
@@ -108,6 +108,7 @@ struct ble_ll_conn_sm_flags {
     uint32_t encrypted : 1;
     uint32_t encrypt_ltk_req : 1;
     uint32_t encrypt_event_sent : 1;
+    uint32_t pending_encrypt_restart : 1;
     uint32_t version_ind_txd : 1;
     uint32_t version_ind_rxd : 1;
     uint32_t features_rxd : 1;
diff --git a/nimble/controller/src/ble_ll_ctrl.c 
b/nimble/controller/src/ble_ll_ctrl.c
index d2b8a31b..da12a5f3 100644
--- a/nimble/controller/src/ble_ll_ctrl.c
+++ b/nimble/controller/src/ble_ll_ctrl.c
@@ -2684,6 +2684,9 @@ ble_ll_ctrl_proc_start(struct ble_ll_conn_sm *connsm, int 
ctrl_proc,
 void
 ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm)
 {
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
+    struct os_mbuf *om;
+#endif
     int i;
 
     /* XXX: TODO new rules! Cannot start certain control procedures if other
@@ -2706,6 +2709,22 @@ ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm)
         return;
     }
 
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
+    if (connsm->flags.pending_encrypt_restart) {
+        /* This flag should only be set after LL_PAUSE_ENC_RSP was txd from
+         * central and there should be already active encryption procedure
+         * ongoing. We need to restart encryption to complete key refresh.
+         */
+        BLE_LL_ASSERT(connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_ENCRYPT);
+        BLE_LL_ASSERT(IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_ENCRYPT));
+
+        om = ble_ll_ctrl_proc_init(connsm, BLE_LL_CTRL_PROC_ENCRYPT, NULL);
+        if (om) {
+            connsm->flags.pending_encrypt_restart = 0;
+        }
+    }
+#endif
+
     /* If there is a running procedure or no pending, do nothing */
     if ((connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_IDLE) &&
         (connsm->pending_ctrl_procs != 0)) {
@@ -2755,9 +2774,6 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct 
os_mbuf *om)
     uint8_t *dptr;
     uint8_t *rspbuf;
     uint8_t *rspdata;
-#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
-    int restart_encryption;
-#endif
     int rc = 0;
     uint8_t rsp_opcode = 0;
 
@@ -2802,10 +2818,6 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct 
os_mbuf *om)
 
     ble_ll_trace_u32x2(BLE_LL_TRACE_ID_CTRL_RX, opcode, len);
 
-#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
-    restart_encryption = 0;
-#endif
-
     /* If opcode comes from reserved value or CtrlData fields is invalid
      * we shall respond with LL_UNKNOWN_RSP
      */
@@ -2956,9 +2968,6 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct 
os_mbuf *om)
         break;
     case BLE_LL_CTRL_PAUSE_ENC_RSP:
         rsp_opcode = ble_ll_ctrl_rx_pause_enc_rsp(connsm);
-        if (rsp_opcode == BLE_LL_CTRL_PAUSE_ENC_RSP) {
-            restart_encryption = 1;
-        }
         break;
 #endif
     case BLE_LL_CTRL_PING_REQ:
@@ -3032,13 +3041,6 @@ ll_ctrl_send_rsp:
         }
         len = g_ble_ll_ctrl_pkt_lengths[rsp_opcode] + 1;
         ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, len);
-#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
-        if (restart_encryption) {
-            /* XXX: what happens if this fails? Meaning we cant allocate
-               mbuf? */
-            ble_ll_ctrl_proc_init(connsm, BLE_LL_CTRL_PROC_ENCRYPT, NULL);
-        }
-#endif
     }
 
 #if MYNEWT_VAL(BLE_LL_CONN_INIT_AUTO_DLE)
@@ -3206,6 +3208,8 @@ ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct 
ble_ll_conn_sm *connsm)
     case BLE_LL_CTRL_PAUSE_ENC_RSP:
         if (connsm->conn_role == BLE_LL_CONN_ROLE_PERIPHERAL) {
             connsm->enc_data.enc_state = CONN_ENC_S_PAUSE_ENC_RSP_WAIT;
+        } else {
+            connsm->flags.pending_encrypt_restart = 1;
         }
         break;
 #endif

Reply via email to