Keep local IRK in permanent storage 32/115532/1 accepted/tizen/3.0/common/20170221.125520 accepted/tizen/3.0/ivi/20170221.050915 accepted/tizen/3.0/mobile/20170221.050807 accepted/tizen/3.0/tv/20170221.050830 accepted/tizen/3.0/wearable/20170221.050851 submit/tizen_3.0/20170220.233212
authorSeungyoun Ju <sy39.ju@samsung.com>
Fri, 10 Feb 2017 08:42:11 +0000 (17:42 +0900)
committerSeungyoun Ju <sy39.ju@samsung.com>
Mon, 20 Feb 2017 08:21:48 +0000 (17:21 +0900)
[Model] COMMON
[BinType] AP
[Customer] OPEN

[Issue#] N/A
[Request] Internal
[Occurrence Version] N/A

[Problem] When local IRK is changed, iOS rejects re-pairing request (iOS issue).
 This issue happens in below scenario.
 1. Pair with iOS
 2. Factory-reset DUT
 3. Try to pair with iOS again without unpairing on iOS
 4. iOS sends SMP pairing error with "Unspecified reason". So until user
   unpairs DUT on iOS, re-pairing is not possible.

 And when local IRK is not distributed at BLE pairing with some android
 devices, those devices cannot connect to DUT again via BLE (Android issue).
 1. Pair with Galaxy A5 2016 / Note 4 via BLE
 2. Disconnect
 3. Try to connect again via BLE
 4. A5 2016 / Note 4 try to connect to DUT using 00:00:00:00:00:00
   address. So it is failed.

 To solve these issues, DUT distributes a IRK. And after resetting DUT,
 retain the IRK.
[Cause & Measure] Compatibility issues with other OS's.
[Checking Method]
 ===
 1. Pair with iOS
 2. Factory-reset DUT
 3. Try to pair with iOS again without unpairing on iOS
 4. iOS sends SMP pairing error with "Unspecified reason". So until user
   unpairs DUT on iOS, re-pairing is not possible.
 ===
 1. Pair with Galaxy A5 2016 / Note 4 via BLE
 2. Disconnect
 3. Try to connect again via BLE
 4. A5 2016 / Note 4 try to connect to DUT using 00:00:00:00:00:00
 ===

[Team] Basic connection
[Developer] Seungyoun Ju
[Solution company] Samsung
[Change Type] Specification change

Change-Id: Icf0f2899028f13764dd09aec1b6851a5efa4d00b

src/adapter.c

index f649825..82bfa36 100644 (file)
@@ -245,7 +245,6 @@ struct btd_adapter {
        char *current_alias;            /* current adapter name alias */
        char *stored_alias;             /* stored adapter name alias */
 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
-       bool le_privacy_enabled;        /* whether LE Privacy feature enabled */
        uint8_t *local_irk;     /* adapter local IRK */
        uint8_t disc_type;
        bool ipsp_intialized;           /* Ipsp Initialization state */
@@ -538,22 +537,6 @@ static void store_adapter_info(struct btd_adapter *adapter)
        if (adapter->stored_alias)
                g_key_file_set_string(key_file, "General", "Alias",
                                                        adapter->stored_alias);
-#ifdef TIZEN_FEATURE_BLUEZ_MODIFY
-       if (adapter->local_irk) {
-               int i;
-               char key_str[35];
-               char *ptr = key_str;
-
-               ptr[0] = '0';
-               ptr[1] = 'x';
-               ptr += 2;
-               for (i = 0; i < MGMT_IRK_SIZE; i++, ptr += 2)
-                       snprintf(ptr, 3, "%2.2X", adapter->local_irk[i]);
-
-               g_key_file_set_string(key_file, "General", "LocalIrk", key_str);
-       }
-#endif
-
        ba2str(&adapter->bdaddr, address);
        snprintf(filename, PATH_MAX, STORAGEDIR "/%s/settings", address);
 
@@ -573,8 +556,9 @@ static void trigger_passive_scanning(struct btd_adapter *adapter);
 static bool set_mode(struct btd_adapter *adapter, uint16_t opcode,
                                                        uint8_t mode);
 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
+static bool load_local_irk(struct btd_adapter *adapter);
+static bool set_local_irk(struct btd_adapter *adapter);
 static bool set_privacy(struct btd_adapter *adapter, bool privacy);
-static bool set_irk(struct btd_adapter *adapter, bool set);
 #endif
 
 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
@@ -854,6 +838,19 @@ static void settings_changed(struct btd_adapter *adapter, uint32_t settings)
                adapter->advertising = adapter->current_settings & MGMT_SETTING_ADVERTISING;
                advertising_state_changed(adapter, 0, adapter->advertising);
        }
+
+       if ((changed_mask & MGMT_SETTING_PRIVACY) &&
+           !(adapter->current_settings & MGMT_SETTING_PRIVACY)) {
+               DBG("LE Privacy feature is disabled");
+
+               /*
+                * Some Android devices don't consider the device as LE one,
+                * if the device doesn't distribute IRK when pairing.
+                * Because of this compatibility issue, set IRK
+                * even though privacy feature is disabled.
+                */
+               set_local_irk(adapter);
+       }
 #endif
 }
 
@@ -9339,9 +9336,6 @@ static void load_config(struct btd_adapter *adapter)
        char address[18];
        struct stat st;
        GError *gerr = NULL;
-#ifdef TIZEN_FEATURE_BLUEZ_MODIFY
-       char *str;
-#endif
 
        ba2str(&adapter->bdaddr, address);
 
@@ -9392,23 +9386,6 @@ static void load_config(struct btd_adapter *adapter)
                gerr = NULL;
        }
 
-#ifdef TIZEN_FEATURE_BLUEZ_MODIFY
-       /* Get Local IRK */
-       str = g_key_file_get_string(key_file, "General", "LocalIrk", &gerr);
-       if (gerr || !str || strlen(str) != 34) {
-               g_error_free(gerr);
-               gerr = NULL;
-
-               g_free(adapter->local_irk);
-               adapter->local_irk = NULL;
-       } else {
-               if (!adapter->local_irk)
-                       adapter->local_irk = g_malloc0(MGMT_IRK_SIZE);
-
-               str2buf(&str[2], adapter->local_irk, MGMT_IRK_SIZE);
-       }
-#endif
-
        g_key_file_free(key_file);
 }
 
@@ -9459,12 +9436,6 @@ static struct btd_adapter *btd_adapter_new(uint16_t index)
        DBG("Modalias: %s", adapter->modalias);
        DBG("Discoverable timeout: %u seconds", adapter->discoverable_timeout);
        DBG("Pairable timeout: %u seconds", adapter->pairable_timeout);
-#ifdef TIZEN_FEATURE_BLUEZ_MODIFY
-       if (main_opts.le_privacy)
-               DBG("LE Privacy is enabled.");
-       else
-               DBG("LE Privacy is disabled.");
-#endif
        adapter->auths = g_queue_new();
 
 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
@@ -12506,18 +12477,24 @@ static int adapter_register(struct btd_adapter *adapter)
 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
        adapter_print_devices(adapter);
 
-       if (adapter->le_privacy_enabled &&
-           (adapter->supported_settings & MGMT_SETTING_PRIVACY))
-               set_privacy(adapter, true);
-       else {
+       if (load_local_irk(adapter)) {
+               if (!(adapter->supported_settings & MGMT_SETTING_PRIVACY))
+                       main_opts.le_privacy = false;
+
                /*
                 * Some Android devices don't consider the device as LE one,
                 * if the device doesn't distribute IRK when pairing.
                 * Because of this compatibility issue, set IRK
                 * even though privacy feature is disabled.
                 */
-               DBG("LE privacy feature not configured or supported");
-               set_irk(adapter, true);
+               set_local_irk(adapter);
+
+               if (main_opts.le_privacy) {
+                       DBG("Enable LE Privacy feature");
+                       set_privacy(adapter, true);
+               } else {
+                       DBG("Disable LE Privacy feature");
+               }
        }
 #endif
 
@@ -12849,6 +12826,92 @@ static uint8_t *generate_irk(void)
        return irk;
 }
 
+#define LOCAL_IRK_DIRNAME      "/csa/bluetooth"
+#define LOCAL_IRK_FILENAME     ".local_irk"
+
+static bool store_local_irk(struct btd_adapter *adapter)
+{
+       int fd;
+       int ret;
+
+       if (adapter->local_irk == NULL) {
+               error("Local IRK is not proper");
+               return false;
+       }
+
+       if (access(LOCAL_IRK_DIRNAME, F_OK) < 0) {
+               if (mkdir(LOCAL_IRK_DIRNAME, 0755) < 0) {
+                       error("Cannot create a directory for local IRK : %s",
+                                       strerror(errno));
+                       return false;
+               }
+       }
+
+       fd = open(LOCAL_IRK_DIRNAME"/"LOCAL_IRK_FILENAME,
+                       O_WRONLY | O_CREAT | O_TRUNC, 0644);
+       if (fd < 0) {
+               error("Cannot open a file for local IRK : %s", strerror(errno));
+               return false;
+       }
+
+       ret = write(fd, adapter->local_irk, MGMT_IRK_SIZE);
+       if (ret != MGMT_IRK_SIZE) {
+               error("Cannot write local IRK [%d] : %s", ret, strerror(errno));
+
+               close(fd);
+               unlink(LOCAL_IRK_DIRNAME"/"LOCAL_IRK_FILENAME);
+               return false;
+       }
+
+       ret = fdatasync(fd);
+       if (ret < 0)
+               error("sync failed : %s", strerror(errno));
+
+       close(fd);
+       return true;
+}
+
+static bool load_local_irk(struct btd_adapter *adapter)
+{
+       int fd;
+       int ret;
+
+       if (access(LOCAL_IRK_DIRNAME"/"LOCAL_IRK_FILENAME, F_OK) < 0) {
+               adapter->local_irk = generate_irk();
+               if (store_local_irk(adapter) < 0) {
+                       error("Cannot store Local IRK");
+                       g_free(adapter->local_irk);
+                       return false;
+               }
+
+               return true;
+       }
+
+       if (adapter->local_irk) {
+               DBG("Local IRK is already loaded");
+               return true;
+       }
+
+       fd = open(LOCAL_IRK_DIRNAME"/"LOCAL_IRK_FILENAME, O_RDONLY);
+       if (fd < 0) {
+               error("Cannot open local IRK file : %s", strerror(errno));
+               return false;
+       }
+
+       adapter->local_irk = g_malloc0(MGMT_IRK_SIZE);
+
+       ret = read(fd, adapter->local_irk, MGMT_IRK_SIZE);
+       if (ret != MGMT_IRK_SIZE) {
+               error("Cannot read local IRK [%d] : %s", ret, strerror(errno));
+               g_free(adapter->local_irk);
+               close(fd);
+               return false;
+       }
+
+       close(fd);
+       return true;
+}
+
 static void set_privacy_complete(uint8_t status, uint16_t length,
        const void *param, void *user_data)
 {
@@ -12866,27 +12929,22 @@ static bool set_privacy(struct btd_adapter *adapter, bool privacy)
 {
        struct mgmt_cp_set_privacy cp;
 
-       memset(&cp, 0, sizeof(cp));
-
-       if (privacy) {
-               if (adapter->local_irk == NULL) {
-                       adapter->local_irk = generate_irk();
-                       if (adapter->local_irk == NULL)
-                               goto fail;
-               }
+       if (!adapter->local_irk) {
+               error("Local IRK is not available");
+               return false;
+       }
 
-               store_adapter_info(adapter);
+       memset(&cp, 0, sizeof(cp));
+       memcpy(cp.irk, adapter->local_irk, MGMT_IRK_SIZE);
 
+       if (privacy)
                cp.privacy = 0x01;
-               memcpy(cp.irk, adapter->local_irk, MGMT_IRK_SIZE);
-       }
 
        if (mgmt_send(adapter->mgmt, MGMT_OP_SET_PRIVACY,
                                adapter->dev_id, sizeof(cp), &cp,
                                set_privacy_complete, adapter, NULL) > 0)
                return true;
 
-fail:
        error("Failed to set privacy and load local irk for index %u",
                        adapter->dev_id);
        return false;
@@ -12904,29 +12962,22 @@ static void set_irk_complete(uint8_t status, uint16_t length,
                DBG("Setting IRK is succeed for hci%u", adapter->dev_id);
 }
 
-static bool set_irk(struct btd_adapter *adapter, bool set)
+static bool set_local_irk(struct btd_adapter *adapter)
 {
        struct mgmt_cp_set_irk cp;
 
-       memset(&cp, 0, sizeof(cp));
-
-       if (set) {
-               if (adapter->local_irk == NULL) {
-                       adapter->local_irk = generate_irk();
-                       if (adapter->local_irk == NULL)
-                               goto fail;
-               }
-
-               store_adapter_info(adapter);
-               memcpy(cp.irk, adapter->local_irk, MGMT_IRK_SIZE);
+       if (!adapter->local_irk) {
+               error("Local IRK is not available");
+               return false;
        }
 
+       memcpy(cp.irk, adapter->local_irk, MGMT_IRK_SIZE);
+
        if (mgmt_send(adapter->mgmt, MGMT_OP_SET_IRK,
                                adapter->dev_id, sizeof(cp), &cp,
                                set_irk_complete, adapter, NULL) > 0)
                return true;
 
-fail:
        error("Failed to set irk %u", adapter->dev_id);
        return false;
 }
@@ -13154,7 +13205,7 @@ static void read_info_complete(uint8_t status, uint16_t length,
 
 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
        /* Set the RPA resolution value to '1' if privacy is supported */
-       if (adapter->le_privacy_enabled &&
+       if (main_opts.le_privacy &&
                        adapter->supported_settings & MGMT_SETTING_PRIVACY)
                adapter->central_rpa_res_support = 0x01;
 #endif