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

commit 03f4d1645adf1ad13041ec4b650ed207a45b2edd
Author: Mariusz Skamra <[email protected]>
AuthorDate: Tue Jan 7 11:30:09 2025 +0100

    nimble/ll/isoal: Add initial framed PDU ISOAL support
    
    This adds framed PDU ISOAL support
---
 nimble/controller/include/controller/ble_ll_iso.h  |  35 +-
 .../controller/include/controller/ble_ll_iso_big.h |   3 -
 .../controller/include/controller/ble_ll_isoal.h   |  43 +-
 nimble/controller/src/ble_ll.c                     |  11 +-
 nimble/controller/src/ble_ll_hci.c                 |   2 +-
 nimble/controller/src/ble_ll_iso.c                 | 194 ++++-
 nimble/controller/src/ble_ll_iso_big.c             | 103 +--
 nimble/controller/src/ble_ll_isoal.c               | 375 +++++---
 nimble/controller/test/src/ble_ll_isoal.c          | 966 +++++++++++++++++++++
 nimble/controller/test/src/ble_ll_test.c           |   2 +
 nimble/controller/test/syscfg.yml                  |   4 +
 nimble/include/nimble/ble.h                        |   2 +
 nimble/include/nimble/hci_common.h                 |   4 +
 13 files changed, 1501 insertions(+), 243 deletions(-)

diff --git a/nimble/controller/include/controller/ble_ll_iso.h 
b/nimble/controller/include/controller/ble_ll_iso.h
index fb20a4f34..768dd9923 100644
--- a/nimble/controller/include/controller/ble_ll_iso.h
+++ b/nimble/controller/include/controller/ble_ll_iso.h
@@ -21,11 +21,28 @@
 #define H_BLE_LL_ISO
 
 #include <stdint.h>
+#include <controller/ble_ll_isoal.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+struct ble_ll_iso_conn {
+    /* Connection handle */
+    uint16_t handle;
+
+    /* ISOAL Multiplexer */
+    struct ble_ll_isoal_mux mux;
+
+    /* HCI SDU Fragment */
+    struct os_mbuf *frag;
+
+    /* Number of Completed Packets */
+    uint16_t num_completed_pkt;
+
+    STAILQ_ENTRY(ble_ll_iso_conn) iso_conn_q_next;
+};
+
 /* HCI command handlers */
 int ble_ll_iso_read_tx_sync(const uint8_t *cmdbuf, uint8_t len, uint8_t 
*rspbuf, uint8_t *rsplen);
 int ble_ll_iso_set_cig_param(const uint8_t *cmdbuf, uint8_t len, uint8_t 
*rspbuf, uint8_t *rsplen);
@@ -47,7 +64,23 @@ int ble_ll_iso_receive_test(const uint8_t *cmdbuf, uint8_t 
len);
 int ble_ll_iso_read_counters_test(const uint8_t *cmdbuf, uint8_t len);
 int ble_ll_iso_end_test(const uint8_t *cmdbuf, uint8_t len);
 
-struct ble_ll_isoal_mux *ble_ll_iso_find_mux_by_handle(uint16_t conn_handle);
+void ble_ll_iso_init(void);
+void ble_ll_iso_reset(void);
+
+/* ISO Data handler */
+int ble_ll_iso_data_in(struct os_mbuf *om);
+
+int ble_ll_iso_pdu_get(struct ble_ll_iso_conn *conn, uint8_t idx, uint8_t 
*llid, void *dptr);
+
+void ble_ll_iso_conn_init(struct ble_ll_iso_conn *conn, uint16_t conn_handle,
+                          uint8_t max_pdu, uint32_t iso_interval_us,
+                          uint32_t sdu_interval_us, uint8_t bn, uint8_t pte, 
uint8_t framing);
+void ble_ll_iso_conn_free(struct ble_ll_iso_conn *conn);
+
+int ble_ll_iso_conn_event_start(struct ble_ll_iso_conn *conn, uint32_t 
timestamp);
+int ble_ll_iso_conn_event_done(struct ble_ll_iso_conn *conn);
+
+struct ble_ll_iso_conn *ble_ll_iso_conn_find_by_handle(uint16_t conn_handle);
 
 #ifdef __cplusplus
 }
diff --git a/nimble/controller/include/controller/ble_ll_iso_big.h 
b/nimble/controller/include/controller/ble_ll_iso_big.h
index 47d33bd3b..8576fc549 100644
--- a/nimble/controller/include/controller/ble_ll_iso_big.h
+++ b/nimble/controller/include/controller/ble_ll_iso_big.h
@@ -33,9 +33,6 @@ int ble_ll_iso_big_biginfo_copy(struct ble_ll_iso_big *big, 
uint8_t *dptr,
                                 uint32_t base_ticks, uint8_t base_rem_us);
 int ble_ll_iso_big_biginfo_len(struct ble_ll_iso_big *big);
 
-struct ble_ll_iso_bis *ble_ll_iso_big_find_bis_by_handle(uint16_t conn_handle);
-struct ble_ll_isoal_mux *ble_ll_iso_big_find_mux_by_handle(uint16_t 
conn_handle);
-
 void ble_ll_iso_big_chan_map_update(void);
 
 void ble_ll_iso_big_halt(void);
diff --git a/nimble/controller/include/controller/ble_ll_isoal.h 
b/nimble/controller/include/controller/ble_ll_isoal.h
index 3bb7075bc..a590a0f6e 100644
--- a/nimble/controller/include/controller/ble_ll_isoal.h
+++ b/nimble/controller/include/controller/ble_ll_isoal.h
@@ -20,14 +20,13 @@
 #ifndef H_BLE_LL_ISOAL_
 #define H_BLE_LL_ISOAL_
 
+#include <os/os_mbuf.h>
 #include <syscfg/syscfg.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-#if MYNEWT_VAL(BLE_LL_ISO)
-
 struct ble_ll_isoal_mux {
 #if MYNEWT_VAL(BLE_LL_ISOAL_MUX_PREFILL)
     uint8_t active;
@@ -44,37 +43,53 @@ struct ble_ll_isoal_mux {
     /* Number of SDUs available for current event */
     uint8_t sdu_in_event;
 
+    /* Burst Number */
+    uint8_t bn;
+
     STAILQ_HEAD(, os_mbuf_pkthdr) sdu_q;
     uint16_t sdu_q_len;
 
-    struct os_mbuf *frag;
-
     uint32_t sdu_counter;
 
     uint32_t event_tx_timestamp;
     uint32_t last_tx_timestamp;
     uint16_t last_tx_packet_seq_num;
+
+    /* The head SDU Segment is the Continuation of an SDU */
+    uint8_t sc : 1;
+    uint8_t framed : 1;
+    uint8_t framing_mode : 1;
 };
 
-void
-ble_ll_isoal_mux_init(struct ble_ll_isoal_mux *mux, uint8_t max_pdu,
-                      uint32_t iso_interval_us, uint32_t sdu_interval_us,
-                      uint8_t bn, uint8_t pte);
+#define BLE_LL_ISOAL_SEGHDR(sc, cmplt, len) \
+        ((uint16_t)((sc) & 0x01) | (((cmplt) & 0x01) << 1) | ((len) & 0xff) << 
8)
+
+#define BLE_LL_ISOAL_SEGHDR_SC(word)    ((word) & 0x01)
+#define BLE_LL_ISOAL_SEGHDR_CMPLT(word) ((word >> 1) & 0x01)
+#define BLE_LL_ISOAL_SEGHDR_LEN(word)   ((word >> 8) & 0xff)
+
+#define BLE_LL_ISOAL_MUX_IS_FRAMED(framing) \
+        ((framing) == BLE_HCI_ISO_FRAMING_FRAMED_SEGMENTABLE || \
+         (framing) == BLE_HCI_ISO_FRAMING_FRAMED_UNSEGMENTED)
+
+void ble_ll_isoal_mux_init(struct ble_ll_isoal_mux *mux, uint8_t max_pdu,
+                           uint32_t iso_interval_us, uint32_t sdu_interval_us,
+                           uint8_t bn, uint8_t pte, bool framed,
+                           uint8_t framing_mode);
 void ble_ll_isoal_mux_free(struct ble_ll_isoal_mux *mux);
 
 int ble_ll_isoal_mux_event_start(struct ble_ll_isoal_mux *mux,
                                  uint32_t timestamp);
 int ble_ll_isoal_mux_event_done(struct ble_ll_isoal_mux *mux);
 
-int
-ble_ll_isoal_mux_unframed_get(struct ble_ll_isoal_mux *mux, uint8_t idx,
-                              uint8_t *llid, void *dptr);
+int ble_ll_isoal_mux_pdu_get(struct ble_ll_isoal_mux *mux, uint8_t idx,
+                             uint8_t *llid, void *dptr);
+
+void ble_ll_isoal_mux_sdu_enqueue(struct ble_ll_isoal_mux *mux,
+                                  struct os_mbuf *om);
 
 void ble_ll_isoal_init(void);
 void ble_ll_isoal_reset(void);
-int ble_ll_isoal_data_in(struct os_mbuf *om);
-
-#endif /* BLE_LL_ISO */
 
 #ifdef __cplusplus
 }
diff --git a/nimble/controller/src/ble_ll.c b/nimble/controller/src/ble_ll.c
index 238bfad1d..cc11a93b4 100644
--- a/nimble/controller/src/ble_ll.c
+++ b/nimble/controller/src/ble_ll.c
@@ -47,7 +47,7 @@
 #include "controller/ble_ll_sync.h"
 #include "controller/ble_fem.h"
 #if MYNEWT_VAL(BLE_LL_ISO)
-#include "controller/ble_ll_isoal.h"
+#include "controller/ble_ll_iso.h"
 #endif
 #if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER)
 #include "controller/ble_ll_iso_big.h"
@@ -1685,13 +1685,14 @@ ble_ll_reset(void)
     ble_fem_lna_init();
 #endif
 
-#if MYNEWT_VAL(BLE_LL_ISO)
-    ble_ll_isoal_reset();
-#endif
 #if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER)
     ble_ll_iso_big_reset();
 #endif
 
+#if MYNEWT_VAL(BLE_LL_ISO)
+    ble_ll_iso_reset();
+#endif
+
     /* Re-initialize the PHY */
     rc = ble_phy_init();
 
@@ -1968,7 +1969,7 @@ ble_ll_init(void)
 #endif
 
 #if MYNEWT_VAL(BLE_LL_ISO)
-    ble_ll_isoal_init();
+    ble_ll_iso_init();
 #endif
 #if MYNEWT_VAL(BLE_LL_ISO_BROADCASTER)
     ble_ll_iso_big_init();
diff --git a/nimble/controller/src/ble_ll_hci.c 
b/nimble/controller/src/ble_ll_hci.c
index e8250284e..e969963ae 100644
--- a/nimble/controller/src/ble_ll_hci.c
+++ b/nimble/controller/src/ble_ll_hci.c
@@ -1995,7 +1995,7 @@ int
 ble_ll_hci_iso_rx(struct os_mbuf *om)
 {
 #if MYNEWT_VAL(BLE_LL_ISO)
-    ble_ll_isoal_data_in(om);
+    ble_ll_iso_data_in(om);
 #else
     os_mbuf_free_chain(om);
 #endif
diff --git a/nimble/controller/src/ble_ll_iso.c 
b/nimble/controller/src/ble_ll_iso.c
index 46e25ee52..034996d5f 100644
--- a/nimble/controller/src/ble_ll_iso.c
+++ b/nimble/controller/src/ble_ll_iso.c
@@ -23,27 +23,26 @@
 #include <controller/ble_ll.h>
 #include <controller/ble_ll_isoal.h>
 #include <controller/ble_ll_iso.h>
-#include <controller/ble_ll_iso_big.h>
+#include <controller/ble_ll_tmr.h>
 
 #if MYNEWT_VAL(BLE_LL_ISO)
 
+STAILQ_HEAD(ble_ll_iso_conn_q, ble_ll_iso_conn);
+struct ble_ll_iso_conn_q ll_iso_conn_q;
+
 int
 ble_ll_iso_setup_iso_data_path(const uint8_t *cmdbuf, uint8_t cmdlen,
                                uint8_t *rspbuf, uint8_t *rsplen)
 {
     const struct ble_hci_le_setup_iso_data_path_cp *cmd = (const void *)cmdbuf;
     struct ble_hci_le_setup_iso_data_path_rp *rsp = (void *)rspbuf;
-    struct ble_ll_iso_bis *bis;
+    struct ble_ll_iso_conn *conn;
     uint16_t conn_handle;
 
     conn_handle = le16toh(cmd->conn_handle);
-    switch (BLE_LL_CONN_HANDLE_TYPE(conn_handle)) {
-    case BLE_LL_CONN_HANDLE_TYPE_BIS:
-        bis = ble_ll_iso_big_find_bis_by_handle(conn_handle);
-        if (bis) {
-            break;
-        }
-    default:
+
+    conn = ble_ll_iso_conn_find_by_handle(conn_handle);
+    if (!conn) {
         return BLE_ERR_UNK_CONN_ID;
     }
 
@@ -83,18 +82,18 @@ ble_ll_iso_read_tx_sync(const uint8_t *cmdbuf, uint8_t 
cmdlen,
 {
     const struct ble_hci_le_read_iso_tx_sync_cp *cmd = (const void *)cmdbuf;
     struct ble_hci_le_read_iso_tx_sync_rp *rsp = (void *)rspbuf;
-    struct ble_ll_isoal_mux *mux;
+    struct ble_ll_iso_conn *iso_conn;
     uint16_t handle;
 
     handle = le16toh(cmd->conn_handle);
-    mux = ble_ll_iso_find_mux_by_handle(handle);
-    if (!mux) {
+    iso_conn = ble_ll_iso_conn_find_by_handle(handle);
+    if (!iso_conn) {
         return BLE_ERR_UNK_CONN_ID;
     }
 
     rsp->conn_handle = cmd->conn_handle;
-    rsp->packet_seq_num = htole16(mux->last_tx_packet_seq_num);
-    rsp->tx_timestamp = htole32(mux->last_tx_timestamp);
+    rsp->packet_seq_num = htole16(iso_conn->mux.last_tx_packet_seq_num);
+    rsp->tx_timestamp = htole32(iso_conn->mux.last_tx_timestamp);
     put_le24(rsp->time_offset, 0);
 
     *rsplen = sizeof(*rsp);
@@ -102,15 +101,170 @@ ble_ll_iso_read_tx_sync(const uint8_t *cmdbuf, uint8_t 
cmdlen,
     return 0;
 }
 
-struct ble_ll_isoal_mux *
-ble_ll_iso_find_mux_by_handle(uint16_t conn_handle)
+struct ble_ll_iso_conn *
+ble_ll_iso_conn_find_by_handle(uint16_t conn_handle)
+{
+    struct ble_ll_iso_conn *conn;
+
+    STAILQ_FOREACH(conn, &ll_iso_conn_q, iso_conn_q_next) {
+        if (conn_handle == conn->handle) {
+            return conn;
+        }
+    }
+
+    return NULL;
+}
+
+void
+ble_ll_iso_init(void)
+{
+    STAILQ_INIT(&ll_iso_conn_q);
+    ble_ll_isoal_init();
+}
+
+void
+ble_ll_iso_reset(void)
+{
+    STAILQ_INIT(&ll_iso_conn_q);
+    ble_ll_isoal_reset();
+}
+
+int
+ble_ll_iso_data_in(struct os_mbuf *om)
 {
-    switch (BLE_LL_CONN_HANDLE_TYPE(conn_handle)) {
-    case BLE_LL_CONN_HANDLE_TYPE_BIS:
-        return ble_ll_iso_big_find_mux_by_handle(conn_handle);
+    struct ble_hci_iso *hci_iso;
+    struct ble_hci_iso_data *hci_iso_data;
+    struct ble_ll_iso_conn *conn;
+    struct ble_mbuf_hdr *blehdr;
+    uint16_t data_hdr_len;
+    uint16_t handle;
+    uint16_t conn_handle;
+    uint16_t length;
+    uint16_t pb_flag;
+    uint16_t ts_flag;
+    uint32_t timestamp = 0;
+
+    hci_iso = (void *)om->om_data;
+
+    handle = le16toh(hci_iso->handle);
+    conn_handle = BLE_HCI_ISO_CONN_HANDLE(handle);
+    pb_flag = BLE_HCI_ISO_PB_FLAG(handle);
+    ts_flag = BLE_HCI_ISO_TS_FLAG(handle);
+    length = BLE_HCI_ISO_LENGTH(le16toh(hci_iso->length));
+
+    conn = ble_ll_iso_conn_find_by_handle(conn_handle);
+    if (!conn) {
+        os_mbuf_free_chain(om);
+        return BLE_ERR_UNK_CONN_ID;
+    }
+
+    data_hdr_len = 0;
+    if ((pb_flag == BLE_HCI_ISO_PB_FIRST) ||
+        (pb_flag == BLE_HCI_ISO_PB_COMPLETE)) {
+        blehdr = BLE_MBUF_HDR_PTR(om);
+        blehdr->txiso.packet_seq_num = ++conn->mux.sdu_counter;
+        blehdr->txiso.cpu_timestamp = ble_ll_tmr_get();
+
+        if (ts_flag) {
+            timestamp = get_le32(om->om_data + sizeof(*hci_iso));
+            data_hdr_len += sizeof(uint32_t);
+        }
+        blehdr->txiso.hci_timestamp = timestamp;
+
+        hci_iso_data = (void *)(om->om_data + sizeof(*hci_iso) + data_hdr_len);
+        data_hdr_len += sizeof(*hci_iso_data);
+    }
+    os_mbuf_adj(om, sizeof(*hci_iso) + data_hdr_len);
+
+    if (OS_MBUF_PKTLEN(om) != length - data_hdr_len) {
+        os_mbuf_free_chain(om);
+        return BLE_ERR_MEM_CAPACITY;
+    }
+
+    switch (pb_flag) {
+    case BLE_HCI_ISO_PB_FIRST:
+        BLE_LL_ASSERT(!conn->frag);
+        conn->frag = om;
+        om = NULL;
+        break;
+    case BLE_HCI_ISO_PB_CONTINUATION:
+        BLE_LL_ASSERT(conn->frag);
+        os_mbuf_concat(conn->frag, om);
+        om = NULL;
+        break;
+    case BLE_HCI_ISO_PB_COMPLETE:
+        BLE_LL_ASSERT(!conn->frag);
+        break;
+    case BLE_HCI_ISO_PB_LAST:
+        BLE_LL_ASSERT(conn->frag);
+        os_mbuf_concat(conn->frag, om);
+        om = conn->frag;
+        conn->frag = NULL;
+        break;
     default:
-        return NULL;
+        BLE_LL_ASSERT(0);
+        break;
+    }
+
+    if (om) {
+        ble_ll_isoal_mux_sdu_enqueue(&conn->mux, om);
     }
+
+    return 0;
+}
+
+int
+ble_ll_iso_pdu_get(struct ble_ll_iso_conn *conn, uint8_t idx, uint8_t *llid, 
void *dptr)
+{
+    return ble_ll_isoal_mux_pdu_get(&conn->mux, idx, llid, dptr);
+}
+
+void
+ble_ll_iso_conn_init(struct ble_ll_iso_conn *conn, uint16_t conn_handle,
+                     uint8_t max_pdu, uint32_t iso_interval_us,
+                     uint32_t sdu_interval_us, uint8_t bn, uint8_t pte,
+                     uint8_t framing)
+{
+    os_sr_t sr;
+
+    memset(conn, 0, sizeof(*conn));
+
+    conn->handle = conn_handle;
+    ble_ll_isoal_mux_init(&conn->mux, max_pdu, iso_interval_us, 
sdu_interval_us,
+                          bn, pte, BLE_LL_ISOAL_MUX_IS_FRAMED(framing),
+                          framing == BLE_HCI_ISO_FRAMING_FRAMED_UNSEGMENTED);
+
+    OS_ENTER_CRITICAL(sr);
+    STAILQ_INSERT_TAIL(&ll_iso_conn_q, conn, iso_conn_q_next);
+    OS_EXIT_CRITICAL(sr);
+}
+
+void
+ble_ll_iso_conn_free(struct ble_ll_iso_conn *conn)
+{
+    os_sr_t sr;
+
+    OS_ENTER_CRITICAL(sr);
+    STAILQ_REMOVE(&ll_iso_conn_q, conn, ble_ll_iso_conn, iso_conn_q_next);
+    OS_EXIT_CRITICAL(sr);
+
+    ble_ll_isoal_mux_free(&conn->mux);
+}
+
+int
+ble_ll_iso_conn_event_start(struct ble_ll_iso_conn *conn, uint32_t timestamp)
+{
+    ble_ll_isoal_mux_event_start(&conn->mux, timestamp);
+
+    return 0;
+}
+
+int
+ble_ll_iso_conn_event_done(struct ble_ll_iso_conn *conn)
+{
+    conn->num_completed_pkt += ble_ll_isoal_mux_event_done(&conn->mux);
+
+    return conn->num_completed_pkt;
 }
 
 #endif /* BLE_LL_ISO */
diff --git a/nimble/controller/src/ble_ll_iso_big.c 
b/nimble/controller/src/ble_ll_iso_big.c
index 8976c5e26..2a5e60de3 100644
--- a/nimble/controller/src/ble_ll_iso_big.c
+++ b/nimble/controller/src/ble_ll_iso_big.c
@@ -27,7 +27,7 @@
 #include <controller/ble_ll_adv.h>
 #include <controller/ble_ll_crypto.h>
 #include <controller/ble_ll_hci.h>
-#include <controller/ble_ll_isoal.h>
+#include <controller/ble_ll_iso.h>
 #include <controller/ble_ll_iso_big.h>
 #include <controller/ble_ll_pdu.h>
 #include <controller/ble_ll_sched.h>
@@ -53,7 +53,6 @@ struct ble_ll_iso_big;
 struct ble_ll_iso_bis {
     struct ble_ll_iso_big *big;
     uint8_t num;
-    uint16_t conn_handle;
 
     uint32_t aa;
     uint32_t crc_init;
@@ -69,8 +68,7 @@ struct ble_ll_iso_bis {
         uint8_t g;
     } tx;
 
-    struct ble_ll_isoal_mux mux;
-    uint16_t num_completed_pkt;
+    struct ble_ll_iso_conn conn;
 
     STAILQ_ENTRY(ble_ll_iso_bis) bis_q_next;
 };
@@ -88,8 +86,8 @@ struct big_params {
     uint16_t max_sdu;
     uint8_t max_pdu;
     uint8_t phy;
+    uint8_t framing;
     uint8_t interleaved : 1;
-    uint8_t framed : 1;
     uint8_t encrypted : 1;
     uint8_t broadcast_code[16];
 };
@@ -112,6 +110,7 @@ struct ble_ll_iso_big {
     uint8_t nse; /* 1-31 */
     uint8_t interleaved : 1;
     uint8_t framed : 1;
+    uint8_t framing_mode : 1;
     uint8_t encrypted : 1;
     uint8_t giv[8];
     uint8_t gskd[16];
@@ -203,43 +202,6 @@ big_sched_set(struct ble_ll_iso_big *big)
     }
 }
 
-struct ble_ll_iso_bis *
-ble_ll_iso_big_find_bis_by_handle(uint16_t conn_handle)
-{
-    struct ble_ll_iso_bis *bis;
-    uint8_t bis_idx;
-
-    if (!BLE_LL_CONN_HANDLE_IS_BIS(conn_handle)) {
-        return NULL;
-    }
-
-    bis_idx = BLE_LL_CONN_HANDLE_IDX(conn_handle);
-
-    if (bis_idx >= BIS_POOL_SIZE) {
-        return NULL;
-    }
-
-    bis = &bis_pool[bis_idx];
-    if (!bis->big) {
-        return NULL;
-    }
-
-    return bis;
-}
-
-struct ble_ll_isoal_mux *
-ble_ll_iso_big_find_mux_by_handle(uint16_t conn_handle)
-{
-    struct ble_ll_iso_bis *bis;
-
-    bis = ble_ll_iso_big_find_bis_by_handle(conn_handle);
-    if (bis) {
-        return &bis->mux;
-    }
-
-    return NULL;
-}
-
 static void
 ble_ll_iso_big_biginfo_chanmap_update(struct ble_ll_iso_big *big)
 {
@@ -275,8 +237,8 @@ ble_ll_iso_big_biginfo_calc(struct ble_ll_iso_big *big, 
uint32_t seed_aa)
     put_le24(buf, (big->irc << 20) | (big->bis_spacing));
     buf += 3;
 
-    /* max_pdu, rfu */
-    put_le16(buf, big->max_pdu);
+    /* max_pdu, rfu, framing_mode */
+    put_le16(buf, big->max_pdu | (big->framing_mode) << 15);
     buf += 2;
 
     /* seed_access_address */
@@ -296,7 +258,8 @@ ble_ll_iso_big_biginfo_calc(struct ble_ll_iso_big *big, 
uint32_t seed_aa)
     buf += 5;
 
     /* bis_payload_cnt, framing */
-    memset(buf, 0x00, 5);
+    memset(buf, 0x01, 5);
+    buf[4] |= (big->framed << 7) & 0x80;
 }
 
 int
@@ -357,7 +320,7 @@ ble_ll_iso_big_biginfo_copy(struct ble_ll_iso_big *big, 
uint8_t *dptr,
     *dptr++ = (counter >> 8) & 0xff;
     *dptr++ = (counter >> 16) & 0xff;
     *dptr++ = (counter >> 24) & 0xff;
-    *dptr++ = (counter >> 32) & 0xff;
+    *dptr++ = ((counter >> 32) & 0x7f) | ((big->framed << 7) & 0x80);
 
     if (big->encrypted) {
         memcpy(dptr, big->giv, 8);
@@ -390,7 +353,7 @@ ble_ll_iso_big_free(struct ble_ll_iso_big *big)
     ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &big->event_done);
 
     STAILQ_FOREACH(bis, &big->bis_q, bis_q_next) {
-        ble_ll_isoal_mux_free(&bis->mux);
+        ble_ll_iso_conn_free(&bis->conn);
         bis->big = NULL;
         bis_pool_free++;
     }
@@ -503,15 +466,12 @@ ble_ll_iso_big_event_done(struct ble_ll_iso_big *big)
 #endif
 
     STAILQ_FOREACH(bis, &big->bis_q, bis_q_next) {
-        num_completed_pkt = ble_ll_isoal_mux_event_done(&bis->mux);
+        num_completed_pkt = ble_ll_iso_conn_event_done(&bis->conn);
         if (hci_ev && num_completed_pkt) {
             idx = hci_ev_ncp->count++;
-            hci_ev_ncp->completed[idx].handle = htole16(bis->conn_handle);
-            hci_ev_ncp->completed[idx].packets = htole16(num_completed_pkt +
-                                                         
bis->num_completed_pkt);
-            bis->num_completed_pkt = 0;
-        } else {
-            bis->num_completed_pkt += num_completed_pkt;
+            hci_ev_ncp->completed[idx].handle = htole16(bis->conn.handle);
+            hci_ev_ncp->completed[idx].packets = htole16(num_completed_pkt);
+            bis->conn.num_completed_pkt = 0;
         }
 
 #if MYNEWT_VAL(BLE_LL_ISO_HCI_FEEDBACK_INTERVAL_MS)
@@ -523,7 +483,7 @@ ble_ll_iso_big_event_done(struct ble_ll_iso_big *big)
              */
             exp = bis->mux.sdu_per_event - bis->mux.sdu_per_interval;
             idx = fb_hci_subev->count++;
-            fb_hci_subev->feedback[idx].handle = htole16(bis->conn_handle);
+            fb_hci_subev->feedback[idx].handle = htole16(bis->conn.handle);
             fb_hci_subev->feedback[idx].sdu_per_interval = 
bis->mux.sdu_per_interval;
             fb_hci_subev->feedback[idx].diff = (int8_t)(bis->mux.sdu_q_len - 
exp);
         }
@@ -723,7 +683,7 @@ ble_ll_iso_big_subevent_pdu_cb(uint8_t *dptr, void *arg, 
uint8_t *hdr_byte)
     }
 
 #if 1
-    pdu_len = ble_ll_isoal_mux_unframed_get(&bis->mux, idx, &llid, dptr);
+    pdu_len = ble_ll_iso_pdu_get(&bis->conn, idx, &llid, dptr);
 #else
     llid = 0;
     pdu_len = big->max_pdu;
@@ -860,12 +820,10 @@ ble_ll_iso_big_event_sched_cb(struct ble_ll_sched_item 
*sch)
 
     ble_ll_tx_power_set(g_ble_ll_tx_power);
 
-    BLE_LL_ASSERT(!big->framed);
-
     /* XXX calculate this in advance at the end of previous event? */
     big->tx.subevents_rem = big->num_bis * big->nse;
     STAILQ_FOREACH(bis, &big->bis_q, bis_q_next) {
-        ble_ll_isoal_mux_event_start(&bis->mux, (uint64_t)big->event_start *
+        ble_ll_iso_conn_event_start(&bis->conn, (uint64_t)big->event_start *
                                                 1000000 / 32768 +
                                                 big->event_start_us);
 
@@ -969,6 +927,7 @@ ble_ll_iso_big_create(uint8_t big_handle, uint8_t 
adv_handle, uint8_t num_bis,
     struct ble_ll_iso_bis *bis;
     struct ble_ll_adv_sm *advsm;
     uint32_t seed_aa;
+    uint16_t conn_handle;
     uint8_t pte;
     uint8_t gc;
     uint8_t idx;
@@ -1046,10 +1005,11 @@ ble_ll_iso_big_create(uint8_t big_handle, uint8_t 
adv_handle, uint8_t num_bis,
         bis->num = big->num_bis;
         bis->crc_init = (big->crc_init << 8) | (big->num_bis);
 
-        BLE_LL_ASSERT(!big->framed);
+        conn_handle = BLE_LL_CONN_HANDLE(BLE_LL_CONN_HANDLE_TYPE_BIS, idx);
 
-        ble_ll_isoal_mux_init(&bis->mux, bp->max_pdu, bp->iso_interval * 1250,
-                              bp->sdu_interval, bp->bn, pte);
+        ble_ll_iso_conn_init(&bis->conn, conn_handle, bp->max_pdu,
+                             bp->iso_interval * 1250, bp->sdu_interval,
+                             bp->bn, pte, bp->framing);
     }
 
     bis_pool_free -= num_bis;
@@ -1059,7 +1019,8 @@ ble_ll_iso_big_create(uint8_t big_handle, uint8_t 
adv_handle, uint8_t num_bis,
     big->irc = bp->irc;
     big->nse = bp->nse;
     big->interleaved = bp->interleaved;
-    big->framed = bp->framed;
+    big->framed = bp->framing != BLE_HCI_ISO_FRAMING_UNFRAMED;
+    big->framing_mode = bp->framing == BLE_HCI_ISO_FRAMING_FRAMED_UNSEGMENTED;
     big->encrypted = bp->encrypted;
     big->sdu_interval = bp->sdu_interval;
     big->iso_interval = bp->iso_interval;
@@ -1288,7 +1249,7 @@ ble_ll_iso_big_hci_evt_complete(void)
 
     idx = 0;
     STAILQ_FOREACH(bis, &big->bis_q, bis_q_next) {
-        evt->conn_handle[idx] = htole16(bis->conn_handle);
+        evt->conn_handle[idx] = htole16(bis->conn.handle);
         idx++;
     }
 
@@ -1314,7 +1275,7 @@ ble_ll_iso_big_hci_create(const uint8_t *cmdbuf, uint8_t 
len)
         !IN_RANGE(le16toh(cmd->max_sdu), 0x0001, 0x0fff) ||
         !IN_RANGE(le16toh(cmd->max_transport_latency), 0x0005, 0x0fa0) ||
         !IN_RANGE(cmd->rtn, 0x00, 0x1e) ||
-        (cmd->packing > 1) || (cmd->framing > 1) || (cmd->encryption) > 1) {
+        (cmd->packing > 1) || (cmd->framing > 2) || (cmd->encryption) > 1) {
         return BLE_ERR_INV_HCI_CMD_PARMS;
     }
 
@@ -1341,7 +1302,7 @@ ble_ll_iso_big_hci_create(const uint8_t *cmdbuf, uint8_t 
len)
         bp.phy = BLE_PHY_CODED;
     }
     bp.interleaved = cmd->packing;
-    bp.framed = cmd->framing;
+    bp.framing = cmd->framing;
     bp.encrypted = cmd->encryption;
     memcpy(bp.broadcast_code, cmd->broadcast_code, 16);
 
@@ -1424,7 +1385,7 @@ ble_ll_iso_big_hci_create_test(const uint8_t *cmdbuf, 
uint8_t len)
         bp.phy = BLE_PHY_CODED;
     }
     bp.interleaved = cmd->packing;
-    bp.framed = cmd->framing;
+    bp.framing = cmd->framing;
     bp.encrypted = cmd->encryption;
     memcpy(bp.broadcast_code, cmd->broadcast_code, 16);
 
@@ -1434,7 +1395,7 @@ ble_ll_iso_big_hci_create_test(const uint8_t *cmdbuf, 
uint8_t len)
 
     iso_interval_us = bp.iso_interval * 1250;
 
-    if (!bp.framed) {
+    if (bp.framing == BLE_HCI_ISO_FRAMING_UNFRAMED) {
         /* sdu_interval shall be an integer multiple of iso_interval */
         if (iso_interval_us % bp.sdu_interval) {
             return BLE_ERR_INV_HCI_CMD_PARMS;
@@ -1491,7 +1452,6 @@ void
 ble_ll_iso_big_init(void)
 {
     struct ble_ll_iso_big *big;
-    struct ble_ll_iso_bis *bis;
     uint8_t idx;
 
     memset(big_pool, 0, sizeof(big_pool));
@@ -1509,11 +1469,6 @@ ble_ll_iso_big_init(void)
         ble_npl_event_init(&big->event_done, ble_ll_iso_big_event_done_ev, 
big);
     }
 
-    for (idx = 0; idx < BIS_POOL_SIZE; idx++) {
-        bis = &bis_pool[idx];
-        bis->conn_handle = BLE_LL_CONN_HANDLE(BLE_LL_CONN_HANDLE_TYPE_BIS, 
idx);
-    }
-
     big_pool_free = ARRAY_SIZE(big_pool);
     bis_pool_free = ARRAY_SIZE(bis_pool);
 }
diff --git a/nimble/controller/src/ble_ll_isoal.c 
b/nimble/controller/src/ble_ll_isoal.c
index 8e7bfa4d0..8c8516b6d 100644
--- a/nimble/controller/src/ble_ll_isoal.c
+++ b/nimble/controller/src/ble_ll_isoal.c
@@ -19,10 +19,8 @@
 
 #include <stdint.h>
 #include <syscfg/syscfg.h>
-#include <nimble/hci_common.h>
 #include <controller/ble_ll.h>
 #include <controller/ble_ll_isoal.h>
-#include <controller/ble_ll_iso.h>
 
 #ifndef min
 #define min(a, b) ((a) < (b) ? (a) : (b))
@@ -30,27 +28,32 @@
 
 #if MYNEWT_VAL(BLE_LL_ISO)
 
-STAILQ_HEAD(ble_ll_iso_tx_q, os_mbuf_pkthdr);
-
-static struct ble_npl_event ll_isoal_tx_pkt_in;
-static struct ble_ll_iso_tx_q ll_isoal_tx_q;
-
 void
 ble_ll_isoal_mux_init(struct ble_ll_isoal_mux *mux, uint8_t max_pdu,
                       uint32_t iso_interval_us, uint32_t sdu_interval_us,
-                      uint8_t bn, uint8_t pte)
+                      uint8_t bn, uint8_t pte, bool framed, uint8_t 
framing_mode)
 {
     memset(mux, 0, sizeof(*mux));
 
     mux->max_pdu = max_pdu;
     /* Core 5.3, Vol 6, Part G, 2.1 */
     mux->sdu_per_interval = iso_interval_us / sdu_interval_us;
-    mux->pdu_per_sdu = bn / mux->sdu_per_interval;
+
+    if (framed) {
+        /* TODO */
+    } else {
+        mux->pdu_per_sdu = bn / mux->sdu_per_interval;
+    }
 
     mux->sdu_per_event = (1 + pte) * mux->sdu_per_interval;
 
+    mux->bn = bn;
+
     STAILQ_INIT(&mux->sdu_q);
     mux->sdu_q_len = 0;
+
+    mux->framed = framed;
+    mux->framing_mode = framing_mode;
 }
 
 void
@@ -77,54 +80,20 @@ ble_ll_isoal_mux_free(struct ble_ll_isoal_mux *mux)
     STAILQ_INIT(&mux->sdu_q);
 }
 
-static void
-ble_ll_isoal_mux_tx_pkt_in(struct ble_ll_isoal_mux *mux, struct os_mbuf *om,
-                           uint8_t pb, uint32_t timestamp)
+void
+ble_ll_isoal_mux_sdu_enqueue(struct ble_ll_isoal_mux *mux, struct os_mbuf *om)
 {
     struct os_mbuf_pkthdr *pkthdr;
-    struct ble_mbuf_hdr *blehdr;
     os_sr_t sr;
 
     BLE_LL_ASSERT(mux);
 
-    switch (pb) {
-    case BLE_HCI_ISO_PB_FIRST:
-        BLE_LL_ASSERT(!mux->frag);
-        mux->frag = om;
-        om = NULL;
-        break;
-    case BLE_HCI_ISO_PB_CONTINUATION:
-        BLE_LL_ASSERT(mux->frag);
-        os_mbuf_concat(mux->frag, om);
-        om = NULL;
-        break;
-    case BLE_HCI_ISO_PB_COMPLETE:
-        BLE_LL_ASSERT(!mux->frag);
-        break;
-    case BLE_HCI_ISO_PB_LAST:
-        BLE_LL_ASSERT(mux->frag);
-        os_mbuf_concat(mux->frag, om);
-        om = mux->frag;
-        mux->frag = NULL;
-        break;
-    default:
-        BLE_LL_ASSERT(0);
-        break;
-    }
-
-    if (!om) {
-        return;
-    }
-
-    blehdr = BLE_MBUF_HDR_PTR(om);
-    blehdr->txiso.packet_seq_num = ++mux->sdu_counter;
-
     OS_ENTER_CRITICAL(sr);
     pkthdr = OS_MBUF_PKTHDR(om);
     STAILQ_INSERT_TAIL(&mux->sdu_q, pkthdr, omp_next);
     mux->sdu_q_len++;
 #if MYNEWT_VAL(BLE_LL_ISOAL_MUX_PREFILL)
-    if (mux->sdu_q_len == mux->sdu_per_event) {
+    if (mux->sdu_q_len >= mux->sdu_per_event) {
         mux->active = 1;
     }
 #endif
@@ -138,26 +107,32 @@ ble_ll_isoal_mux_event_start(struct ble_ll_isoal_mux 
*mux, uint32_t timestamp)
     /* If prefill is enabled, we always expect to have required number of SDUs
      * in queue, otherwise we disable mux until enough SDUs are queued again.
      */
-    mux->sdu_in_event = mux->sdu_per_event;
-    if (mux->sdu_in_event > mux->sdu_q_len) {
+    if (mux->sdu_per_event > mux->sdu_q_len) {
         mux->active = 0;
     }
-    if (!mux->active) {
+    if (mux->active && mux->framed) {
+        mux->sdu_in_event = mux->sdu_q_len;
+    } else if (mux->active) {
+        mux->sdu_in_event = mux->sdu_per_event;
+    } else {
         mux->sdu_in_event = 0;
     }
 #else
-    mux->sdu_in_event = min(mux->sdu_q_len, mux->sdu_per_event);
+    if (mux->framed) {
+        mux->sdu_in_event = mux->sdu_q_len;
+    } else {
+        mux->sdu_in_event = min(mux->sdu_q_len, mux->sdu_per_event);
+    }
 #endif
     mux->event_tx_timestamp = timestamp;
 
     return mux->sdu_in_event;
 }
 
-int
-ble_ll_isoal_mux_event_done(struct ble_ll_isoal_mux *mux)
+static int
+ble_ll_isoal_mux_unframed_event_done(struct ble_ll_isoal_mux *mux)
 {
     struct os_mbuf_pkthdr *pkthdr;
-    struct ble_mbuf_hdr *blehdr;
     struct os_mbuf *om;
     struct os_mbuf *om_next;
     uint8_t num_sdu;
@@ -166,14 +141,6 @@ ble_ll_isoal_mux_event_done(struct ble_ll_isoal_mux *mux)
 
     num_sdu = min(mux->sdu_in_event, mux->sdu_per_interval);
 
-    pkthdr = STAILQ_FIRST(&mux->sdu_q);
-    if (pkthdr) {
-        om = OS_MBUF_PKTHDR_TO_MBUF(pkthdr);
-        blehdr = BLE_MBUF_HDR_PTR(om);
-        mux->last_tx_timestamp = mux->event_tx_timestamp;
-        mux->last_tx_packet_seq_num = blehdr->txiso.packet_seq_num;
-    }
-
 #if MYNEWT_VAL(BLE_LL_ISO_HCI_DISCARD_THRESHOLD)
     /* Drop queued SDUs if number of queued SDUs exceeds defined threshold.
      * Threshold is defined as number of ISO events. If number of queued SDUs
@@ -188,6 +155,7 @@ ble_ll_isoal_mux_event_done(struct ble_ll_isoal_mux *mux)
     }
 #endif
 
+    pkthdr = STAILQ_FIRST(&mux->sdu_q);
     while (pkthdr && num_sdu--) {
         OS_ENTER_CRITICAL(sr);
         STAILQ_REMOVE_HEAD(&mux->sdu_q, omp_next);
@@ -211,7 +179,119 @@ ble_ll_isoal_mux_event_done(struct ble_ll_isoal_mux *mux)
     return pkt_freed;
 }
 
+static int
+ble_ll_isoal_mux_framed_event_done(struct ble_ll_isoal_mux *mux)
+{
+    struct os_mbuf_pkthdr *pkthdr;
+    struct os_mbuf *om;
+    struct os_mbuf *om_next;
+    uint8_t num_sdu;
+    uint8_t num_pdu;
+    uint8_t pdu_offset = 0;
+    uint8_t frag_len = 0;
+    uint8_t rem_len = 0;
+    uint8_t hdr_len = 0;
+    int pkt_freed = 0;
+    bool sc = mux->sc;
+    os_sr_t sr;
+
+    num_sdu = mux->sdu_in_event;
+    if (num_sdu == 0) {
+        return 0;
+    }
+
+    num_pdu = mux->bn;
+
+#if MYNEWT_VAL(BLE_LL_ISO_HCI_DISCARD_THRESHOLD)
+    /* Drop queued SDUs if number of queued SDUs exceeds defined threshold.
+     * Threshold is defined as number of ISO events. If number of queued SDUs
+     * exceeds number of SDUs required for single event (i.e. including pt)
+     * and number of subsequent ISO events defined by threshold value, we'll
+     * drop any excessive SDUs and notify host as if they were sent.
+     */
+    uint32_t thr = MYNEWT_VAL(BLE_LL_ISO_HCI_DISCARD_THRESHOLD);
+    if (mux->sdu_q_len > mux->sdu_per_event + thr * mux->sdu_per_interval) {
+        num_sdu = mux->sdu_q_len - mux->sdu_per_event -
+                  thr * mux->sdu_per_interval;
+    }
+#endif
+
+    /* Drop num_pdu PDUs */
+    pkthdr = STAILQ_FIRST(&mux->sdu_q);
+    while (pkthdr && num_sdu--) {
+        om = OS_MBUF_PKTHDR_TO_MBUF(pkthdr);
+
+        while (om && num_pdu > 0) {
+            rem_len = om->om_len;
+            hdr_len = sc ? 2 /* Segmentation Header */
+                         : 5 /* Segmentation Header + TimeOffset */;
+
+            if (mux->max_pdu <= hdr_len + pdu_offset) {
+                /* Advance to next PDU */
+                pdu_offset = 0;
+                num_pdu--;
+                continue;
+            }
+
+            frag_len = min(rem_len, mux->max_pdu - hdr_len - pdu_offset);
+
+            pdu_offset += hdr_len + frag_len;
+
+            os_mbuf_adj(om, frag_len);
+
+            if (frag_len == rem_len) {
+                om_next = SLIST_NEXT(om, om_next);
+                os_mbuf_free(om);
+                pkt_freed++;
+                om = om_next;
+            } else {
+                sc = 1;
+            }
+        }
+
+        if (num_pdu == 0) {
+            break;
+        }
+
+        OS_ENTER_CRITICAL(sr);
+        STAILQ_REMOVE_HEAD(&mux->sdu_q, omp_next);
+        BLE_LL_ASSERT(mux->sdu_q_len > 0);
+        mux->sdu_q_len--;
+        OS_EXIT_CRITICAL(sr);
+
+        sc = 0;
+        pkthdr = STAILQ_FIRST(&mux->sdu_q);
+    }
+
+    mux->sdu_in_event = 0;
+    mux->sc = sc;
+
+    return pkt_freed;
+}
+
 int
+ble_ll_isoal_mux_event_done(struct ble_ll_isoal_mux *mux)
+{
+    struct os_mbuf_pkthdr *pkthdr;
+    struct ble_mbuf_hdr *blehdr;
+    struct os_mbuf *om;
+
+    pkthdr = STAILQ_FIRST(&mux->sdu_q);
+    if (pkthdr) {
+        om = OS_MBUF_PKTHDR_TO_MBUF(pkthdr);
+        blehdr = BLE_MBUF_HDR_PTR(om);
+        mux->last_tx_timestamp = mux->event_tx_timestamp;
+        mux->last_tx_packet_seq_num = blehdr->txiso.packet_seq_num;
+    }
+
+    if (mux->framed) {
+        return ble_ll_isoal_mux_framed_event_done(mux);
+    }
+
+    return ble_ll_isoal_mux_unframed_event_done(mux);
+}
+
+static int
 ble_ll_isoal_mux_unframed_get(struct ble_ll_isoal_mux *mux, uint8_t idx,
                               uint8_t *llid, void *dptr)
 {
@@ -258,96 +338,141 @@ ble_ll_isoal_mux_unframed_get(struct ble_ll_isoal_mux 
*mux, uint8_t idx,
     return pdu_len;
 }
 
-static void
-ble_ll_isoal_tx_pkt_in(struct ble_npl_event *ev)
+static int
+ble_ll_isoal_mux_framed_get(struct ble_ll_isoal_mux *mux, uint8_t idx,
+                            uint8_t *llid, uint8_t *dptr)
 {
-    struct os_mbuf *om;
+    struct ble_mbuf_hdr *blehdr;
     struct os_mbuf_pkthdr *pkthdr;
-    struct ble_hci_iso *hci_iso;
-    struct ble_hci_iso_data *hci_iso_data;
-    struct ble_ll_isoal_mux *mux;
-    uint16_t data_hdr_len;
-    uint16_t handle;
-    uint16_t conn_handle;
-    uint16_t length;
-    uint16_t pb_flag;
-    uint16_t ts_flag;
-    uint32_t timestamp = 0;
-    os_sr_t sr;
+    struct os_mbuf *om;
+    uint32_t time_offset;
+    uint16_t seghdr;
+    uint16_t rem_len = 0;
+    uint16_t sdu_offset = 0;
+    uint8_t num_sdu;
+    uint8_t num_pdu;
+    uint8_t frag_len;
+    uint8_t pdu_offset = 0;
+    bool sc = mux->sc;
+    uint8_t hdr_len = 0;
+
+    *llid = 0b10;
 
-    while (STAILQ_FIRST(&ll_isoal_tx_q)) {
-        pkthdr = STAILQ_FIRST(&ll_isoal_tx_q);
+    num_sdu = mux->sdu_in_event;
+    if (num_sdu == 0) {
+        return 0;
+    }
+
+    num_pdu = idx;
+
+    /* Skip the idx PDUs */
+    pkthdr = STAILQ_FIRST(&mux->sdu_q);
+    while (pkthdr && num_sdu > 0 && num_pdu > 0) {
         om = OS_MBUF_PKTHDR_TO_MBUF(pkthdr);
 
-        OS_ENTER_CRITICAL(sr);
-        STAILQ_REMOVE_HEAD(&ll_isoal_tx_q, omp_next);
-        OS_EXIT_CRITICAL(sr);
+        rem_len = OS_MBUF_PKTLEN(om) - sdu_offset;
+        hdr_len = sc ? 2 /* Segmentation Header */
+                     : 5 /* Segmentation Header + TimeOffset */;
 
-        hci_iso = (void *)om->om_data;
+        if (mux->max_pdu <= hdr_len + pdu_offset) {
+            /* Advance to next PDU */
+            pdu_offset = 0;
+            num_pdu--;
+            continue;
+        }
 
-        handle = le16toh(hci_iso->handle);
-        conn_handle = BLE_HCI_ISO_CONN_HANDLE(handle);
-        pb_flag = BLE_HCI_ISO_PB_FLAG(handle);
-        ts_flag = BLE_HCI_ISO_TS_FLAG(handle);
-        length = BLE_HCI_ISO_LENGTH(le16toh(hci_iso->length));
+        frag_len = min(rem_len, mux->max_pdu - hdr_len - pdu_offset);
 
-        data_hdr_len = 0;
-        if ((pb_flag == BLE_HCI_ISO_PB_FIRST) ||
-            (pb_flag == BLE_HCI_ISO_PB_COMPLETE)) {
-            if (ts_flag) {
-                timestamp = get_le32(om->om_data + sizeof(*hci_iso));
-                data_hdr_len += sizeof(uint32_t);
-            }
+        pdu_offset += hdr_len + frag_len;
+
+        if (frag_len == rem_len) {
+            /* Process next SDU */
+            sdu_offset = 0;
+            num_sdu--;
+            pkthdr = STAILQ_NEXT(pkthdr, omp_next);
+
+            sc = 0;
+        } else {
+            sdu_offset += frag_len;
 
-            hci_iso_data = (void *)(om->om_data + sizeof(*hci_iso) + 
data_hdr_len);
-            data_hdr_len += sizeof(*hci_iso_data);
+            sc = 1;
         }
-        os_mbuf_adj(om, sizeof(*hci_iso) + data_hdr_len);
+    }
 
-        if (OS_MBUF_PKTLEN(om) != length - data_hdr_len) {
-            os_mbuf_free_chain(om);
-            continue;
+    if (num_pdu > 0) {
+        return 0;
+    }
+
+    BLE_LL_ASSERT(pdu_offset == 0);
+
+    while (pkthdr && num_sdu > 0) {
+        om = OS_MBUF_PKTHDR_TO_MBUF(pkthdr);
+
+        rem_len = OS_MBUF_PKTLEN(om) - sdu_offset;
+        hdr_len = sc ? 2 /* Segmentation Header */
+                     : 5 /* Segmentation Header + TimeOffset */;
+
+        if (mux->max_pdu <= hdr_len + pdu_offset) {
+            break;
         }
 
-        mux = ble_ll_iso_find_mux_by_handle(conn_handle);
-        if (!mux) {
-            os_mbuf_free_chain(om);
-            continue;
+        frag_len = min(rem_len, mux->max_pdu - hdr_len - pdu_offset);
+
+        /* Segmentation Header */
+        seghdr = BLE_LL_ISOAL_SEGHDR(sc, frag_len == rem_len, frag_len + 
hdr_len - 2);
+        put_le16(dptr + pdu_offset, seghdr);
+        pdu_offset += 2;
+
+        /* Time Offset */
+        if (hdr_len > 2) {
+            blehdr = BLE_MBUF_HDR_PTR(om);
+
+            time_offset = mux->event_tx_timestamp -
+                          blehdr->txiso.cpu_timestamp;
+            put_le24(dptr + pdu_offset, time_offset);
+            pdu_offset += 3;
+        }
+
+        /* ISO Data Fragment */
+        os_mbuf_copydata(om, sdu_offset, frag_len, dptr + pdu_offset);
+        pdu_offset += frag_len;
+
+        if (frag_len == rem_len) {
+            /* Process next SDU */
+            sdu_offset = 0;
+            num_sdu--;
+            pkthdr = STAILQ_NEXT(pkthdr, omp_next);
+
+            sc = 0;
+        } else {
+            sdu_offset += frag_len;
+
+            sc = 1;
         }
+    }
+
+    return pdu_offset;
+}
 
-        ble_ll_isoal_mux_tx_pkt_in(mux, om, pb_flag, timestamp);
+int
+ble_ll_isoal_mux_pdu_get(struct ble_ll_isoal_mux *mux, uint8_t idx,
+                         uint8_t *llid, void *dptr)
+{
+    if (mux->framed) {
+        return ble_ll_isoal_mux_framed_get(mux, idx, llid, dptr);
     }
+
+    return ble_ll_isoal_mux_unframed_get(mux, idx, llid, dptr);
 }
 
 void
 ble_ll_isoal_init(void)
 {
-    STAILQ_INIT(&ll_isoal_tx_q);
-    ble_npl_event_init(&ll_isoal_tx_pkt_in, ble_ll_isoal_tx_pkt_in, NULL);
 }
 
 void
 ble_ll_isoal_reset(void)
 {
-    STAILQ_INIT(&ll_isoal_tx_q);
-    ble_npl_eventq_remove(&g_ble_ll_data.ll_evq, &ll_isoal_tx_pkt_in);
-}
-
-int
-ble_ll_isoal_data_in(struct os_mbuf *om)
-{
-    struct os_mbuf_pkthdr *hdr;
-    os_sr_t sr;
-
-    hdr = OS_MBUF_PKTHDR(om);
-
-    OS_ENTER_CRITICAL(sr);
-    STAILQ_INSERT_TAIL(&ll_isoal_tx_q, hdr, omp_next);
-    OS_EXIT_CRITICAL(sr);
-
-    ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &ll_isoal_tx_pkt_in);
-
-    return 0;
 }
 
 #endif /* BLE_LL_ISO */
diff --git a/nimble/controller/test/src/ble_ll_isoal.c 
b/nimble/controller/test/src/ble_ll_isoal.c
new file mode 100644
index 000000000..c10006c14
--- /dev/null
+++ b/nimble/controller/test/src/ble_ll_isoal.c
@@ -0,0 +1,966 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <stdint.h>
+#include <controller/ble_ll_isoal.h>
+#include <os/os_mbuf.h>
+#include <nimble/ble.h>
+#include <nimble/hci_common.h>
+#include <testutil/testutil.h>
+
+#define TSPX_max_sdu_length         (503)
+#define HCI_iso_sdu_max             (MYNEWT_VAL(BLE_TRANSPORT_ISO_SIZE) - 4)
+
+#define MBUF_TEST_POOL_BUF_SIZE     (TSPX_max_sdu_length + 
BLE_MBUF_MEMBLOCK_OVERHEAD)
+#define MBUF_TEST_POOL_BUF_COUNT    (10)
+
+os_membuf_t os_mbuf_membuf[OS_MEMPOOL_SIZE(MBUF_TEST_POOL_BUF_SIZE, 
MBUF_TEST_POOL_BUF_COUNT)];
+
+static struct os_mbuf_pool os_mbuf_pool;
+static struct os_mempool os_mbuf_mempool;
+static uint8_t os_mbuf_test_data[TSPX_max_sdu_length];
+
+void
+os_mbuf_test_setup(void)
+{
+    int rc;
+    int i;
+
+    rc = os_mempool_init(&os_mbuf_mempool, MBUF_TEST_POOL_BUF_COUNT,
+                         MBUF_TEST_POOL_BUF_SIZE, &os_mbuf_membuf[0], 
"mbuf_pool");
+    TEST_ASSERT_FATAL(rc == 0, "Error creating memory pool %d", rc);
+
+    rc = os_mbuf_pool_init(&os_mbuf_pool, &os_mbuf_mempool,
+                           MBUF_TEST_POOL_BUF_SIZE, MBUF_TEST_POOL_BUF_COUNT);
+    TEST_ASSERT_FATAL(rc == 0, "Error creating mbuf pool %d", rc);
+
+    for (i = 0; i < sizeof os_mbuf_test_data; i++) {
+        os_mbuf_test_data[i] = i;
+    }
+
+    TEST_ASSERT_FATAL(os_mbuf_mempool.mp_block_size == MBUF_TEST_POOL_BUF_SIZE,
+                      "mp_block_size is %d", os_mbuf_mempool.mp_block_size);
+    TEST_ASSERT_FATAL(os_mbuf_mempool.mp_num_free == MBUF_TEST_POOL_BUF_COUNT,
+                      "mp_num_free is %d", os_mbuf_mempool.mp_num_free);
+}
+
+TEST_CASE_SELF(test_ble_ll_isoal_mux_init) {
+    struct ble_ll_isoal_mux mux;
+    const uint32_t iso_interval_us = 10000;
+    const uint32_t sdu_interval_us = 10000;
+    const bool Framed = 0;
+    const bool Framing_Mode = 0;
+    const uint8_t bn = 1;
+    const uint8_t max_pdu = 250;
+
+    ble_ll_isoal_mux_init(&mux, max_pdu, iso_interval_us, sdu_interval_us, bn,
+                          0, Framed, Framing_Mode);
+
+    TEST_ASSERT(mux.pdu_per_sdu == (bn * sdu_interval_us) / iso_interval_us);
+
+    ble_ll_isoal_mux_free(&mux);
+}
+
+TEST_CASE_SELF(ble_ll_isoal_mux_pdu_get_unframed_1_sdu_2_pdu) {
+    struct ble_ll_isoal_mux mux;
+    struct os_mbuf *sdu_1, *sdu_2;
+    const uint32_t iso_interval_us = 20000;
+    const uint32_t sdu_interval_us = 10000;
+    const bool Framed = 0;
+    const bool Framing_Mode = 0;
+    const uint8_t bn = 6;
+    const uint8_t max_pdu = 40;
+    const uint8_t sdu_len = 3 * max_pdu;
+    static uint8_t data[40];
+    int num_completed_pkt;
+    int pdu_len;
+    uint8_t llid = 0x00;
+    int rc;
+
+    ble_ll_isoal_mux_init(&mux, max_pdu, iso_interval_us, sdu_interval_us, bn,
+                          0, Framed, Framing_Mode);
+
+    /* SDU #1 */
+    sdu_1 = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr));
+    TEST_ASSERT_FATAL(sdu_1 != NULL);
+    rc = os_mbuf_append(sdu_1, os_mbuf_test_data, sdu_len);
+    TEST_ASSERT_FATAL(rc == 0);
+    ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_1);
+
+    /* SDU #2 */
+    sdu_2 = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr));
+    TEST_ASSERT_FATAL(sdu_2 != NULL);
+    rc = os_mbuf_append(sdu_2, os_mbuf_test_data, sdu_len);
+    TEST_ASSERT_FATAL(rc == 0);
+    ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_2);
+
+    ble_ll_isoal_mux_event_start(&mux, 90990);
+
+    /* PDU #1 */
+    pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data);
+    TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len);
+    /* Unframed CIS Data PDU; start or continuation fragment of an SDU. */
+    TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid);
+
+    /* PDU #2 */
+    pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, data);
+    TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len);
+    /* Unframed CIS Data PDU; start or continuation fragment of an SDU. */
+    TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid);
+
+    /* PDU #3 */
+    pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 2, &llid, data);
+    TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len);
+    /* Unframed CIS Data PDU; end fragment of an SDU or a complete SDU. */
+    TEST_ASSERT(llid == 0b00, "LLID is incorrect %d", llid);
+
+    /* PDU #4 */
+    pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data);
+    TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len);
+    /* Unframed CIS Data PDU; start or continuation fragment of an SDU. */
+    TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid);
+
+    /* PDU #5 */
+    pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, data);
+    TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len);
+    /* Unframed CIS Data PDU; start or continuation fragment of an SDU. */
+    TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid);
+
+    /* PDU #6 */
+    pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 2, &llid, data);
+    TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len);
+    /* Unframed CIS Data PDU; end fragment of an SDU or a complete SDU. */
+    TEST_ASSERT(llid == 0b00, "LLID is incorrect %d", llid);
+
+    num_completed_pkt = ble_ll_isoal_mux_event_done(&mux);
+    TEST_ASSERT(num_completed_pkt > 0, "num_completed_pkt is incorrect %d", 
num_completed_pkt);
+
+    ble_ll_isoal_mux_free(&mux);
+}
+
+TEST_CASE_SELF(test_ble_ll_isoal_mux_get_unframed_pdu) {
+    struct ble_ll_isoal_mux mux;
+    struct os_mbuf *sdu_1, *sdu_2;
+    const uint32_t iso_interval_us = 20000;
+    const uint32_t sdu_interval_us = 10000;
+    const bool Framed = 0;
+    const bool Framing_Mode = 0;
+    const uint8_t bn = 6;
+    const uint8_t max_pdu = 40;
+    const uint8_t sdu_len = 3 * max_pdu;
+    static uint8_t data[40];
+    int num_completed_pkt;
+    int pdu_len;
+    uint8_t llid = 0x00;
+    int rc;
+
+    ble_ll_isoal_mux_init(&mux, max_pdu, iso_interval_us, sdu_interval_us, bn,
+                          0, Framed, Framing_Mode);
+
+    /* SDU #1 */
+    sdu_1 = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr));
+    TEST_ASSERT_FATAL(sdu_1 != NULL);
+    rc = os_mbuf_append(sdu_1, os_mbuf_test_data, sdu_len);
+    TEST_ASSERT_FATAL(rc == 0);
+    ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_1);
+
+    /* SDU #2 */
+    sdu_2 = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr));
+    TEST_ASSERT_FATAL(sdu_2 != NULL);
+    rc = os_mbuf_append(sdu_2, os_mbuf_test_data, sdu_len);
+    TEST_ASSERT_FATAL(rc == 0);
+    ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_2);
+
+    ble_ll_isoal_mux_event_start(&mux, 90990);
+
+    /* PDU #1 */
+    pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data);
+    TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len);
+    /* Unframed CIS Data PDU; start or continuation fragment of an SDU. */
+    TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid);
+
+    /* PDU #2 */
+    pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, data);
+    TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len);
+    /* Unframed CIS Data PDU; start or continuation fragment of an SDU. */
+    TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid);
+
+    /* PDU #3 */
+    pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 2, &llid, data);
+    TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len);
+    /* Unframed CIS Data PDU; end fragment of an SDU or a complete SDU. */
+    TEST_ASSERT(llid == 0b00, "LLID is incorrect %d", llid);
+
+    /* PDU #4 */
+    pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data);
+    TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len);
+    /* Unframed CIS Data PDU; start or continuation fragment of an SDU. */
+    TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid);
+
+    /* PDU #5 */
+    pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, data);
+    TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len);
+    /* Unframed CIS Data PDU; start or continuation fragment of an SDU. */
+    TEST_ASSERT(llid == 0b01, "LLID is incorrect %d", llid);
+
+    /* PDU #6 */
+    pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 2, &llid, data);
+    TEST_ASSERT(pdu_len == max_pdu, "PDU length is incorrect %d", pdu_len);
+    /* Unframed CIS Data PDU; end fragment of an SDU or a complete SDU. */
+    TEST_ASSERT(llid == 0b00, "LLID is incorrect %d", llid);
+
+    num_completed_pkt = ble_ll_isoal_mux_event_done(&mux);
+    TEST_ASSERT(num_completed_pkt > 0, "num_completed_pkt is incorrect %d",
+                num_completed_pkt);
+
+    ble_ll_isoal_mux_free(&mux);
+}
+
+TEST_CASE_SELF(test_ble_ll_isoal_mux_sdu_not_in_event) {
+    struct ble_ll_isoal_mux mux;
+    struct os_mbuf *sdu_1;
+    const uint32_t iso_interval_us = 10000;
+    const uint32_t sdu_interval_us = 10000;
+    const bool Framed = 1;
+    const bool Framing_Mode = 0;
+    const uint8_t bn = 2;
+    const uint8_t max_pdu = 40;
+    const uint8_t sdu_len = 40;
+    static uint8_t data[40];
+    int num_completed_pkt;
+    int pdu_len;
+    uint8_t llid = 0x00;
+    int rc;
+
+    ble_ll_isoal_mux_init(&mux, max_pdu, iso_interval_us, sdu_interval_us, bn,
+                          0, Framed, Framing_Mode);
+
+    ble_ll_isoal_mux_event_start(&mux, 90990);
+    TEST_ASSERT_FATAL(mux.sdu_in_event == 0,
+                      "sdu_in_event %d != 0", mux.sdu_in_event);
+
+    /* SDU #1 */
+    sdu_1 = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr));
+    TEST_ASSERT_FATAL(sdu_1 != NULL);
+    rc = os_mbuf_append(sdu_1, os_mbuf_test_data, sdu_len);
+    TEST_ASSERT_FATAL(rc == 0);
+    ble_ll_isoal_mux_sdu_enqueue(&mux, sdu_1);
+
+    TEST_ASSERT_FATAL(mux.sdu_in_event == 0,
+                      "sdu_in_event %d != 0", mux.sdu_in_event);
+
+    /* PDU #1 */
+    pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, data);
+    TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len);
+    TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid);
+
+    /* PDU #2 */
+    pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 1, &llid, data);
+    TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len);
+    TEST_ASSERT(llid == 0b10, "LLID is incorrect %d", llid);
+
+    num_completed_pkt = ble_ll_isoal_mux_event_done(&mux);
+    TEST_ASSERT(num_completed_pkt == 0, "num_completed_pkt is incorrect %d",
+                num_completed_pkt);
+
+    ble_ll_isoal_mux_free(&mux);
+}
+
+static int
+test_sdu_enqueue(struct ble_ll_isoal_mux *mux, uint16_t sdu_len,
+                 uint16_t packet_seq_num, uint32_t timestamp)
+{
+    struct ble_mbuf_hdr *blehdr;
+    struct os_mbuf *sdu, *frag;
+    uint16_t sdu_frag_len;
+    uint16_t offset = 0;
+    uint8_t num_pkt = 0;
+    int rc;
+
+    TEST_ASSERT_FATAL(sdu_len <= TSPX_max_sdu_length, "incorrect sdu length");
+
+    sdu = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr));
+    TEST_ASSERT_FATAL(sdu != NULL);
+    blehdr = BLE_MBUF_HDR_PTR(sdu);
+    blehdr->txiso.packet_seq_num = packet_seq_num;
+    blehdr->txiso.cpu_timestamp = timestamp;
+
+    /* First SDU Fragment */
+    sdu_frag_len = min(sdu_len, HCI_iso_sdu_max);
+    rc = os_mbuf_append(sdu, os_mbuf_test_data, sdu_frag_len);
+    TEST_ASSERT_FATAL(rc == 0);
+
+    offset += sdu_frag_len;
+    num_pkt++;
+
+    while (offset < sdu_len) {
+        frag = os_mbuf_get_pkthdr(&os_mbuf_pool, sizeof(struct ble_mbuf_hdr));
+        TEST_ASSERT_FATAL(frag != NULL);
+
+        /* Subsequent SDU Fragments */
+        sdu_frag_len = min(sdu_len - offset, HCI_iso_sdu_max);
+        rc = os_mbuf_append(sdu, &os_mbuf_test_data[offset], sdu_frag_len);
+        TEST_ASSERT_FATAL(rc == 0);
+
+        offset += sdu_frag_len;
+        num_pkt++;
+
+        os_mbuf_concat(sdu, frag);
+    }
+
+    ble_ll_isoal_mux_sdu_enqueue(mux, sdu);
+
+    return num_pkt;
+}
+
+static void
+test_pdu_verify(uint8_t *pdu, int pdu_len, uint16_t sdu_offset)
+{
+    for (int i = 0; i < pdu_len; i++) {
+        TEST_ASSERT(pdu[i] == os_mbuf_test_data[sdu_offset + i],
+                    "PDU verification failed pdu[%d] %d != %d",
+                    i, pdu[i], os_mbuf_test_data[sdu_offset + i]);
+    }
+}
+
+struct test_ial_broadcast_single_sdu_bis_cfg {
+    uint8_t NSE;
+    uint8_t Framed;
+    uint8_t Framing_Mode;
+    uint8_t Max_PDU;
+    uint8_t LLID;
+    uint8_t BN;
+    uint32_t SDU_Interval;
+    uint32_t ISO_Interval;
+};
+
+static void
+test_ial_teardown(struct ble_ll_isoal_mux *mux)
+{
+    ble_ll_isoal_mux_free(mux);
+    TEST_ASSERT_FATAL(os_mbuf_mempool.mp_block_size == MBUF_TEST_POOL_BUF_SIZE,
+                      "mp_block_size is %d", os_mbuf_mempool.mp_block_size);
+    TEST_ASSERT_FATAL(os_mbuf_mempool.mp_num_free == MBUF_TEST_POOL_BUF_COUNT,
+                      "mp_num_free is %d", os_mbuf_mempool.mp_num_free);
+}
+
+static void
+test_ial_setup(struct ble_ll_isoal_mux *mux, uint8_t max_pdu,
+               uint32_t iso_interval_us, uint32_t sdu_interval_us,
+               uint8_t bn, uint8_t pte, bool framed, uint8_t framing_mode)
+{
+    ble_ll_isoal_mux_init(mux, max_pdu, iso_interval_us, sdu_interval_us,
+                          bn, pte, framed, framing_mode);
+}
+
+static void
+test_ial_broadcast_single_sdu_bis(const struct 
test_ial_broadcast_single_sdu_bis_cfg *cfg)
+{
+    struct ble_ll_isoal_mux mux;
+    int num_completed_pkt;
+    int pdu_len;
+    uint32_t timeoffset;
+    uint16_t seg_hdr;
+    const uint8_t Max_SDU = 32;
+    uint8_t pdu[cfg->Max_PDU];
+    uint8_t llid = 0xff;
+
+    test_ial_setup(&mux, cfg->Max_PDU, cfg->ISO_Interval,
+                   cfg->SDU_Interval, cfg->BN, 0, cfg->Framed,
+                   cfg->Framing_Mode);
+
+    /* Send Single SDU */
+    test_sdu_enqueue(&mux, Max_SDU, 0, 20000);
+
+    ble_ll_isoal_mux_event_start(&mux, 30500);
+
+    /* PDU #1 */
+    pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, pdu);
+    TEST_ASSERT(llid == cfg->LLID, "LLID is incorrect %d", llid);
+
+    if (cfg->Framed) {
+        TEST_ASSERT(pdu_len == 2 /* Header */ + 3 /* TimeOffset */ + Max_SDU,
+                    "PDU length is incorrect %d", pdu_len);
+        seg_hdr = get_le16(&pdu[0]);
+        TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_SC(seg_hdr) == 0, "SC is incorrect %d",
+                    BLE_LL_ISOAL_SEGHDR_SC(seg_hdr));
+        TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_CMPLT(seg_hdr) == 1, "CMPLT is 
incorrect %d",
+                    BLE_LL_ISOAL_SEGHDR_CMPLT(seg_hdr));
+        TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_LEN(seg_hdr) == 3 /* TimeOffset */ + 
Max_SDU,
+                    "Length is incorrect %d", 
BLE_LL_ISOAL_SEGHDR_LEN(seg_hdr));
+        timeoffset = get_le24(&pdu[2]);
+        TEST_ASSERT(timeoffset == 10500, "Time offset is incorrect %d", 
timeoffset);
+
+        test_pdu_verify(&pdu[5], Max_SDU, 0);
+    } else {
+        TEST_ASSERT(pdu_len == Max_SDU, "PDU length is incorrect %d", pdu_len);
+
+        test_pdu_verify(&pdu[0], Max_SDU, 0);
+    }
+
+    num_completed_pkt = ble_ll_isoal_mux_event_done(&mux);
+    TEST_ASSERT(num_completed_pkt > 0, "num_completed_pkt is incorrect %d", 
num_completed_pkt);
+
+    test_ial_teardown(&mux);
+}
+
+TEST_CASE_SELF(test_ial_bis_unf_brd_bv_01_c) {
+    const struct test_ial_broadcast_single_sdu_bis_cfg cfg = {
+        .NSE = 2,
+        .Framed = 0,
+        .Framing_Mode = 0,
+        .Max_PDU = 40,
+        .LLID = 0b00,
+        .BN = 1,
+        .SDU_Interval = 10000,
+        .ISO_Interval = 10000,
+    };
+
+    test_ial_broadcast_single_sdu_bis(&cfg);
+}
+
+TEST_CASE_SELF(test_ial_bis_unf_brd_bv_02_c) {
+    const struct test_ial_broadcast_single_sdu_bis_cfg cfg = {
+        .NSE = 4,
+        .Framed = 0,
+        .Framing_Mode = 0,
+        .Max_PDU = 40,
+        .LLID = 0b00,
+        .BN = 2,
+        .SDU_Interval = 5000,
+        .ISO_Interval = 10000,
+    };
+
+    test_ial_broadcast_single_sdu_bis(&cfg);
+}
+
+TEST_CASE_SELF(test_ial_bis_fra_brd_bv_06_c) {
+    const struct test_ial_broadcast_single_sdu_bis_cfg cfg = {
+        .NSE = 4,
+        .Framed = 1,
+        .Framing_Mode = 0,
+        .Max_PDU = 40,
+        .LLID = 0b10,
+        .BN = 2,
+        .SDU_Interval = 5000,
+        .ISO_Interval = 10000,
+    };
+
+    test_ial_broadcast_single_sdu_bis(&cfg);
+}
+
+TEST_CASE_SELF(test_ial_bis_fra_brd_bv_08_c) {
+    const struct test_ial_broadcast_single_sdu_bis_cfg cfg = {
+        .NSE = 2,
+        .Framed = 1,
+        .Framing_Mode = 0,
+        .Max_PDU = 40,
+        .LLID = 0b10,
+        .BN = 1,
+        .SDU_Interval = 10000,
+        .ISO_Interval = 10000,
+    };
+
+    test_ial_broadcast_single_sdu_bis(&cfg);
+}
+
+TEST_CASE_SELF(test_ial_bis_fra_brd_bv_29_c) {
+    const struct test_ial_broadcast_single_sdu_bis_cfg cfg = {
+        .NSE = 6,
+        .Framed = 1,
+        .Framing_Mode = 1,
+        .Max_PDU = 32 + 5,
+        .LLID = 0b10,
+        .BN = 3,
+        .SDU_Interval = 5000,
+        .ISO_Interval = 10000,
+    };
+
+    test_ial_broadcast_single_sdu_bis(&cfg);
+}
+
+struct test_ial_broadcast_large_sdu_bis_cfg {
+    uint8_t NSE;
+    uint8_t Framed;
+    uint8_t Framing_Mode;
+    uint8_t BN;
+    uint32_t SDU_Interval;
+    uint32_t ISO_Interval;
+};
+struct test_ial_broadcast_large_sdu_bis_round {
+    uint16_t sdu_len;
+    uint8_t sc_packets_num;
+};
+
+static void
+test_ial_broadcast_large_sdu_bis(const struct 
test_ial_broadcast_large_sdu_bis_cfg *cfg)
+{
+    const struct test_ial_broadcast_large_sdu_bis_round rounds[] = {
+        {.sdu_len = 495, .sc_packets_num = 1},
+        {.sdu_len = 503, .sc_packets_num = 2},
+    };
+    struct ble_ll_isoal_mux mux;
+    /* const uint16_t Max_SDU = 503; */
+    const uint8_t Max_PDU = 251;
+    int num_completed_pkt;
+    int num_expected_pkt;
+    int pdu_len;
+    uint8_t pdu[Max_PDU];
+    uint32_t timestamp;
+    uint16_t seg_hdr;
+    uint16_t sdu_offset;
+    uint8_t llid = 0xff;
+    uint8_t sc_packets_num;
+    uint8_t seg_len;
+    uint8_t idx;
+
+    test_ial_setup(&mux, Max_PDU, cfg->ISO_Interval,
+                   cfg->SDU_Interval, cfg->BN, 0, cfg->Framed,
+                   cfg->Framing_Mode);
+
+    for (size_t round = 0; round < ARRAY_SIZE(rounds); round++) {
+        sc_packets_num = 0;
+        sdu_offset = 0;
+
+        timestamp = (round + 1) * cfg->SDU_Interval;
+
+        num_expected_pkt = test_sdu_enqueue(&mux, rounds[round].sdu_len, 
round, timestamp);
+
+        ble_ll_isoal_mux_event_start(&mux, timestamp + 100);
+
+        for (idx = 0; idx < cfg->BN; idx++) {
+            pdu_len = ble_ll_isoal_mux_pdu_get(&mux, idx, &llid, pdu);
+            if (pdu_len == 0) {
+                TEST_ASSERT_FATAL(sdu_offset == rounds[round].sdu_len,
+                                  "Round #%d: idx %d sdu_offset %d",
+                                  round, idx, sdu_offset);
+                continue;
+            }
+
+            /* The IUT sends the specified number of Start/Continuation
+             * packets specified in Table 4.29 of ISO Data PDUs to the
+             * Lower Tester with the LLID=0b01 for unframed payloads and
+             * LLID=0b10 for framed payloads, and Payload Data every 251
+             * bytes offset in step 1.
+             */
+            if (sc_packets_num < rounds[round].sc_packets_num) {
+                TEST_ASSERT_FATAL(pdu_len == 251, "Round #%d: idx #%d: Length 
is incorrect %d",
+                                  round, idx, pdu_len);
+
+                if (cfg->Framed) {
+                    TEST_ASSERT_FATAL(llid == 0b10, "Round #%d: LLID is 
incorrect %d", round, llid);
+
+                    seg_hdr = get_le16(&pdu[0]);
+                    seg_len = BLE_LL_ISOAL_SEGHDR_LEN(seg_hdr);
+                    if (idx == 0) {
+                        TEST_ASSERT_FATAL(BLE_LL_ISOAL_SEGHDR_SC(seg_hdr) == 0,
+                                          "Round #%d: SC is incorrect %d",
+                                          round, 
BLE_LL_ISOAL_SEGHDR_SC(seg_hdr));
+
+                        test_pdu_verify(&pdu[5], seg_len - 3, 0);
+                        sdu_offset += seg_len - 3;
+                    } else {
+                        TEST_ASSERT_FATAL(BLE_LL_ISOAL_SEGHDR_SC(seg_hdr) == 1,
+                                          "Round #%d: SC is incorrect %d",
+                                          round, 
BLE_LL_ISOAL_SEGHDR_SC(seg_hdr));
+
+                        test_pdu_verify(&pdu[2], seg_len, sdu_offset);
+                        sdu_offset += seg_len;
+                    }
+                } else {
+                    TEST_ASSERT_FATAL(llid == 0b01, "Round #%d: LLID is 
incorrect %d", round, llid);
+
+                    test_pdu_verify(&pdu[0], pdu_len, sdu_offset);
+                    sdu_offset += pdu_len;
+                }
+
+                sc_packets_num++;
+            } else {
+                /* The IUT sends the last ISO Data PDU to the Lower Tester
+                 * with the LLID=0b00 for unframed payloads and LLID=0b10
+                 * for framed payloads, with the remaining Payload Data.
+                 */
+                if (cfg->Framed) {
+                    TEST_ASSERT_FATAL(pdu_len == rounds[round].sdu_len - 
sdu_offset + 2,
+                                      "Round #%d: idx %d: PDU length is 
incorrect %d != %d",
+                                      round, idx, pdu_len, 
rounds[round].sdu_len - sdu_offset + 2);
+                    TEST_ASSERT_FATAL(llid == 0b10, "Round #%d: LLID is 
incorrect %d",
+                                      round, llid);
+
+                    seg_hdr = get_le16(&pdu[0]);
+                    TEST_ASSERT_FATAL(BLE_LL_ISOAL_SEGHDR_SC(seg_hdr),
+                                      "Round #%d: SC is incorrect %d",
+                                      round, BLE_LL_ISOAL_SEGHDR_SC(seg_hdr));
+                    TEST_ASSERT_FATAL(BLE_LL_ISOAL_SEGHDR_CMPLT(seg_hdr),
+                                      "Round #%d: CMPLT is incorrect %d",
+                                      round, 
BLE_LL_ISOAL_SEGHDR_CMPLT(seg_hdr));
+                    seg_len = BLE_LL_ISOAL_SEGHDR_LEN(seg_hdr);
+
+                    test_pdu_verify(&pdu[2], seg_len, sdu_offset);
+                    sdu_offset += seg_len;
+                } else {
+                    TEST_ASSERT_FATAL(pdu_len == rounds[round].sdu_len - 
sdu_offset,
+                                      "Round #%d: idx %d: PDU length is 
incorrect %d != %d",
+                                      round, idx, pdu_len, 
rounds[round].sdu_len - sdu_offset);
+                    TEST_ASSERT_FATAL(llid == 0b00, "Round #%d: LLID is 
incorrect %d", round, llid);
+
+                    test_pdu_verify(&pdu[0], pdu_len, sdu_offset);
+                    sdu_offset += pdu_len;
+                }
+            }
+        }
+
+        num_completed_pkt = ble_ll_isoal_mux_event_done(&mux);
+        TEST_ASSERT(num_completed_pkt == num_expected_pkt,
+                    "num_completed_pkt %d != %d", num_completed_pkt, 
num_expected_pkt);
+    }
+
+    test_ial_teardown(&mux);
+}
+
+TEST_CASE_SELF(test_ial_bis_fra_brd_bv_13_c) {
+    const struct test_ial_broadcast_large_sdu_bis_cfg cfg = {
+        .NSE = 10,
+        .Framed = 1,
+        .Framing_Mode = 0,
+        .BN = 5,
+        .SDU_Interval = 15000,
+        .ISO_Interval = 30000,
+    };
+
+    test_ial_broadcast_large_sdu_bis(&cfg);
+}
+
+TEST_CASE_SELF(test_ial_bis_fra_brd_bv_15_c) {
+    const struct test_ial_broadcast_large_sdu_bis_cfg cfg = {
+        .NSE = 6,
+        .Framed = 1,
+        .Framing_Mode = 0,
+        .BN = 3,
+        .SDU_Interval = 20000,
+        .ISO_Interval = 20000,
+    };
+
+    test_ial_broadcast_large_sdu_bis(&cfg);
+}
+
+struct test_ial_broadcast_multiple_small_sdus_bis_cfg {
+    uint8_t NSE;
+    uint8_t BN;
+    uint8_t Max_PDU;
+    uint32_t SDU_Interval;
+    uint32_t ISO_Interval;
+};
+
+static void
+test_ial_broadcast_multiple_small_sdus_bis(const struct 
test_ial_broadcast_multiple_small_sdus_bis_cfg *cfg)
+{
+    struct ble_ll_isoal_mux mux;
+    /* const uint16_t Max_SDU = 25; */
+    const uint8_t LLID = 0b10;
+    const uint8_t Framed = 0x01;
+    const uint8_t Framing_Mode = 0;
+    int pdu_len;
+    uint8_t pdu[cfg->Max_PDU];
+    uint32_t sdu_1_ts, sdu_2_ts, event_ts;
+    uint32_t timeoffset;
+    uint16_t seg_hdr;
+    uint8_t llid = 0xff;
+    uint8_t seg_len;
+    uint8_t *seg;
+
+    test_ial_setup(&mux, cfg->Max_PDU, cfg->ISO_Interval,
+                   cfg->SDU_Interval, cfg->BN, 0, Framed,
+                   Framing_Mode);
+
+    /* The Upper Tester sends to the IUT a small SDU1 with data length of 20 
bytes. */
+    sdu_1_ts = 100;
+    test_sdu_enqueue(&mux, 20, 0, sdu_1_ts);
+
+    /* The Upper Tester sends to the IUT a small SDU2 with data length of 25 
bytes. */
+    sdu_2_ts = sdu_1_ts + cfg->SDU_Interval;
+    test_sdu_enqueue(&mux, 25, 0, sdu_2_ts);
+
+    event_ts = sdu_2_ts + 200;
+    ble_ll_isoal_mux_event_start(&mux, event_ts);
+
+    /* The IUT sends a single Broadcast ISO Data PDU with SDU1 followed by 
SDU2 over the BIS.
+     * Each SDU header has SC = 0 and CMPT = 1.
+     */
+    pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, pdu);
+    TEST_ASSERT(llid == LLID, "LLID is incorrect %d", llid);
+
+    /* SDU 1 */
+    seg = &pdu[0];
+    TEST_ASSERT(pdu_len > 24, "PDU length is incorrect %d", pdu_len);
+    seg_hdr = get_le16(&seg[0]);
+    TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_SC(seg_hdr) == 0,
+                "SC is incorrect %d", BLE_LL_ISOAL_SEGHDR_SC(seg_hdr));
+    TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_CMPLT(seg_hdr) == 1,
+                "SC is incorrect %d", BLE_LL_ISOAL_SEGHDR_CMPLT(seg_hdr));
+    seg_len = BLE_LL_ISOAL_SEGHDR_LEN(seg_hdr);
+    TEST_ASSERT(seg_len == 20 + 3, "Segment length is incorrect %d", pdu_len);
+    timeoffset = get_le24(&seg[2]);
+    TEST_ASSERT(timeoffset == event_ts - sdu_1_ts,
+                "Time offset is incorrect %d", timeoffset);
+
+    /* SDU 1 */
+    seg = &pdu[25];
+    TEST_ASSERT(pdu_len == 55, "PDU length is incorrect %d", pdu_len);
+    seg_hdr = get_le16(&seg[0]);
+    TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_SC(seg_hdr) == 0,
+                "SC is incorrect %d", BLE_LL_ISOAL_SEGHDR_SC(seg_hdr));
+    TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_CMPLT(seg_hdr) == 1,
+                "SC is incorrect %d", BLE_LL_ISOAL_SEGHDR_CMPLT(seg_hdr));
+    seg_len = BLE_LL_ISOAL_SEGHDR_LEN(seg_hdr);
+    TEST_ASSERT(seg_len == 25 + 3, "Segment length is incorrect %d", pdu_len);
+    timeoffset = get_le24(&seg[2]);
+    TEST_ASSERT(timeoffset == event_ts - sdu_2_ts,
+                "Time offset is incorrect %d", timeoffset);
+
+    (void)ble_ll_isoal_mux_event_done(&mux);
+
+    test_ial_teardown(&mux);
+}
+
+TEST_CASE_SELF(test_ial_bis_fra_brd_bv_17_c) {
+    const struct test_ial_broadcast_multiple_small_sdus_bis_cfg cfg = {
+        .NSE = 2,
+        .BN = 1,
+        .Max_PDU = 68,
+        .SDU_Interval = 500,
+        .ISO_Interval = 1000,
+    };
+
+    test_ial_broadcast_multiple_small_sdus_bis(&cfg);
+}
+
+TEST_CASE_SELF(test_ial_bis_fra_brd_bv_18_c) {
+    const struct test_ial_broadcast_multiple_small_sdus_bis_cfg cfg = {
+        .NSE = 2,
+        .BN = 1,
+        .Max_PDU = 68,
+        .SDU_Interval = 1000,
+        .ISO_Interval = 2000,
+    };
+
+    test_ial_broadcast_multiple_small_sdus_bis(&cfg);
+}
+
+TEST_CASE_SELF(test_ial_bis_fra_brd_bv_20_c) {
+    const struct test_ial_broadcast_multiple_small_sdus_bis_cfg cfg = {
+        .NSE = 4,
+        .BN = 2,
+        .Max_PDU = 65,
+        .SDU_Interval = 500,
+        .ISO_Interval = 2000,
+    };
+
+    test_ial_broadcast_multiple_small_sdus_bis(&cfg);
+}
+
+struct test_ial_segmentation_header {
+    uint8_t SC;
+    uint8_t CMPLT;
+    uint8_t LENGTH;
+};
+struct test_ial_broadcast_zero_length_sdu_bis_cfg {
+    uint8_t NSE;
+    uint8_t Framed;
+    uint8_t Framing_Mode;
+    uint8_t LLID;
+    uint8_t BN;
+    struct test_ial_segmentation_header Segmentation_Header;
+    bool Time_Offset;
+};
+
+static void
+test_ial_broadcast_zero_length_sdu_bis(const struct 
test_ial_broadcast_zero_length_sdu_bis_cfg *cfg)
+{
+    struct ble_ll_isoal_mux mux;
+    const uint32_t ISO_Interval = 10000;
+    const uint32_t SDU_Interval = 10000;
+    /* const uint16_t Max_SDU = 32; */
+    const uint16_t Max_PDU = 32;
+    int pdu_len;
+    uint8_t pdu[Max_PDU];
+    uint32_t timeoffset;
+    uint16_t seg_hdr;
+    uint8_t llid = 0xff;
+
+    test_ial_setup(&mux, Max_PDU, ISO_Interval, SDU_Interval,
+                   cfg->BN, 0, cfg->Framed, cfg->Framing_Mode);
+
+    /* The Upper Tester sends an HCI ISO Data packet to the IUT with zero data 
length. */
+    test_sdu_enqueue(&mux, 0, 0, 100);
+
+    ble_ll_isoal_mux_event_start(&mux, 500);
+
+    /* The IUT sends a single Broadcast ISO Data PDU with the LLID,
+     * Framed, Framing_Mode, the segmentation header and time offset
+     * fields as specified in Table 4.35. Length is 0 if LLID is 0b00
+     * and is 5 (Segmentation Header + TimeOffset) if LLID is 0b10.
+     * SDU field is empty..
+     */
+    pdu_len = ble_ll_isoal_mux_pdu_get(&mux, 0, &llid, pdu);
+    TEST_ASSERT(llid == cfg->LLID, "LLID is incorrect %d", llid);
+
+    if (cfg->LLID == 0b00) {
+        TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len);
+    } else if (cfg->LLID == 0b01) {
+        TEST_ASSERT(pdu_len == 5, "PDU length is incorrect %d", pdu_len);
+    }
+
+    if (cfg->Framed) {
+        seg_hdr = get_le16(&pdu[0]);
+        TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_SC(seg_hdr) == 
cfg->Segmentation_Header.SC,
+                    "SC is incorrect %d", BLE_LL_ISOAL_SEGHDR_SC(seg_hdr));
+        TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_CMPLT(seg_hdr) == 
cfg->Segmentation_Header.CMPLT,
+                    "CMPLT is incorrect %d", 
BLE_LL_ISOAL_SEGHDR_CMPLT(seg_hdr));
+        TEST_ASSERT(BLE_LL_ISOAL_SEGHDR_LEN(seg_hdr) == 
cfg->Segmentation_Header.LENGTH,
+                    "LENGTH is incorrect %d", 
BLE_LL_ISOAL_SEGHDR_LEN(seg_hdr));
+        timeoffset = get_le24(&pdu[2]);
+        TEST_ASSERT(timeoffset == 400, "Time offset is incorrect %d", 
timeoffset);
+    }
+
+    for (uint8_t idx = 1; idx < cfg->BN; idx++) {
+        pdu_len = ble_ll_isoal_mux_pdu_get(&mux, idx, &llid, pdu);
+        TEST_ASSERT(llid == cfg->LLID, "LLID is incorrect %d", llid);
+        TEST_ASSERT(pdu_len == 0, "PDU length is incorrect %d", pdu_len);
+    }
+
+    (void)ble_ll_isoal_mux_event_done(&mux);
+
+    test_ial_teardown(&mux);
+}
+
+TEST_CASE_SELF(test_ial_bis_fra_brd_bv_25_c) {
+    const struct test_ial_broadcast_zero_length_sdu_bis_cfg cfg = {
+        .NSE = 6,
+        .Framed = 1,
+        .Framing_Mode = 0,
+        .LLID = 0b10,
+        .BN = 2,
+        .Segmentation_Header.SC = 0,
+        .Segmentation_Header.CMPLT = 1,
+        .Segmentation_Header.LENGTH = 3,
+        .Time_Offset = true,
+    };
+
+    test_ial_broadcast_zero_length_sdu_bis(&cfg);
+}
+
+TEST_CASE_SELF(test_ial_bis_fra_brd_bv_26_c) {
+    const struct test_ial_broadcast_zero_length_sdu_bis_cfg cfg = {
+        .NSE = 2,
+        .Framed = 1,
+        .Framing_Mode = 0,
+        .LLID = 0b10,
+        .BN = 1,
+        .Segmentation_Header.SC = 0,
+        .Segmentation_Header.CMPLT = 1,
+        .Segmentation_Header.LENGTH = 3,
+        .Time_Offset = true,
+    };
+
+    test_ial_broadcast_zero_length_sdu_bis(&cfg);
+}
+
+TEST_CASE_SELF(test_ial_bis_fra_brd_bv_27_c) {
+    const struct test_ial_broadcast_zero_length_sdu_bis_cfg cfg = {
+        .NSE = 4,
+        .Framed = 1,
+        .Framing_Mode = 0,
+        .LLID = 0b10,
+        .BN = 1,
+        .Segmentation_Header.SC = 0,
+        .Segmentation_Header.CMPLT = 1,
+        .Segmentation_Header.LENGTH = 3,
+        .Time_Offset = true,
+    };
+
+    test_ial_broadcast_zero_length_sdu_bis(&cfg);
+}
+
+TEST_CASE_SELF(test_ial_bis_fra_brd_bv_28_c) {
+    const struct test_ial_broadcast_zero_length_sdu_bis_cfg cfg = {
+        .NSE = 6,
+        .Framed = 1,
+        .Framing_Mode = 0,
+        .LLID = 0b10,
+        .BN = 3,
+        .Segmentation_Header.SC = 0,
+        .Segmentation_Header.CMPLT = 1,
+        .Segmentation_Header.LENGTH = 3,
+        .Time_Offset = true,
+    };
+
+    test_ial_broadcast_zero_length_sdu_bis(&cfg);
+}
+
+TEST_CASE_SELF(test_ial_bis_fra_brd_bv_30_c) {
+    const struct test_ial_broadcast_zero_length_sdu_bis_cfg cfg = {
+        .NSE = 6,
+        .Framed = 1,
+        .Framing_Mode = 1,
+        .LLID = 0b10,
+        .BN = 2,
+        .Segmentation_Header.SC = 0,
+        .Segmentation_Header.CMPLT = 1,
+        .Segmentation_Header.LENGTH = 3,
+        .Time_Offset = true,
+    };
+
+    test_ial_broadcast_zero_length_sdu_bis(&cfg);
+}
+
+TEST_SUITE(ble_ll_isoal_test_suite) {
+    os_mbuf_test_setup();
+
+    ble_ll_isoal_init();
+
+    test_ble_ll_isoal_mux_init();
+    test_ble_ll_isoal_mux_get_unframed_pdu();
+    test_ble_ll_isoal_mux_sdu_not_in_event();
+
+    /* Broadcast Single SDU, BIS */
+    test_ial_bis_unf_brd_bv_01_c();
+    test_ial_bis_unf_brd_bv_02_c();
+    test_ial_bis_fra_brd_bv_06_c();
+    test_ial_bis_fra_brd_bv_08_c();
+    test_ial_bis_fra_brd_bv_29_c();
+
+    /* Broadcast Large SDU, BIS */
+    test_ial_bis_fra_brd_bv_13_c();
+    test_ial_bis_fra_brd_bv_15_c();
+
+    /* Broadcast Multiple, Small SDUs, BIS */
+    test_ial_bis_fra_brd_bv_17_c();
+    test_ial_bis_fra_brd_bv_18_c();
+    test_ial_bis_fra_brd_bv_20_c();
+
+    /* Broadcast a Zero-Length SDU, BIS */
+    test_ial_bis_fra_brd_bv_25_c();
+    test_ial_bis_fra_brd_bv_26_c();
+    test_ial_bis_fra_brd_bv_27_c();
+    test_ial_bis_fra_brd_bv_28_c();
+    test_ial_bis_fra_brd_bv_30_c();
+
+    ble_ll_isoal_reset();
+}
diff --git a/nimble/controller/test/src/ble_ll_test.c 
b/nimble/controller/test/src/ble_ll_test.c
index 2b36cb1f3..7bfbf9bd2 100644
--- a/nimble/controller/test/src/ble_ll_test.c
+++ b/nimble/controller/test/src/ble_ll_test.c
@@ -25,6 +25,7 @@
 TEST_SUITE_DECL(ble_ll_aa_test_suite);
 TEST_SUITE_DECL(ble_ll_crypto_test_suite);
 TEST_SUITE_DECL(ble_ll_csa2_test_suite);
+TEST_SUITE_DECL(ble_ll_isoal_test_suite);
 
 int
 main(int argc, char **argv)
@@ -32,6 +33,7 @@ main(int argc, char **argv)
     ble_ll_aa_test_suite();
     ble_ll_crypto_test_suite();
     ble_ll_csa2_test_suite();
+    ble_ll_isoal_test_suite();
 
     return tu_any_failed;
 }
diff --git a/nimble/controller/test/syscfg.yml 
b/nimble/controller/test/syscfg.yml
index 6edad438b..f7a3c4ef5 100644
--- a/nimble/controller/test/syscfg.yml
+++ b/nimble/controller/test/syscfg.yml
@@ -18,8 +18,12 @@
 
 syscfg.vals:
     BLE_LL_CFG_FEAT_LE_CSA2: 1
+    BLE_LL_ISO: 1
+    BLE_VERSION: 54
 
     # Prevent priority conflict with controller task.
     MCU_TIMER_POLLER_PRIO: 1
     MCU_UART_POLLER_PRIO: 2
     NATIVE_SOCKETS_PRIO: 3
+
+    BLE_TRANSPORT_ISO_SIZE: 255
diff --git a/nimble/include/nimble/ble.h b/nimble/include/nimble/ble.h
index a2add5d79..d5e41a37c 100644
--- a/nimble/include/nimble/ble.h
+++ b/nimble/include/nimble/ble.h
@@ -128,6 +128,8 @@ struct ble_mbuf_hdr_txinfo
 
 struct ble_mbuf_hdr_txiso {
     uint16_t packet_seq_num;
+    uint32_t cpu_timestamp;
+    uint32_t hci_timestamp;
 };
 
 /**
diff --git a/nimble/include/nimble/hci_common.h 
b/nimble/include/nimble/hci_common.h
index f4fe5a7f8..f1d2eb46d 100644
--- a/nimble/include/nimble/hci_common.h
+++ b/nimble/include/nimble/hci_common.h
@@ -2466,6 +2466,10 @@ struct hci_data_hdr
 
 #define BLE_HCI_ISO_DATA_PATH_ID_HCI            0x00
 
+#define BLE_HCI_ISO_FRAMING_UNFRAMED            0x00
+#define BLE_HCI_ISO_FRAMING_FRAMED_SEGMENTABLE  0x01
+#define BLE_HCI_ISO_FRAMING_FRAMED_UNSEGMENTED  0x02
+
 struct ble_hci_iso {
     uint16_t handle;
     uint16_t length;

Reply via email to