You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by we...@apache.org on 2016/08/16 02:46:03 UTC

incubator-mynewt-core git commit: MYNEWT-83: use a fixed buffer for reception.

Repository: incubator-mynewt-core
Updated Branches:
  refs/heads/develop 02f9f5277 -> 40c072ebd


MYNEWT-83: use a fixed buffer for reception.

The changes for this ticket caused the code to ack a packet at
the link layer even though it was not handed to the host. This
is an error; the link layer should only ack data packets that
were handed to the host.


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/40c072eb
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/40c072eb
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/40c072eb

Branch: refs/heads/develop
Commit: 40c072ebdde316339581823525b5237d4c5565f4
Parents: 02f9f52
Author: William San Filippo <wi...@runtime.io>
Authored: Mon Aug 15 19:44:27 2016 -0700
Committer: William San Filippo <wi...@runtime.io>
Committed: Mon Aug 15 19:45:54 2016 -0700

----------------------------------------------------------------------
 .../controller/include/controller/ble_ll.h      | 11 +++
 .../controller/include/controller/ble_phy.h     |  8 +--
 net/nimble/controller/src/ble_ll.c              | 73 +++++++++++++++++++-
 net/nimble/controller/src/ble_ll_conn.c         | 24 +++++--
 net/nimble/drivers/native/src/ble_phy.c         | 55 +++++----------
 net/nimble/drivers/nrf51/src/ble_phy.c          | 62 +++++------------
 net/nimble/drivers/nrf52/src/ble_phy.c          | 62 +++++------------
 7 files changed, 149 insertions(+), 146 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/40c072eb/net/nimble/controller/include/controller/ble_ll.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll.h b/net/nimble/controller/include/controller/ble_ll.h
index 51d725c..7865cf8 100644
--- a/net/nimble/controller/include/controller/ble_ll.h
+++ b/net/nimble/controller/include/controller/ble_ll.h
@@ -86,6 +86,7 @@ STATS_SECT_START(ble_ll_stats)
     STATS_SECT_ENTRY(hci_events_sent)
     STATS_SECT_ENTRY(bad_ll_state)
     STATS_SECT_ENTRY(bad_acl_hdr)
+    STATS_SECT_ENTRY(no_bufs)
     STATS_SECT_ENTRY(rx_adv_pdu_crc_ok)
     STATS_SECT_ENTRY(rx_adv_pdu_crc_err)
     STATS_SECT_ENTRY(rx_adv_bytes_crc_ok)
@@ -312,6 +313,16 @@ int ble_ll_is_our_devaddr(uint8_t *addr, int addr_type);
  */
 void ble_ll_acl_data_in(struct os_mbuf *txpkt);
 
+/**
+ * Allocate a pdu (chain) for reception.
+ *
+ * @param len Length of PDU. This includes the PDU header as well as payload.
+ * Does not include MIC if encrypted.
+ *
+ * @return struct os_mbuf* Pointer to mbuf chain to hold received packet
+ */
+struct os_mbuf *ble_ll_rxpdu_alloc(uint16_t len);
+
 /*--- PHY interfaces ---*/
 struct ble_mbuf_hdr;
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/40c072eb/net/nimble/controller/include/controller/ble_phy.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_phy.h b/net/nimble/controller/include/controller/ble_phy.h
index 74f349a..585c2dc 100644
--- a/net/nimble/controller/include/controller/ble_phy.h
+++ b/net/nimble/controller/include/controller/ble_phy.h
@@ -97,12 +97,8 @@ int ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans);
 /* Place the PHY into receive mode */
 int ble_phy_rx(void);
 
-/*
- * Retrieve the received PDU from the PHY. This returns an mbuf with
- * the most recently received PDU in it. It also contains the ble_hdr
- * as well
- */
-struct os_mbuf *ble_phy_rxpdu_get(uint8_t *dptr, uint16_t mblen);
+/* Copies the received PHY buffer into the allocated pdu */
+void ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu);
 
 /* Get an RSSI reading */
 int ble_phy_rssi_get(void);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/40c072eb/net/nimble/controller/src/ble_ll.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll.c b/net/nimble/controller/src/ble_ll.c
index b8fcca5..3beb28e 100644
--- a/net/nimble/controller/src/ble_ll.c
+++ b/net/nimble/controller/src/ble_ll.c
@@ -151,6 +151,7 @@ STATS_NAME_START(ble_ll_stats)
     STATS_NAME(ble_ll_stats, hci_events_sent)
     STATS_NAME(ble_ll_stats, bad_ll_state)
     STATS_NAME(ble_ll_stats, bad_acl_hdr)
+    STATS_NAME(ble_ll_stats, no_bufs)
     STATS_NAME(ble_ll_stats, rx_adv_pdu_crc_ok)
     STATS_NAME(ble_ll_stats, rx_adv_pdu_crc_err)
     STATS_NAME(ble_ll_stats, rx_adv_bytes_crc_ok)
@@ -262,6 +263,68 @@ ble_ll_count_rx_adv_pdus(uint8_t pdu_type)
     }
 }
 
+/**
+ * Allocate a pdu (chain) for reception.
+ *
+ * @param len
+ *
+ * @return struct os_mbuf*
+ */
+struct os_mbuf *
+ble_ll_rxpdu_alloc(uint16_t len)
+{
+    uint16_t mb_bytes;
+    struct os_mbuf *m;
+    struct os_mbuf *n;
+    struct os_mbuf *p;
+    struct os_mbuf_pkthdr *pkthdr;
+
+    p = os_msys_get_pkthdr(len, sizeof(struct ble_mbuf_hdr));
+    if (!p) {
+        goto rxpdu_alloc_exit;
+    }
+
+    /* Set packet length */
+    pkthdr = OS_MBUF_PKTHDR(p);
+    pkthdr->omp_len = len;
+
+    /*
+     * NOTE: first mbuf in chain will have data pre-pended to it so we adjust
+     * m_data by a word.
+     */
+    p->om_data += 4;
+    mb_bytes = (p->om_omp->omp_databuf_len - p->om_pkthdr_len - 4);
+
+    if (mb_bytes < len) {
+        n = p;
+        len -= mb_bytes;
+        while (len) {
+            m = os_msys_get(len, 0);
+            if (!m) {
+                os_mbuf_free_chain(p);
+                p = NULL;
+                goto rxpdu_alloc_exit;
+            }
+            /* Chain new mbuf to existing chain */
+            SLIST_NEXT(n, om_next) = m;
+            n = m;
+            mb_bytes = m->om_omp->omp_databuf_len;
+            if (mb_bytes >= len) {
+                len = 0;
+            } else {
+                len -= mb_bytes;
+            }
+        }
+    }
+
+
+rxpdu_alloc_exit:
+    if (!p) {
+        STATS_INC(ble_ll_stats, no_bufs);
+    }
+    return p;
+}
+
 int
 ble_ll_chk_txrx_octets(uint16_t octets)
 {
@@ -806,13 +869,19 @@ ble_ll_rx_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
     switch (BLE_MBUF_HDR_RX_STATE(rxhdr)) {
     case BLE_LL_STATE_ADV:
         if (!badpkt) {
-            rxpdu = ble_phy_rxpdu_get(rxbuf, len + BLE_LL_PDU_HDR_LEN);
+            rxpdu = ble_ll_rxpdu_alloc(len + BLE_LL_PDU_HDR_LEN);
+            if (rxpdu) {
+                ble_phy_rxpdu_copy(rxbuf, rxpdu);
+            }
         }
         rc = ble_ll_adv_rx_isr_end(pdu_type, rxpdu, crcok);
         break;
     case BLE_LL_STATE_SCANNING:
         if (!badpkt) {
-            rxpdu = ble_phy_rxpdu_get(rxbuf, len + BLE_LL_PDU_HDR_LEN);
+            rxpdu = ble_ll_rxpdu_alloc(len + BLE_LL_PDU_HDR_LEN);
+            if (rxpdu) {
+                ble_phy_rxpdu_copy(rxbuf, rxpdu);
+            }
         }
         rc = ble_ll_scan_rx_isr_end(rxpdu, crcok);
         break;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/40c072eb/net/nimble/controller/src/ble_ll_conn.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn.c b/net/nimble/controller/src/ble_ll_conn.c
index fb95367..e3c40e2 100644
--- a/net/nimble/controller/src/ble_ll_conn.c
+++ b/net/nimble/controller/src/ble_ll_conn.c
@@ -2350,12 +2350,13 @@ init_rx_isr_exit:
      * We have to restart receive if we cant hand up pdu. We return 0 so that
      * the phy does not get disabled.
      */
-    rxpdu = ble_phy_rxpdu_get(rxbuf, pyld_len + BLE_LL_PDU_HDR_LEN);
+    rxpdu = ble_ll_rxpdu_alloc(pyld_len + BLE_LL_PDU_HDR_LEN);
     if (rxpdu == NULL) {
         ble_phy_disable();
         ble_phy_rx();
         rc = 0;
     } else {
+        ble_phy_rxpdu_copy(rxbuf, rxpdu);
         ble_ll_rx_pdu_in(rxpdu);
     }
 
@@ -2627,6 +2628,19 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
     struct os_mbuf *rxpdu;
     struct ble_mbuf_hdr *txhdr;
 
+    /* Retrieve the header and payload length */
+    hdr_byte = rxbuf[0];
+    rx_pyld_len = rxbuf[1];
+
+    /*
+     * We need to attempt to allocate a buffer here. The reason we do this
+     * now is that we should not ack the packet if we have no receive
+     * buffers available. We want to free up our transmit PDU if it was
+     * acked, but we should not ack the received frame if we cant hand it up.
+     * NOTE: we hand up empty pdu's to the LL task!
+     */
+    rxpdu = ble_ll_rxpdu_alloc(rx_pyld_len + BLE_LL_PDU_HDR_LEN);
+
     /*
      * We should have a current connection state machine. If we dont, we just
      * hand the packet to the higher layer to count it.
@@ -2638,10 +2652,6 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
         goto conn_exit;
     }
 
-    /* Set the handle in the ble mbuf header */
-    hdr_byte = rxbuf[0];
-    rx_pyld_len = rxbuf[1];
-
     /*
      * Check the packet CRC. A connection event can continue even if the
      * received PDU does not pass the CRC check. If we receive two consecutive
@@ -2686,7 +2696,7 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
          */
         hdr_sn = hdr_byte & BLE_LL_DATA_HDR_SN_MASK;
         conn_nesn = connsm->next_exp_seqnum;
-        if ((hdr_sn && conn_nesn) || (!hdr_sn && !conn_nesn)) {
+        if (rxpdu && ((hdr_sn && conn_nesn) || (!hdr_sn && !conn_nesn))) {
             connsm->next_exp_seqnum ^= 1;
 #if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 1)
             if (CONN_F_ENCRYPTED(connsm) && !ble_ll_conn_is_empty_pdu(rxbuf)) {
@@ -2815,8 +2825,8 @@ chk_rx_terminate_ind:
 
 conn_exit:
     /* Copy the received pdu and hand it up */
-    rxpdu = ble_phy_rxpdu_get(rxbuf, rxbuf[1] + BLE_LL_PDU_HDR_LEN);
     if (rxpdu) {
+        ble_phy_rxpdu_copy(rxbuf, rxpdu);
         ble_ll_rx_pdu_in(rxpdu);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/40c072eb/net/nimble/drivers/native/src/ble_phy.c
----------------------------------------------------------------------
diff --git a/net/nimble/drivers/native/src/ble_phy.c b/net/nimble/drivers/native/src/ble_phy.c
index 4eb5d97..ff195fc 100644
--- a/net/nimble/drivers/native/src/ble_phy.c
+++ b/net/nimble/drivers/native/src/ble_phy.c
@@ -141,14 +141,15 @@ ble_xcvr_clear_irq(uint32_t mask)
 /**
  * Copies the data from the phy receive buffer into a mbuf chain.
  *
- *
  * @param dptr Pointer to receive buffer
- * @param len Length of receive buffer to copy.
+ * @param rxpdu Pointer to already allocated mbuf chain
+ *
+ * NOTE: the packet header already has the total mbuf length in it. The
+ * lengths of the individual mbufs are not set prior to calling.
  *
- * @return struct os_mbuf* Pointer to mbuf. NULL if no mbuf available.
  */
-struct os_mbuf *
-ble_phy_rxpdu_get(uint8_t *dptr, uint16_t len)
+void
+ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu)
 {
     uint16_t rem_bytes;
     uint16_t mb_bytes;
@@ -156,35 +157,25 @@ ble_phy_rxpdu_get(uint8_t *dptr, uint16_t len)
     uint32_t *dst;
     uint32_t *src;
     struct os_mbuf *m;
-    struct os_mbuf *n;
-    struct os_mbuf *p;
     struct ble_mbuf_hdr *ble_hdr;
     struct os_mbuf_pkthdr *pkthdr;
 
     /* Better be aligned */
     assert(((uint32_t)dptr & 3) == 0);
 
-    p = os_msys_get_pkthdr(len, sizeof(struct ble_mbuf_hdr));
-    if (!p) {
-        STATS_INC(ble_phy_stats, no_bufs);
-        return NULL;
-    }
+    pkthdr = OS_MBUF_PKTHDR(rxpdu);
+    rem_bytes = pkthdr->omp_len;
 
-    /*
-     * Fill in the mbuf pkthdr first. NOTE: first mbuf in chain will have data
-     * pre-pended to it so we adjust m_data by a word.
-     */
-    p->om_data += 4;
-    dst = (uint32_t *)(p->om_data);
+    /* Fill in the mbuf pkthdr first. */
+    dst = (uint32_t *)(rxpdu->om_data);
     src = (uint32_t *)dptr;
 
-    rem_bytes = len;
-    mb_bytes = (p->om_omp->omp_databuf_len - p->om_pkthdr_len - 4);
+    mb_bytes = (rxpdu->om_omp->omp_databuf_len - rxpdu->om_pkthdr_len - 4);
     copylen = min(mb_bytes, rem_bytes);
     copylen &= 0xFFFC;
     rem_bytes -= copylen;
     mb_bytes -= copylen;
-    p->om_len = copylen;
+    rxpdu->om_len = copylen;
     while (copylen > 0) {
         *dst = *src;
         ++dst;
@@ -193,7 +184,7 @@ ble_phy_rxpdu_get(uint8_t *dptr, uint16_t len)
     }
 
     /* Copy remaining bytes */
-    m = p;
+    m = rxpdu;
     while (rem_bytes > 0) {
         /* If there are enough bytes in the mbuf, copy them and leave */
         if (rem_bytes <= mb_bytes) {
@@ -202,16 +193,8 @@ ble_phy_rxpdu_get(uint8_t *dptr, uint16_t len)
             break;
         }
 
-        n = os_msys_get(rem_bytes, 0);
-        if (!n) {
-            os_mbuf_free_chain(p);
-            STATS_INC(ble_phy_stats, no_bufs);
-            return NULL;
-        }
-
-        /* Chain new mbuf to existing chain */
-        SLIST_NEXT(m, om_next) = n;
-        m = n;
+        m = SLIST_NEXT(m, om_next);
+        assert(m != NULL);
 
         mb_bytes = m->om_omp->omp_databuf_len;
         copylen = min(mb_bytes, rem_bytes);
@@ -228,15 +211,9 @@ ble_phy_rxpdu_get(uint8_t *dptr, uint16_t len)
         }
     }
 
-    /* Set packet length */
-    pkthdr = OS_MBUF_PKTHDR(p);
-    pkthdr->omp_len = len;
-
     /* Copy ble header */
-    ble_hdr = BLE_MBUF_HDR_PTR(p);
+    ble_hdr = BLE_MBUF_HDR_PTR(rxpdu);
     memcpy(ble_hdr, &g_ble_phy_data.rxhdr, sizeof(struct ble_mbuf_hdr));
-
-    return p;
 }
 
 void

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/40c072eb/net/nimble/drivers/nrf51/src/ble_phy.c
----------------------------------------------------------------------
diff --git a/net/nimble/drivers/nrf51/src/ble_phy.c b/net/nimble/drivers/nrf51/src/ble_phy.c
index 15a2da7..a24a434 100644
--- a/net/nimble/drivers/nrf51/src/ble_phy.c
+++ b/net/nimble/drivers/nrf51/src/ble_phy.c
@@ -28,11 +28,6 @@
 #include "controller/ble_ll.h"
 #include "mcu/nrf51_bitfields.h"
 
-/*
- * XXX: need to make the copy from mbuf into the PHY data structures 32-bit
- * copies or we are screwed.
- */
-
 /* XXX: 4) Make sure RF is higher priority interrupt than schedule */
 
 /*
@@ -113,7 +108,6 @@ STATS_SECT_START(ble_phy_stats)
     STATS_SECT_ENTRY(rx_valid)
     STATS_SECT_ENTRY(rx_crc_err)
     STATS_SECT_ENTRY(rx_late)
-    STATS_SECT_ENTRY(no_bufs)
     STATS_SECT_ENTRY(radio_state_errs)
     STATS_SECT_ENTRY(rx_hw_err)
     STATS_SECT_ENTRY(tx_hw_err)
@@ -131,7 +125,6 @@ STATS_NAME_START(ble_phy_stats)
     STATS_NAME(ble_phy_stats, rx_valid)
     STATS_NAME(ble_phy_stats, rx_crc_err)
     STATS_NAME(ble_phy_stats, rx_late)
-    STATS_NAME(ble_phy_stats, no_bufs)
     STATS_NAME(ble_phy_stats, radio_state_errs)
     STATS_NAME(ble_phy_stats, rx_hw_err)
     STATS_NAME(ble_phy_stats, tx_hw_err)
@@ -187,14 +180,15 @@ struct nrf_ccm_data g_nrf_ccm_data;
 /**
  * Copies the data from the phy receive buffer into a mbuf chain.
  *
- *
  * @param dptr Pointer to receive buffer
- * @param len Length of receive buffer to copy.
+ * @param rxpdu Pointer to already allocated mbuf chain
+ *
+ * NOTE: the packet header already has the total mbuf length in it. The
+ * lengths of the individual mbufs are not set prior to calling.
  *
- * @return struct os_mbuf* Pointer to mbuf. NULL if no mbuf available.
  */
-struct os_mbuf *
-ble_phy_rxpdu_get(uint8_t *dptr, uint16_t len)
+void
+ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu)
 {
     uint16_t rem_bytes;
     uint16_t mb_bytes;
@@ -202,35 +196,25 @@ ble_phy_rxpdu_get(uint8_t *dptr, uint16_t len)
     uint32_t *dst;
     uint32_t *src;
     struct os_mbuf *m;
-    struct os_mbuf *n;
-    struct os_mbuf *p;
     struct ble_mbuf_hdr *ble_hdr;
     struct os_mbuf_pkthdr *pkthdr;
 
     /* Better be aligned */
     assert(((uint32_t)dptr & 3) == 0);
 
-    p = os_msys_get_pkthdr(len, sizeof(struct ble_mbuf_hdr));
-    if (!p) {
-        STATS_INC(ble_phy_stats, no_bufs);
-        return NULL;
-    }
+    pkthdr = OS_MBUF_PKTHDR(rxpdu);
+    rem_bytes = pkthdr->omp_len;
 
-    /*
-     * Fill in the mbuf pkthdr first. NOTE: first mbuf in chain will have data
-     * pre-pended to it so we adjust m_data by a word.
-     */
-    p->om_data += 4;
-    dst = (uint32_t *)(p->om_data);
+    /* Fill in the mbuf pkthdr first. */
+    dst = (uint32_t *)(rxpdu->om_data);
     src = (uint32_t *)dptr;
 
-    rem_bytes = len;
-    mb_bytes = (p->om_omp->omp_databuf_len - p->om_pkthdr_len - 4);
+    mb_bytes = (rxpdu->om_omp->omp_databuf_len - rxpdu->om_pkthdr_len - 4);
     copylen = min(mb_bytes, rem_bytes);
     copylen &= 0xFFFC;
     rem_bytes -= copylen;
     mb_bytes -= copylen;
-    p->om_len = copylen;
+    rxpdu->om_len = copylen;
     while (copylen > 0) {
         *dst = *src;
         ++dst;
@@ -239,7 +223,7 @@ ble_phy_rxpdu_get(uint8_t *dptr, uint16_t len)
     }
 
     /* Copy remaining bytes */
-    m = p;
+    m = rxpdu;
     while (rem_bytes > 0) {
         /* If there are enough bytes in the mbuf, copy them and leave */
         if (rem_bytes <= mb_bytes) {
@@ -248,16 +232,8 @@ ble_phy_rxpdu_get(uint8_t *dptr, uint16_t len)
             break;
         }
 
-        n = os_msys_get(rem_bytes, 0);
-        if (!n) {
-            os_mbuf_free_chain(p);
-            STATS_INC(ble_phy_stats, no_bufs);
-            return NULL;
-        }
-
-        /* Chain new mbuf to existing chain */
-        SLIST_NEXT(m, om_next) = n;
-        m = n;
+        m = SLIST_NEXT(m, om_next);
+        assert(m != NULL);
 
         mb_bytes = m->om_omp->omp_databuf_len;
         copylen = min(mb_bytes, rem_bytes);
@@ -274,15 +250,9 @@ ble_phy_rxpdu_get(uint8_t *dptr, uint16_t len)
         }
     }
 
-    /* Set packet length */
-    pkthdr = OS_MBUF_PKTHDR(p);
-    pkthdr->omp_len = len;
-
     /* Copy ble header */
-    ble_hdr = BLE_MBUF_HDR_PTR(p);
+    ble_hdr = BLE_MBUF_HDR_PTR(rxpdu);
     memcpy(ble_hdr, &g_ble_phy_data.rxhdr, sizeof(struct ble_mbuf_hdr));
-
-    return p;
 }
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/40c072eb/net/nimble/drivers/nrf52/src/ble_phy.c
----------------------------------------------------------------------
diff --git a/net/nimble/drivers/nrf52/src/ble_phy.c b/net/nimble/drivers/nrf52/src/ble_phy.c
index 8ffab96..2e34669 100644
--- a/net/nimble/drivers/nrf52/src/ble_phy.c
+++ b/net/nimble/drivers/nrf52/src/ble_phy.c
@@ -29,11 +29,6 @@
 #include "controller/ble_ll.h"
 #include "mcu/nrf52_bitfields.h"
 
-/*
- * XXX: need to make the copy from mbuf into the PHY data structures 32-bit
- * copies or we are screwed.
- */
-
 /* XXX: 4) Make sure RF is higher priority interrupt than schedule */
 
 /*
@@ -107,7 +102,6 @@ STATS_SECT_START(ble_phy_stats)
     STATS_SECT_ENTRY(rx_valid)
     STATS_SECT_ENTRY(rx_crc_err)
     STATS_SECT_ENTRY(rx_late)
-    STATS_SECT_ENTRY(no_bufs)
     STATS_SECT_ENTRY(radio_state_errs)
     STATS_SECT_ENTRY(rx_hw_err)
     STATS_SECT_ENTRY(tx_hw_err)
@@ -125,7 +119,6 @@ STATS_NAME_START(ble_phy_stats)
     STATS_NAME(ble_phy_stats, rx_valid)
     STATS_NAME(ble_phy_stats, rx_crc_err)
     STATS_NAME(ble_phy_stats, rx_late)
-    STATS_NAME(ble_phy_stats, no_bufs)
     STATS_NAME(ble_phy_stats, radio_state_errs)
     STATS_NAME(ble_phy_stats, rx_hw_err)
     STATS_NAME(ble_phy_stats, tx_hw_err)
@@ -188,14 +181,15 @@ struct nrf_ccm_data g_nrf_ccm_data;
 /**
  * Copies the data from the phy receive buffer into a mbuf chain.
  *
- *
  * @param dptr Pointer to receive buffer
- * @param len Length of receive buffer to copy.
+ * @param rxpdu Pointer to already allocated mbuf chain
+ *
+ * NOTE: the packet header already has the total mbuf length in it. The
+ * lengths of the individual mbufs are not set prior to calling.
  *
- * @return struct os_mbuf* Pointer to mbuf. NULL if no mbuf available.
  */
-struct os_mbuf *
-ble_phy_rxpdu_get(uint8_t *dptr, uint16_t len)
+void
+ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu)
 {
     uint16_t rem_bytes;
     uint16_t mb_bytes;
@@ -203,35 +197,25 @@ ble_phy_rxpdu_get(uint8_t *dptr, uint16_t len)
     uint32_t *dst;
     uint32_t *src;
     struct os_mbuf *m;
-    struct os_mbuf *n;
-    struct os_mbuf *p;
     struct ble_mbuf_hdr *ble_hdr;
     struct os_mbuf_pkthdr *pkthdr;
 
     /* Better be aligned */
     assert(((uint32_t)dptr & 3) == 0);
 
-    p = os_msys_get_pkthdr(len, sizeof(struct ble_mbuf_hdr));
-    if (!p) {
-        STATS_INC(ble_phy_stats, no_bufs);
-        return NULL;
-    }
+    pkthdr = OS_MBUF_PKTHDR(rxpdu);
+    rem_bytes = pkthdr->omp_len;
 
-    /*
-     * Fill in the mbuf pkthdr first. NOTE: first mbuf in chain will have data
-     * pre-pended to it so we adjust m_data by a word.
-     */
-    p->om_data += 4;
-    dst = (uint32_t *)(p->om_data);
+    /* Fill in the mbuf pkthdr first. */
+    dst = (uint32_t *)(rxpdu->om_data);
     src = (uint32_t *)dptr;
 
-    rem_bytes = len;
-    mb_bytes = (p->om_omp->omp_databuf_len - p->om_pkthdr_len - 4);
+    mb_bytes = (rxpdu->om_omp->omp_databuf_len - rxpdu->om_pkthdr_len - 4);
     copylen = min(mb_bytes, rem_bytes);
     copylen &= 0xFFFC;
     rem_bytes -= copylen;
     mb_bytes -= copylen;
-    p->om_len = copylen;
+    rxpdu->om_len = copylen;
     while (copylen > 0) {
         *dst = *src;
         ++dst;
@@ -240,7 +224,7 @@ ble_phy_rxpdu_get(uint8_t *dptr, uint16_t len)
     }
 
     /* Copy remaining bytes */
-    m = p;
+    m = rxpdu;
     while (rem_bytes > 0) {
         /* If there are enough bytes in the mbuf, copy them and leave */
         if (rem_bytes <= mb_bytes) {
@@ -249,16 +233,8 @@ ble_phy_rxpdu_get(uint8_t *dptr, uint16_t len)
             break;
         }
 
-        n = os_msys_get(rem_bytes, 0);
-        if (!n) {
-            os_mbuf_free_chain(p);
-            STATS_INC(ble_phy_stats, no_bufs);
-            return NULL;
-        }
-
-        /* Chain new mbuf to existing chain */
-        SLIST_NEXT(m, om_next) = n;
-        m = n;
+        m = SLIST_NEXT(m, om_next);
+        assert(m != NULL);
 
         mb_bytes = m->om_omp->omp_databuf_len;
         copylen = min(mb_bytes, rem_bytes);
@@ -275,15 +251,9 @@ ble_phy_rxpdu_get(uint8_t *dptr, uint16_t len)
         }
     }
 
-    /* Set packet length */
-    pkthdr = OS_MBUF_PKTHDR(p);
-    pkthdr->omp_len = len;
-
     /* Copy ble header */
-    ble_hdr = BLE_MBUF_HDR_PTR(p);
+    ble_hdr = BLE_MBUF_HDR_PTR(rxpdu);
     memcpy(ble_hdr, &g_ble_phy_data.rxhdr, sizeof(struct ble_mbuf_hdr));
-
-    return p;
 }
 
 /**