Cross transport key mapping fixes

Change-Id: I22d97303054eccc876c4a9c7c0a50e369ff4fa62
diff --git a/stack/btm/btm_ble.c b/stack/btm/btm_ble.c
index c72ed3f..8201c57 100644
--- a/stack/btm/btm_ble.c
+++ b/stack/btm/btm_ble.c
@@ -125,11 +125,10 @@
         BCM_STRNCPY_S ((char *)p_dev_rec->sec_bd_name, sizeof (p_dev_rec->sec_bd_name),
                        (char *)bd_name, BTM_MAX_REM_BD_NAME_LEN);
     }
-    p_dev_rec->device_type = dev_type;
+    p_dev_rec->device_type |= dev_type;
     p_dev_rec->ble.ble_addr_type = addr_type;
-    BTM_TRACE_DEBUG ("p_dev_rec->device_type =0x%x  addr_type=0x%x sec_flags=0x%x",
-                      dev_type,  addr_type, p_dev_rec->sec_flags);
 
+    memcpy (p_dev_rec->ble.pseudo_addr, bd_addr, BD_ADDR_LEN);
     /* sync up with the Inq Data base*/
     p_info = BTM_InqDbRead(bd_addr);
     if (p_info)
@@ -1395,7 +1394,7 @@
 
     }
     /* to notify GATT to send data if any request is pending */
-    gatt_notify_enc_cmpl(p_dev_rec->bd_addr);
+    gatt_notify_enc_cmpl(p_dev_rec->ble.pseudo_addr);
 }
 
 /*******************************************************************************
diff --git a/stack/btm/btm_ble_addr.c b/stack/btm/btm_ble_addr.c
index 142b8d8..b3a3b33 100644
--- a/stack/btm/btm_ble_addr.c
+++ b/stack/btm/btm_ble_addr.c
@@ -262,6 +262,74 @@
     }
     return FALSE;
 }
+
+/*******************************************************************************
+**
+** Function         btm_ble_init_pseudo_addr
+**
+** Description      This function is used to initialize pseudo address.
+**                  If pseudo address is not available, use dummy address
+**
+** Returns          TRUE is updated; FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN btm_ble_init_pseudo_addr (tBTM_SEC_DEV_REC *p_dev_rec, BD_ADDR new_pseudo_addr)
+{
+    BD_ADDR dummy_bda = {0};
+
+    if (memcmp(p_dev_rec->ble.pseudo_addr, dummy_bda, BD_ADDR_LEN) == 0)
+    {
+        memcpy(p_dev_rec->ble.pseudo_addr, new_pseudo_addr, BD_ADDR_LEN);
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_addr_resolvable
+**
+** Description      This function checks if a RPA is resolvable by the device key.
+**
+** Returns          TRUE is resolvable; FALSE otherwise.
+**
+*******************************************************************************/
+BOOLEAN btm_ble_addr_resolvable (BD_ADDR rpa, tBTM_SEC_DEV_REC *p_dev_rec)
+{
+    BOOLEAN rt = FALSE;
+
+    if (!BTM_BLE_IS_RESOLVE_BDA(rpa))
+        return rt;
+
+    UINT8 rand[3];
+    tSMP_ENC output;
+    if ((p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) &&
+        (p_dev_rec->ble.key_type & BTM_LE_KEY_PID))
+    {
+        BTM_TRACE_DEBUG("%s try to resolve", __func__);
+        /* use the 3 MSB of bd address as prand */
+        rand[0] = rpa[2];
+        rand[1] = rpa[1];
+        rand[2] = rpa[0];
+
+        /* generate X = E irk(R0, R1, R2) and R is random address 3 LSO */
+        SMP_Encrypt(p_dev_rec->ble.keys.irk, BT_OCTET16_LEN,
+                    &rand[0], 3, &output);
+
+        rand[0] = rpa[5];
+        rand[1] = rpa[4];
+        rand[2] = rpa[3];
+
+        if (!memcmp(output.param_buf, &rand[0], 3))
+        {
+            btm_ble_init_pseudo_addr (p_dev_rec, rpa);
+            rt = TRUE;
+        }
+    }
+    return rt;
+}
+
 /*******************************************************************************
 **
 ** Function         btm_ble_match_random_bda
@@ -276,23 +344,24 @@
 static BOOLEAN btm_ble_match_random_bda(UINT16 rec_index)
 {
 #if (BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE)
-    tBTM_SEC_DEV_REC    *p_dev_rec;
-    tBTM_LE_RANDOM_CB   *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
-    UINT8       rand[3];
-    tSMP_ENC    output;
-
     /* use the 3 MSB of bd address as prand */
+
+    tBTM_LE_RANDOM_CB *p_mgnt_cb = &btm_cb.ble_ctr_cb.addr_mgnt_cb;
+    UINT8 rand[3];
     rand[0] = p_mgnt_cb->random_bda[2];
     rand[1] = p_mgnt_cb->random_bda[1];
     rand[2] = p_mgnt_cb->random_bda[0];
 
-    BTM_TRACE_EVENT("btm_ble_match_random_bda rec_index = %d", rec_index);
+    BTM_TRACE_EVENT("%s rec_index = %d", __func__, rec_index);
 
     if (rec_index < BTM_SEC_MAX_DEVICE_RECORDS)
     {
+        tSMP_ENC output;
+        tBTM_SEC_DEV_REC *p_dev_rec;
         p_dev_rec = &btm_cb.sec_dev_rec[rec_index];
 
-        BTM_TRACE_DEBUG("sec_flags = %02x device_type = %d", p_dev_rec->sec_flags, p_dev_rec->device_type);
+        BTM_TRACE_DEBUG("sec_flags = %02x device_type = %d", p_dev_rec->sec_flags,
+                        p_dev_rec->device_type);
 
         if ((p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) &&
             (p_dev_rec->ble.key_type & BTM_LE_KEY_PID))
@@ -370,7 +439,7 @@
     tBTM_SEC_DEV_REC    *p_dev_rec = NULL;
     BTM_TRACE_EVENT ("btm_ble_map_bda_to_conn_bda");
     if ((p_dev_rec = btm_find_dev (bd_addr)) != NULL &&
-        p_dev_rec->device_type == BT_DEVICE_TYPE_BLE)
+        (p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE)
     {
         if (p_dev_rec->ble.ble_addr_type != BLE_ADDR_PUBLIC)
         {
@@ -439,8 +508,12 @@
 
         /* assign the original address to be the current report address */
         memcpy(bd_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
-        *p_addr_type = p_dev_rec->ble.ble_addr_type;
 
+        /* assign the original address to be the current report address */
+        if (!btm_ble_init_pseudo_addr (p_dev_rec, bd_addr))
+            memcpy(bd_addr, p_dev_rec->ble.pseudo_addr, BD_ADDR_LEN);
+
+        *p_addr_type = p_dev_rec->ble.ble_addr_type;
         return TRUE;
     }
 #endif
@@ -487,8 +560,8 @@
                                                   UINT8 rra_type)
 {
 #if BLE_PRIVACY_SPT == TRUE
-    UINT8               rra_dummy = FALSE;
-    BD_ADDR             dummy_bda = {0};
+    UINT8 rra_dummy = FALSE;
+    BD_ADDR dummy_bda = {0};
 
     if (memcmp(dummy_bda, rpa, BD_ADDR_LEN) == 0)
         rra_dummy = TRUE;
@@ -515,7 +588,10 @@
                     __func__, p_sec_rec->ble.active_addr_type);
 
     /* connection refresh remote address */
-    tACL_CONN *p_acl = p_acl = btm_bda_to_acl(p_sec_rec->bd_addr, BT_TRANSPORT_LE);
+    tACL_CONN *p_acl = btm_bda_to_acl(p_sec_rec->bd_addr, BT_TRANSPORT_LE);
+    if (p_acl == NULL)
+        p_acl = btm_bda_to_acl(p_sec_rec->ble.pseudo_addr, BT_TRANSPORT_LE);
+
     if (p_acl != NULL)
     {
         if (rra_type == BTM_BLE_ADDR_PSEUDO)
diff --git a/stack/btm/btm_ble_gap.c b/stack/btm/btm_ble_gap.c
index 46953db..8912c25 100644
--- a/stack/btm/btm_ble_gap.c
+++ b/stack/btm/btm_ble_gap.c
@@ -2654,8 +2654,10 @@
     {
         /* new device */
         if (p_i == NULL ||
-            (/* assume a DUMO device, BR/EDR inquiry is always active */
-             p_i && p_i->inq_info.results.device_type == BT_DEVICE_TYPE_BLE && p_i->scan_rsp))
+            /* assume a DUMO device, BR/EDR inquiry is always active */
+            (p_i &&
+            (p_i->inq_info.results.device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE &&
+             p_i->scan_rsp))
         {
             BTM_TRACE_WARNING("INQ RES: Extra Response Received...cancelling inquiry..");
 
diff --git a/stack/btm/btm_ble_int.h b/stack/btm/btm_ble_int.h
index 9d5c493..adf0837 100644
--- a/stack/btm/btm_ble_int.h
+++ b/stack/btm/btm_ble_int.h
@@ -290,42 +290,43 @@
     /*****************************************************
     **      BLE Inquiry
     *****************************************************/
-    tBTM_BLE_INQ_CB     inq_var;
+    tBTM_BLE_INQ_CB inq_var;
 
     /* observer callback and timer */
     tBTM_INQ_RESULTS_CB *p_obs_results_cb;
-    tBTM_CMPL_CB        *p_obs_cmpl_cb;
-    TIMER_LIST_ENT      obs_timer_ent;
+    tBTM_CMPL_CB *p_obs_cmpl_cb;
+    TIMER_LIST_ENT obs_timer_ent;
 
     /* background connection procedure cb value */
-    tBTM_BLE_CONN_TYPE  bg_conn_type;
-    UINT16              scan_int;
-    UINT16              scan_win;
-    tBTM_BLE_SEL_CBACK  *p_select_cback;
+    tBTM_BLE_CONN_TYPE bg_conn_type;
+    UINT16 scan_int;
+    UINT16 scan_win;
+    tBTM_BLE_SEL_CBACK *p_select_cback;
 
     /* white list information */
     UINT8                   white_list_avail_size;
     tBTM_BLE_WL_STATE       wl_state;
 
-    BUFFER_Q                conn_pending_q;
-    tBTM_BLE_CONN_ST        conn_state;
+    BUFFER_Q conn_pending_q;
+    tBTM_BLE_CONN_ST conn_state;
 
     /* random address management control block */
-    tBTM_LE_RANDOM_CB   addr_mgnt_cb;
+    tBTM_LE_RANDOM_CB addr_mgnt_cb;
 
-    BOOLEAN          enabled;
+    BOOLEAN enabled;
 
 #if BLE_PRIVACY_SPT == TRUE
-    BOOLEAN             mixed_mode; /* privacy 1.2 mixed mode is on or not */
-    tBTM_PRIVACY_MODE   privacy_mode;               /* privacy mode */
-    UINT8               resolving_list_avail_size;     /* resolving list available size */
-    tBTM_BLE_RESOLVE_Q   resolving_list_pend_q;
+    BOOLEAN mixed_mode; /* privacy 1.2 mixed mode is on or not */
+    tBTM_PRIVACY_MODE privacy_mode;               /* privacy mode */
+    UINT8 resolving_list_avail_size;     /* resolving list available size */
+    UINT8 *irk_list_mask;     /* IRK list availability mask, up to max entry bits */
+    tBTM_BLE_RESOLVE_Q resolving_list_pend_q;
 #endif
-    tBTM_BLE_WL_OP  wl_op_q[BTM_BLE_MAX_BG_CONN_DEV_NUM];
+    tBTM_BLE_WL_OP wl_op_q[BTM_BLE_MAX_BG_CONN_DEV_NUM];
 
     /* current BLE link state */
-    tBTM_BLE_STATE_MASK           cur_states;  /* bit mask of tBTM_BLE_STATE */
-    UINT8  link_count[2];    /* total link count master and slave*/
+    tBTM_BLE_STATE_MASK cur_states;  /* bit mask of tBTM_BLE_STATE */
+    UINT8 link_count[2];    /* total link count master and slave*/
 } tBTM_BLE_CB;
 
 #ifdef __cplusplus
diff --git a/stack/btm/btm_ble_privacy.c b/stack/btm/btm_ble_privacy.c
index b905eac..9174116 100644
--- a/stack/btm/btm_ble_privacy.c
+++ b/stack/btm/btm_ble_privacy.c
@@ -62,13 +62,12 @@
 ** Returns          void
 **
 *******************************************************************************/
-void btm_ble_enq_resolving_list_pending(BD_ADDR psuedo_bda, UINT8 op_code)
+void btm_ble_enq_resolving_list_pending(BD_ADDR pseudo_bda, UINT8 op_code)
 {
-    tBTM_BLE_RESOLVE_Q          *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
+    tBTM_BLE_RESOLVE_Q *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
 
-    memcpy(p_q->resolve_q_random_pseudo[p_q->q_next], psuedo_bda, BD_ADDR_LEN);
+    memcpy(p_q->resolve_q_random_pseudo[p_q->q_next], pseudo_bda, BD_ADDR_LEN);
     p_q->resolve_q_action[p_q->q_next] = op_code;
-
     p_q->q_next ++;
     p_q->q_next %= controller_get_interface()->get_ble_resolving_list_max_size();
 }
@@ -85,13 +84,13 @@
 ** Returns          void
 **
 *******************************************************************************/
-BOOLEAN btm_ble_brcm_find_resolving_pending_entry(BD_ADDR psuedo_addr, UINT8 action)
+BOOLEAN btm_ble_brcm_find_resolving_pending_entry(BD_ADDR pseudo_addr, UINT8 action)
 {
     tBTM_BLE_RESOLVE_Q *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
 
-    for (UINT8 i = p_q->q_pending; i != p_q->q_next; )
+    for (UINT8 i = p_q->q_pending; i != p_q->q_next;)
     {
-        if (memcmp(p_q->resolve_q_random_pseudo[i], psuedo_addr, BD_ADDR_LEN) == 0 &&
+        if (memcmp(p_q->resolve_q_random_pseudo[i], pseudo_addr, BD_ADDR_LEN) == 0 &&
             action == p_q->resolve_q_action[i])
             return TRUE;
 
@@ -107,52 +106,83 @@
 **
 ** Description      dequeue target address from resolving pending operation queue
 **
-** Parameters       psuedo_addr: psuedo_addr device address
+** Parameters       pseudo_addr: pseudo_addr device address
 **
 ** Returns          void
 **
 *******************************************************************************/
-BOOLEAN btm_ble_deq_resolving_pending(BD_ADDR psuedo_addr)
+BOOLEAN btm_ble_deq_resolving_pending(BD_ADDR pseudo_addr)
 {
     tBTM_BLE_RESOLVE_Q *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
 
     if (p_q->q_next != p_q->q_pending)
     {
-        memcpy(psuedo_addr, p_q->resolve_q_random_pseudo[p_q->q_pending], BD_ADDR_LEN);
+        memcpy(pseudo_addr, p_q->resolve_q_random_pseudo[p_q->q_pending], BD_ADDR_LEN);
         memset(p_q->resolve_q_random_pseudo[p_q->q_pending], 0, BD_ADDR_LEN);
-
         p_q->q_pending ++;
         p_q->q_pending %= controller_get_interface()->get_ble_resolving_list_max_size();
-
         return TRUE;
     }
+
     return FALSE;
 }
 
 /*******************************************************************************
 **
-** Function         btm_ble_find_resolving_list_entry
+** Function         btm_ble_clear_irk_index
 **
-** Description      find the device record if the pseudo address is currently in
-**                  the resolving list
+** Description      clear IRK list index mask for availability
 **
-** Returns          pointer to the security device record; NULL otherwise
+** Returns          none
 **
 *******************************************************************************/
-tBTM_SEC_DEV_REC * btm_ble_find_resolving_list_entry(BD_ADDR pseudo_bda)
+void btm_ble_clear_irk_index(UINT8 index)
 {
-    tBTM_SEC_DEV_REC  *p_dev_rec = &btm_cb.sec_dev_rec[0];
+    tBTM_SEC_DEV_REC *p_dev_rec = &btm_cb.sec_dev_rec[0];
+    UINT8 byte;
+    UINT8 bit;
 
     for (UINT8 i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i ++, p_dev_rec++)
     {
-        if ((p_dev_rec->sec_flags & BTM_SEC_IN_USE) &&
-            (p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) &&
-            memcmp(p_dev_rec->bd_addr, pseudo_bda, BD_ADDR_LEN) == 0)
+        if (index < controller_get_interface()->get_ble_resolving_list_max_size())
         {
-            return p_dev_rec ;
+            byte = index / 8;
+            bit = index % 8;
+            btm_cb.ble_ctr_cb.irk_list_mask[byte] &= (~(1 << bit));
         }
     }
-    return NULL;
+}
+
+/*******************************************************************************
+**
+** Function         btm_ble_find_irk_index
+**
+** Description      find the first available IRK list index
+**
+** Returns          index from 0 ~ max (127 default)
+**
+*******************************************************************************/
+UINT8 btm_ble_find_irk_index(void)
+{
+    UINT8 i = 0;
+    UINT8 byte;
+    UINT8 bit;
+
+    while (i < controller_get_interface()->get_ble_resolving_list_max_size())
+    {
+        byte = i / 8;
+        bit = i % 8;
+
+        if ((btm_cb.ble_ctr_cb.irk_list_mask[byte] & (1 << bit)) == 0)
+        {
+            btm_cb.ble_ctr_cb.irk_list_mask[byte] |= (1 << bit);
+            return i;
+        }
+        i++;
+    }
+
+    BTM_TRACE_ERROR ("%s failed, list full", __func__);
+    return i;
 }
 
 /*******************************************************************************
@@ -166,21 +196,25 @@
 *******************************************************************************/
 void btm_ble_update_resolving_list(BD_ADDR pseudo_bda, BOOLEAN add)
 {
-    tBTM_SEC_DEV_REC   *p_dev_rec = btm_find_dev (pseudo_bda);
-
+    tBTM_SEC_DEV_REC *p_dev_rec = btm_find_dev(pseudo_bda);
     if (p_dev_rec == NULL)
         return;
 
     if (add)
     {
         p_dev_rec->ble.in_controller_list |= BTM_RESOLVING_LIST_BIT;
-        /* set resolving list entry index : = max- available - 1*/
-        p_dev_rec->ble.resolving_list_index =
-            controller_get_interface()->get_ble_resolving_list_max_size() -
-                                btm_cb.ble_ctr_cb.resolving_list_avail_size - 1;
-    } else {
+        if (!controller_get_interface()->supports_ble_privacy())
+            p_dev_rec->ble.resolving_list_index = btm_ble_find_irk_index();
+    }
+    else
+    {
         p_dev_rec->ble.in_controller_list &= ~BTM_RESOLVING_LIST_BIT;
-        p_dev_rec->ble.resolving_list_index = 0;
+        if (!controller_get_interface()->supports_ble_privacy())
+        {
+           /* clear IRK list index mask */
+           btm_ble_clear_irk_index(p_dev_rec->ble.resolving_list_index);
+           p_dev_rec->ble.resolving_list_index = 0;
+        }
     }
 }
 
@@ -196,31 +230,37 @@
 *******************************************************************************/
 void btm_ble_clear_resolving_list_complete(UINT8 *p, UINT16 evt_len)
 {
-    UINT8 status;
+    UINT8 status = 0;
     STREAM_TO_UINT8(status, p);
 
-    BTM_TRACE_DEBUG("%s status = %d", __func__, status);
-
-    /* standard HCI status only have one status byte, if greater than 3, VSC complete received */
-    if (evt_len >= 3)
-    {
-        /* VSC complete has one extra byte for op code and list size, skip it here */
-        p ++;
-        /* updated the available list size, and current list size */
-        UINT8 max_resolving_list_size;
-        STREAM_TO_UINT8(max_resolving_list_size, p);
-        controller_get_interface()->set_ble_resolving_list_max_size(max_resolving_list_size);
-    }
+    BTM_TRACE_DEBUG("%s status=%d", __func__, status);
 
     if (status == HCI_SUCCESS)
     {
-        btm_cb.ble_ctr_cb.resolving_list_avail_size  =
+        if (evt_len >= 3)
+        {
+            /* VSC complete has one extra byte for op code and list size, skip it here */
+            p ++;
+
+            /* updated the available list size, and current list size */
+            uint8_t irk_list_sz_max = 0;
+            STREAM_TO_UINT8(irk_list_sz_max, p);
+
+            if (controller_get_interface()->get_ble_resolving_list_max_size() == 0)
+                btm_ble_resolving_list_init(irk_list_sz_max);
+
+            uint8_t irk_mask_size = (irk_list_sz_max % 8) ?
+                            (irk_list_sz_max / 8 + 1) : (irk_list_sz_max / 8);
+            memset(btm_cb.ble_ctr_cb.irk_list_mask, 0, irk_mask_size);
+        }
+
+        btm_cb.ble_ctr_cb.resolving_list_avail_size =
             controller_get_interface()->get_ble_resolving_list_max_size();
 
-        BTM_TRACE_DEBUG("%s resolving_list_avail_size = %d",
+        BTM_TRACE_DEBUG("%s resolving_list_avail_size=%d",
                         __func__, btm_cb.ble_ctr_cb.resolving_list_avail_size);
 
-        for (UINT8 i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i ++)
+        for (UINT8 i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; ++i)
             btm_cb.sec_dev_rec[i].ble.in_controller_list &= ~BTM_RESOLVING_LIST_BIT;
     }
 }
@@ -237,13 +277,13 @@
 *******************************************************************************/
 void btm_ble_add_resolving_list_entry_complete(UINT8 *p, UINT16 evt_len)
 {
-    UINT8           status;
+    UINT8 status;
     STREAM_TO_UINT8(status, p);
 
     BTM_TRACE_DEBUG("%s status = %d", __func__, status);
 
     BD_ADDR pseudo_bda;
-    if (!btm_ble_deq_resolving_pending( pseudo_bda))
+    if (!btm_ble_deq_resolving_pending(pseudo_bda))
     {
         BTM_TRACE_DEBUG("no pending resolving list operation");
         return;
@@ -260,7 +300,6 @@
         }
         else
             btm_cb.ble_ctr_cb.resolving_list_avail_size --;
-
     }
     else if (status == HCI_ERR_MEMORY_FULL) /* BT_ERROR_CODE_MEMORY_CAPACITY_EXCEEDED  */
     {
@@ -281,10 +320,10 @@
 *******************************************************************************/
 void btm_ble_remove_resolving_list_entry_complete(UINT8 *p, UINT16 evt_len)
 {
-    BD_ADDR         pseudo_bda;
+    BD_ADDR pseudo_bda;
+    UINT8 status;
 
-    UINT8           status;
-    STREAM_TO_UINT8  (status, p);
+    STREAM_TO_UINT8(status, p);
 
     BTM_TRACE_DEBUG("%s status = %d", __func__, status);
 
@@ -299,14 +338,14 @@
         /* proprietary: spec does not have these extra bytes */
         if (evt_len > 2)
         {
-            p ++;  /* skip opcode */
+            p ++; /* skip opcode */
             STREAM_TO_UINT8(btm_cb.ble_ctr_cb.resolving_list_avail_size, p);
         }
         else
-            btm_cb.ble_ctr_cb.resolving_list_avail_size ++;
-
+            btm_cb.ble_ctr_cb.resolving_list_avail_size++;
     }
 }
+
 /*******************************************************************************
 **
 ** Function         btm_ble_read_resolving_list_entry_complete
@@ -409,14 +448,19 @@
 *******************************************************************************/
 tBTM_STATUS btm_ble_remove_resolving_list_entry(tBTM_SEC_DEV_REC *p_dev_rec)
 {
-    tBTM_STATUS st = BTM_NO_RESOURCES;
+    /* if controller does not support RPA offloading or privacy 1.2, skip */
+    if (controller_get_interface()->get_ble_resolving_list_max_size())
+        return BTM_WRONG_MODE;
 
+    tBTM_STATUS st = BTM_NO_RESOURCES;
     if (controller_get_interface()->supports_ble_privacy())
     {
-        if (btsnd_hcic_ble_rm_device_resolving_list (p_dev_rec->ble.static_addr_type,
-                                                 p_dev_rec->ble.static_addr))
+        if (btsnd_hcic_ble_rm_device_resolving_list(p_dev_rec->ble.static_addr_type,
+                                                    p_dev_rec->ble.static_addr))
             st =  BTM_CMD_STARTED;
-    } else {
+    }
+    else
+    {
         UINT8 param[20]= {0};
         UINT8 *p = param;
 
@@ -424,16 +468,14 @@
         UINT8_TO_STREAM(p, p_dev_rec->ble.static_addr_type);
         BDADDR_TO_STREAM(p, p_dev_rec->ble.static_addr);
 
-        st = BTM_VendorSpecificCommand (HCI_VENDOR_BLE_RPA_VSC,
-                                        BTM_BLE_META_REMOVE_IRK_LEN,
-                                        param,
-                                        btm_ble_resolving_list_vsc_op_cmpl);
+        st = BTM_VendorSpecificCommand(HCI_VENDOR_BLE_RPA_VSC,
+                                       BTM_BLE_META_REMOVE_IRK_LEN,
+                                       param,
+                                       btm_ble_resolving_list_vsc_op_cmpl);
     }
 
     if (st == BTM_CMD_STARTED)
-    {
         btm_ble_enq_resolving_list_pending( p_dev_rec->bd_addr, BTM_BLE_META_REMOVE_IRK_ENTRY);
-    }
 
     return st;
 }
@@ -494,8 +536,8 @@
     if (controller_get_interface()->supports_ble_privacy())
     {
         if (btsnd_hcic_ble_read_resolvable_addr_peer(p_dev_rec->ble.static_addr_type,
-                                                 p_dev_rec->ble.static_addr))
-             st =  BTM_CMD_STARTED;
+                                                     p_dev_rec->ble.static_addr))
+            st =  BTM_CMD_STARTED;
     }
     else
     {
@@ -512,9 +554,8 @@
     }
 
     if (st == BTM_CMD_STARTED)
-    {
-        btm_ble_enq_resolving_list_pending(p_dev_rec->bd_addr, BTM_BLE_META_READ_IRK_ENTRY);
-    }
+        btm_ble_enq_resolving_list_pending(p_dev_rec->bd_addr,
+                                           BTM_BLE_META_READ_IRK_ENTRY);
 
     return st;
 }
@@ -532,28 +573,31 @@
 *******************************************************************************/
 BOOLEAN btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC *p_dev_rec)
 {
-    BOOLEAN         rt = FALSE;
-    tBTM_BLE_CB     *p_cb = &btm_cb.ble_ctr_cb;
-
+    BOOLEAN rt = FALSE;
     BTM_TRACE_DEBUG("%s btm_cb.ble_ctr_cb.privacy_mode = %d", __func__,
-                    btm_cb.ble_ctr_cb.privacy_mode);
+                                btm_cb.ble_ctr_cb.privacy_mode);
 
+    /* if controller does not support RPA offloading or privacy 1.2, skip */
+    if (controller_get_interface()->get_ble_resolving_list_max_size() == 0)
+        return FALSE;
+
+    BTM_TRACE_DEBUG("%s btm_cb.ble_ctr_cb.privacy_mode = %d",
+                    __func__, btm_cb.ble_ctr_cb.privacy_mode);
+
+    /* only add RPA enabled device into resolving list */
     if (p_dev_rec != NULL && /* RPA is being used and PID is known */
         p_dev_rec->sec_flags & BTM_SEC_IN_USE &&
-        /* only add RPA enabled device into resolving list */
-        (((p_dev_rec->ble.key_type & BTM_LE_KEY_PID) != 0
-          && BTM_BLE_IS_RESOLVE_BDA(p_dev_rec->bd_addr))
-       || ((p_dev_rec->ble.key_type & BTM_LE_KEY_LID) != 0
-          && btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE)))
+        ((p_dev_rec->ble.key_type & BTM_LE_KEY_PID) != 0 ||
+        ((p_dev_rec->ble.key_type & BTM_LE_KEY_LID) != 0 &&
+          btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE)))
     {
         if (!(p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) &&
             btm_ble_brcm_find_resolving_pending_entry(p_dev_rec->bd_addr,
                                                       BTM_BLE_META_ADD_IRK_ENTRY) == FALSE)
         {
-            if (p_cb->resolving_list_avail_size > 0)
+            if (btm_cb.ble_ctr_cb.resolving_list_avail_size > 0)
             {
-                btm_ble_update_resolving_list( p_dev_rec->bd_addr, TRUE);
-
+                btm_ble_update_resolving_list(p_dev_rec->bd_addr, TRUE);
                 if (controller_get_interface()->supports_ble_privacy())
                 {
                     UINT8 dummy_irk[HCIC_BLE_IRK_SIZE];
@@ -561,9 +605,9 @@
 
                     UINT8 *peer_irk;
                     if (BTM_BLE_IS_RESOLVE_BDA(p_dev_rec->bd_addr))
-                        peer_irk = p_dev_rec->ble.keys.irk;
+                         peer_irk = p_dev_rec->ble.keys.irk;
                     else
-                        peer_irk = dummy_irk;
+                         peer_irk = dummy_irk;
 
                     UINT8 *local_irk;
                     if (btm_cb.ble_ctr_cb.privacy_mode != BTM_PRIVACY_NONE)
@@ -573,17 +617,29 @@
 
                     BD_ADDR dummy_bda = {0};
                     /* for device not assigning static address, use pseudo address as identity */
+                    peer_irk = p_dev_rec->ble.keys.irk;
+                    local_irk = btm_cb.devcb.id_keys.irk;
+
+                    // do not enter IRK if peer or local device does not have privacy turned on
+                    // disable, assume IRK indicate privacy could be enabled at any point,
+                    // warning: this could take up unnecessary spot in controller resolving list,
+                    // and could possible degrade performance; this could prevent conneccting
+                    // to peripheral device which has privacy disabled but IRK delivered per
+                    // standard privacy 1.2 requirement. Need FW mixed mode support to connect
+                    // to both RPA and static address.
                     if (memcmp(p_dev_rec->ble.static_addr, dummy_bda, BD_ADDR_LEN) == 0)
                     {
                         memcpy(p_dev_rec->ble.static_addr, p_dev_rec->bd_addr, BD_ADDR_LEN);
                         p_dev_rec->ble.static_addr_type = p_dev_rec->ble.ble_addr_type;
                     }
 
+                    BTM_TRACE_DEBUG("%s:adding device to controller resolving list", __func__);
+                    // use identical IRK for now
                     rt = btsnd_hcic_ble_add_device_resolving_list(p_dev_rec->ble.static_addr_type,
-                              p_dev_rec->ble.static_addr, peer_irk, local_irk); // use identical IRK for now 
+                              p_dev_rec->ble.static_addr, peer_irk, local_irk);
                 }
-               else
-               {
+                else
+                {
                     UINT8 param[40] = {0};
                     UINT8 *p = param;
 
@@ -593,16 +649,16 @@
                     BDADDR_TO_STREAM(p,p_dev_rec->ble.static_addr);
 
                     if (BTM_VendorSpecificCommand (HCI_VENDOR_BLE_RPA_VSC,
-                                                    BTM_BLE_META_ADD_IRK_LEN,
-                                                    param,
-                                                    btm_ble_resolving_list_vsc_op_cmpl)
-                                                    == BTM_CMD_STARTED)
+                                                   BTM_BLE_META_ADD_IRK_LEN,
+                                                   param,
+                                                   btm_ble_resolving_list_vsc_op_cmpl)
+                                                   == BTM_CMD_STARTED)
                         rt = TRUE;
-               }
+                }
 
                if (rt)
-                    btm_ble_enq_resolving_list_pending(p_dev_rec->bd_addr,
-                                                       BTM_BLE_META_ADD_IRK_ENTRY);
+                   btm_ble_enq_resolving_list_pending(p_dev_rec->bd_addr,
+                                                      BTM_BLE_META_ADD_IRK_ENTRY);
             }
         }
         else
@@ -631,14 +687,17 @@
 *******************************************************************************/
 void btm_ble_resolving_list_remove_dev(tBTM_SEC_DEV_REC *p_dev_rec)
 {
-    btm_ble_update_resolving_list( p_dev_rec->bd_addr, FALSE);
+    btm_ble_update_resolving_list(p_dev_rec->bd_addr, FALSE);
 
     if ((p_dev_rec->ble.in_controller_list & BTM_RESOLVING_LIST_BIT) &&
         btm_ble_brcm_find_resolving_pending_entry(p_dev_rec->bd_addr,
                                                   BTM_BLE_META_REMOVE_IRK_ENTRY) == FALSE)
     {
+        btm_ble_update_resolving_list( p_dev_rec->bd_addr, FALSE);
         btm_ble_remove_resolving_list_entry(p_dev_rec);
-    } else {
+    }
+    else
+    {
         BTM_TRACE_DEBUG("Device not in resolving list");
     }
 }
@@ -679,6 +738,10 @@
 *******************************************************************************/
 void btm_ble_disable_resolving_list(void)
 {
+    /* if controller does not support RPA offloading or privacy 1.2, skip */
+    if (controller_get_interface()->get_ble_resolving_list_max_size() == 0)
+        return;
+
     if (btm_cb.ble_ctr_cb.enabled)
     {
         if (!controller_get_interface()->supports_ble_privacy())
@@ -725,7 +788,7 @@
 BOOLEAN btm_ble_resolving_list_empty(void)
 {
     return (controller_get_interface()->get_ble_resolving_list_max_size() ==
-                                    btm_cb.ble_ctr_cb.resolving_list_avail_size);
+            btm_cb.ble_ctr_cb.resolving_list_avail_size);
 }
 
 /*******************************************************************************
@@ -752,7 +815,6 @@
             btm_ble_enable_resolving_list();
         else
             btm_ble_disable_resolving_list();
-
         return;
     }
 
@@ -782,13 +844,18 @@
 *******************************************************************************/
 void btm_ble_resolving_list_init(UINT8 max_irk_list_sz)
 {
-    tBTM_BLE_RESOLVE_Q          *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
+    tBTM_BLE_RESOLVE_Q *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
+    UINT8 irk_mask_size =  (max_irk_list_sz % 8) ?
+                           (max_irk_list_sz/8 + 1) : (max_irk_list_sz/8);
 
     if (max_irk_list_sz > 0)
     {
-        p_q->resolve_q_random_pseudo = (BD_ADDR*)GKI_getbuf (sizeof (BD_ADDR) *
-                                                  max_irk_list_sz);
-        p_q->resolve_q_action = (UINT8*) GKI_getbuf (max_irk_list_sz);
+        p_q->resolve_q_random_pseudo = (BD_ADDR *)GKI_getbuf(sizeof(BD_ADDR) * max_irk_list_sz);
+        p_q->resolve_q_action = (UINT8 *)GKI_getbuf(max_irk_list_sz);
+
+        /* RPA offloading feature */
+        if (btm_cb.ble_ctr_cb.irk_list_mask == NULL)
+            btm_cb.ble_ctr_cb.irk_list_mask = (UINT8 *)GKI_getbuf(irk_mask_size);
 
         BTM_TRACE_DEBUG ("%s max_irk_list_sz = %d", __func__, max_irk_list_sz);
     }
@@ -810,7 +877,7 @@
 *******************************************************************************/
 void btm_ble_resolving_list_cleanup(void)
 {
-    tBTM_BLE_RESOLVE_Q          *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
+    tBTM_BLE_RESOLVE_Q *p_q = &btm_cb.ble_ctr_cb.resolving_list_pend_q;
 
     if (p_q->resolve_q_random_pseudo)
         GKI_freebuf(p_q->resolve_q_random_pseudo);
@@ -819,5 +886,9 @@
        GKI_freebuf(p_q->resolve_q_action);
 
     controller_get_interface()->set_ble_resolving_list_max_size(0);
+    if (btm_cb.ble_ctr_cb.irk_list_mask)
+       GKI_freebuf(btm_cb.ble_ctr_cb.irk_list_mask);
+
+    btm_cb.ble_ctr_cb.irk_list_mask = NULL;
 }
 #endif
diff --git a/stack/btm/btm_dev.c b/stack/btm/btm_dev.c
index 3053dbe..faae4f5 100644
--- a/stack/btm/btm_dev.c
+++ b/stack/btm/btm_dev.c
@@ -155,6 +155,7 @@
 #endif
 
     p_dev_rec->rmt_io_caps = io_cap;
+    p_dev_rec->device_type |= BT_DEVICE_TYPE_BREDR;
 
     return(TRUE);
 }
@@ -427,18 +428,26 @@
 ** Returns          Pointer to the record or NULL
 **
 *******************************************************************************/
-tBTM_SEC_DEV_REC *btm_find_dev (BD_ADDR bd_addr)
+tBTM_SEC_DEV_REC *btm_find_dev(BD_ADDR bd_addr)
 {
     tBTM_SEC_DEV_REC *p_dev_rec = &btm_cb.sec_dev_rec[0];
-    int i;
 
     if (bd_addr)
     {
-        for (i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++)
+        for (uint8_t i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++)
         {
-            if ((p_dev_rec->sec_flags & BTM_SEC_IN_USE)
-                && (!memcmp (p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN)))
-                return(p_dev_rec);
+            if (p_dev_rec->sec_flags & BTM_SEC_IN_USE)
+            {
+                if (!memcmp (p_dev_rec->bd_addr, bd_addr, BD_ADDR_LEN))
+                    return(p_dev_rec);
+
+                // If a LE random address is looking for device record
+                if (!memcmp(p_dev_rec->ble.pseudo_addr, bd_addr, BD_ADDR_LEN))
+                    return (p_dev_rec);
+
+                if (btm_ble_addr_resolvable(bd_addr, p_dev_rec))
+                    return(p_dev_rec);
+            }
         }
     }
     return(NULL);
@@ -446,6 +455,59 @@
 
 /*******************************************************************************
 **
+** Function         btm_consolidate_dev
+**
+** Description      combine security records if identified as same peer
+**
+** Returns          none
+**
+*******************************************************************************/
+void btm_consolidate_dev(tBTM_SEC_DEV_REC *p_target_rec)
+{
+    tBTM_SEC_DEV_REC *p_dev_rec = &btm_cb.sec_dev_rec[0];
+    tBTM_SEC_DEV_REC temp_rec = *p_target_rec;
+    BD_ADDR dummy_bda = {0};
+
+    BTM_TRACE_DEBUG("%s", __func__);
+
+    for (uint8_t i = 0; i < BTM_SEC_MAX_DEVICE_RECORDS; i++, p_dev_rec++)
+    {
+        if (p_target_rec!= p_dev_rec && p_dev_rec->sec_flags & BTM_SEC_IN_USE)
+        {
+            if (!memcmp (p_dev_rec->bd_addr, p_target_rec->bd_addr, BD_ADDR_LEN))
+            {
+                memcpy(p_target_rec, p_dev_rec, sizeof(tBTM_SEC_DEV_REC));
+                p_target_rec->ble = temp_rec.ble;
+                p_target_rec->enc_key_size = temp_rec.enc_key_size;
+                p_target_rec->ble_hci_handle = temp_rec.ble_hci_handle;
+                p_target_rec->conn_params = temp_rec.conn_params;
+                p_target_rec->device_type |= temp_rec.device_type;
+                p_target_rec->sec_flags |= temp_rec.sec_flags;
+
+                p_target_rec->new_encryption_key_is_p256 = temp_rec.new_encryption_key_is_p256;
+                p_target_rec->no_smp_on_br = temp_rec.no_smp_on_br;
+                /* mark the combined record as unused */
+                p_dev_rec->sec_flags &= ~BTM_SEC_IN_USE;
+                break;
+            }
+
+            /* an RPA device entry is a duplicate of the target record */
+            if (btm_ble_addr_resolvable(p_dev_rec->bd_addr, p_target_rec))
+            {
+                if (memcmp(p_target_rec->ble.pseudo_addr, p_dev_rec->bd_addr, BD_ADDR_LEN) == 0)
+                {
+                    p_target_rec->ble.ble_addr_type = p_dev_rec->ble.ble_addr_type;
+                    p_target_rec->device_type |= p_dev_rec->device_type;
+                    p_dev_rec->sec_flags &= ~BTM_SEC_IN_USE;
+                }
+                break;
+            }
+        }
+    }
+}
+
+/*******************************************************************************
+**
 ** Function         btm_find_or_alloc_dev
 **
 ** Description      Look for the record in the device database for the record
diff --git a/stack/btm/btm_int.h b/stack/btm/btm_int.h
index ec0a03f..a8a1090 100644
--- a/stack/btm/btm_int.h
+++ b/stack/btm/btm_int.h
@@ -467,6 +467,7 @@
 
 typedef struct
 {
+    BD_ADDR pseudo_addr; /* LE pseudo address of the device if different from device address  */
     tBLE_ADDR_TYPE      ble_addr_type;  /* LE device type: public or random address */
     tBLE_ADDR_TYPE      static_addr_type;   /* static address type */
     BD_ADDR             static_addr;    /* static address */
@@ -585,6 +586,9 @@
                                                     ** Link encrypted with such LK can be used
                                                     ** for SM over BR/EDR.
                                                     */
+    BOOLEAN no_smp_on_br;       /* if set to TRUE then SMP on BR/EDR doesn't */
+                                /* work, i.e. link keys crosspairing */
+                                /* SC BR/EDR->SC LE doesn't happen */
 #endif
 
 // btla-specific ++
@@ -1004,10 +1008,10 @@
 extern void btm_ble_add_2_white_list_complete(UINT8 status);
 extern void btm_ble_remove_from_white_list_complete(UINT8 *p, UINT16 evt_len);
 extern void btm_ble_clear_white_list_complete(UINT8 *p, UINT16 evt_len);
+extern BOOLEAN btm_ble_addr_resolvable(BD_ADDR rpa, tBTM_SEC_DEV_REC *p_dev_rec);
 extern tBTM_STATUS btm_ble_read_resolving_list_entry(tBTM_SEC_DEV_REC *p_dev_rec);
 extern BOOLEAN btm_ble_resolving_list_load_dev(tBTM_SEC_DEV_REC *p_dev_rec);
 extern void btm_ble_resolving_list_remove_dev(tBTM_SEC_DEV_REC *p_dev_rec);
-extern tBTM_STATUS btm_ble_read_resolving_list_entry(tBTM_SEC_DEV_REC *p_dev_rec);
 #endif  /* BLE_INCLUDED */
 
 /* Vendor Specific Command complete evt handler */
@@ -1070,7 +1074,9 @@
 extern void  btm_sec_clear_ble_keys (tBTM_SEC_DEV_REC  *p_dev_rec);
 extern  BOOLEAN btm_sec_find_bonded_dev (UINT8 start_idx, UINT8 *p_found_idx, tBTM_SEC_DEV_REC **p_rec);
 extern BOOLEAN btm_sec_is_a_bonded_dev (BD_ADDR bda);
+extern void btm_consolidate_dev(tBTM_SEC_DEV_REC *p_target_rec);
 extern BOOLEAN btm_sec_is_le_capable_dev (BD_ADDR bda);
+extern BOOLEAN btm_ble_init_pseudo_addr (tBTM_SEC_DEV_REC *p_dev_rec, BD_ADDR new_pseudo_addr);
 #endif /* BLE_INCLUDED */
 
 extern tINQ_DB_ENT *btm_inq_db_new (BD_ADDR p_bda);
diff --git a/stack/btm/btm_sec.c b/stack/btm/btm_sec.c
index c806782..33d0efc 100644
--- a/stack/btm/btm_sec.c
+++ b/stack/btm/btm_sec.c
@@ -995,6 +995,7 @@
 #if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
     if (transport == BT_TRANSPORT_LE)
     {
+        btm_ble_init_pseudo_addr (p_dev_rec, bd_addr);
         p_dev_rec->sec_flags &= ~ BTM_SEC_LE_MASK;
 
         if (SMP_Pair(bd_addr) == SMP_STARTED)
@@ -4058,20 +4059,25 @@
         else
         {
             BTM_TRACE_DEBUG ("TRYING TO DECIDE IF CAN USE SMP_BR_CHNL");
-            if (p_dev_rec->new_encryption_key_is_p256 && (btm_sec_use_smp_br_chnl(p_dev_rec)))
+            if (p_dev_rec->new_encryption_key_is_p256 && (btm_sec_use_smp_br_chnl(p_dev_rec))
+                /* no LE keys are available, do deriving */
+                 && (!(p_dev_rec->sec_flags &BTM_SEC_LE_LINK_KEY_KNOWN) ||
+                /* or BR key is higher security than existing LE keys */
+                 (!(p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_AUTHED) &&
+                 (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED))))
             {
                 BTM_TRACE_DEBUG ("link encrypted afer dedic bonding can use SMP_BR_CHNL");
 
                 if (btm_sec_is_master(p_dev_rec))
                 {
-                    // Encryption is required to start SM over BR/EDR.
-                    // Indicate that this is encryption after authentication.
+                    // Encryption is required to start SM over BR/EDR
+                    // indicate that this is encryption after authentication
                     BTM_SetEncryption(p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR, NULL, NULL);
                 }
             }
-
             l2cu_start_post_bond_timer (p_dev_rec->hci_handle);
         }
+
         return;
     }
 
@@ -4150,7 +4156,8 @@
 
     /* For transaction collision we need to wait and repeat.  There is no need */
     /* for random timeout because only slave should receive the result */
-    if ((status == HCI_ERR_LMP_ERR_TRANS_COLLISION) || (status == HCI_ERR_DIFF_TRANSACTION_COLLISION))
+    if ((status == HCI_ERR_LMP_ERR_TRANS_COLLISION) ||
+        (status == HCI_ERR_DIFF_TRANSACTION_COLLISION))
     {
         btm_sec_auth_collision(handle);
         return;
@@ -4181,15 +4188,14 @@
     BTM_TRACE_DEBUG ("after update p_dev_rec->sec_flags=0x%x", p_dev_rec->sec_flags );
 
 #if BLE_INCLUDED == TRUE && SMP_INCLUDED == TRUE
-    if (acl_idx != MAX_L2CAP_LINKS )
+    if (acl_idx != MAX_L2CAP_LINKS)
         p_acl = &btm_cb.acl_db[acl_idx];
 
     btm_sec_check_pending_enc_req (p_dev_rec, p_acl->transport, encr_enable);
 
     if (p_acl && p_acl->transport == BT_TRANSPORT_LE)
     {
-        if (status == HCI_ERR_KEY_MISSING ||
-            status == HCI_ERR_AUTH_FAILURE ||
+        if (status == HCI_ERR_KEY_MISSING || status == HCI_ERR_AUTH_FAILURE ||
             status == HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE)
         {
             p_dev_rec->sec_flags &= ~ (BTM_SEC_LE_LINK_KEY_KNOWN);
@@ -4199,29 +4205,44 @@
         return;
     }
     else
+    {
         /* BR/EDR connection, update the encryption key size to be 16 as always */
         p_dev_rec->enc_key_size = 16;
+    }
 
-    BTM_TRACE_DEBUG ("in btm_sec_encrypt_change new_encr_key_256 is %d",
-                       p_dev_rec->new_encryption_key_is_p256);
+     BTM_TRACE_DEBUG ("in %s new_encr_key_256 is %d",
+                       __func__, p_dev_rec->new_encryption_key_is_p256);
 
     if ((status == HCI_SUCCESS) && encr_enable && (p_dev_rec->hci_handle == handle))
     {
         if (p_dev_rec->new_encryption_key_is_p256)
         {
             if (btm_sec_use_smp_br_chnl(p_dev_rec) &&
-                btm_sec_is_master(p_dev_rec))
+                btm_sec_is_master(p_dev_rec) &&
+                /* if LE key is not known, do deriving */
+                (!(p_dev_rec->sec_flags &BTM_SEC_LE_LINK_KEY_KNOWN) ||
+                /* or BR key is higher security than existing LE keys */
+                 (!(p_dev_rec->sec_flags & BTM_SEC_LE_LINK_KEY_AUTHED)
+                 && (p_dev_rec->sec_flags & BTM_SEC_LINK_KEY_AUTHED))))
             {
                 /* BR/EDR is encrypted with LK that can be used to derive LE LTK */
                 p_dev_rec->new_encryption_key_is_p256 = FALSE;
 
-                BTM_TRACE_DEBUG ("btm_sec_encrypt_change start SM over BR/EDR");
-                SMP_BR_PairWith(p_dev_rec->bd_addr);
+                if (p_dev_rec->no_smp_on_br)
+                {
+                    BTM_TRACE_DEBUG ("%s NO SM over BR/EDR", __func__);
+                }
+                else
+                {
+                    BTM_TRACE_DEBUG ("%s start SM over BR/EDR", __func__);
+                    SMP_BR_PairWith(p_dev_rec->bd_addr);
+                }
             }
         }
         else
-        {   /* BR/EDR is successfully encrypted. Correct LK type if needed
-              (BR/EDR LK derived from LE LTK was used for encryption) */
+        {
+            // BR/EDR is successfully encrypted. Correct LK type if needed
+            // (BR/EDR LK derived from LE LTK was used for encryption)
             if ((encr_enable == 1)  && /* encryption is ON for SSP */
                 /* LK type is for BR/EDR SC */
                 (p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256 ||
@@ -4254,7 +4275,6 @@
     }
 
     p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
-
     /* If encryption setup failed, notify the waiting layer */
     if (status != HCI_SUCCESS)
     {
@@ -4264,7 +4284,6 @@
 
     /* Encryption setup succeeded, execute the next security procedure, if any */
     status = (UINT8)btm_sec_execute_procedure (p_dev_rec);
-
     /* If there is no next procedure, or procedure failed to start, notify the caller */
     if (status != BTM_CMD_STARTED)
         btm_sec_dev_rec_cback_event (p_dev_rec, status, FALSE);
@@ -4808,23 +4827,22 @@
                                                    p_link_key, p_dev_rec->link_key_type);
         }
     }
-#if BTM_CROSS_TRANSP_KEY_DERIVATION == TRUE
     else
     {
         if ((p_dev_rec->link_key_type == BTM_LKEY_TYPE_UNAUTH_COMB_P_256) ||
             (p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256))
         {
-             p_dev_rec->new_encr_key_256 = TRUE;
+             p_dev_rec->new_encryption_key_is_p256 = TRUE;
              BTM_TRACE_DEBUG ("%s set new_encr_key_256 to %d",
-                               __func__, p_dev_rec->new_encr_key_256);
+                               __func__, p_dev_rec->new_encryption_key_is_p256);
         }
     }
-#endif
 
     /* If name is not known at this point delay calling callback until the name is   */
     /* resolved. Unless it is a HID Device and we really need to send all link keys. */
     if ((!(p_dev_rec->sec_flags & BTM_SEC_NAME_KNOWN)
-        &&  ((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) != BTM_COD_MAJOR_PERIPHERAL)) )
+        &&  ((p_dev_rec->dev_class[1] & BTM_COD_MAJOR_CLASS_MASK) != BTM_COD_MAJOR_PERIPHERAL))
+        && !ltk_derived_lk)
     {
         BTM_TRACE_EVENT ("btm_sec_link_key_notification()  Delayed BDA: %08x%04x Type:%d",
                           (p_bda[0]<<24) + (p_bda[1]<<16) + (p_bda[2]<<8) + p_bda[3],
@@ -4846,7 +4864,9 @@
     /* If its not us who perform authentication, we should tell stackserver */
     /* that some authentication has been completed                          */
     /* This is required when different entities receive link notification and auth complete */
-    if (!(p_dev_rec->security_required & BTM_SEC_OUT_AUTHENTICATE))
+    if (!(p_dev_rec->security_required & BTM_SEC_OUT_AUTHENTICATE)
+        /* for derived key, always send authentication callback for BR channel */
+         || ltk_derived_lk)
     {
         if (btm_cb.api.p_auth_complete_callback)
             (*btm_cb.api.p_auth_complete_callback) (p_dev_rec->bd_addr, p_dev_rec->dev_class,
@@ -4860,8 +4880,17 @@
     {
         if (btm_cb.api.p_link_key_callback)
         {
-            (*btm_cb.api.p_link_key_callback) (p_bda, p_dev_rec->dev_class,  p_dev_rec->sec_bd_name,
-                                               p_link_key, p_dev_rec->link_key_type);
+            if (ltk_derived_lk)
+            {
+                BTM_TRACE_DEBUG ("btm_sec_link_key_notification()  LTK derived LK is saved already"
+                                    " (key_type = %d)", p_dev_rec->link_key_type);
+            }
+            else
+            {
+                (*btm_cb.api.p_link_key_callback) (p_bda, p_dev_rec->dev_class,
+                                                   p_dev_rec->sec_bd_name,
+                                                   p_link_key, p_dev_rec->link_key_type);
+            }
         }
     }
 }
@@ -5839,12 +5868,15 @@
 void btm_sec_dev_rec_cback_event (tBTM_SEC_DEV_REC *p_dev_rec, UINT8 res, BOOLEAN is_le_transport)
 {
     tBTM_SEC_CALLBACK   *p_callback = p_dev_rec->p_callback;
-    tBT_TRANSPORT transport = is_le_transport ? BT_TRANSPORT_LE : BT_TRANSPORT_BR_EDR;
 
     if (p_dev_rec->p_callback)
     {
         p_dev_rec->p_callback = NULL;
-        (*p_callback) (p_dev_rec->bd_addr, transport, p_dev_rec->p_ref_data, res);
+
+        if (is_le_transport)
+           (*p_callback) (p_dev_rec->ble.pseudo_addr, BT_TRANSPORT_LE, p_dev_rec->p_ref_data, res);
+        else
+           (*p_callback) (p_dev_rec->bd_addr, BT_TRANSPORT_BR_EDR, p_dev_rec->p_ref_data, res);
     }
 
     btm_sec_check_pending_reqs();
@@ -6214,11 +6246,8 @@
     BOOLEAN le_capable = FALSE;
 
 #if (BLE_INCLUDED== TRUE)
-    if (p_dev_rec && ((p_dev_rec->device_type == BT_DEVICE_TYPE_DUMO) ||
-         (p_dev_rec->device_type == BT_DEVICE_TYPE_BLE) ) )
-    {
+    if (p_dev_rec && (p_dev_rec->device_type & BT_DEVICE_TYPE_BLE) == BT_DEVICE_TYPE_BLE)
         le_capable  = TRUE;
-    }
 #endif
     return le_capable;
 }
diff --git a/stack/include/btm_api.h b/stack/include/btm_api.h
index de0b195..a4d1ba3 100644
--- a/stack/include/btm_api.h
+++ b/stack/include/btm_api.h
@@ -1399,6 +1399,10 @@
 #define BTM_AUTH_BONDS      6   /* the general/dedicated bonding bits  */
 #define BTM_AUTH_YN_BIT     1   /* this is the Yes or No bit  */
 
+#define BTM_BLE_INITIATOR_KEY_SIZE 15
+#define BTM_BLE_RESPONDER_KEY_SIZE 15
+#define BTM_BLE_MAX_KEY_SIZE       16
+
 typedef UINT8 tBTM_AUTH_REQ;
 
 enum
@@ -1613,9 +1617,10 @@
 /* data type for tBTM_LE_COMPLT */
 typedef struct
 {
-    UINT8       reason;
-    UINT8       sec_level;
-    BOOLEAN     is_pair_cancel;
+    UINT8 reason;
+    UINT8 sec_level;
+    BOOLEAN is_pair_cancel;
+    BOOLEAN smp_over_br;
 }tBTM_LE_COMPLT;
 #endif
 
diff --git a/stack/include/smp_api.h b/stack/include/smp_api.h
index 37669b4..62ef1db 100644
--- a/stack/include/smp_api.h
+++ b/stack/include/smp_api.h
@@ -203,6 +203,14 @@
 #define SMP_SEC_DEFAULT_KEY      (SMP_SEC_KEY_TYPE_ENC | SMP_SEC_KEY_TYPE_ID | \
                                   SMP_SEC_KEY_TYPE_CSRK | SMP_SEC_KEY_TYPE_LK)
 
+#define SMP_SC_KEY_STARTED      0   /* passkey entry started */
+#define SMP_SC_KEY_ENTERED      1   /* passkey digit entered */
+#define SMP_SC_KEY_ERASED       2   /* passkey digit erased */
+#define SMP_SC_KEY_CLEARED      3   /* passkey cleared */
+#define SMP_SC_KEY_COMPLT       4   /* passkey entry completed */
+#define SMP_SC_KEY_OUT_OF_RANGE 5   /* out of range */
+typedef UINT8 tSMP_SC_KEY_TYPE;
+
 /* data type for BTM_SP_IO_REQ_EVT */
 typedef struct
 {
@@ -216,9 +224,10 @@
 
 typedef struct
 {
-    tSMP_STATUS       reason;
-    tSMP_SEC_LEVEL    sec_level;
-    BOOLEAN     is_pair_cancel;
+    tSMP_STATUS reason;
+    tSMP_SEC_LEVEL sec_level;
+    BOOLEAN is_pair_cancel;
+    BOOLEAN smp_over_br;
 } tSMP_CMPL;
 
 typedef struct
diff --git a/stack/l2cap/l2c_link.c b/stack/l2cap/l2c_link.c
index fa2fcce..97bf58d 100644
--- a/stack/l2cap/l2c_link.c
+++ b/stack/l2cap/l2c_link.c
@@ -424,16 +424,21 @@
         if (p_lcb->ccb_queue.p_first_ccb != NULL || p_lcb->p_pending_ccb)
         {
             L2CAP_TRACE_DEBUG("l2c_link_hci_disc_comp: Restarting pending ACL request");
+            transport = p_lcb->transport;
 #if BLE_INCLUDED == TRUE
             /* for LE link, always drop and re-open to ensure to get LE remote feature */
             if (p_lcb->transport == BT_TRANSPORT_LE)
             {
-                BD_ADDR bd_addr;
-                memcpy(bd_addr, p_lcb->remote_bd_addr, BD_ADDR_LEN);
-                l2cu_release_lcb (p_lcb);
-                // make sure Tx credit allocation is redistributed in between links by calling l2cu_allocate_lcb
-                p_lcb = l2cu_allocate_lcb (bd_addr, FALSE, BT_TRANSPORT_LE);
-                transport = BT_TRANSPORT_LE;
+                l2cb.is_ble_connecting = FALSE;
+                btm_acl_removed (p_lcb->remote_bd_addr, p_lcb->transport);
+                /* Release any held buffers */
+                BT_HDR *p_buf;
+                while (!list_is_empty(p_lcb->link_xmit_data_q))
+                {
+                    p_buf = list_front(p_lcb->link_xmit_data_q);
+                    list_remove(p_lcb->link_xmit_data_q, p_buf);
+                    GKI_freebuf(p_buf);
+                }
             }
             else
 #endif
diff --git a/stack/l2cap/l2c_main.c b/stack/l2cap/l2c_main.c
index 634f1cd..212d5df 100644
--- a/stack/l2cap/l2c_main.c
+++ b/stack/l2cap/l2c_main.c
@@ -186,6 +186,11 @@
     STREAM_TO_UINT16 (l2cap_len, p);
     STREAM_TO_UINT16 (rcv_cid, p);
 
+   /* for BLE channel, always notify connection when ACL data received on the link */
+   if (p_lcb && p_lcb->transport == BT_TRANSPORT_LE && p_lcb->link_state != LST_DISCONNECTING)
+      /* only process fixed channel data as channel open indication when link is not in disconnecting mode */
+        l2cble_notify_le_connection(p_lcb->remote_bd_addr);
+
     /* Find the CCB for this CID */
     if (rcv_cid >= L2CAP_BASE_APPL_CID)
     {
@@ -261,14 +266,10 @@
         counter_add("l2cap.fix.rx.pkts", 1);
         /* If no CCB for this channel, allocate one */
         if (p_lcb &&
-            /* discard fixed channel data when link is disconnecting */
+            /* only process fixed channel data when link is open or wait for data indication */
             (p_lcb->link_state != LST_DISCONNECTING) &&
-            l2cu_initialize_fixed_ccb (p_lcb, rcv_cid,
-                &l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
+            l2cu_initialize_fixed_ccb (p_lcb, rcv_cid, &l2cb.fixed_reg[rcv_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
         {
-#if(defined BLE_INCLUDED && (BLE_INCLUDED == TRUE))
-            l2cble_notify_le_connection(p_lcb->remote_bd_addr);
-#endif
             p_ccb = p_lcb->p_fixed_ccbs[rcv_cid - L2CAP_FIRST_FIXED_CHNL];
 
             if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
diff --git a/stack/smp/smp_act.c b/stack/smp/smp_act.c
index 397a2ca..f1c6936 100644
--- a/stack/smp/smp_act.c
+++ b/stack/smp/smp_act.c
@@ -46,7 +46,7 @@
     smp_generate_ltk,
     smp_send_id_info,
     smp_generate_csrk,
-    smp_derive_link_key_from_long_term_key
+    smp_set_derive_link_key
 };
 
 /*******************************************************************************
@@ -58,7 +58,8 @@
     SMP_TRACE_DEBUG("%s before update role=%d recv=%d local_i_key = %02x, local_r_key = %02x",
         __func__, p_cb->role, recv, p_cb->local_i_key, p_cb->local_r_key);
 
-    if (((p_cb->le_secure_connections_mode_is_used) || (p_cb->smp_over_br)) &&
+    if (((p_cb->le_secure_connections_mode_is_used) ||
+        (p_cb->smp_over_br)) &&
         ((key_type == SMP_SEC_KEY_TYPE_ENC) || (key_type == SMP_SEC_KEY_TYPE_LK)))
     {
         /* in LE SC mode LTK, CSRK and BR/EDR LK are derived locally instead of
@@ -176,11 +177,9 @@
                         p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK;
                     }
 
-#if BTM_CROSS_TRANSP_KEY_DERIVATION == FALSE
                     SMP_TRACE_WARNING ("Cross transport key derivation is not supported");
                     p_cb->local_i_key &= ~SMP_SEC_KEY_TYPE_LK;
                     p_cb->local_r_key &= ~SMP_SEC_KEY_TYPE_LK;
-#endif
 
                     SMP_TRACE_WARNING("set auth_req: 0x%02x, local_i_key: 0x%02x, local_r_key: 0x%02x",
                         p_cb->loc_auth_req, p_cb->local_i_key, p_cb->local_r_key);
@@ -986,6 +985,11 @@
     STREAM_TO_BDADDR(pid_key.static_addr, p);
     memcpy(pid_key.irk, p_cb->tk, BT_OCTET16_LEN);
 
+    /* to use as BD_ADDR for lk derived from ltk */
+    p_cb->id_addr_rcvd = TRUE;
+    p_cb->id_addr_type = pid_key.addr_type;
+    memcpy(p_cb->id_addr, pid_key.static_addr, BD_ADDR_LEN);
+
     /* store the ID key from peer device */
     if ((p_cb->peer_auth_req & SMP_AUTH_BOND) && (p_cb->loc_auth_req & SMP_AUTH_BOND))
         btm_sec_save_le_key(p_cb->pairing_bda, BTM_LE_KEY_PID,
@@ -1217,8 +1221,8 @@
     SMP_TRACE_DEBUG("%s role=%d (0-master) r_keys=0x%x i_keys=0x%x",
                       __func__, p_cb->role, p_cb->local_r_key, p_cb->local_i_key);
 
-    if (p_cb->role == HCI_ROLE_SLAVE||
-        (!p_cb->local_r_key && p_cb->role == HCI_ROLE_MASTER))
+    if (p_cb->role == HCI_ROLE_SLAVE ||
+       (!p_cb->local_r_key && p_cb->role == HCI_ROLE_MASTER))
     {
         smp_key_pick_key(p_cb, p_data);
     }
@@ -1228,6 +1232,12 @@
         /* state check to prevent re-entrant */
         if (smp_get_state() == SMP_STATE_BOND_PENDING)
         {
+            if (p_cb->derive_lk)
+            {
+                smp_derive_link_key_from_long_term_key(p_cb, NULL);
+                p_cb->derive_lk = FALSE;
+            }
+
             if (p_cb->total_tx_unacked == 0)
                 smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
             else
@@ -1976,6 +1986,25 @@
 
 /*******************************************************************************
 **
+** Function         smp_set_derive_link_key
+**
+** Description      This function is called to set flag that indicates that
+**                  BR/EDR LK has to be derived from LTK after all keys are
+**                  distributed.
+**
+** Returns          void
+**
+*******************************************************************************/
+void smp_set_derive_link_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
+{
+    SMP_TRACE_DEBUG ("%s", __func__);
+    p_cb->derive_lk = TRUE;
+    smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_LK, FALSE);
+    smp_key_distribution(p_cb, NULL);
+}
+
+/*******************************************************************************
+**
 ** Function         smp_derive_link_key_from_long_term_key
 **
 ** Description      This function is called to derive BR/EDR LK from LTK.
@@ -1996,7 +2025,6 @@
     }
 
     smp_update_key_mask (p_cb, SMP_SEC_KEY_TYPE_LK, FALSE);
-
     SMP_TRACE_DEBUG("%s successfully completed", __FUNCTION__);
     smp_key_distribution(p_cb, NULL);
 }
diff --git a/stack/smp/smp_int.h b/stack/smp/smp_int.h
index 24aa3ec..52b0301 100644
--- a/stack/smp/smp_int.h
+++ b/stack/smp/smp_int.h
@@ -270,6 +270,10 @@
     UINT8           trace_level;
     BD_ADDR         pairing_bda;
     tSMP_STATE      state;
+    BOOLEAN         derive_lk;
+    BOOLEAN         id_addr_rcvd;
+    tBLE_ADDR_TYPE  id_addr_type;
+    BD_ADDR         id_addr;
     BOOLEAN         smp_over_br;
     tSMP_BR_STATE   br_state;           /* if SMP over BR/ERD has priority over SMP */
     UINT8           failure;
@@ -305,8 +309,9 @@
                                             /* either in Secure Connections mode or not at all */
     tSMP_ASSO_MODEL selected_association_model;
     BOOLEAN         le_secure_connections_mode_is_used;
-    tBTM_SP_KEY_TYPE  local_keypress_notification;
-    tBTM_SP_KEY_TYPE  peer_keypress_notification;
+    BOOLEAN le_sc_kp_notif_is_used;
+    tSMP_SC_KEY_TYPE local_keypress_notification;
+    tSMP_SC_KEY_TYPE peer_keypress_notification;
     UINT8           round;       /* authentication stage 1 round for passkey association model */
     UINT32          number_to_display;
     BT_OCTET16      mac_key;
@@ -447,9 +452,10 @@
 extern void smp_start_passkey_verification(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
 extern void smp_process_secure_connection_oob_data(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
 extern void smp_process_secure_connection_long_term_key(void);
-extern void smp_derive_link_key_from_long_term_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
 extern void smp_set_local_oob_keys(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
 extern void smp_set_local_oob_random_commitment(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_set_derive_link_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
+extern void smp_derive_link_key_from_long_term_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
 extern void smp_br_process_pairing_command(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
 extern void smp_br_process_security_grant(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
 extern void smp_br_process_slave_keys_response(tSMP_CB *p_cb, tSMP_INT_DATA *p_data);
diff --git a/stack/smp/smp_keys.c b/stack/smp/smp_keys.c
index 47d0125..f301530 100644
--- a/stack/smp/smp_keys.c
+++ b/stack/smp/smp_keys.c
@@ -1926,9 +1926,27 @@
 BOOLEAN smp_calculate_link_key_from_long_term_key(tSMP_CB *p_cb)
 {
     tBTM_SEC_DEV_REC *p_dev_rec;
+    BD_ADDR bda_for_lk;
+    tBLE_ADDR_TYPE conn_addr_type;
 
     SMP_TRACE_DEBUG ("%s", __func__);
 
+    if (p_cb->id_addr_rcvd && p_cb->id_addr_type == BLE_ADDR_PUBLIC)
+    {
+        SMP_TRACE_DEBUG ("Use rcvd identity address as BD_ADDR of LK rcvd identity address");
+        memcpy(bda_for_lk, p_cb->id_addr, BD_ADDR_LEN);
+    }
+    else if ((BTM_ReadRemoteConnectionAddr(p_cb->pairing_bda, bda_for_lk, &conn_addr_type)) &&
+              conn_addr_type == BLE_ADDR_PUBLIC)
+    {
+        SMP_TRACE_DEBUG ("Use rcvd connection address as BD_ADDR of LK");
+    }
+    else
+    {
+        SMP_TRACE_WARNING ("Don't have peer public address to associate with LK");
+        return FALSE;
+    }
+
     if ((p_dev_rec = btm_find_dev (p_cb->pairing_bda)) == NULL)
     {
         SMP_TRACE_ERROR("%s failed to find Security Record", __func__);
@@ -1989,7 +2007,7 @@
         p = notif_link_key;
         ARRAY16_TO_STREAM(p, link_key);
 
-        btm_sec_link_key_notification (p_cb->pairing_bda, notif_link_key, link_key_type);
+        btm_sec_link_key_notification (bda_for_lk, notif_link_key, link_key_type);
 
         SMP_TRACE_EVENT ("%s is completed", __func__);
     }
diff --git a/stack/smp/smp_utils.c b/stack/smp/smp_utils.c
index 9f2e532..3e592f2 100644
--- a/stack/smp/smp_utils.c
+++ b/stack/smp/smp_utils.c
@@ -942,6 +942,7 @@
     SMP_TRACE_DEBUG ("smp_proc_pairing_cmpl ");
 
     evt_data.cmplt.reason = p_cb->status;
+    evt_data.cmplt.smp_over_br = p_cb->smp_over_br;
 
     if (p_cb->status == SMP_SUCCESS)
         evt_data.cmplt.sec_level = p_cb->sec_level;