Implement OOB pairing for LE devices using TK.

This patch implements OOB pairing for LE devices using TK. Patches
for other pairing methods, and other transports will follow.

Bug: 22932952
Change-Id: Iad3c0c035de3b5a62ef24d3e3b655773fa03d5c1
diff --git a/btif/co/bta_dm_co.c b/btif/co/bta_dm_co.c
index c9ac4fc..19139af 100644
--- a/btif/co/bta_dm_co.c
+++ b/btif/co/bta_dm_co.c
@@ -402,18 +402,20 @@
                           tBTA_LE_KEY_TYPE  *p_resp_key )
 {
     UNUSED(bd_addr);
-    /* if OOB is not supported, this call-out function does not need to do anything
-     * otherwise, look for the OOB data associated with the address and set *p_oob_data accordingly
-     * If the answer can not be obtained right away,
-     * set *p_oob_data to BTA_OOB_UNKNOWN and call bta_dm_ci_io_req() when the answer is available */
-
-    *p_oob_data = FALSE;
 
     /* *p_auth_req by default is FALSE for devices with NoInputNoOutput; TRUE for other devices. */
 
     if (bte_appl_cfg.ble_auth_req)
         *p_auth_req = bte_appl_cfg.ble_auth_req | (bte_appl_cfg.ble_auth_req & 0x04) | ((*p_auth_req) & 0x04);
 
+    /* if OOB is not supported, this call-out function does not need to do anything
+     * otherwise, look for the OOB data associated with the address and set *p_oob_data accordingly.
+     * If the answer can not be obtained right away,
+     * set *p_oob_data to BTA_OOB_UNKNOWN and call bta_dm_ci_io_req() when the answer is available.
+     */
+
+    btif_dm_set_oob_for_le_io_req(bd_addr, p_oob_data, p_auth_req);
+
     if (bte_appl_cfg.ble_io_cap <=4)
         *p_io_cap = bte_appl_cfg.ble_io_cap;
 
diff --git a/btif/include/btif_api.h b/btif/include/btif_api.h
index 62687d3..75bfebf 100644
--- a/btif/include/btif_api.h
+++ b/btif/include/btif_api.h
@@ -210,6 +210,18 @@
 
 /*******************************************************************************
 **
+** Function         btif_dm_create_bond_out_of_band
+**
+** Description      Initiate bonding with the specified device using OOB 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);
+
+/*******************************************************************************
+**
 ** Function         btif_dm_cancel_bond
 **
 ** Description      Initiate bonding with the specified device
diff --git a/btif/include/btif_dm.h b/btif/include/btif_dm.h
index 5b88bbe..fb9bb4d 100644
--- a/btif/include/btif_dm.h
+++ b/btif/include/btif_dm.h
@@ -50,6 +50,8 @@
  * Out-of-band functions
  */
 void btif_dm_set_oob_for_io_req(tBTA_OOB_DATA  *p_oob_data);
+void btif_dm_set_oob_for_le_io_req(BD_ADDR bd_addr, tBTA_OOB_DATA  *p_oob_data,
+                                   tBTA_LE_AUTH_REQ *p_auth_req);
 #ifdef BTIF_DM_OOB_TEST
 void btif_dm_load_local_oob(void);
 void btif_dm_proc_loc_oob(BOOLEAN valid, BT_OCTET16 c, BT_OCTET16 r);
diff --git a/btif/src/bluetooth.c b/btif/src/bluetooth.c
index 1c91607..204f90d 100644
--- a/btif/src/bluetooth.c
+++ b/btif/src/bluetooth.c
@@ -256,6 +256,16 @@
     return btif_dm_create_bond(bd_addr, transport);
 }
 
+static int create_bond_out_of_band(const bt_bdaddr_t *bd_addr, int transport,
+                                   const bt_out_of_band_data_t *oob_data)
+{
+    /* sanity check */
+    if (interface_ready() == FALSE)
+        return BT_STATUS_NOT_READY;
+
+    return btif_dm_create_bond_out_of_band(bd_addr, transport, oob_data);
+}
+
 static int cancel_bond(const bt_bdaddr_t *bd_addr)
 {
     /* sanity check */
@@ -439,6 +449,7 @@
     start_discovery,
     cancel_discovery,
     create_bond,
+    create_bond_out_of_band,
     remove_bond,
     cancel_bond,
     get_connection_state,
diff --git a/btif/src/btif_dm.c b/btif/src/btif_dm.c
index eb5992b..4888700 100644
--- a/btif/src/btif_dm.c
+++ b/btif/src/btif_dm.c
@@ -149,11 +149,11 @@
     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
@@ -208,6 +208,7 @@
 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,
@@ -232,6 +233,12 @@
 **  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;
@@ -1876,6 +1883,7 @@
             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. ");
@@ -2324,6 +2332,25 @@
 
 /*******************************************************************************
 **
+** 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);
+    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
@@ -2726,18 +2753,48 @@
     }
 }
 
-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 (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))
     {
-        *p_oob_data = FALSE;
+        *p_has_oob_data = FALSE;
     }
     else
     {
-        *p_oob_data = TRUE;
+        *p_has_oob_data = TRUE;
     }
-    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);
+}
+
+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)
+{
+
+    /* 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))
+    {
+        /* 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_has_oob_data = FALSE;
+    }
+    BTIF_TRACE_DEBUG("%s *p_has_oob_data=%d", __func__, *p_has_oob_data);
 }
 
 #ifdef BTIF_DM_OOB_TEST
@@ -2751,13 +2808,12 @@
 #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();
         }
     }
@@ -2777,16 +2833,14 @@
     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')
@@ -2796,11 +2850,11 @@
             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);
@@ -2826,9 +2880,9 @@
     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')
@@ -2838,35 +2892,35 @@
         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;
@@ -2920,6 +2974,10 @@
     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 */
@@ -3188,6 +3246,39 @@
               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)
 {
diff --git a/service/hal/fake_bluetooth_interface.cpp b/service/hal/fake_bluetooth_interface.cpp
index 3dec807..19cdda1 100644
--- a/service/hal/fake_bluetooth_interface.cpp
+++ b/service/hal/fake_bluetooth_interface.cpp
@@ -58,6 +58,7 @@
   nullptr, /* start_discovery */
   nullptr, /* cancel_discovery */
   nullptr, /* create_bond */
+  nullptr, /* create_bond_out_of_band */
   nullptr, /* remove_bond */
   nullptr, /* cancel_bond */
   nullptr, /* get_connection_state */
diff --git a/stack/btm/btm_ble.c b/stack/btm/btm_ble.c
index 487bc01..c5a83f7 100644
--- a/stack/btm/btm_ble.c
+++ b/stack/btm/btm_ble.c
@@ -467,7 +467,9 @@
 **
 ** Parameters:      bd_addr     - Address of the peer device
 **                  res         - result of the operation SMP_SUCCESS if success
-**                  p_data      - simple pairing Randomizer  C.
+**                  p_data      - oob data, depending on transport and capabilities.
+**                                Might be "Simple Pairing Randomizer", or
+**                                "Security Manager TK Value".
 **
 *******************************************************************************/
 void BTM_BleOobDataReply(BD_ADDR bd_addr, UINT8 res, UINT8 len, UINT8 *p_data)