OSDN Git Service

Clean up bond event dump printout
[android-x86/system-bt.git] / btif / src / btif_dm.c
index e6ff7f3..2aceb6e 100644 (file)
 #include "btif_dm.h"
 
 #include <assert.h>
+#include <pthread.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
+#include <time.h>
 #include <unistd.h>
 
 #include <hardware/bluetooth.h>
@@ -61,9 +63,9 @@
 #include "bta_gatt_api.h"
 #include "device/include/interop.h"
 #include "include/stack_config.h"
-#include "osi/include/log.h"
 #include "osi/include/allocator.h"
 #include "osi/include/log.h"
+#include "osi/include/metrics.h"
 #include "stack_config.h"
 #include "stack/btm/btm_int.h"
 
@@ -149,11 +151,11 @@ typedef struct
     BD_NAME bd_name;
 } btif_dm_remote_name_t;
 
+/* this structure holds optional OOB data for remote device */
 typedef struct
 {
-    BT_OCTET16 sp_c;
-    BT_OCTET16 sp_r;
-    BD_ADDR  oob_bdaddr;  /* peer bdaddr*/
+    BD_ADDR  bdaddr;    /* peer bdaddr */
+    bt_out_of_band_data_t oob_data;
 } btif_dm_oob_cb_t;
 
 typedef struct
@@ -177,11 +179,29 @@ typedef struct
     unsigned int   manufact_id;
 }skip_sdp_entry_t;
 
+typedef enum
+{
+    BTIF_DM_FUNC_CREATE_BOND,
+    BTIF_DM_FUNC_CANCEL_BOND,
+    BTIF_DM_FUNC_REMOVE_BOND,
+    BTIF_DM_FUNC_BOND_STATE_CHANGED,
+} bt_bond_function_t;
+
+typedef struct
+{
+    bt_bdaddr_t bd_addr;
+    bt_bond_function_t function;
+    bt_bond_state_t state;
+    struct timespec timestamp;
+} btif_bond_event_t;
+
 #define BTA_SERVICE_ID_TO_SERVICE_MASK(id)       (1 << (id))
 
 #define MAX_SDP_BL_ENTRIES 3
 #define UUID_HUMAN_INTERFACE_DEVICE "00001124-0000-1000-8000-00805f9b34fb"
 
+#define MAX_BTIF_BOND_EVENT_ENTRIES 15
+
 static skip_sdp_entry_t sdp_blacklist[] = {{76}}; //Apple Mouse and Keyboard
 
 /* This flag will be true if HCI_Inquiry is in progress */
@@ -191,6 +211,18 @@ static BOOLEAN btif_dm_inquiry_in_progress = FALSE;
 **  Static variables
 ************************************************************************************/
 static char btif_default_local_name[DEFAULT_LOCAL_NAME_MAX+1] = {'\0'};
+static uid_set_t* uid_set = NULL;
+
+/* A circular array to keep track of the most recent bond events */
+static btif_bond_event_t btif_dm_bond_events[MAX_BTIF_BOND_EVENT_ENTRIES + 1];
+
+static pthread_mutex_t bond_event_lock;
+
+/* |btif_num_bond_events| keeps track of the total number of events and can be
+   greater than |MAX_BTIF_BOND_EVENT_ENTRIES| */
+static size_t btif_num_bond_events = 0;
+static size_t btif_events_start_index = 0;
+static size_t btif_events_end_index = 0;
 
 /******************************************************************************
 **  Static functions
@@ -208,13 +240,20 @@ static void btif_dm_ble_key_notif_evt(tBTA_DM_SP_KEY_NOTIF *p_ssp_key_notif);
 static void btif_dm_ble_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl);
 static void btif_dm_ble_passkey_req_evt(tBTA_DM_PIN_REQ *p_pin_req);
 static void btif_dm_ble_key_nc_req_evt(tBTA_DM_SP_KEY_NOTIF *p_notif_req) ;
+static void btif_dm_ble_oob_req_evt(tBTA_DM_SP_RMT_OOB *req_oob_type);
 #endif
 
 static void bte_scan_filt_param_cfg_evt(UINT8 action_type,
                                            tBTA_DM_BLE_PF_AVBL_SPACE avbl_space,
-                                           tBTA_DM_BLE_REF_VALUE ref_value, tBTA_STATUS status);
+                                           tBTA_DM_BLE_REF_VALUE ref_value,
+                                           tBTA_STATUS status);
 
 static char* btif_get_default_local_name();
+
+static void btif_stats_add_bond_event(const bt_bdaddr_t *bd_addr,
+                                      bt_bond_function_t function,
+                                      bt_bond_state_t state);
+
 /******************************************************************************
 **  Externs
 ******************************************************************************/
@@ -232,6 +271,12 @@ extern void bta_gatt_convert_uuid16_to_uuid128(UINT8 uuid_128[LEN_UUID_128], UIN
 **  Functions
 ******************************************************************************/
 
+static bool is_empty_128bit(uint8_t *data)
+{
+    static const uint8_t zero[16] = { 0 };
+    return !memcmp(zero, data, sizeof(zero));
+}
+
 static void btif_dm_data_copy(uint16_t event, char *dst, char *src)
 {
     tBTA_DM_SEC *dst_dm_sec = (tBTA_DM_SEC*)dst;
@@ -247,7 +292,6 @@ static void btif_dm_data_copy(uint16_t event, char *dst, char *src)
     {
         dst_dm_sec->ble_key.p_key_value = osi_malloc(sizeof(tBTM_LE_KEY_VALUE));
         assert(src_dm_sec->ble_key.p_key_value);
-        assert(dst_dm_sec->ble_key.p_key_value);
         memcpy(dst_dm_sec->ble_key.p_key_value, src_dm_sec->ble_key.p_key_value, sizeof(tBTM_LE_KEY_VALUE));
     }
 }
@@ -255,7 +299,19 @@ static void btif_dm_data_copy(uint16_t event, char *dst, char *src)
 static void btif_dm_data_free(uint16_t event, tBTA_DM_SEC *dm_sec)
 {
     if (event == BTA_DM_BLE_KEY_EVT)
-        osi_free(dm_sec->ble_key.p_key_value);
+        osi_free_and_reset((void **)&dm_sec->ble_key.p_key_value);
+}
+
+void btif_dm_init(uid_set_t* set)
+{
+    uid_set = set;
+    pthread_mutex_init(&bond_event_lock, NULL);
+}
+
+void btif_dm_cleanup(void)
+{
+    uid_set = NULL;
+    pthread_mutex_destroy(&bond_event_lock);
 }
 
 bt_status_t btif_in_execute_service_request(tBTA_SERVICE_ID service_id,
@@ -485,6 +541,9 @@ BOOLEAN check_sdp_bl(const bt_bdaddr_t *remote_bdaddr)
 
 static void bond_state_changed(bt_status_t status, bt_bdaddr_t *bd_addr, bt_bond_state_t state)
 {
+
+    btif_stats_add_bond_event(bd_addr, BTIF_DM_FUNC_BOND_STATE_CHANGED, state);
+
     // Send bonding state only once - based on outgoing/incoming we may receive duplicates
     if ((pairing_cb.state == state) && (state == BT_BOND_STATE_BONDING))
     {
@@ -823,12 +882,9 @@ static void search_services_copy_cb(UINT16 event, char *p_dest, char *p_src)
                                                         (UINT8*)(p_dest + sizeof(tBTA_DM_SEARCH));
                        memcpy(p_dest_data->disc_res.p_uuid_list, p_src_data->disc_res.p_uuid_list,
                               p_src_data->disc_res.num_uuids*MAX_UUID_SIZE);
-                       osi_freebuf(p_src_data->disc_res.p_uuid_list);
-                  }
-                  if (p_src_data->disc_res.p_raw_data != NULL)
-                  {
-                      osi_freebuf(p_src_data->disc_res.p_raw_data);
+                       osi_free_and_reset((void **)&p_src_data->disc_res.p_uuid_list);
                   }
+                  osi_free_and_reset((void **)&p_src_data->disc_res.p_raw_data);
               }
          } break;
     }
@@ -1090,6 +1146,20 @@ static void btif_dm_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl)
         }
     }
 
+    // We could have received a new link key without going through the pairing flow.
+    // If so, we don't want to perform SDP or any other operations on the authenticated
+    // device.
+    if (bdcmp(p_auth_cmpl->bd_addr, pairing_cb.bd_addr) != 0) {
+      char address[32];
+      bt_bdaddr_t bt_bdaddr;
+
+      memcpy(bt_bdaddr.address, p_auth_cmpl->bd_addr,
+             sizeof(bt_bdaddr.address));
+      bdaddr_to_string(&bt_bdaddr, address, sizeof(address));
+      LOG_INFO(LOG_TAG, "%s skipping SDP since we did not initiate pairing to %s.", __func__, address);
+      return;
+    }
+
     // Skip SDP for certain  HID Devices
     if (p_auth_cmpl->success)
     {
@@ -1866,6 +1936,7 @@ static void btif_dm_upstreams_evt(UINT16 event, char* p_param)
             break;
         case BTA_DM_BLE_OOB_REQ_EVT:
             BTIF_TRACE_DEBUG("BTA_DM_BLE_OOB_REQ_EVT. ");
+            btif_dm_ble_oob_req_evt(&p_data->rmt_oob);
             break;
         case BTA_DM_BLE_LOCAL_IR_EVT:
             BTIF_TRACE_DEBUG("BTA_DM_BLE_LOCAL_IR_EVT. ");
@@ -1946,7 +2017,10 @@ static void btif_dm_upstreams_evt(UINT16 event, char* p_param)
             energy_info.tx_time = p_ener_data->tx_time;
             energy_info.idle_time = p_ener_data->idle_time;
             energy_info.energy_used = p_ener_data->energy_used;
-            HAL_CBACK(bt_hal_cbacks, energy_info_cb, &energy_info);
+
+            bt_uid_traffic_t* data = uid_set_read_and_clear(uid_set);
+            HAL_CBACK(bt_hal_cbacks, energy_info_cb, &energy_info, data);
+            osi_free(data);
             break;
         }
 #endif
@@ -2306,6 +2380,8 @@ bt_status_t btif_dm_create_bond(const bt_bdaddr_t *bd_addr, int transport)
     if (pairing_cb.state != BT_BOND_STATE_NONE)
         return BT_STATUS_BUSY;
 
+    btif_stats_add_bond_event(bd_addr, BTIF_DM_FUNC_CREATE_BOND, pairing_cb.state);
+
     btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_CREATE_BOND,
                           (char *)&create_bond_cb, sizeof(btif_dm_create_bond_cb_t), NULL);
 
@@ -2314,6 +2390,25 @@ bt_status_t btif_dm_create_bond(const bt_bdaddr_t *bd_addr, int transport)
 
 /*******************************************************************************
 **
+** Function         btif_dm_create_bond_out_of_band
+**
+** Description      Initiate bonding with the specified device using out of band data
+**
+** Returns          bt_status_t
+**
+*******************************************************************************/
+bt_status_t btif_dm_create_bond_out_of_band(const bt_bdaddr_t *bd_addr, int transport, const bt_out_of_band_data_t *oob_data)
+{
+    bdcpy(oob_cb.bdaddr, bd_addr->address);
+    memcpy(&oob_cb.oob_data, oob_data, sizeof(bt_out_of_band_data_t));
+
+    bdstr_t bdstr;
+    BTIF_TRACE_EVENT("%s: bd_addr=%s, transport=%d", __FUNCTION__, bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr)), transport);
+    return btif_dm_create_bond(bd_addr, transport);
+}
+
+/*******************************************************************************
+**
 ** Function         btif_dm_cancel_bond
 **
 ** Description      Initiate bonding with the specified device
@@ -2328,6 +2423,8 @@ bt_status_t btif_dm_cancel_bond(const bt_bdaddr_t *bd_addr)
 
     BTIF_TRACE_EVENT("%s: bd_addr=%s", __FUNCTION__, bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr)));
 
+    btif_stats_add_bond_event(bd_addr, BTIF_DM_FUNC_CANCEL_BOND, pairing_cb.state);
+
     /* TODO:
     **  1. Restore scan modes
     **  2. special handling for HID devices
@@ -2416,6 +2513,9 @@ bt_status_t btif_dm_remove_bond(const bt_bdaddr_t *bd_addr)
     bdstr_t bdstr;
 
     BTIF_TRACE_EVENT("%s: bd_addr=%s", __FUNCTION__, bdaddr_to_string(bd_addr, bdstr, sizeof(bdstr)));
+
+    btif_stats_add_bond_event(bd_addr, BTIF_DM_FUNC_REMOVE_BOND, pairing_cb.state);
+
     btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_REMOVE_BOND,
                           (char *)bd_addr, sizeof(bt_bdaddr_t), NULL);
 
@@ -2716,18 +2816,48 @@ void btif_dm_proc_io_rsp(BD_ADDR bd_addr, tBTA_IO_CAP io_cap,
     }
 }
 
-void btif_dm_set_oob_for_io_req(tBTA_OOB_DATA  *p_oob_data)
+void btif_dm_set_oob_for_io_req(tBTA_OOB_DATA  *p_has_oob_data)
+{
+    if (is_empty_128bit(oob_cb.oob_data.c192))
+    {
+        *p_has_oob_data = FALSE;
+    }
+    else
+    {
+        *p_has_oob_data = TRUE;
+    }
+    BTIF_TRACE_DEBUG("%s: *p_has_oob_data=%d", __func__, *p_has_oob_data);
+}
+
+void btif_dm_set_oob_for_le_io_req(BD_ADDR bd_addr, tBTA_OOB_DATA  *p_has_oob_data,
+                                   tBTA_LE_AUTH_REQ *p_auth_req)
 {
-    if (oob_cb.sp_c[0] == 0 && oob_cb.sp_c[1] == 0 &&
-        oob_cb.sp_c[2] == 0 && oob_cb.sp_c[3] == 0 )
+
+    /* We currently support only Security Manager TK as OOB data for LE transport.
+       If it's not present mark no OOB data.
+     */
+    if (!is_empty_128bit(oob_cb.oob_data.sm_tk))
     {
-        *p_oob_data = FALSE;
+        /* make sure OOB data is for this particular device */
+        if (memcmp(bd_addr, oob_cb.bdaddr, BD_ADDR_LEN) == 0) {
+            // When using OOB with TK, SC Secure Connections bit must be disabled.
+            tBTA_LE_AUTH_REQ mask = ~BTM_LE_AUTH_REQ_SC_ONLY;
+            *p_auth_req = ((*p_auth_req) & mask);
+
+            *p_has_oob_data = TRUE;
+        }
+        else
+        {
+            *p_has_oob_data = FALSE;
+            BTIF_TRACE_WARNING("%s: remote address didn't match OOB data address",
+                               __func__);
+        }
     }
     else
     {
-        *p_oob_data = TRUE;
+        *p_has_oob_data = FALSE;
     }
-    BTIF_TRACE_DEBUG("btif_dm_set_oob_for_io_req *p_oob_data=%d", *p_oob_data);
+    BTIF_TRACE_DEBUG("%s *p_has_oob_data=%d", __func__, *p_has_oob_data);
 }
 
 #ifdef BTIF_DM_OOB_TEST
@@ -2741,13 +2871,12 @@ void btif_dm_load_local_oob(void)
 #if !defined(OS_GENERIC)
     char prop_oob[PROPERTY_VALUE_MAX];
     property_get("service.brcm.bt.oob", prop_oob, "3");
-    BTIF_TRACE_DEBUG("btif_dm_load_local_oob prop_oob = %s",prop_oob);
+    BTIF_TRACE_DEBUG("%s: prop_oob = %s", __func__, prop_oob);
     if (prop_oob[0] != '3')
     {
-        if (oob_cb.sp_c[0] == 0 && oob_cb.sp_c[1] == 0 &&
-            oob_cb.sp_c[2] == 0 && oob_cb.sp_c[3] == 0 )
+        if (is_empty_128bit(oob_cb.oob_data.c192))
         {
-            BTIF_TRACE_DEBUG("btif_dm_load_local_oob: read OOB, call BTA_DmLocalOob()");
+            BTIF_TRACE_DEBUG("%s: read OOB, call BTA_DmLocalOob()", __func__);
             BTA_DmLocalOob();
         }
     }
@@ -2767,16 +2896,14 @@ void btif_dm_proc_loc_oob(BOOLEAN valid, BT_OCTET16 c, BT_OCTET16 r)
     char *path_b = "/data/misc/bluedroid/LOCAL/b.key";
     char *path = NULL;
     char prop_oob[PROPERTY_VALUE_MAX];
-    BTIF_TRACE_DEBUG("btif_dm_proc_loc_oob: valid=%d", valid);
-    if (oob_cb.sp_c[0] == 0 && oob_cb.sp_c[1] == 0 &&
-        oob_cb.sp_c[2] == 0 && oob_cb.sp_c[3] == 0 &&
-        valid)
+    BTIF_TRACE_DEBUG("%s: valid=%d", __func__, valid);
+    if (is_empty_128bit(oob_cb.oob_data.c192) && valid)
     {
         BTIF_TRACE_DEBUG("save local OOB data in memory");
-        memcpy(oob_cb.sp_c, c, BT_OCTET16_LEN);
-        memcpy(oob_cb.sp_r, r, BT_OCTET16_LEN);
+        memcpy(oob_cb.oob_data.c192, c, BT_OCTET16_LEN);
+        memcpy(oob_cb.oob_data.r192, r, BT_OCTET16_LEN);
         property_get("service.brcm.bt.oob", prop_oob, "3");
-        BTIF_TRACE_DEBUG("btif_dm_proc_loc_oob prop_oob = %s",prop_oob);
+        BTIF_TRACE_DEBUG("%s: prop_oob = %s", __func__, prop_oob);
         if (prop_oob[0] == '1')
             path = path_a;
         else if (prop_oob[0] == '2')
@@ -2786,11 +2913,11 @@ void btif_dm_proc_loc_oob(BOOLEAN valid, BT_OCTET16 c, BT_OCTET16 r)
             fp = fopen(path, "wb+");
             if (fp == NULL)
             {
-                BTIF_TRACE_DEBUG("btif_dm_proc_loc_oob: failed to save local OOB data to %s", path);
+                BTIF_TRACE_DEBUG("%s: failed to save local OOB data to %s", __func__, path);
             }
             else
             {
-                BTIF_TRACE_DEBUG("btif_dm_proc_loc_oob: save local OOB data into file %s",path);
+                BTIF_TRACE_DEBUG("%s: save local OOB data into file %s", __func__, path);
                 fwrite (c , 1 , BT_OCTET16_LEN , fp );
                 fwrite (r , 1 , BT_OCTET16_LEN , fp );
                 fclose(fp);
@@ -2816,9 +2943,9 @@ BOOLEAN btif_dm_proc_rmt_oob(BD_ADDR bd_addr,  BT_OCTET16 p_c, BT_OCTET16 p_r)
     char prop_oob[PROPERTY_VALUE_MAX];
     BOOLEAN result = FALSE;
     bt_bdaddr_t bt_bd_addr;
-    bdcpy(oob_cb.oob_bdaddr, bd_addr);
+    bdcpy(oob_cb.bdaddr, bd_addr);
     property_get("service.brcm.bt.oob", prop_oob, "3");
-    BTIF_TRACE_DEBUG("btif_dm_proc_rmt_oob prop_oob = %s",prop_oob);
+    BTIF_TRACE_DEBUG("%s: prop_oob = %s", __func__, prop_oob);
     if (prop_oob[0] == '1')
         path = path_b;
     else if (prop_oob[0] == '2')
@@ -2828,35 +2955,35 @@ BOOLEAN btif_dm_proc_rmt_oob(BD_ADDR bd_addr,  BT_OCTET16 p_c, BT_OCTET16 p_r)
         fp = fopen(path, "rb");
         if (fp == NULL)
         {
-            BTIF_TRACE_DEBUG("btapp_dm_rmt_oob_reply: failed to read OOB keys from %s",path);
+            BTIF_TRACE_DEBUG("%s: failed to read OOB keys from %s", __func__, path);
             return FALSE;
         }
         else
         {
-            BTIF_TRACE_DEBUG("btif_dm_proc_rmt_oob: read OOB data from %s",path);
+            BTIF_TRACE_DEBUG("%s: read OOB data from %s", __func__, path);
             fread (p_c , 1 , BT_OCTET16_LEN , fp );
             fread (p_r , 1 , BT_OCTET16_LEN , fp );
             fclose(fp);
         }
-        BTIF_TRACE_DEBUG("----btif_dm_proc_rmt_oob: TRUE");
+        BTIF_TRACE_DEBUG("----%s: TRUE", __func__);
         sprintf(t, "%02x:%02x:%02x:%02x:%02x:%02x",
-                oob_cb.oob_bdaddr[0], oob_cb.oob_bdaddr[1], oob_cb.oob_bdaddr[2],
-                oob_cb.oob_bdaddr[3], oob_cb.oob_bdaddr[4], oob_cb.oob_bdaddr[5]);
-        BTIF_TRACE_DEBUG("----btif_dm_proc_rmt_oob: peer_bdaddr = %s", t);
+                oob_cb.bdaddr[0], oob_cb.bdaddr[1], oob_cb.bdaddr[2],
+                oob_cb.bdaddr[3], oob_cb.bdaddr[4], oob_cb.bdaddr[5]);
+        BTIF_TRACE_DEBUG("----%s: peer_bdaddr = %s", __func__, t);
         sprintf(t, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
                 p_c[0], p_c[1], p_c[2],  p_c[3],  p_c[4],  p_c[5],  p_c[6],  p_c[7],
                 p_c[8], p_c[9], p_c[10], p_c[11], p_c[12], p_c[13], p_c[14], p_c[15]);
-        BTIF_TRACE_DEBUG("----btif_dm_proc_rmt_oob: c = %s",t);
+        BTIF_TRACE_DEBUG("----%s: c = %s", __func__, t);
         sprintf(t, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
                 p_r[0], p_r[1], p_r[2],  p_r[3],  p_r[4],  p_r[5],  p_r[6],  p_r[7],
                 p_r[8], p_r[9], p_r[10], p_r[11], p_r[12], p_r[13], p_r[14], p_r[15]);
-        BTIF_TRACE_DEBUG("----btif_dm_proc_rmt_oob: r = %s",t);
+        BTIF_TRACE_DEBUG("----%s: r = %s", __func__, t);
         bdcpy(bt_bd_addr.address, bd_addr);
         btif_transfer_context(btif_dm_generic_evt, BTIF_DM_CB_BOND_STATE_BONDING,
                               (char *)&bt_bd_addr, sizeof(bt_bdaddr_t), NULL);
         result = TRUE;
     }
-    BTIF_TRACE_DEBUG("btif_dm_proc_rmt_oob result=%d",result);
+    BTIF_TRACE_DEBUG("%s: result=%d", __func__, result);
     return result;
 #else  /* defined(OS_GENERIC) */
     return FALSE;
@@ -2910,6 +3037,10 @@ static void btif_dm_ble_auth_cmpl_evt (tBTA_DM_AUTH_CMPL *p_auth_cmpl)
     bt_bond_state_t state = BT_BOND_STATE_NONE;
 
     bdcpy(bd_addr.address, p_auth_cmpl->bd_addr);
+
+    /* Clear OOB data */
+    memset(&oob_cb, 0, sizeof(oob_cb));
+
     if ( (p_auth_cmpl->success == TRUE) && (p_auth_cmpl->key_present) )
     {
         /* store keys */
@@ -3178,6 +3309,39 @@ static void btif_dm_ble_key_nc_req_evt(tBTA_DM_SP_KEY_NOTIF *p_notif_req)
               p_notif_req->passkey);
 }
 
+static void btif_dm_ble_oob_req_evt(tBTA_DM_SP_RMT_OOB *req_oob_type)
+{
+    BTIF_TRACE_DEBUG("%s", __FUNCTION__);
+
+    bt_bdaddr_t bd_addr;
+    bdcpy(bd_addr.address, req_oob_type->bd_addr);
+
+    /* We currently support only Security Manager TK as OOB data. We already
+     * checked if it's present in btif_dm_set_oob_for_le_io_req, but check here
+     * again. If it's not present do nothing, pairing will timeout.
+     */
+    if (is_empty_128bit(oob_cb.oob_data.sm_tk)) {
+        return;
+    }
+
+    /* make sure OOB data is for this particular device */
+    if (memcmp(req_oob_type->bd_addr, oob_cb.bdaddr, BD_ADDR_LEN) != 0) {
+        BTIF_TRACE_WARNING("%s: remote address didn't match OOB data address", __func__);
+        return;
+    }
+
+    /* Remote name update */
+    btif_update_remote_properties(req_oob_type->bd_addr , req_oob_type->bd_name,
+                                          NULL, BT_DEVICE_TYPE_BLE);
+
+    bond_state_changed(BT_STATUS_SUCCESS, &bd_addr, BT_BOND_STATE_BONDING);
+    pairing_cb.is_ssp = FALSE;
+    pairing_cb.is_le_only = TRUE;
+    pairing_cb.is_le_nc = FALSE;
+
+    BTM_BleOobDataReply(req_oob_type->bd_addr, 0, 16, oob_cb.oob_data.sm_tk);
+}
+
 void btif_dm_update_ble_remote_properties( BD_ADDR bd_addr, BD_NAME bd_name,
                                            tBT_DEVICE_TYPE dev_type)
 {
@@ -3286,3 +3450,101 @@ static char* btif_get_default_local_name() {
 #endif  /* !defined(OS_GENERIC) */
     return btif_default_local_name;
 }
+
+static void btif_stats_add_bond_event(const bt_bdaddr_t *bd_addr,
+                                      bt_bond_function_t function,
+                                      bt_bond_state_t state) {
+    pthread_mutex_lock(&bond_event_lock);
+
+    btif_bond_event_t* event = &btif_dm_bond_events[btif_events_end_index];
+    memcpy(&event->bd_addr, bd_addr, sizeof(bt_bdaddr_t));
+    event->function = function;
+    event->state = state;
+    clock_gettime(CLOCK_MONOTONIC, &event->timestamp);
+
+    btif_num_bond_events++;
+    btif_events_end_index = (btif_events_end_index + 1) % (MAX_BTIF_BOND_EVENT_ENTRIES + 1);
+    if (btif_events_end_index == btif_events_start_index) {
+        btif_events_start_index = (btif_events_start_index + 1) % (MAX_BTIF_BOND_EVENT_ENTRIES + 1);
+    }
+
+    int type;
+    btif_get_device_type(event->bd_addr.address, &type);
+    device_type_t device_type;
+    switch (type) {
+        case BT_DEVICE_TYPE_BREDR:
+            device_type = DEVICE_TYPE_BREDR;
+            break;
+        case BT_DEVICE_TYPE_BLE:
+            device_type = DEVICE_TYPE_LE;
+            break;
+        case BT_DEVICE_TYPE_DUMO:
+            device_type = DEVICE_TYPE_DUMO;
+            break;
+        default:
+            device_type = DEVICE_TYPE_UNKNOWN;
+            break;
+    }
+    // TODO (apanicke): Add disconnect reason and
+    // device class to the pair event.
+    uint64_t ts = event->timestamp.tv_sec * 1000 +
+                  event->timestamp.tv_nsec / 1000000;
+    metrics_pair_event(0, ts, 0, device_type);
+
+    pthread_mutex_unlock(&bond_event_lock);
+}
+
+void btif_debug_bond_event_dump(int fd) {
+    pthread_mutex_lock(&bond_event_lock);
+    dprintf(fd, "\nBond Events: \n");
+    dprintf(fd, "  Total Number of events: %zu\n", btif_num_bond_events);
+    if (btif_num_bond_events > 0)
+        dprintf(fd, "  Time          BD_ADDR            Function             State\n");
+
+    for (size_t i = btif_events_start_index; i != btif_events_end_index;
+         i = (i + 1) % (MAX_BTIF_BOND_EVENT_ENTRIES + 1)) {
+        btif_bond_event_t* event = &btif_dm_bond_events[i];
+
+        char eventtime[15];
+        struct tm *tstamp = localtime(&event->timestamp.tv_sec);
+        strftime(eventtime, sizeof(eventtime), "%H:%M:%S.%%03u", tstamp);
+        snprintf(eventtime, sizeof(eventtime), eventtime, (event->timestamp.tv_nsec) / 1000000);
+
+        char bdaddr[18];
+        bdaddr_to_string(&event->bd_addr, bdaddr, sizeof(bdaddr));
+
+        char* func_name;
+        switch (event->function) {
+            case BTIF_DM_FUNC_CREATE_BOND:
+                func_name = "btif_dm_create_bond";
+                break;
+            case BTIF_DM_FUNC_REMOVE_BOND:
+                func_name = "btif_dm_remove_bond";
+                break;
+            case BTIF_DM_FUNC_BOND_STATE_CHANGED:
+                func_name = "bond_state_changed ";
+                break;
+            default:
+                func_name = "Invalid value      ";
+                break;
+        }
+
+        char* bond_state;
+        switch (event->state) {
+            case BT_BOND_STATE_NONE:
+                bond_state = "BOND_STATE_NONE";
+                break;
+            case BT_BOND_STATE_BONDING:
+                bond_state = "BOND_STATE_BONDING";
+                break;
+            case BT_BOND_STATE_BONDED:
+                bond_state = "BOND_STATE_BONDED";
+                break;
+            default:
+                bond_state = "Invalid bond state";
+                break;
+        }
+        dprintf(fd, "  %s  %s  %s  %s\n", eventtime, bdaddr, func_name, bond_state);
+    }
+    pthread_mutex_unlock(&bond_event_lock);
+}