Initial cut of LL privacy

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/7327c542
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/7327c542
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/7327c542

Branch: refs/heads/develop
Commit: 7327c542d000b1323c669bba791da45fd87139b3
Parents: 6e95f44
Author: William San Filippo <wi...@runtime.io>
Authored: Wed May 18 14:06:01 2016 -0700
Committer: Paul Dietrich <paulfdietr...@yahoo.com>
Committed: Thu Jun 2 12:53:52 2016 -0700

----------------------------------------------------------------------
 .../controller/include/controller/ble_hw.h      |  35 +-
 .../controller/include/controller/ble_ll.h      |   1 +
 .../include/controller/ble_ll_resolv.h          |  79 ++++
 .../controller/include/controller/ble_phy.h     |   6 +
 net/nimble/controller/src/ble_ll.c              |  29 +-
 net/nimble/controller/src/ble_ll_adv.c          | 255 +++++++------
 net/nimble/controller/src/ble_ll_conn.c         |  34 +-
 net/nimble/controller/src/ble_ll_conn_priv.h    |   3 +-
 net/nimble/controller/src/ble_ll_ctrl.c         |   2 +-
 net/nimble/controller/src/ble_ll_hci.c          |  27 ++
 net/nimble/controller/src/ble_ll_rand.c         |  26 ++
 net/nimble/controller/src/ble_ll_resolv.c       | 378 +++++++++++++++++++
 net/nimble/controller/src/ble_ll_scan.c         |   2 +
 net/nimble/drivers/nrf51/src/ble_hw.c           | 195 ++++++++--
 net/nimble/drivers/nrf51/src/ble_phy.c          | 107 +++++-
 net/nimble/drivers/nrf52/src/ble_hw.c           | 116 +++++-
 net/nimble/drivers/nrf52/src/ble_phy.c          |  85 ++++-
 net/nimble/host/src/host_hci_cmd.c              |   4 +-
 net/nimble/include/nimble/ble.h                 |   6 +-
 net/nimble/include/nimble/hci_common.h          |   2 +-
 net/nimble/include/nimble/nimble_opt.h          |   7 +-
 21 files changed, 1189 insertions(+), 210 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7327c542/net/nimble/controller/include/controller/ble_hw.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_hw.h 
b/net/nimble/controller/include/controller/ble_hw.h
index 6166e58..da425de 100644
--- a/net/nimble/controller/include/controller/ble_hw.h
+++ b/net/nimble/controller/include/controller/ble_hw.h
@@ -6,7 +6,7 @@
  * 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,
@@ -57,23 +57,44 @@ int ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias);
 
 /**
  * Start the random number generator
- * 
- * @return int 
+ *
+ * @return int
  */
 int ble_hw_rng_start(void);
 
 /**
  * Stop the random generator
- * 
- * @return int 
+ *
+ * @return int
  */
 int ble_hw_rng_stop(void);
 
 /**
  * Read the random number generator.
- * 
- * @return uint8_t 
+ *
+ * @return uint8_t
  */
 uint8_t ble_hw_rng_read(void);
 
+/*  Clear the resolving list*/
+void ble_hw_resolv_list_clear(void);
+
+/* Add a device to the hw resolving list */
+int ble_hw_resolv_list_add(uint8_t *irk);
+
+/* Remove a device from the hw resolving list */
+void ble_hw_resolv_list_rmv(int index);
+
+/* Returns the size of the whitelist in HW */
+uint8_t ble_hw_resolv_list_size(void);
+
+/* Enable the resolving list */
+void ble_hw_resolv_list_enable(void);
+
+/* Disables resolving list devices */
+void ble_hw_resolv_list_disable(void);
+
+/* Returns index of resolved address; -1 if not resolved */
+int ble_hw_resolv_list_match(void);
+
 #endif /* H_BLE_HW_ */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7327c542/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 8c8cb54..9a4014c 100644
--- a/net/nimble/controller/include/controller/ble_ll.h
+++ b/net/nimble/controller/include/controller/ble_ll.h
@@ -354,6 +354,7 @@ int ble_ll_chk_txrx_time(uint16_t time);
 int ble_ll_rand_init(void);
 void ble_ll_rand_sample(uint8_t rnum);
 int ble_ll_rand_data_get(uint8_t *buf, uint8_t len);
+void ble_ll_rand_prand_get(uint8_t *prand);
 int ble_ll_rand_start(void);
 
 /*

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7327c542/net/nimble/controller/include/controller/ble_ll_resolv.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_resolv.h 
b/net/nimble/controller/include/controller/ble_ll_resolv.h
new file mode 100644
index 0000000..bddf70b
--- /dev/null
+++ b/net/nimble/controller/include/controller/ble_ll_resolv.h
@@ -0,0 +1,79 @@
+/**
+ * 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.
+ */
+
+#ifndef H_BLE_LL_RESOLV_
+#define H_BLE_LL_RESOLV_
+
+/*
+ * An entry in the resolving list.
+ *      The identity address is stored in little endian format.
+ *      The IRKs are stored in big endian format.
+ */
+struct ble_ll_resolv_entry
+{
+    uint8_t rl_valid;
+    uint8_t rl_addr_type;
+    uint8_t rl_identity_addr[BLE_DEV_ADDR_LEN];
+    uint8_t rl_local_irk[16];
+    uint8_t rl_peer_irk[16];
+};
+
+extern struct ble_ll_resolv_entry g_ble_ll_resolv_list[];
+
+/* Clear the resolving list */
+int ble_ll_resolv_list_clr(void);
+
+/* Read the size of the resolving list */
+int ble_ll_resolv_list_read_size(uint8_t *rspbuf, uint8_t *rsplen);
+
+/* Add a device to the resolving list */
+int ble_ll_resolv_list_add(uint8_t *cmdbuf);
+
+/* Remove a device from the resolving list */
+int ble_ll_resolv_list_rmv(uint8_t *cmdbuf);
+
+/* Address resolution enable command */
+int ble_ll_resolv_enable_cmd(uint8_t *cmdbuf);
+
+int ble_ll_resolv_peer_addr_rd(uint8_t *cmdbuf);
+void ble_ll_resolv_local_addr_rd(uint8_t *cmdbuf);
+
+/* Enable resolving list */
+void ble_ll_resolv_list_enable(void);
+
+/* Disable resolving list */
+void ble_ll_resolv_list_disable(void);
+
+/* Finds 'addr' in resolving list. */
+struct ble_ll_resolv_entry *
+ble_ll_resolv_list_find(uint8_t *addr, uint8_t addr_type);
+
+/* Called to determine if the IRK is all zero. */
+int ble_ll_resolv_irk_nonzero(uint8_t *irk);
+
+/* Returns true if address resolution is enabled */
+uint8_t ble_ll_resolv_enabled(void);
+
+/* Reset private address resolution */
+void ble_ll_resolv_list_reset(void);
+
+void ble_ll_resolv_gen_priv_addr(struct ble_ll_resolv_entry *rl, int local,
+                                 uint8_t *addr);
+
+#endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7327c542/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 edbfd89..1333c19 100644
--- a/net/nimble/controller/include/controller/ble_phy.h
+++ b/net/nimble/controller/include/controller/ble_phy.h
@@ -139,4 +139,10 @@ void ble_phy_encrypt_disable(void);
 /* Set the packet counters and dir used by LE encyption */
 void ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir);
 
+/* Enable phy resolving list */
+void ble_phy_resolv_list_enable(void);
+
+/* Disable phy resolving list */
+void ble_phy_resolv_list_disable(void);
+
 #endif /* H_BLE_PHY_ */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7327c542/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 7ff290d..e53d56f 100644
--- a/net/nimble/controller/src/ble_ll.c
+++ b/net/nimble/controller/src/ble_ll.c
@@ -33,6 +33,8 @@
 #include "controller/ble_ll_sched.h"
 #include "controller/ble_ll_scan.h"
 #include "controller/ble_ll_hci.h"
+#include "controller/ble_ll_whitelist.h"
+#include "controller/ble_ll_resolv.h"
 #include "ble_ll_conn_priv.h"
 #include "hal/hal_cputime.h"
 
@@ -286,11 +288,26 @@ ble_ll_chk_txrx_time(uint16_t time)
     return rc;
 }
 
+/* WWW: check where called to see if correct */
+/**
+ * Checks to see if the address is a resolvable private address. Th
+ *
+ *
+ * @param addr
+ *
+ * @return int
+ */
 int
 ble_ll_is_resolvable_priv_addr(uint8_t *addr)
 {
-    /* XXX: implement this */
-    return 0;
+    int rc;
+
+    if ((addr[5] & 0xc0) == 0x40) {
+        rc = 1;
+    } else {
+        rc = 0;
+    }
+    return rc;
 }
 
 /* Checks to see that the device is a valid random address */
@@ -1065,6 +1082,14 @@ ble_ll_reset(void)
     /* Reset our random address */
     memset(g_random_addr, 0, BLE_DEV_ADDR_LEN);
 
+    /* Clear the whitelist */
+    ble_ll_whitelist_clear();
+
+    /* Reset resolving list */
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+    ble_ll_resolv_list_reset();
+#endif
+
     /* Re-initialize the PHY */
     rc = ble_phy_init();
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7327c542/net/nimble/controller/src/ble_ll_adv.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_adv.c 
b/net/nimble/controller/src/ble_ll_adv.c
index 8a1e8e6..c49686c 100644
--- a/net/nimble/controller/src/ble_ll_adv.c
+++ b/net/nimble/controller/src/ble_ll_adv.c
@@ -26,11 +26,13 @@
 #include "nimble/nimble_opt.h"
 #include "nimble/hci_common.h"
 #include "controller/ble_phy.h"
+#include "controller/ble_hw.h"
 #include "controller/ble_ll.h"
 #include "controller/ble_ll_adv.h"
 #include "controller/ble_ll_sched.h"
 #include "controller/ble_ll_scan.h"
 #include "controller/ble_ll_whitelist.h"
+#include "controller/ble_ll_resolv.h"
 #include "ble_ll_conn_priv.h"
 #include "hal/hal_cputime.h"
 #include "hal/hal_gpio.h"
@@ -39,7 +41,6 @@
  * 1) Need to look at advertising and scan request PDUs. Do I allocate these
  * once? Do I use a different pool for smaller ones? Do I statically declare
  * them?
- * 2) Only public device addresses supported right now.
  * 3) How do features get supported? What happens if device does not support
  * advertising? (for example)
  * 4) How to determine the advertising interval we will actually use. As of
@@ -69,16 +70,19 @@ struct ble_ll_adv_sm
     uint8_t adv_chan;
     uint8_t scan_rsp_len;
     uint8_t adv_pdu_len;
+    int8_t adv_rpa_index;
     uint16_t adv_itvl_min;
     uint16_t adv_itvl_max;
     uint32_t adv_itvl_usecs;
     uint32_t adv_event_start_time;
     uint32_t adv_pdu_start_time;
     uint32_t adv_dir_hd_end_time;
+    uint8_t adva[BLE_DEV_ADDR_LEN];
+    uint8_t adv_rpa[BLE_DEV_ADDR_LEN];
+    uint8_t peer_addr[BLE_DEV_ADDR_LEN];
     uint8_t initiator_addr[BLE_DEV_ADDR_LEN];
     uint8_t adv_data[BLE_ADV_DATA_MAX_LEN];
     uint8_t scan_rsp_data[BLE_SCAN_RSP_DATA_MAX_LEN];
-    struct os_mbuf *scan_rsp_pdu;
     struct os_event adv_txdone_ev;
     struct ble_ll_sched_item adv_sch;
 };
@@ -130,36 +134,6 @@ ble_ll_adv_first_chan(struct ble_ll_adv_sm *advsm)
 }
 
 /**
- * Compares the advertiser address in an advertising PDU (scan request or
- * connect request) with our address to see if there is a match
- *
- * @param rxbuf Pointer to received PDU
- *
- * @return int Returns memcmp return values (0 = match).
- */
-static int
-ble_ll_adv_addr_cmp(uint8_t *rxbuf)
-{
-    int rc;
-    uint8_t *adva;
-    uint8_t *our_addr;
-    uint8_t rxaddr_type;
-
-    /* Determine if this is addressed to us */
-    rxaddr_type = rxbuf[0] & BLE_ADV_PDU_HDR_RXADD_MASK;
-    if (rxaddr_type) {
-        our_addr = g_random_addr;
-    } else {
-        our_addr = g_dev_addr;
-    }
-
-    adva = rxbuf + BLE_LL_PDU_HDR_LEN + BLE_DEV_ADDR_LEN;
-    rc = memcmp(our_addr, adva, BLE_DEV_ADDR_LEN);
-
-    return rc;
-}
-
-/**
  * Create the advertising PDU
  *
  * @param advsm Pointer to advertisement state machine
@@ -172,7 +146,6 @@ ble_ll_adv_pdu_make(struct ble_ll_adv_sm *advsm, struct 
os_mbuf *m)
     uint8_t     *dptr;
     uint8_t     pdulen;
     uint8_t     pdu_type;
-    uint8_t     *addr;
 
     /* assume this is not a direct ind */
     adv_data_len = advsm->adv_len;
@@ -219,16 +192,9 @@ ble_ll_adv_pdu_make(struct ble_ll_adv_sm *advsm, struct 
os_mbuf *m)
     /* Set the PDU length in the state machine (includes header) */
     advsm->adv_pdu_len = pdulen + BLE_LL_PDU_HDR_LEN;
 
-    /* Construct scan response */
-    if (advsm->own_addr_type == BLE_HCI_ADV_OWN_ADDR_PUBLIC) {
-        addr = g_dev_addr;
-    } else if (advsm->own_addr_type == BLE_HCI_ADV_OWN_ADDR_RANDOM) {
+    /* Set TxAdd to random if needed */
+    if (advsm->own_addr_type & 1) {
         pdu_type |= BLE_ADV_PDU_HDR_TXADD_RAND;
-        addr = g_random_addr;
-    } else {
-        /* XXX: unsupported for now. Should never happen */
-        addr = NULL;
-        assert(0);
     }
 
     /* Get the advertising PDU and initialize it*/
@@ -236,7 +202,7 @@ ble_ll_adv_pdu_make(struct ble_ll_adv_sm *advsm, struct 
os_mbuf *m)
 
     /* Construct advertisement */
     dptr = m->om_data;
-    memcpy(dptr, addr, BLE_DEV_ADDR_LEN);
+    memcpy(dptr, advsm->adva, BLE_DEV_ADDR_LEN);
     dptr += BLE_DEV_ADDR_LEN;
 
     /* For ADV_DIRECT_IND, we need to put initiators address in there */
@@ -255,52 +221,42 @@ ble_ll_adv_pdu_make(struct ble_ll_adv_sm *advsm, struct 
os_mbuf *m)
  *
  * @param advsm
  */
-static void
+static struct os_mbuf *
 ble_ll_adv_scan_rsp_pdu_make(struct ble_ll_adv_sm *advsm)
 {
     uint8_t     scan_rsp_len;
     uint8_t     *dptr;
-    uint8_t     *addr;
     uint8_t     pdulen;
     uint8_t     hdr;
     struct os_mbuf *m;
 
+    /* Obtain scan response buffer */
+    m = os_msys_get_pkthdr(BLE_MBUF_PAYLOAD_SIZE, sizeof(struct ble_mbuf_hdr));
+    if (!m) {
+        return NULL;
+    }
+
     /* Make sure that the length is valid */
     scan_rsp_len = advsm->scan_rsp_len;
     assert(scan_rsp_len <= BLE_SCAN_RSP_DATA_MAX_LEN);
 
-    /* Set PDU payload length */
+    /* Set BLE transmit header */
     pdulen = BLE_DEV_ADDR_LEN + scan_rsp_len;
-
-    /* Get the advertising PDU */
-    m = advsm->scan_rsp_pdu;
-    assert(m != NULL);
-
-    /* Construct scan response */
-    if (advsm->own_addr_type == BLE_HCI_ADV_OWN_ADDR_PUBLIC) {
-        hdr = BLE_ADV_PDU_TYPE_SCAN_RSP;
-        addr = g_dev_addr;
-    } else if (advsm->own_addr_type == BLE_HCI_ADV_OWN_ADDR_RANDOM) {
-        hdr = BLE_ADV_PDU_TYPE_SCAN_RSP | BLE_ADV_PDU_HDR_TXADD_RAND;
-        addr = g_random_addr;
-    } else {
-        /* XXX: unsupported for now  */
-        hdr = 0;
-        addr = NULL;
-        assert(0);
+    hdr = BLE_ADV_PDU_TYPE_SCAN_RSP;
+    if (advsm->own_addr_type & 1) {
+        hdr |= BLE_ADV_PDU_HDR_TXADD_RAND;
     }
 
-    /* Set BLE transmit header */
     ble_ll_mbuf_init(m, pdulen, hdr);
 
-    /* Put our address into buffer */
+    /* Construct scan response */
     dptr = m->om_data;
-    memcpy(dptr, addr, BLE_DEV_ADDR_LEN);
-
-    /* Copy in scan response data, if any */
+    memcpy(dptr, advsm->adva, BLE_DEV_ADDR_LEN);
     if (scan_rsp_len != 0) {
         memcpy(dptr + BLE_DEV_ADDR_LEN, advsm->scan_rsp_data, scan_rsp_len);
     }
+
+    return m;
 }
 
 /**
@@ -363,6 +319,15 @@ ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch)
     ble_phy_encrypt_disable();
 #endif
 
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+    advsm->adv_rpa_index = 0;
+    if (ble_ll_resolv_enabled()) {
+        ble_phy_resolv_list_enable();
+    } else {
+        ble_phy_resolv_list_disable();
+    }
+#endif
+
     /* Set phy mode based on type of advertisement */
     if (advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) {
         end_trans = BLE_PHY_TRANSITION_NONE;
@@ -552,13 +517,17 @@ ble_ll_adv_set_adv_params(uint8_t *cmd)
         return BLE_ERR_INV_HCI_CMD_PARMS;
     }
 
-    /*
-     * XXX: return unsupported feature if own is address is not public or
-     * static random as we have not implemented non-static random addresses.
-     */
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+    if (own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) {
+        /* Copy peer address */
+        memcpy(advsm->peer_addr, cmd + 7, BLE_DEV_ADDR_LEN);
+    }
+#else
+    /* If we dont support privacy these own address types wont work */
     if (own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) {
         return BLE_ERR_UNSUPPORTED;
     }
+#endif
 
     /* There are only three adv channels, so check for any outside the range */
     adv_chanmask = cmd[13];
@@ -628,6 +597,8 @@ static int
 ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm)
 {
     uint8_t adv_chan;
+    uint8_t *addr;
+    struct ble_ll_resolv_entry *rl;
 
     /*
      * This is not in the specification. I will reject the command with a
@@ -642,9 +613,35 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm)
         }
     }
 
+    /* Set advertising address */
+    if ((advsm->own_addr_type & 1) == 0) {
+        addr = g_dev_addr;
+    } else {
+        addr = g_random_addr;
+    }
+    memcpy(advsm->adva, addr, BLE_DEV_ADDR_LEN);
+
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+    /* WWW:
+     * 1) Make sure we are doing this for the proper adv types
+     */
+    if (ble_ll_resolv_enabled()) {
+        if (advsm->own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) {
+            rl = ble_ll_resolv_list_find(advsm->peer_addr, 
advsm->peer_addr_type);
+            if (rl && ble_ll_resolv_irk_nonzero(rl->rl_local_irk)) {
+                ble_ll_resolv_gen_priv_addr(rl, 1, advsm->adva);
+            }
+        }
+        ble_phy_resolv_list_enable();
+    } else {
+        ble_phy_resolv_list_disable();
+    }
+#endif
+
     /* Set flag telling us that advertising is enabled */
     advsm->enabled = 1;
 
+    /* WWW: what about privacy for direct? */
     /* Determine the advertising interval we will use */
     if (advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) {
         /* Set it to max. allowed for high duty cycle advertising */
@@ -654,11 +651,6 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm)
         advsm->adv_itvl_usecs *= BLE_LL_ADV_ITVL;
     }
 
-    /* Create scan response PDU (if needed) */
-    if (advsm->adv_type != BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) {
-        ble_ll_adv_scan_rsp_pdu_make(advsm);
-    }
-
     /* Set first advertising channel */
     adv_chan = ble_ll_adv_first_chan(advsm);
     advsm->adv_chan = adv_chan;
@@ -758,7 +750,6 @@ int
 ble_ll_adv_set_scan_rsp_data(uint8_t *cmd, uint8_t len)
 {
     uint8_t datalen;
-    os_sr_t sr;
     struct ble_ll_adv_sm *advsm;
 
     /* Check for valid scan response data length */
@@ -772,15 +763,6 @@ ble_ll_adv_set_scan_rsp_data(uint8_t *cmd, uint8_t len)
     advsm->scan_rsp_len = datalen;
     memcpy(advsm->scan_rsp_data, cmd + 1, datalen);
 
-    /* Re-make the scan response PDU since data may have changed */
-    OS_ENTER_CRITICAL(sr);
-    /*
-     * XXX: there is a chance, even with interrupts disabled, that
-     * we are transmitting the scan response PDU while writing to it.
-     */
-    ble_ll_adv_scan_rsp_pdu_make(advsm);
-    OS_EXIT_CRITICAL(sr);
-
     return 0;
 }
 
@@ -828,27 +810,53 @@ static int
 ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu)
 {
     int rc;
+    int index;
     uint8_t chk_whitelist;
     uint8_t txadd;
     uint8_t *rxbuf;
+    uint8_t *adva;
     struct ble_mbuf_hdr *ble_hdr;
     struct ble_ll_adv_sm *advsm;
+    struct os_mbuf *scan_rsp;
 
+    /* See if adva in the request (scan or connect) matches what we sent */
+    advsm = &g_ble_ll_adv_sm;
     rxbuf = rxpdu->om_data;
-    if (ble_ll_adv_addr_cmp(rxbuf)) {
+    adva = rxbuf + BLE_LL_PDU_HDR_LEN + BLE_DEV_ADDR_LEN;
+    if (memcmp(advsm->adva, adva, BLE_DEV_ADDR_LEN)) {
         return -1;
     }
 
     /* Set device match bit if we are whitelisting */
-    advsm = &g_ble_ll_adv_sm;
     if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) {
         chk_whitelist = advsm->adv_filter_policy & 1;
     } else {
         chk_whitelist = advsm->adv_filter_policy & 2;
     }
 
-    /* Set device match bit if we are whitelisting */
     ble_hdr = BLE_MBUF_HDR_PTR(rxpdu);
+
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+    uint8_t *peer;
+
+    peer = rxbuf + BLE_LL_PDU_HDR_LEN;
+    if (ble_ll_is_resolvable_priv_addr(peer) && ble_ll_resolv_enabled()) {
+        index = ble_hw_resolv_list_match();
+        if (index >= 0) {
+            advsm->adv_rpa_index = index;
+            ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_RESOLVED;
+            if (chk_whitelist) {
+                chk_whitelist = 0;
+            }
+        } else {
+            if (chk_whitelist) {
+                return -1;
+            }
+        }
+    }
+#endif
+
+    /* Set device match bit if we are whitelisting */
     if (chk_whitelist) {
         /* Get the scanners address type */
         if (rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK) {
@@ -861,17 +869,25 @@ ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu)
         if (!ble_ll_whitelist_match(rxbuf + BLE_LL_PDU_HDR_LEN, txadd)) {
             return -1;
         }
-        ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_DEVMATCH;
     }
 
+    /*
+     * We set the device match bit to tell the upper layer that we will
+     * accept the request
+     */
+    ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_DEVMATCH;
+
     /* Setup to transmit the scan response if appropriate */
     rc = -1;
     if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) {
-        ble_phy_set_txend_cb(ble_ll_adv_tx_done, &g_ble_ll_adv_sm);
-        rc = ble_phy_tx(advsm->scan_rsp_pdu, BLE_PHY_TRANSITION_NONE);
-        if (!rc) {
-            ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_SCAN_RSP_TXD;
-            STATS_INC(ble_ll_stats, scan_rsp_txg);
+        scan_rsp = ble_ll_adv_scan_rsp_pdu_make(advsm);
+        if (scan_rsp) {
+            ble_phy_set_txend_cb(ble_ll_adv_tx_done, &g_ble_ll_adv_sm);
+            rc = ble_phy_tx(scan_rsp, BLE_PHY_TRANSITION_NONE);
+            if (!rc) {
+                ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_SCAN_RSP_TXD;
+                STATS_INC(ble_ll_stats, scan_rsp_txg);
+            }
         }
     }
 
@@ -893,6 +909,7 @@ ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct ble_mbuf_hdr 
*hdr)
 {
     int valid;
     uint8_t pyld_len;
+    uint8_t resolved;
     uint8_t *inita;
     uint32_t endtime;
     struct ble_ll_adv_sm *advsm;
@@ -900,14 +917,10 @@ ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct 
ble_mbuf_hdr *hdr)
     /* Check filter policy. */
     valid = 0;
     advsm = &g_ble_ll_adv_sm;
-    if (advsm->adv_filter_policy & 2) {
-        if (hdr->rxinfo.flags & BLE_MBUF_HDR_F_DEVMATCH) {
-            /* valid connection request received */
-            valid = 1;
-        }
-    } else {
-        /* If this is for us? */
-        if (!ble_ll_adv_addr_cmp(rxbuf)) {
+    inita = rxbuf + BLE_LL_PDU_HDR_LEN;
+    if (hdr->rxinfo.flags & BLE_MBUF_HDR_F_DEVMATCH) {
+        valid = 1;
+        if ((advsm->adv_filter_policy & 2) == 0) {
             /*
              * Only accept connect requests from the desired address if we
              * are doing directed advertising
@@ -915,22 +928,36 @@ ble_ll_adv_conn_req_rxd(uint8_t *rxbuf, struct 
ble_mbuf_hdr *hdr)
             if ((advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) ||
                 (advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_LD)) {
                 /* XXX: not sure if this works if address is random */
+                /* WWW: deal with RPA */
                 /* Compare addresses */
-                inita = rxbuf + BLE_LL_PDU_HDR_LEN;
-                if (!memcmp(advsm->initiator_addr, inita, BLE_DEV_ADDR_LEN)) {
-                    valid = 1;
+                if (memcmp(advsm->initiator_addr, inita, BLE_DEV_ADDR_LEN)) {
+                    valid = 0;
                 }
-            } else {
-                valid = 1;
             }
         }
     }
 
     if (valid) {
+        resolved = BLE_MBUF_HDR_RESOLVED(hdr);
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+        if (resolved) {
+            /* Retain the resolvable private address that we received. */
+            memcpy(advsm->adv_rpa, inita, BLE_DEV_ADDR_LEN);
+
+            /*
+             * Overwrite received inita with identity address since that
+             * is used from now on.
+             */
+            memcpy(inita,
+                   g_ble_ll_resolv_list[advsm->adv_rpa_index].rl_identity_addr,
+                   BLE_DEV_ADDR_LEN);
+        }
+#endif
+
         /* Try to start slave connection. If successful, stop advertising */
         pyld_len = rxbuf[1] & BLE_ADV_PDU_HDR_LEN_MASK;
         endtime = hdr->beg_cputime + BLE_TX_DUR_USECS_M(pyld_len);
-        valid = ble_ll_conn_slave_start(rxbuf, endtime);
+        valid = ble_ll_conn_slave_start(rxbuf, endtime, resolved);
         if (valid) {
             ble_ll_adv_sm_stop(advsm);
         }
@@ -1251,9 +1278,6 @@ ble_ll_adv_reset(void)
     /* Stop advertising state machine */
     ble_ll_adv_sm_stop(advsm);
 
-    /* Free scan pdu's */
-    os_mbuf_free_chain(advsm->scan_rsp_pdu);
-
     /* re-initialize the advertiser state machine */
     ble_ll_adv_init();
 }
@@ -1285,10 +1309,5 @@ ble_ll_adv_init(void)
     /* Initialize advertising tx done event */
     advsm->adv_txdone_ev.ev_type = BLE_LL_EVENT_ADV_EV_DONE;
     advsm->adv_txdone_ev.ev_arg = advsm;
-
-    /* Get a scan response mbuf (packet header) and attach to state machine */
-    advsm->scan_rsp_pdu = os_msys_get_pkthdr(BLE_MBUF_PAYLOAD_SIZE,
-                                             sizeof(struct ble_mbuf_hdr));
-    assert(advsm->scan_rsp_pdu != NULL);
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7327c542/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 e42f589..fe72a8e 100644
--- a/net/nimble/controller/src/ble_ll_conn.c
+++ b/net/nimble/controller/src/ble_ll_conn.c
@@ -1302,6 +1302,8 @@ ble_ll_conn_master_init(struct ble_ll_conn_sm *connsm,
     connsm->slave_latency = hcc->conn_latency;
     connsm->supervision_tmo = hcc->supervision_timeout;
 
+    /* WWW: if not using whitelist, what happens if we resolve the address?
+       we would have to set the differently huh? CHeck this out... */
     /* Set own address type and peer address if needed */
     connsm->own_addr_type = hcc->own_addr_type;
     if (hcc->filter_policy == 0) {
@@ -1775,6 +1777,7 @@ ble_ll_conn_created(struct ble_ll_conn_sm *connsm, 
uint32_t endtime)
                 ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD);
             }
         }
+        /* WWW: enhanced connection complete! */
         ble_ll_conn_comp_event_send(connsm, BLE_ERR_SUCCESS);
     }
 
@@ -2744,14 +2747,13 @@ ble_ll_conn_set_global_chanmap(uint8_t num_used_chans, 
uint8_t *chanmap)
  * @return 0: connection not started; 1 connecton started
  */
 int
-ble_ll_conn_slave_start(uint8_t *rxbuf, uint32_t conn_req_end)
+ble_ll_conn_slave_start(uint8_t *rxbuf, uint32_t conn_req_end, uint8_t 
resolved)
 {
     int rc;
     uint32_t temp;
     uint32_t crcinit;
     uint8_t *inita;
     uint8_t *dptr;
-    uint8_t addr_type;
     struct ble_ll_conn_sm *connsm;
 
     /* Ignore the connection request if we are already connected*/
@@ -2759,12 +2761,13 @@ ble_ll_conn_slave_start(uint8_t *rxbuf, uint32_t 
conn_req_end)
     SLIST_FOREACH(connsm, &g_ble_ll_conn_active_list, act_sle) {
         if (!memcmp(&connsm->peer_addr, inita, BLE_DEV_ADDR_LEN)) {
             if (rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK) {
-                addr_type = BLE_HCI_CONN_PEER_ADDR_RANDOM;
+                if (connsm->peer_addr_type & 1) {
+                    return 0;
+                }
             } else {
-                addr_type = BLE_HCI_CONN_PEER_ADDR_PUBLIC;
-            }
-            if (connsm->peer_addr_type == addr_type) {
-                return 0;
+                if ((connsm->peer_addr_type & 1) == 0) {
+                    return 0;
+                }
             }
         }
     }
@@ -2821,13 +2824,22 @@ ble_ll_conn_slave_start(uint8_t *rxbuf, uint32_t 
conn_req_end)
         goto err_slave_start;
     }
 
-    /* XXX: might want to set this differently based on adv. filter policy! */
+    /* WWW: what about master when it makes a connection? It has to do this
+       properly! */
     /* Set the address of device that we are connecting with */
-    memcpy(&connsm->peer_addr, rxbuf + BLE_LL_PDU_HDR_LEN, BLE_DEV_ADDR_LEN);
+    memcpy(&connsm->peer_addr, inita, BLE_DEV_ADDR_LEN);
     if (rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK) {
-        connsm->peer_addr_type = BLE_HCI_CONN_PEER_ADDR_RANDOM;
+        if (resolved) {
+            connsm->peer_addr_type = BLE_HCI_CONN_PEER_ADDR_RANDOM_IDENT;
+        } else {
+            connsm->peer_addr_type = BLE_HCI_CONN_PEER_ADDR_RANDOM;
+        }
     } else {
-        connsm->peer_addr_type = BLE_HCI_CONN_PEER_ADDR_PUBLIC;
+        if (resolved) {
+            connsm->peer_addr_type = BLE_HCI_CONN_PEER_ADDR_PUBLIC_IDENT;
+        } else {
+            connsm->peer_addr_type = BLE_HCI_CONN_PEER_ADDR_PUBLIC;
+        }
     }
 
     /* Calculate number of used channels; make sure it meets min requirement */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7327c542/net/nimble/controller/src/ble_ll_conn_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn_priv.h 
b/net/nimble/controller/src/ble_ll_conn_priv.h
index 4cfd041..24a7a1e 100644
--- a/net/nimble/controller/src/ble_ll_conn_priv.h
+++ b/net/nimble/controller/src/ble_ll_conn_priv.h
@@ -92,7 +92,8 @@ void ble_ll_conn_datalen_update(struct ble_ll_conn_sm *connsm,
                                 struct ble_ll_len_req *req);
 
 /* Advertising interface */
-int ble_ll_conn_slave_start(uint8_t *rxbuf, uint32_t conn_req_end);
+int ble_ll_conn_slave_start(uint8_t *rxbuf, uint32_t conn_req_end,
+                            uint8_t resolved);
 
 /* Link Layer interface */
 void ble_ll_conn_module_init(void);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7327c542/net/nimble/controller/src/ble_ll_ctrl.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_ctrl.c 
b/net/nimble/controller/src/ble_ll_ctrl.c
index aee7c83..73a5ac2 100644
--- a/net/nimble/controller/src/ble_ll_ctrl.c
+++ b/net/nimble/controller/src/ble_ll_ctrl.c
@@ -25,8 +25,8 @@
 #include "controller/ble_ll.h"
 #include "controller/ble_ll_hci.h"
 #include "controller/ble_ll_ctrl.h"
-#include "ble_ll_conn_priv.h"
 #include "controller/ble_hw.h"
+#include "ble_ll_conn_priv.h"
 
 /* To use spec sample data for testing */
 #undef BLE_LL_ENCRYPT_USE_TEST_DATA

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7327c542/net/nimble/controller/src/ble_ll_hci.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_hci.c 
b/net/nimble/controller/src/ble_ll_hci.c
index 862eebc..3cbec48 100644
--- a/net/nimble/controller/src/ble_ll_hci.c
+++ b/net/nimble/controller/src/ble_ll_hci.c
@@ -30,6 +30,7 @@
 #include "controller/ble_ll.h"
 #include "controller/ble_ll_hci.h"
 #include "controller/ble_ll_whitelist.h"
+#include "controller/ble_ll_resolv.h"
 #include "ble_ll_conn_priv.h"
 
 /* LE event mask */
@@ -639,6 +640,32 @@ ble_ll_hci_le_cmd_proc(uint8_t *cmdbuf, uint16_t ocf, 
uint8_t *rsplen)
         rc = ble_ll_hci_le_wr_sugg_data_len(cmdbuf);
         break;
 #endif
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+    case BLE_HCI_OCF_LE_ADD_RESOLV_LIST :
+        ble_ll_resolv_list_add(cmdbuf);
+        break;
+    case BLE_HCI_OCF_LE_RMV_RESOLV_LIST:
+        ble_ll_resolv_list_rmv(cmdbuf);
+        break;
+    case BLE_HCI_OCF_LE_CLR_RESOLV_LIST:
+        rc = ble_ll_resolv_list_clr();
+        break;
+    case BLE_HCI_OCF_LE_RD_RESOLV_LIST_SIZE:
+        rc = ble_ll_resolv_list_read_size(rspbuf, rsplen);
+        break;
+    case BLE_HCI_OCF_LE_RD_PEER_RESOLV_ADDR:
+        rc = ble_ll_resolv_peer_addr_rd(cmdbuf);
+        break;
+    case BLE_HCI_OCF_LE_RD_LOCAL_RESOLV_ADDR:
+        ble_ll_resolv_local_addr_rd(cmdbuf);
+        break;
+    case BLE_HCI_OCF_LE_SET_ADDR_RES_EN:
+        rc = ble_ll_resolv_enable_cmd(cmdbuf);
+        break;
+    case BLE_HCI_OCF_LE_SET_RPA_TMO:
+        /* XXX: implement */
+        break;
+#endif
     case BLE_HCI_OCF_LE_RD_MAX_DATA_LEN:
         rc = ble_ll_hci_le_rd_max_data_len(rspbuf, rsplen);
         break;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7327c542/net/nimble/controller/src/ble_ll_rand.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_rand.c 
b/net/nimble/controller/src/ble_ll_rand.c
index f0e69f7..4da599f 100644
--- a/net/nimble/controller/src/ble_ll_rand.c
+++ b/net/nimble/controller/src/ble_ll_rand.c
@@ -103,6 +103,32 @@ ble_ll_rand_data_get(uint8_t *buf, uint8_t len)
 }
 
 /**
+ * Called to obtain a "prand" as defined in core V4.2 Vol 6 Part B 1.3.2.2
+ *
+ * @param prand
+ */
+void
+ble_ll_rand_prand_get(uint8_t *prand)
+{
+    uint16_t sum;
+
+    while (1) {
+        /* Get 24 bits of random data */
+        ble_ll_rand_data_get(prand, 3);
+
+        /* Prand cannot be all zeros or 1's. */
+        sum = prand[0] + prand[1] + prand[2];
+        if ((sum != 0) && (sum != (3 * 0xff))) {
+            break;
+        }
+    }
+
+    /* Upper two bits must be 01 */
+    prand[2] &= ~0xc0;
+    prand[2] |= 0x40;
+}
+
+/**
  * Start the generation of random numbers
  *
  * @return int

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7327c542/net/nimble/controller/src/ble_ll_resolv.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_resolv.c 
b/net/nimble/controller/src/ble_ll_resolv.c
new file mode 100644
index 0000000..62d85e4
--- /dev/null
+++ b/net/nimble/controller/src/ble_ll_resolv.c
@@ -0,0 +1,378 @@
+/**
+ * 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 <assert.h>
+#include <string.h>
+#include "os/os.h"
+#include "nimble/ble.h"
+#include "nimble/nimble_opt.h"
+#include "controller/ble_ll.h"
+#include "controller/ble_ll_resolv.h"
+#include "controller/ble_ll_hci.h"
+#include "controller/ble_ll_scan.h"
+#include "controller/ble_ll_adv.h"
+#include "controller/ble_hw.h"
+#include "ble_ll_conn_priv.h"
+
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+
+/* Flag denoting whether or not address translation is enabled. */
+uint8_t g_ble_ll_addr_res_enabled;
+uint8_t g_ble_ll_resolv_list_size;
+uint8_t g_ble_ll_resolv_list_cnt;
+
+struct ble_ll_resolv_entry 
g_ble_ll_resolv_list[NIMBLE_OPT_LL_RESOLV_LIST_SIZE];
+
+/**
+ * Called to determine if a change is allowed to the resolving list at this
+ * time. We are not allowed to modify the resolving list if address translation
+ * is enabled and we are either scanning, advertising, or attempting to create
+ * a connection.
+ *
+ * @return int 0: not allowed. 1: allowed.
+ */
+static int
+ble_ll_resolv_list_chg_allowed(void)
+{
+    int rc;
+
+    if (g_ble_ll_addr_res_enabled && (ble_ll_adv_enabled()  ||
+                                      ble_ll_scan_enabled() ||
+                                      g_ble_ll_conn_create_sm)) {
+        rc = 0;
+    } else {
+        rc = 1;
+    }
+    return rc;
+}
+
+/**
+ * Called to determine if the IRK is all zero.
+ *
+ * @param irk
+ *
+ * @return int 0: IRK has a non-zero value. 1: IRK is all zero.
+ */
+int
+ble_ll_resolv_irk_nonzero(uint8_t *irk)
+{
+    int i;
+    int rc;
+
+    rc = 1;
+    for (i = 0; i < 16; ++i) {
+        if (*irk != 0) {
+            rc = 0;
+            break;
+        }
+        ++irk;
+    }
+
+    return rc;
+}
+
+/**
+ * Clear the resolving list
+ *
+ * @return int 0: success, BLE error code otherwise
+ */
+int
+ble_ll_resolv_list_clr(void)
+{
+    /* Check proper state */
+    if (!ble_ll_resolv_list_chg_allowed()) {
+        return BLE_ERR_CMD_DISALLOWED;
+    }
+
+    /* Sets total on list to 0. Clears HW resolve list */
+    g_ble_ll_resolv_list_cnt = 0;
+    ble_hw_resolv_list_clear();
+
+    return BLE_ERR_SUCCESS;
+}
+
+/**
+ * Read the size of the resolving list. This is the total number of resolving
+ * list entries allowed by the controller.
+ *
+ * @param rspbuf Pointer to response buffer
+ *
+ * @return int 0: success.
+ */
+int
+ble_ll_resolv_list_read_size(uint8_t *rspbuf, uint8_t *rsplen)
+{
+    rspbuf[0] = g_ble_ll_resolv_list_size;
+    *rsplen = 1;
+    return BLE_ERR_SUCCESS;
+}
+
+/**
+ * Used to determine if the device is on the resolving list.
+ *
+ * @param addr
+ * @param addr_type Public address (0) or random address (1)
+ *
+ * @return int 0: device is not on resolving list; otherwise the return value
+ * is the 'position' of the device in the resolving list (the index of the
+ * element plus 1).
+ */
+static int
+ble_ll_is_on_resolv_list(uint8_t *addr, uint8_t addr_type)
+{
+    int i;
+    struct ble_ll_resolv_entry *rl;
+
+    rl = &g_ble_ll_resolv_list[0];
+    for (i = 0; i < g_ble_ll_resolv_list_cnt; ++i) {
+        if ((rl->rl_addr_type == addr_type) &&
+            (!memcmp(&rl->rl_identity_addr[0], addr, BLE_DEV_ADDR_LEN))) {
+            return i + 1;
+        }
+        ++rl;
+    }
+
+    return 0;
+}
+
+/**
+ * Used to determine if the device is on the resolving list.
+ *
+ * @param addr
+ * @param addr_type Public address (0) or random address (1)
+ *
+ * @return Pointer to resolving list entry or NULL if no entry found.
+ */
+struct ble_ll_resolv_entry *
+ble_ll_resolv_list_find(uint8_t *addr, uint8_t addr_type)
+{
+    int i;
+    struct ble_ll_resolv_entry *rl;
+
+    rl = &g_ble_ll_resolv_list[0];
+    for (i = 0; i < g_ble_ll_resolv_list_cnt; ++i) {
+        if ((rl->rl_addr_type == addr_type) &&
+            (!memcmp(&rl->rl_identity_addr[0], addr, BLE_DEV_ADDR_LEN))) {
+            return rl;
+        }
+        ++rl;
+    }
+
+    return NULL;
+}
+
+/**
+ * Is there a match between the device and a device on the resolving list
+ *
+ * @param addr
+ * @param addr_type Public address (0) or random address (1)
+ *
+ * @return int
+ */
+int
+ble_ll_resolv_list_match(uint8_t *addr, uint8_t addr_type)
+{
+    int rc;
+    /* WWW: will this be used? */
+#ifdef BLE_USES_HW_RESOLV_LIST
+    rc = ble_hw_resolv_list_match();
+#else
+    rc = ble_ll_is_on_resolv_list(addr, addr_type);
+#endif
+    return rc;
+}
+
+/**
+ * Add a device to the resolving list
+ *
+ * @return int
+ */
+int
+ble_ll_resolv_list_add(uint8_t *cmdbuf)
+{
+    int rc;
+    uint8_t addr_type;
+    uint8_t *ident_addr;
+    struct ble_ll_resolv_entry *rl;
+
+    /* Must be in proper state */
+    if (!ble_ll_resolv_list_chg_allowed()) {
+        return BLE_ERR_CMD_DISALLOWED;
+    }
+
+    /* Check if we have any open entries */
+    if (g_ble_ll_resolv_list_cnt >= g_ble_ll_resolv_list_size) {
+        return BLE_ERR_MEM_CAPACITY;
+    }
+
+    addr_type = cmdbuf[0];
+    ident_addr = cmdbuf + 1;
+
+    rc = BLE_ERR_SUCCESS;
+    if (!ble_ll_is_on_resolv_list(ident_addr, addr_type)) {
+        rl = &g_ble_ll_resolv_list[g_ble_ll_resolv_list_cnt];
+        rl->rl_addr_type = addr_type;
+        memcpy(&rl->rl_identity_addr[0], ident_addr, BLE_DEV_ADDR_LEN);
+        swap_buf(rl->rl_peer_irk, cmdbuf + 7, 16);
+        swap_buf(rl->rl_local_irk, cmdbuf + 23, 16);
+        ++g_ble_ll_resolv_list_cnt;
+
+        rc = ble_hw_resolv_list_add(rl->rl_peer_irk);
+    }
+
+    return rc;
+}
+
+/**
+ * Remove a device from the resolving list
+ *
+ * @param cmdbuf
+ *
+ * @return int 0: success, BLE error code otherwise
+ */
+int
+ble_ll_resolv_list_rmv(uint8_t *cmdbuf)
+{
+    int position;
+    uint8_t addr_type;
+    uint8_t *ident_addr;
+
+    /* Must be in proper state */
+    if (!ble_ll_resolv_list_chg_allowed()) {
+        return BLE_ERR_CMD_DISALLOWED;
+    }
+
+    addr_type = cmdbuf[0];
+    ident_addr = cmdbuf + 1;
+
+    /* Remove from IRK records */
+    position = ble_ll_is_on_resolv_list(ident_addr, addr_type);
+    if (position && (position < g_ble_ll_resolv_list_cnt)) {
+        memmove(&g_ble_ll_resolv_list[position - 1],
+                &g_ble_ll_resolv_list[position],
+                g_ble_ll_resolv_list_cnt - position);
+        --g_ble_ll_resolv_list_cnt;
+
+        /* Remove from HW list */
+        ble_hw_resolv_list_rmv(position - 1);
+    }
+
+    return BLE_ERR_SUCCESS;
+}
+
+/**
+ * Called to enable or disable address resolution in the controller
+ *
+ * @param cmdbuf
+ *
+ * @return int
+ */
+int
+ble_ll_resolv_enable_cmd(uint8_t *cmdbuf)
+{
+    int rc;
+
+    if (ble_ll_adv_enabled() || ble_ll_scan_enabled() ||
+        g_ble_ll_conn_create_sm) {
+        rc = BLE_ERR_CMD_DISALLOWED;
+    } else {
+        /* WWW: do we do anything here if we change state? */
+        g_ble_ll_addr_res_enabled = cmdbuf[0];
+        rc = BLE_ERR_SUCCESS;
+    }
+
+    return rc;
+}
+
+int
+ble_ll_resolv_peer_addr_rd(uint8_t *cmdbuf)
+{
+    /* XXX */
+    return 0;
+}
+
+void
+ble_ll_resolv_local_addr_rd(uint8_t *cmdbuf)
+{
+}
+
+/**
+ * Called the generate a resolvable private address
+ *
+ *
+ * @param rl
+ * @param local
+ * @param addr Pointer to resolvable private address
+ */
+void
+ble_ll_resolv_gen_priv_addr(struct ble_ll_resolv_entry *rl, int local,
+                            uint8_t *addr)
+{
+    uint8_t *irk;
+    uint8_t *prand;
+    struct ble_encryption_block ecb;
+
+    assert(rl != NULL);
+    assert(addr != NULL);
+
+    /* Get prand */
+    prand = addr + 3;
+    ble_ll_rand_prand_get(prand);
+
+    /* Calculate hash, hash = ah(local IRK, prand) */
+    if (local) {
+        irk = rl->rl_local_irk;
+    } else {
+        irk = rl->rl_peer_irk;
+    }
+
+    memcpy(ecb.key, irk, BLE_ENC_BLOCK_SIZE);
+    memset(ecb.plain_text, 0, BLE_ENC_BLOCK_SIZE);
+    swap_buf(&ecb.plain_text[13], prand, 3);
+
+    /* Calculate hash */
+    ble_hw_encrypt_block(&ecb);
+    swap_buf(addr, ecb.cipher_text, 3);
+}
+
+/**
+ * Returns whether or not address resolution is enabled.
+ *
+ * @return uint8_t
+ */
+uint8_t
+ble_ll_resolv_enabled(void)
+{
+    return g_ble_ll_addr_res_enabled;
+}
+
+/**
+ * Called to reset private address resolution module.
+ */
+void
+ble_ll_resolv_list_reset(void)
+{
+    ble_ll_resolv_list_clr();
+    g_ble_ll_addr_res_enabled = 0;
+    /* XXX: deal with HW restrictions */
+    g_ble_ll_resolv_list_size = NIMBLE_OPT_LL_RESOLV_LIST_SIZE;
+}
+
+#endif  /* if BLE_LL_CFG_FEAT_LL_PRIVACY == 1 */
+

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7327c542/net/nimble/controller/src/ble_ll_scan.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_scan.c 
b/net/nimble/controller/src/ble_ll_scan.c
index 7ebfc46..f675ec7 100644
--- a/net/nimble/controller/src/ble_ll_scan.c
+++ b/net/nimble/controller/src/ble_ll_scan.c
@@ -392,6 +392,8 @@ ble_ll_hci_send_adv_report(uint8_t pdu_type, uint8_t txadd, 
uint8_t *rxbuf,
             evbuf[3] = 1;       /* number of reports */
             evbuf[4] = evtype;
 
+            /* WWW: Yeah... if we are using private resolvable addresses
+               we need to deal here. The address type is different... */
             /* XXX: need to deal with resolvable addresses here! */
             if (txadd) {
                 evbuf[5] = BLE_HCI_ADV_OWN_ADDR_RANDOM;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7327c542/net/nimble/drivers/nrf51/src/ble_hw.c
----------------------------------------------------------------------
diff --git a/net/nimble/drivers/nrf51/src/ble_hw.c 
b/net/nimble/drivers/nrf51/src/ble_hw.c
index cc9dcbd..498840d 100644
--- a/net/nimble/drivers/nrf51/src/ble_hw.c
+++ b/net/nimble/drivers/nrf51/src/ble_hw.c
@@ -6,7 +6,7 @@
  * 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,
@@ -22,23 +22,45 @@
 #include <string.h>
 #include "os/os.h"
 #include "nimble/ble.h"
+#include "nimble/nimble_opt.h"
 #include "mcu/nrf51_bitfields.h"
 #include "controller/ble_hw.h"
 #include "bsp/cmsis_nvic.h"
 
-/* Total number of white list elements supported by nrf52 */
+/* Total number of white list elements */
 #define BLE_HW_WHITE_LIST_SIZE      (8)
 
+/* Total number of resolving list elements */
+#define BLE_HW_RESOLV_LIST_SIZE     (16)
+
 /* We use this to keep track of which entries are set to valid addresses */
 static uint8_t g_ble_hw_whitelist_mask;
 
 /* Random number generator isr callback */
 ble_rng_isr_cb_t g_ble_rng_isr_cb;
 
+/* If LL privacy is enabled, allocate memory for AAR */
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+
+/* The NRF51 supports up to 16 IRK entries */
+#if (NIMBLE_OPT_LL_RESOLV_LIST_SIZE < 16)
+#define NRF_IRK_LIST_ENTRIES    (NIMBLE_OPT_LL_RESOLV_LIST_SIZE)
+#else
+#define NRF_IRK_LIST_ENTRIES    (16)
+#endif
+
+/* NOTE: each entry is 16 bytes long. */
+uint32_t g_nrf_irk_list[NRF_IRK_LIST_ENTRIES * 4];
+
+/* Current number of IRK entries */
+uint8_t g_nrf_num_irks;
+
+#endif
+
 /**
  * Clear the whitelist
- * 
- * @return int 
+ *
+ * @return int
  */
 void
 ble_hw_whitelist_clear(void)
@@ -48,11 +70,11 @@ ble_hw_whitelist_clear(void)
 }
 
 /**
- * Add a device to the hw whitelist 
- * 
- * @param addr 
- * @param addr_type 
- * 
+ * Add a device to the hw whitelist
+ *
+ * @param addr
+ * @param addr_type
+ *
  * @return int 0: success, BLE error code otherwise
  */
 int
@@ -80,11 +102,11 @@ ble_hw_whitelist_add(uint8_t *addr, uint8_t addr_type)
 }
 
 /**
- * Remove a device from the hw whitelist 
- * 
- * @param addr 
- * @param addr_type 
- * 
+ * Remove a device from the hw whitelist
+ *
+ * @param addr
+ * @param addr_type
+ *
  */
 void
 ble_hw_whitelist_rmv(uint8_t *addr, uint8_t addr_type)
@@ -126,8 +148,8 @@ ble_hw_whitelist_rmv(uint8_t *addr, uint8_t addr_type)
 }
 
 /**
- * Returns the size of the whitelist in HW 
- * 
+ * Returns the size of the whitelist in HW
+ *
  * @return int Number of devices allowed in whitelist
  */
 uint8_t
@@ -137,7 +159,7 @@ ble_hw_whitelist_size(void)
 }
 
 /**
- * Enable the whitelisted devices 
+ * Enable the whitelisted devices
  */
 void
 ble_hw_whitelist_enable(void)
@@ -147,7 +169,7 @@ ble_hw_whitelist_enable(void)
 }
 
 /**
- * Disables the whitelisted devices 
+ * Disables the whitelisted devices
  */
 void
 ble_hw_whitelist_disable(void)
@@ -157,10 +179,10 @@ ble_hw_whitelist_disable(void)
 }
 
 /**
- * Boolean function which returns true ('1') if there is a match on the 
- * whitelist. 
- * 
- * @return int 
+ * Boolean function which returns true ('1') if there is a match on the
+ * whitelist.
+ *
+ * @return int
  */
 int
 ble_hw_whitelist_match(void)
@@ -173,9 +195,12 @@ int
 ble_hw_encrypt_block(struct ble_encryption_block *ecb)
 {
     int rc;
+    uint32_t end;
+    uint32_t err;
 
     /* Stop ECB */
     NRF_ECB->TASKS_STOPECB = 1;
+    /* XXX: does task stop clear these counters? Anyway to do this quicker? */
     NRF_ECB->EVENTS_ENDECB = 0;
     NRF_ECB->EVENTS_ERRORECB = 0;
     NRF_ECB->ECBDATAPTR = (uint32_t)ecb;
@@ -184,14 +209,14 @@ ble_hw_encrypt_block(struct ble_encryption_block *ecb)
     NRF_ECB->TASKS_STARTECB = 1;
 
     /* Wait till error or done */
+    rc = 0;
     while (1) {
-        if (NRF_ECB->EVENTS_ENDECB != 0) {
-            rc = 0;
-            break;
-        }
-
-        if (NRF_ECB->EVENTS_ERRORECB != 0) {
-            rc = -1;
+        end = NRF_ECB->EVENTS_ENDECB;
+        err = NRF_ECB->EVENTS_ERRORECB;
+        if (end || err) {
+            if (err) {
+                rc = -1;
+            }
             break;
         }
     }
@@ -225,11 +250,11 @@ ble_rng_isr(void)
 
 /**
  * Initialize the random number generator
- * 
- * @param cb 
- * @param bias 
- * 
- * @return int 
+ *
+ * @param cb
+ * @param bias
+ *
+ * @return int
  */
 int
 ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias)
@@ -254,8 +279,8 @@ ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias)
 
 /**
  * Start the random number generator
- * 
- * @return int 
+ *
+ * @return int
  */
 int
 ble_hw_rng_start(void)
@@ -278,8 +303,8 @@ ble_hw_rng_start(void)
 
 /**
  * Stop the random generator
- * 
- * @return int 
+ *
+ * @return int
  */
 int
 ble_hw_rng_stop(void)
@@ -298,8 +323,8 @@ ble_hw_rng_stop(void)
 
 /**
  * Read the random number generator.
- * 
- * @return uint8_t 
+ *
+ * @return uint8_t
  */
 uint8_t
 ble_hw_rng_read(void)
@@ -315,3 +340,93 @@ ble_hw_rng_read(void)
 
     return rnum;
 }
+
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY)
+/**
+ * Clear the resolving list
+ *
+ * @return int
+ */
+void
+ble_hw_resolv_list_clear(void)
+{
+    g_nrf_num_irks = 0;
+}
+
+/**
+ * Add a device to the hw resolving list
+ *
+ * @param irk   Pointer to IRK to add
+ *
+ * @return int 0: success, BLE error code otherwise
+ */
+int
+ble_hw_resolv_list_add(uint8_t *irk)
+{
+    uint32_t *nrf_entry;
+
+    /* Find first ununsed device address match element */
+    if (g_nrf_num_irks == NRF_IRK_LIST_ENTRIES) {
+        return BLE_ERR_MEM_CAPACITY;
+    }
+
+    /* Copy into irk list */
+    nrf_entry = &g_nrf_irk_list[4 * g_nrf_num_irks];
+    memcpy(nrf_entry, irk, 16);
+
+    /* Add to total */
+    ++g_nrf_num_irks;
+    return BLE_ERR_SUCCESS;
+}
+
+/**
+ * Remove a device from the hw resolving list
+ *
+ * @param index Index of IRK to remove
+ */
+void
+ble_hw_resolv_list_rmv(int index)
+{
+    uint32_t *irk_entry;
+
+    if (index < g_nrf_num_irks) {
+        --g_nrf_num_irks;
+        irk_entry = &g_nrf_irk_list[index];
+        if (g_nrf_num_irks > index) {
+            memmove(irk_entry, irk_entry + 4, g_nrf_num_irks - index);
+        }
+    }
+}
+
+/**
+ * Returns the size of the whitelist in HW
+ *
+ * @return int Number of devices allowed in whitelist
+ */
+uint8_t
+ble_hw_resolv_list_size(void)
+{
+    return BLE_HW_RESOLV_LIST_SIZE;
+}
+
+/**
+ * Called to determine if the address received was resolved.
+ *
+ * @return int  Negative values indicate unresolved address; positive values
+ *              indicate index in resolving list of resolved address.
+ */
+int
+ble_hw_resolv_list_match(void)
+{
+    uint32_t index;
+
+    if (NRF_AAR->EVENTS_END) {
+        if (NRF_AAR->EVENTS_RESOLVED) {
+            index = NRF_AAR->STATUS;
+            return (int)index;
+        }
+    }
+
+    return -1;
+}
+#endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7327c542/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 e0f1fb2..e44b04d 100644
--- a/net/nimble/drivers/nrf51/src/ble_phy.c
+++ b/net/nimble/drivers/nrf51/src/ble_phy.c
@@ -41,6 +41,10 @@
  * crystal accuracy
  */
 
+/* XXX: private header file? */
+extern uint8_t g_nrf_num_irks;
+extern uint32_t g_nrf_irk_list[];
+
 /* To disable all radio interrupts */
 #define NRF_RADIO_IRQ_MASK_ALL  (0x34FF)
 
@@ -76,7 +80,9 @@ struct ble_phy_obj
     uint8_t phy_transition;
     uint8_t phy_rx_started;
     uint8_t phy_encrypted;
+    uint8_t phy_privacy;
     uint8_t phy_tx_pyld_len;
+    uint32_t phy_aar_scratch;
     uint32_t phy_access_address;
     struct os_mbuf *rxpdu;
     void *txend_arg;
@@ -159,7 +165,7 @@ STATS_NAME_END(ble_phy_stats)
  */
 
 #if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 1)
-
+/* XXX: test this. only needs 43 bytes. Should just not use the macro for 
this*/
 /* Per nordic, the number of bytes needed for scratch is 16 + MAX_PKT_SIZE */
 #define NRF_ENC_SCRATCH_WORDS   (((NIMBLE_OPT_LL_MAX_PKT_SIZE + 16) + 3) / 4)
 
@@ -254,8 +260,30 @@ ble_phy_rx_xcvr_setup(void)
     NRF_RADIO->PACKETPTR = (uint32_t)g_ble_phy_data.rxpdu->om_data;
 #endif
 
-    /* We dont want to trigger TXEN on output compare match */
-    NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk;
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+    if (g_ble_phy_data.phy_privacy) {
+        NRF_RADIO->PCNF0 = (6 << RADIO_PCNF0_LFLEN_Pos) |
+                           (2 << RADIO_PCNF0_S1LEN_Pos) |
+                           (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos);
+        NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Enabled;
+        NRF_AAR->ADDRPTR = (uint32_t)g_ble_phy_data.rxpdu->om_data;
+        NRF_AAR->SCRATCHPTR = (uint32_t)&g_ble_phy_data.phy_aar_scratch;
+        NRF_AAR->EVENTS_END = 0;
+        NRF_AAR->EVENTS_RESOLVED = 0;
+        NRF_AAR->EVENTS_NOTRESOLVED = 0;
+    } else {
+        if (g_ble_phy_data.phy_encrypted == 0) {
+            NRF_RADIO->PCNF0 = (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) |
+                               (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos);
+            /* XXX: do I only need to do this once? Figure out what I can do
+               once. */
+            NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Disabled;
+        }
+    }
+#endif
+
+    /* Turn off trigger TXEN on output compare match and AAR on bcmatch */
+    NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk | PPI_CHEN_CH23_Msk;
 
     /* Reset the rx started flag. Used for the wait for response */
     g_ble_phy_data.phy_rx_started = 0;
@@ -284,8 +312,8 @@ ble_phy_rx_xcvr_setup(void)
 static void
 ble_phy_tx_end_isr(void)
 {
-    uint8_t txlen;
     uint8_t transition;
+    uint8_t txlen;
     uint32_t wfr_time;
 
     /* Better be in TX state! */
@@ -416,8 +444,8 @@ ble_phy_rx_end_isr(void)
     rxpdu = g_ble_phy_data.rxpdu;
     g_ble_phy_data.rxpdu = NULL;
 
-#if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 1)
-    if (g_ble_phy_data.phy_encrypted) {
+#if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 1) || (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+    if (g_ble_phy_data.phy_encrypted || g_ble_phy_data.phy_privacy) {
         /*
          * XXX: This is a horrible ugly hack to deal with the RAM S1 byte.
          * This should get fixed as we should not be handing up the header
@@ -479,6 +507,15 @@ ble_phy_rx_start_isr(void)
         /* Set rx started flag and enable rx end ISR */
         g_ble_phy_data.phy_rx_started = 1;
         NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk;
+
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+        /* Must start aar if we need to  */
+        if (g_ble_phy_data.phy_privacy) {
+            NRF_RADIO->EVENTS_BCMATCH = 0;
+            NRF_PPI->CHENSET = PPI_CHEN_CH23_Msk;
+            NRF_RADIO->BCC = (BLE_DEV_ADDR_LEN + BLE_LL_PDU_HDR_LEN) * 8;
+        }
+#endif
     } else {
         /* Disable PHY */
         ble_phy_disable();
@@ -584,11 +621,20 @@ ble_phy_init(void)
 #if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 1)
     NRF_CCM->INTENCLR = 0xffffffff;
     NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk;
-    NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Enabled;
     NRF_CCM->EVENTS_ERROR = 0;
     memset(g_nrf_encrypt_scratchpad, 0, sizeof(g_nrf_encrypt_scratchpad));
 #endif
 
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+    g_ble_phy_data.phy_aar_scratch = 0;
+    NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0];
+    NRF_AAR->INTENCLR = 0xffffffff;
+    NRF_AAR->EVENTS_END = 0;
+    NRF_AAR->EVENTS_RESOLVED = 0;
+    NRF_AAR->EVENTS_NOTRESOLVED = 0;
+    NRF_AAR->NIRK = 0;
+#endif
+
     /* Set isr in vector table and enable interrupt */
     NVIC_SetPriority(RADIO_IRQn, 0);
     NVIC_SetVector(RADIO_IRQn, (uint32_t)ble_phy_isr);
@@ -675,6 +721,10 @@ ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, 
uint8_t *key,
     NRF_RADIO->PCNF0 = (5 << RADIO_PCNF0_LFLEN_Pos) |
                        (3 << RADIO_PCNF0_S1LEN_Pos) |
                        (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos);
+
+    /* Enable the module (AAR cannot be on while CCM on) */
+    NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Disabled;
+    NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Enabled;
 }
 
 void
@@ -690,6 +740,7 @@ ble_phy_encrypt_disable(void)
     NRF_PPI->CHENCLR = (PPI_CHEN_CH24_Msk | PPI_CHEN_CH25_Msk);
     NRF_CCM->TASKS_STOP = 1;
     NRF_CCM->EVENTS_ERROR = 0;
+    NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Disabled;
 
     /* Switch back to normal length */
     NRF_RADIO->PCNF0 = (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) |
@@ -809,9 +860,16 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans)
         NRF_CCM->EVENTS_ERROR = 0;
         NRF_CCM->MODE = CCM_MODE_MODE_Encryption;
         NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data;
-        NRF_PPI->CHENCLR = PPI_CHEN_CH25_Msk;
+        NRF_PPI->CHENCLR = PPI_CHEN_CH25_Msk | PPI_CHEN_CH23_Msk;
         NRF_PPI->CHENSET = PPI_CHEN_CH24_Msk;
     } else {
+
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+        /* Reconfigure PCNF0 */
+        NRF_RADIO->PCNF0 = (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) |
+                           (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos);
+        NRF_PPI->CHENCLR = PPI_CHEN_CH23_Msk;
+#endif
         /* RAM representation has S0 and LENGTH fields (2 bytes) */
         dptr = (uint8_t *)&g_ble_phy_txrx_buf[0];
         dptr[0] = ble_hdr->txinfo.hdr_byte;
@@ -819,12 +877,21 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans)
         dptr += 2;
     }
 #else
+
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+    /* Reconfigure PCNF0 */
+    NRF_RADIO->PCNF0 = (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) |
+                       (NRF_S0_LEN << RADIO_PCNF0_S0LEN_Pos);
+    NRF_PPI->CHENCLR = PPI_CHEN_CH23_Msk;
+#endif
+
     /* RAM representation has S0 and LENGTH fields (2 bytes) */
     dptr = (uint8_t *)&g_ble_phy_txrx_buf[0];
     dptr[0] = ble_hdr->txinfo.hdr_byte;
     dptr[1] = payload_len;
     dptr += 2;
 #endif
+
     NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_txrx_buf[0];
 
     /* Clear the ready, end and disabled events */
@@ -1015,7 +1082,7 @@ ble_phy_disable(void)
     NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
     NRF_RADIO->SHORTS = 0;
     NRF_RADIO->TASKS_DISABLE = 1;
-    NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk | PPI_CHEN_CH20_Msk;
+    NRF_PPI->CHENCLR = PPI_CHEN_CH23_Msk | PPI_CHEN_CH21_Msk | 
PPI_CHEN_CH20_Msk;
     NVIC_ClearPendingIRQ(RADIO_IRQn);
     g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE;
 }
@@ -1061,13 +1128,6 @@ ble_phy_xcvr_state_get(void)
     return (uint8_t)state;
 }
 
-/*
- * Returns the maximum supported tx/rx PDU payload size, in bytes, for data
- * channel PDUs (this does not apply to advertising channel PDUs). Note
- * that the data channel PDU is composed of a 2-byte header, the payload, and
- * an optional MIC. The maximum payload is 251 bytes.
- */
-
 /**
  * Called to return the maximum data pdu payload length supported by the
  * phy. For this chip, if encryption is enabled, the maximum payload is 27
@@ -1084,3 +1144,18 @@ ble_phy_max_data_pdu_pyld(void)
     return BLE_LL_DATA_PDU_MAX_PYLD;
 #endif
 }
+
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+void
+ble_phy_resolv_list_enable(void)
+{
+    NRF_AAR->NIRK = (uint32_t)g_nrf_num_irks;
+    g_ble_phy_data.phy_privacy = 1;
+}
+
+void
+ble_phy_resolv_list_disable(void)
+{
+    g_ble_phy_data.phy_privacy = 0;
+}
+#endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7327c542/net/nimble/drivers/nrf52/src/ble_hw.c
----------------------------------------------------------------------
diff --git a/net/nimble/drivers/nrf52/src/ble_hw.c 
b/net/nimble/drivers/nrf52/src/ble_hw.c
index aacd983..ea32ce4 100644
--- a/net/nimble/drivers/nrf52/src/ble_hw.c
+++ b/net/nimble/drivers/nrf52/src/ble_hw.c
@@ -22,19 +22,41 @@
 #include <string.h>
 #include "os/os.h"
 #include "nimble/ble.h"
-#include "controller/ble_hw.h"
+#include "nimble/nimble_opt.h"
 #include "mcu/nrf52_bitfields.h"
+#include "controller/ble_hw.h"
 #include "bsp/cmsis_nvic.h"
 
-/* Total number of white list elements supported by nrf52 */
+/* Total number of white list elements */
 #define BLE_HW_WHITE_LIST_SIZE      (8)
 
+/* Total number of resolving list elements */
+#define BLE_HW_RESOLV_LIST_SIZE     (16)
+
 /* We use this to keep track of which entries are set to valid addresses */
 static uint8_t g_ble_hw_whitelist_mask;
 
 /* Random number generator isr callback */
 ble_rng_isr_cb_t g_ble_rng_isr_cb;
 
+/* If LL privacy is enabled, allocate memory for AAR */
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+
+/* The NRF51 supports up to 16 IRK entries */
+#if (NIMBLE_OPT_LL_RESOLV_LIST_SIZE < 16)
+#define NRF_IRK_LIST_ENTRIES    (NIMBLE_OPT_LL_RESOLV_LIST_SIZE)
+#else
+#define NRF_IRK_LIST_ENTRIES    (16)
+#endif
+
+/* NOTE: each entry is 16 bytes long. */
+uint32_t g_nrf_irk_list[NRF_IRK_LIST_ENTRIES * 4];
+
+/* Current number of IRK entries */
+uint8_t g_nrf_num_irks;
+
+#endif
+
 /**
  * Clear the whitelist
  *
@@ -318,3 +340,93 @@ ble_hw_rng_read(void)
 
     return rnum;
 }
+
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY)
+/**
+ * Clear the resolving list
+ *
+ * @return int
+ */
+void
+ble_hw_resolv_list_clear(void)
+{
+    g_nrf_num_irks = 0;
+}
+
+/**
+ * Add a device to the hw resolving list
+ *
+ * @param irk   Pointer to IRK to add
+ *
+ * @return int 0: success, BLE error code otherwise
+ */
+int
+ble_hw_resolv_list_add(uint8_t *irk)
+{
+    uint32_t *nrf_entry;
+
+    /* Find first ununsed device address match element */
+    if (g_nrf_num_irks == NRF_IRK_LIST_ENTRIES) {
+        return BLE_ERR_MEM_CAPACITY;
+    }
+
+    /* Copy into irk list */
+    nrf_entry = &g_nrf_irk_list[4 * g_nrf_num_irks];
+    memcpy(nrf_entry, irk, 16);
+
+    /* Add to total */
+    ++g_nrf_num_irks;
+    return BLE_ERR_SUCCESS;
+}
+
+/**
+ * Remove a device from the hw resolving list
+ *
+ * @param index Index of IRK to remove
+ */
+void
+ble_hw_resolv_list_rmv(int index)
+{
+    uint32_t *irk_entry;
+
+    if (index < g_nrf_num_irks) {
+        --g_nrf_num_irks;
+        irk_entry = &g_nrf_irk_list[index];
+        if (g_nrf_num_irks > index) {
+            memmove(irk_entry, irk_entry + 4, g_nrf_num_irks - index);
+        }
+    }
+}
+
+/**
+ * Returns the size of the whitelist in HW
+ *
+ * @return int Number of devices allowed in whitelist
+ */
+uint8_t
+ble_hw_resolv_list_size(void)
+{
+    return BLE_HW_RESOLV_LIST_SIZE;
+}
+
+/**
+ * Called to determine if the address received was resolved.
+ *
+ * @return int  Negative values indicate unresolved address; positive values
+ *              indicate index in resolving list of resolved address.
+ */
+int
+ble_hw_resolv_list_match(void)
+{
+    uint32_t index;
+
+    if (NRF_AAR->EVENTS_END) {
+        if (NRF_AAR->EVENTS_RESOLVED) {
+            index = NRF_AAR->STATUS;
+            return (int)index;
+        }
+    }
+
+    return -1;
+}
+#endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7327c542/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 13e75fd..08d0d8d 100644
--- a/net/nimble/drivers/nrf52/src/ble_phy.c
+++ b/net/nimble/drivers/nrf52/src/ble_phy.c
@@ -36,6 +36,16 @@
 
 /* XXX: 4) Make sure RF is higher priority interrupt than schedule */
 
+/*
+ * XXX: Maximum possible transmit time is 1 msec for a 60ppm crystal
+ * and 16ms for a 30ppm crystal! We need to limit PDU size based on
+ * crystal accuracy
+ */
+
+/* XXX: private header file? */
+extern uint8_t g_nrf_num_irks;
+extern uint32_t g_nrf_irk_list[];
+
 /* To disable all radio interrupts */
 #define NRF_RADIO_IRQ_MASK_ALL  (0x34FF)
 
@@ -65,7 +75,9 @@ struct ble_phy_obj
     uint8_t phy_transition;
     uint8_t phy_rx_started;
     uint8_t phy_encrypted;
+    uint8_t phy_privacy;
     uint8_t phy_tx_pyld_len;
+    uint32_t phy_aar_scratch;
     uint32_t phy_access_address;
     struct os_mbuf *rxpdu;
     void *txend_arg;
@@ -78,6 +90,7 @@ struct ble_phy_obj g_ble_phy_data;
 static uint32_t g_ble_phy_txrx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4];
 
 #if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 1)
+/* Make sure word-aligned for faster copies */
 static uint32_t g_ble_phy_enc_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4];
 #endif
 
@@ -249,8 +262,23 @@ ble_phy_rx_xcvr_setup(void)
     NRF_RADIO->PACKETPTR = (uint32_t)g_ble_phy_data.rxpdu->om_data;
 #endif
 
-    /* We dont want to trigger TXEN on output compare match */
-    NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk;
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+    if (g_ble_phy_data.phy_privacy) {
+        NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Enabled;
+        NRF_AAR->ADDRPTR = (uint32_t)g_ble_phy_data.rxpdu->om_data;
+        NRF_AAR->SCRATCHPTR = (uint32_t)&g_ble_phy_data.phy_aar_scratch;
+        NRF_AAR->EVENTS_END = 0;
+        NRF_AAR->EVENTS_RESOLVED = 0;
+        NRF_AAR->EVENTS_NOTRESOLVED = 0;
+    } else {
+        if (g_ble_phy_data.phy_encrypted == 0) {
+            NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Disabled;
+        }
+    }
+#endif
+
+    /* Turn off trigger TXEN on output compare match and AAR on bcmatch */
+    NRF_PPI->CHENCLR = PPI_CHEN_CH20_Msk | PPI_CHEN_CH23_Msk;
 
     /* Reset the rx started flag. Used for the wait for response */
     g_ble_phy_data.phy_rx_started = 0;
@@ -412,7 +440,7 @@ ble_phy_rx_end_isr(void)
     /*
      * XXX: This is a horrible ugly hack to deal with the RAM S1 byte
      * that is not sent over the air but is present here. Simply move the
-     * data pointer to deal with it. Fix this later. Do this in the nrf52
+     * data pointer to deal with it. Fix this later.
      */
     dptr[2] = dptr[1];
     dptr[1] = dptr[0];
@@ -469,6 +497,15 @@ ble_phy_rx_start_isr(void)
         /* Set rx started flag and enable rx end ISR */
         g_ble_phy_data.phy_rx_started = 1;
         NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk;
+
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+        /* Must start aar if we need to  */
+        if (g_ble_phy_data.phy_privacy) {
+            NRF_RADIO->EVENTS_BCMATCH = 0;
+            NRF_PPI->CHENSET = PPI_CHEN_CH23_Msk;
+            NRF_RADIO->BCC = (BLE_DEV_ADDR_LEN + BLE_LL_PDU_HDR_LEN) * 8;
+        }
+#endif
     } else {
         /* Disable PHY */
         ble_phy_disable();
@@ -576,11 +613,20 @@ ble_phy_init(void)
 #if (BLE_LL_CFG_FEAT_LE_ENCRYPTION == 1)
     NRF_CCM->INTENCLR = 0xffffffff;
     NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk;
-    NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Enabled;
     NRF_CCM->EVENTS_ERROR = 0;
     memset(g_nrf_encrypt_scratchpad, 0, sizeof(g_nrf_encrypt_scratchpad));
 #endif
 
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+    g_ble_phy_data.phy_aar_scratch = 0;
+    NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0];
+    NRF_AAR->INTENCLR = 0xffffffff;
+    NRF_AAR->EVENTS_END = 0;
+    NRF_AAR->EVENTS_RESOLVED = 0;
+    NRF_AAR->EVENTS_NOTRESOLVED = 0;
+    NRF_AAR->NIRK = 0;
+#endif
+
     /* Set isr in vector table and enable interrupt */
     NVIC_SetPriority(RADIO_IRQn, 0);
     NVIC_SetVector(RADIO_IRQn, (uint32_t)ble_phy_isr);
@@ -662,6 +708,9 @@ ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, 
uint8_t *key,
     memcpy(g_nrf_ccm_data.iv, iv, 8);
     g_nrf_ccm_data.dir_bit = is_master;
     g_ble_phy_data.phy_encrypted = 1;
+    /* Enable the module (AAR cannot be on while CCM on) */
+    NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Disabled;
+    NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Enabled;
 }
 
 void
@@ -677,6 +726,8 @@ ble_phy_encrypt_disable(void)
     NRF_PPI->CHENCLR = (PPI_CHEN_CH24_Msk | PPI_CHEN_CH25_Msk);
     NRF_CCM->TASKS_STOP = 1;
     NRF_CCM->EVENTS_ERROR = 0;
+    NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Disabled;
+
     g_ble_phy_data.phy_encrypted = 0;
 }
 #endif
@@ -752,7 +803,6 @@ ble_phy_rx_set_start_time(uint32_t cputime)
     return rc;
 }
 
-
 int
 ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans)
 {
@@ -785,12 +835,18 @@ ble_phy_tx(struct os_mbuf *txpdu, uint8_t end_trans)
         NRF_CCM->EVENTS_ERROR = 0;
         NRF_CCM->MODE = CCM_MODE_LENGTH_Msk;
         NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data;
-        NRF_PPI->CHENCLR = PPI_CHEN_CH25_Msk;
+        NRF_PPI->CHENCLR = PPI_CHEN_CH25_Msk | PPI_CHEN_CH23_Msk;
         NRF_PPI->CHENSET = PPI_CHEN_CH24_Msk;
     } else {
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+        NRF_PPI->CHENCLR = PPI_CHEN_CH23_Msk;
+#endif
         dptr = (uint8_t *)&g_ble_phy_txrx_buf[0];
     }
 #else
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+    NRF_PPI->CHENCLR = PPI_CHEN_CH23_Msk;
+#endif
     dptr = (uint8_t *)&g_ble_phy_txrx_buf[0];
 #endif
 
@@ -989,7 +1045,7 @@ ble_phy_disable(void)
     NRF_RADIO->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
     NRF_RADIO->SHORTS = 0;
     NRF_RADIO->TASKS_DISABLE = 1;
-    NRF_PPI->CHENCLR = PPI_CHEN_CH21_Msk | PPI_CHEN_CH20_Msk;
+    NRF_PPI->CHENCLR = PPI_CHEN_CH23_Msk | PPI_CHEN_CH21_Msk | 
PPI_CHEN_CH20_Msk;
     NVIC_ClearPendingIRQ(RADIO_IRQn);
     g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE;
 }
@@ -1047,3 +1103,18 @@ ble_phy_max_data_pdu_pyld(void)
 {
     return BLE_LL_DATA_PDU_MAX_PYLD;
 }
+
+#if (BLE_LL_CFG_FEAT_LL_PRIVACY == 1)
+void
+ble_phy_resolv_list_enable(void)
+{
+    NRF_AAR->NIRK = (uint32_t)g_nrf_num_irks;
+    g_ble_phy_data.phy_privacy = 1;
+}
+
+void
+ble_phy_resolv_list_disable(void)
+{
+    g_ble_phy_data.phy_privacy = 0;
+}
+#endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7327c542/net/nimble/host/src/host_hci_cmd.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/host_hci_cmd.c 
b/net/nimble/host/src/host_hci_cmd.c
index 837e6f4..9763974 100644
--- a/net/nimble/host/src/host_hci_cmd.c
+++ b/net/nimble/host/src/host_hci_cmd.c
@@ -1203,9 +1203,9 @@ 
host_hci_cmd_set_resolvable_private_address_timeout(uint16_t timeout,
     int rc;
 
     BLE_HS_DBG_ASSERT(
-        dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_RESOLV_PRIV_ADDR_TO_LEN);
+        dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_RESPRIV_ADDR_TO_LEN);
 
-    host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_RESOLV_PRIV_ADDR,
+    host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_RPA_TMO,
                        BLE_HCI_SET_RESOLV_PRIV_ADDR_TO_LEN, dst);
 
     rc = host_hci_cmd_body_set_resolvable_private_address_timeout(timeout,

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7327c542/net/nimble/include/nimble/ble.h
----------------------------------------------------------------------
diff --git a/net/nimble/include/nimble/ble.h b/net/nimble/include/nimble/ble.h
index 27ad284..f2e7976 100644
--- a/net/nimble/include/nimble/ble.h
+++ b/net/nimble/include/nimble/ble.h
@@ -71,7 +71,8 @@ struct ble_mbuf_hdr_rxinfo
 #define BLE_MBUF_HDR_F_MIC_FAILURE      (0x20)
 #define BLE_MBUF_HDR_F_SCAN_RSP_TXD     (0x10)
 #define BLE_MBUF_HDR_F_SCAN_RSP_CHK     (0x08)
-#define BLE_MBUF_HDR_F_RXSTATE_MASK     (0x07)
+#define BLE_MBUF_HDR_F_RESOLVED         (0x04)
+#define BLE_MBUF_HDR_F_RXSTATE_MASK     (0x03)
 
 /* Transmit info. NOTE: no flags defined */
 struct ble_mbuf_hdr_txinfo
@@ -103,6 +104,9 @@ struct ble_mbuf_hdr
 #define BLE_MBUF_HDR_MIC_FAILURE(hdr)   \
     ((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_MIC_FAILURE)
 
+#define BLE_MBUF_HDR_RESOLVED(hdr)      \
+    ((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_RESOLVED)
+
 #define BLE_MBUF_HDR_RX_STATE(hdr)      \
     ((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_RXSTATE_MASK)
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7327c542/net/nimble/include/nimble/hci_common.h
----------------------------------------------------------------------
diff --git a/net/nimble/include/nimble/hci_common.h 
b/net/nimble/include/nimble/hci_common.h
index 1007477..67fe6e8 100644
--- a/net/nimble/include/nimble/hci_common.h
+++ b/net/nimble/include/nimble/hci_common.h
@@ -119,7 +119,7 @@
 #define BLE_HCI_OCF_LE_RD_PEER_RESOLV_ADDR  (0x002B)
 #define BLE_HCI_OCF_LE_RD_LOCAL_RESOLV_ADDR (0x002C)
 #define BLE_HCI_OCF_LE_SET_ADDR_RES_EN      (0x002D)
-#define BLE_HCI_OCF_LE_SET_RESOLV_PRIV_ADDR (0x002E)
+#define BLE_HCI_OCF_LE_SET_RPA_TMO          (0x002E)
 #define BLE_HCI_OCF_LE_RD_MAX_DATA_LEN      (0x002F)
 
 /* Command Specific Definitions */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/7327c542/net/nimble/include/nimble/nimble_opt.h
----------------------------------------------------------------------
diff --git a/net/nimble/include/nimble/nimble_opt.h 
b/net/nimble/include/nimble/nimble_opt.h
index 38fb5a7..57038b3 100644
--- a/net/nimble/include/nimble/nimble_opt.h
+++ b/net/nimble/include/nimble/nimble_opt.h
@@ -264,6 +264,11 @@
 #define NIMBLE_OPT_LL_WHITELIST_SIZE            (8)
 #endif
 
+/* Size of the resolving ist */
+#ifndef NIMBLE_OPT_LL_RESOLV_LIST_SIZE
+#define NIMBLE_OPT_LL_RESOLV_LIST_SIZE          (4)
+#endif
+
 /*
  * Data length management definitions for connections. These define the maximum
  * size of the PDU's that will be sent and/or received in a connection.
@@ -355,7 +360,7 @@
  * is not supported by the nimble controller.
  */
 #ifndef BLE_LL_CFG_FEAT_LL_PRIVACY
-#define BLE_LL_CFG_FEAT_LL_PRIVACY              (0)
+#define BLE_LL_CFG_FEAT_LL_PRIVACY              (1)
 #endif
 
 /*

Reply via email to