tizen 2.3.1 release
[framework/connectivity/bluez.git] / src / adapter.c
index 2e1df76..5872799 100644 (file)
 #include <config.h>
 #endif
 
-#define _GNU_SOURCE
 #include <stdio.h>
+#include <inttypes.h>
 #include <errno.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <sys/ioctl.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/uuid.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <dirent.h>
 
 #include <glib.h>
 #include <dbus/dbus.h>
-#include <gdbus.h>
+
+#include "bluetooth/bluetooth.h"
+#include "bluetooth/hci.h"
+#include "bluetooth/hci_lib.h"
+#include "bluetooth/sdp.h"
+#include "bluetooth/sdp_lib.h"
+#include "lib/uuid.h"
+#include "lib/mgmt.h"
+
+#include "gdbus/gdbus.h"
 
 #include "log.h"
 #include "textfile.h"
 
+#include "src/shared/mgmt.h"
+#include "src/shared/util.h"
+#include "src/shared/queue.h"
+#include "src/shared/att.h"
+#include "src/shared/gatt-db.h"
+
 #include "hcid.h"
 #include "sdpd.h"
 #include "adapter.h"
-#include "manager.h"
 #include "device.h"
+#include "profile.h"
 #include "dbus-common.h"
-#include "event.h"
 #include "error.h"
-#include "glib-helper.h"
+#include "uuid-helper.h"
 #include "agent.h"
 #include "storage.h"
+#include "attrib/gattrib.h"
+#include "attrib/att.h"
+#include "attrib/gatt.h"
 #include "attrib-server.h"
-#include "att.h"
-
-/* Flags Descriptions */
-#define EIR_LIM_DISC                0x01 /* LE Limited Discoverable Mode */
-#define EIR_GEN_DISC                0x02 /* LE General Discoverable Mode */
-#define EIR_BREDR_UNSUP             0x04 /* BR/EDR Not Supported */
-#define EIR_SIM_CONTROLLER          0x08 /* Simultaneous LE and BR/EDR to Same
-                                           Device Capable (Controller) */
-#define EIR_SIM_HOST                0x10 /* Simultaneous LE and BR/EDR to Same
-                                           Device Capable (Host) */
-
-#define ADV_TYPE_IND           0x00
-#define ADV_TYPE_DIRECT_IND    0x01
-
-#define IO_CAPABILITY_DISPLAYONLY      0x00
-#define IO_CAPABILITY_DISPLAYYESNO     0x01
-#define IO_CAPABILITY_KEYBOARDONLY     0x02
-#define IO_CAPABILITY_NOINPUTNOOUTPUT  0x03
-#define IO_CAPABILITY_INVALID          0xFF
-
-/* Limited Discoverable bit mask in CoD */
-#define LIMITED_BIT                    0x002000
+#include "gatt-database.h"
+#include "eir.h"
+
+#ifdef __TIZEN_PATCH__
+#include "adapter_le_vsc_features.h"
+#endif
+
+#define ADAPTER_INTERFACE      "org.bluez.Adapter1"
+
+#define MODE_OFF               0x00
+#define MODE_CONNECTABLE       0x01
+#define MODE_DISCOVERABLE      0x02
+#define MODE_UNKNOWN           0xff
+
+#define CONN_SCAN_TIMEOUT (3)
+#define IDLE_DISCOV_TIMEOUT (5)
+#define TEMP_DEV_TIMEOUT (3 * 60)
+#define BONDING_TIMEOUT (2 * 60)
+#ifdef __TIZEN_PATCH__
 #define check_address(address) bachk(address)
+#define ADV_DATA_MAX_LENGTH 31
+#define SCAN_RESPONSE_DATA_LENGTH_MAX 31
+#define MANUFACTURER_DATA_LENGTH_MAX 28
+#define PRIVATE_ADDR_TIMEOUT (15 * 60)
+
+#define BT_DISC_TYPE_BREDR     1
+#define BT_DISC_TYPE_LE         2
+#define IDLE_LE_DISCOV_TIMEOUT (3)
+
+#define DISCOV_TYPE_BREDR      1
+#define DISCOV_TYPE_LE 6
+
+#endif /* __TIZEN_PATCH__ */
+static DBusConnection *dbus_conn = NULL;
+
+static bool kernel_conn_control = false;
+
+static GList *adapter_list = NULL;
+static unsigned int adapter_remaining = 0;
+static bool powering_down = false;
+
+static GSList *adapters = NULL;
+
+static struct mgmt *mgmt_master = NULL;
+
+static uint8_t mgmt_version = 0;
+static uint8_t mgmt_revision = 0;
+
+#if 0 // Not used
+#ifdef __TIZEN_PATCH__
+static DBusMessage *write_sec_conn_host_support(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data);
+#endif /* __TIZEN_PATCH__ */
+#endif
 
-static DBusConnection *connection = NULL;
 static GSList *adapter_drivers = NULL;
 
-static GSList *ops_candidates = NULL;
+static GSList *disconnect_list = NULL;
+static GSList *conn_fail_list = NULL;
+
+struct link_key_info {
+       bdaddr_t bdaddr;
+       unsigned char key[16];
+       uint8_t type;
+       uint8_t pin_len;
+};
+
+struct smp_ltk_info {
+       bdaddr_t bdaddr;
+       uint8_t bdaddr_type;
+       uint8_t authenticated;
+       bool master;
+       uint8_t enc_size;
+       uint16_t ediv;
+       uint64_t rand;
+       uint8_t val[16];
+};
+
+struct irk_info {
+       bdaddr_t bdaddr;
+       uint8_t bdaddr_type;
+       uint8_t val[16];
+};
 
-const struct btd_adapter_ops *adapter_ops = NULL;
+struct conn_param {
+       bdaddr_t bdaddr;
+       uint8_t  bdaddr_type;
+       uint16_t min_interval;
+       uint16_t max_interval;
+       uint16_t latency;
+       uint16_t timeout;
+};
 
-struct session_req {
-       struct btd_adapter      *adapter;
-       DBusConnection          *conn;          /* Connection reference */
-       DBusMessage             *msg;           /* Unreplied message ref */
-       char                    *owner;         /* Bus name of the owner */
-       guint                   id;             /* Listener id */
-       uint8_t                 mode;           /* Requested mode */
-       int                     refcount;       /* Session refcount */
-       gboolean                got_reply;      /* Agent reply received */
+struct watch_client {
+       struct btd_adapter *adapter;
+       char *owner;
+       guint watch;
 };
 
 struct service_auth {
+       guint id;
+       unsigned int svc_id;
        service_auth_cb cb;
        void *user_data;
+       const char *uuid;
        struct btd_device *device;
        struct btd_adapter *adapter;
+       struct agent *agent;            /* NULL for queued auths */
+};
+
+struct btd_adapter_pin_cb_iter {
+       GSList *it;                     /* current callback function */
+       unsigned int attempt;           /* numer of times it() was called */
+       /* When the iterator reaches the end, it is NULL and attempt is 0 */
+};
+
+#ifdef __TIZEN_PATCH__
+struct adv_info {
+       int slot_id;    /* Reservied slot id is 0 (Single adv) */
+       bool status;            /* Advertising status */
 };
+#endif
 
 struct btd_adapter {
+       int ref_count;
+
        uint16_t dev_id;
-       int up;
+       struct mgmt *mgmt;
+
+       bdaddr_t bdaddr;                /* controller Bluetooth address */
+#ifdef __TIZEN_PATCH__
+       bdaddr_t rpaddr;                /* controller RPA */
+#endif
+       uint32_t dev_class;             /* controller class of device */
+       char *name;                     /* controller device name */
+       char *short_name;               /* controller short name */
+       uint32_t supported_settings;    /* controller supported settings */
+       uint32_t current_settings;      /* current controller settings */
+
        char *path;                     /* adapter object path */
-       bdaddr_t bdaddr;                /* adapter Bluetooth Address */
-       uint32_t dev_class;             /* Class of Device */
-       guint discov_timeout_id;        /* discoverable timeout id */
-       guint stop_discov_id;           /* stop inquiry/scanning id */
-       uint32_t discov_timeout;        /* discoverable time(sec) */
-       guint pairable_timeout_id;      /* pairable timeout id */
+       uint8_t major_class;            /* configured major class */
+       uint8_t minor_class;            /* configured minor class */
+       char *system_name;              /* configured system name */
+       char *modalias;                 /* device id (modalias) */
+       bool stored_discoverable;       /* stored discoverable mode */
+       uint32_t discoverable_timeout;  /* discoverable time(sec) */
        uint32_t pairable_timeout;      /* pairable time(sec) */
-       uint8_t scan_mode;              /* scan mode: SCAN_DISABLED, SCAN_PAGE,
-                                        * SCAN_INQUIRY */
-#ifdef __TIZEN_PATCH__
-       // Adding Limited state for setting limited discoverable mode
-       gboolean limited;               /* limited discoverable state */
-#endif
-       uint8_t mode;                   /* off, connectable, discoverable,
-                                        * limited */
-       uint8_t global_mode;            /* last valid global mode */
-       struct session_req *pending_mode;
-       int state;                      /* standard inq, periodic inq, name
-                                        * resolving, suspended discovery */
-       GSList *found_devices;
-       GSList *oor_devices;            /* out of range device list */
-       struct agent *agent;            /* For the new API */
-       guint auth_idle_id;             /* Ongoing authorization */
+
+       char *current_alias;            /* current adapter name alias */
+       char *stored_alias;             /* stored adapter name alias */
+#ifdef __TIZEN_PATCH__
+       bool le_privacy_enabled;        /* whether LE Privacy feature enabled */
+       char local_irk[MGMT_IRK_SIZE];  /* adapter local IRK */
+       uint8_t disc_type;
+#endif
+
+       bool discovering;               /* discovering property state */
+       uint8_t discovery_type;         /* current active discovery type */
+       uint8_t discovery_enable;       /* discovery enabled/disabled */
+       bool discovery_suspended;       /* discovery has been suspended */
+       GSList *discovery_list;         /* list of discovery clients */
+       GSList *discovery_found;        /* list of found devices */
+       guint discovery_idle_timeout;   /* timeout between discovery runs */
+       guint passive_scan_timeout;     /* timeout between passive scans */
+       guint temp_devices_timeout;     /* timeout for temporary devices */
+
+       guint pairable_timeout_id;      /* pairable timeout id */
+       guint auth_idle_id;             /* Pending authorization dequeue */
+       GQueue *auths;                  /* Ongoing and pending auths */
+       bool pincode_requested;         /* PIN requested during last bonding */
        GSList *connections;            /* Connected devices */
        GSList *devices;                /* Devices structure pointers */
-       GSList *mode_sessions;          /* Request Mode sessions */
-       GSList *disc_sessions;          /* Discovery sessions */
-       guint scheduler_id;             /* Scheduler handle */
+       GSList *connect_list;           /* Devices to connect when found */
+       struct btd_device *connect_le;  /* LE device waiting to be connected */
        sdp_list_t *services;           /* Services associated to adapter */
 
-       struct hci_dev dev;             /* hci info */
-       gboolean pairable;              /* pairable state */
+       struct btd_gatt_database *database;
+
        gboolean initialized;
+#ifdef __TIZEN_PATCH__
+       GSList *adv_list;       /* List of advertising instance */
+       bool advertising;               /* Advertising active */
+       gchar *version;                 /* Bluetooth Version */
+#if 0 // Not used
+       bool secure_connection;         /* Secure Connection active*/
+       uint16_t auth_payload_timeout; /* Authenticated payload timeout value*/
+
+       bool set_new_rpa;               /* RPA to be set */
+       bool rpa_is_set;                /* RPA is set */
+#endif
 
-       gboolean off_requested;         /* DEVDOWN ioctl was called */
+       uint8_t adv_tx_power;
 
-       gint ref;
+       gboolean le_discovering;                /* LE Discovery active */
+       GSList *le_discovery_list;              /* list of LE discovery clients */
+       gboolean le_auto_connect;               /* LE Auto connection */
+#endif
+
+       GSList *pin_callbacks;
+       GSList *msd_callbacks;
+
+       GSList *drivers;
+       GSList *profiles;
+
+       struct oob_handler *oob_handler;
 
-       GSList *powered_callbacks;
+       unsigned int load_ltks_id;
+       guint load_ltks_timeout;
 
-       gboolean name_stored;
+       unsigned int confirm_name_id;
+       guint confirm_name_timeout;
 
-       GSList *loaded_drivers;
+       unsigned int pair_device_id;
+       guint pair_device_timeout;
+       unsigned int db_id;             /* Service event handler for GATT db */
+#ifdef __TIZEN_PATCH__
+       guint private_addr_timeout;
+#endif
+       bool is_default;                /* true if adapter is default one */
 };
 
-static void adapter_set_pairable_timeout(struct btd_adapter *adapter,
-                                       guint interval);
 
-static int found_device_cmp(const struct remote_dev_info *d1,
-                       const struct remote_dev_info *d2)
+#ifdef __TIZEN_PATCH__
+enum {
+       DISABLE_PRIVACY,
+       ENABLE_PRIVACY,
+       GEN_IRK_THEN_ENABLE_PRIVACY
+};
+#endif
+
+static struct btd_adapter *btd_adapter_lookup(uint16_t index)
 {
-       int ret;
+       GList *list;
 
-       if (bacmp(&d2->bdaddr, BDADDR_ANY)) {
-               ret = bacmp(&d1->bdaddr, &d2->bdaddr);
-               if (ret)
-                       return ret;
-       }
+       for (list = g_list_first(adapter_list); list;
+                                               list = g_list_next(list)) {
+               struct btd_adapter *adapter = list->data;
 
-       if (d2->name_status != NAME_ANY) {
-               ret = (d1->name_status - d2->name_status);
-               if (ret)
-                       return ret;
+               if (adapter->dev_id == index)
+                       return adapter;
        }
 
-       return 0;
+       return NULL;
 }
 
-static void dev_info_free(struct remote_dev_info *dev)
+struct btd_adapter *btd_adapter_get_default(void)
 {
-       g_free(dev->name);
-       g_free(dev->alias);
-       g_slist_foreach(dev->services, (GFunc) g_free, NULL);
-       g_slist_free(dev->services);
-       g_strfreev(dev->uuids);
-       g_free(dev);
+       GList *list;
+
+       for (list = g_list_first(adapter_list); list;
+                                               list = g_list_next(list)) {
+               struct btd_adapter *adapter = list->data;
+
+               if (adapter->is_default)
+                       return adapter;
+       }
+
+       return NULL;
 }
 
-/*
- * Device name expansion
- *   %d - device id
- */
-static char *expand_name(char *dst, int size, char *str, int dev_id)
+bool btd_adapter_is_default(struct btd_adapter *adapter)
 {
-       register int sp, np, olen;
-       char *opt, buf[10];
-
-       if (!str || !dst)
-               return NULL;
+       if (!adapter)
+               return false;
 
-       sp = np = 0;
-       while (np < size - 1 && str[sp]) {
-               switch (str[sp]) {
-               case '%':
-                       opt = NULL;
+       return adapter->is_default;
+}
 
-                       switch (str[sp+1]) {
-                       case 'd':
-                               sprintf(buf, "%d", dev_id);
-                               opt = buf;
-                               break;
+uint16_t btd_adapter_get_index(struct btd_adapter *adapter)
+{
+       if (!adapter)
+               return MGMT_INDEX_NONE;
 
-                       case 'h':
-                               opt = main_opts.host_name;
-                               break;
+       return adapter->dev_id;
+}
 
-                       case '%':
-                               dst[np++] = str[sp++];
-                               /* fall through */
-                       default:
-                               sp++;
-                               continue;
-                       }
+static gboolean process_auth_queue(gpointer user_data);
 
-                       if (opt) {
-                               /* substitute */
-                               olen = strlen(opt);
-                               if (np + olen < size - 1)
-                                       memcpy(dst + np, opt, olen);
-                               np += olen;
-                       }
-                       sp += 2;
-                       continue;
+static void dev_class_changed_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const struct mgmt_cod *rp = param;
+       uint32_t dev_class;
 
-               case '\\':
-                       sp++;
-                       /* fall through */
-               default:
-                       dst[np++] = str[sp++];
-                       break;
-               }
+       if (length < sizeof(*rp)) {
+               error("Wrong size of class of device changed parameters");
+               return;
        }
-       dst[np] = '\0';
-       return dst;
-}
 
-int btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major,
-                                                               uint8_t minor)
-{
-       return adapter_ops->set_dev_class(adapter->dev_id, major, minor);
-}
+       dev_class = rp->val[0] | (rp->val[1] << 8) | (rp->val[2] << 16);
 
-static int pending_remote_name_cancel(struct btd_adapter *adapter)
-{
-       struct remote_dev_info *dev, match;
-       int err;
+       if (dev_class == adapter->dev_class)
+               return;
 
-       /* find the pending remote name request */
-       memset(&match, 0, sizeof(struct remote_dev_info));
-       bacpy(&match.bdaddr, BDADDR_ANY);
-       match.name_status = NAME_REQUESTED;
+       DBG("Class: 0x%06x", dev_class);
 
-       dev = adapter_search_found_devices(adapter, &match);
-       if (!dev) /* no pending request */
-               return -ENODATA;
+       adapter->dev_class = dev_class;
 
-       err = adapter_ops->cancel_resolve_name(adapter->dev_id, &dev->bdaddr);
-       if (err < 0)
-               error("Remote name cancel failed: %s(%d)",
-                                               strerror(errno), errno);
-       return err;
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "Class");
 }
 
-int adapter_resolve_names(struct btd_adapter *adapter)
+static void set_dev_class_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       struct remote_dev_info *dev, match;
-       int err;
-
-       /* Do not attempt to resolve more names if on suspended state */
-       if (adapter->state & STATE_SUSPENDED)
-               return 0;
+       struct btd_adapter *adapter = user_data;
 
-       memset(&match, 0, sizeof(struct remote_dev_info));
-       bacpy(&match.bdaddr, BDADDR_ANY);
-       match.name_status = NAME_REQUIRED;
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to set device class: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
+       }
 
-       dev = adapter_search_found_devices(adapter, &match);
-       if (!dev)
-               return -ENODATA;
+       /*
+        * The parameters are identical and also the task that is
+        * required in both cases. So it is safe to just call the
+        * event handling functions here.
+        */
+       dev_class_changed_callback(adapter->dev_id, length, param, adapter);
+}
 
-       /* send at least one request or return failed if the list is empty */
-       do {
-               /* flag to indicate the current remote name requested */
-               dev->name_status = NAME_REQUESTED;
+static void set_dev_class(struct btd_adapter *adapter)
+{
+       struct mgmt_cp_set_dev_class cp;
 
-               err = adapter_ops->resolve_name(adapter->dev_id, &dev->bdaddr);
+       /*
+        * If the controller does not support BR/EDR operation,
+        * there is no point in trying to set a major and minor
+        * class value.
+        *
+        * This is an optimization for Low Energy only controllers.
+        */
+       if (!(adapter->supported_settings & MGMT_SETTING_BREDR))
+               return;
 
-               if (!err)
-                       break;
+       memset(&cp, 0, sizeof(cp));
 
-               error("Unable to send HCI remote name req: %s (%d)",
-                                               strerror(errno), errno);
+       /*
+        * Silly workaround for a really stupid kernel bug :(
+        *
+        * All current kernel versions assign the major and minor numbers
+        * straight to dev_class[0] and dev_class[1] without considering
+        * the proper bit shifting.
+        *
+        * To make this work, shift the value in userspace for now until
+        * we get a fixed kernel version.
+        */
+       cp.major = adapter->major_class & 0x1f;
+       cp.minor = adapter->minor_class << 2;
 
-               /* if failed, request the next element */
-               /* remove the element from the list */
-               adapter_remove_found_device(adapter, &dev->bdaddr);
+       DBG("sending set device class command for index %u", adapter->dev_id);
 
-               /* get the next element */
-               dev = adapter_search_found_devices(adapter, &match);
-       } while (dev);
+       if (mgmt_send(adapter->mgmt, MGMT_OP_SET_DEV_CLASS,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               set_dev_class_complete, adapter, NULL) > 0)
+               return;
 
-       return err;
+       error("Failed to set class of device for index %u", adapter->dev_id);
 }
 
-static const char *mode2str(uint8_t mode)
+void btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major,
+                                                       uint8_t minor)
 {
-       switch(mode) {
-       case MODE_OFF:
-               return "off";
-       case MODE_CONNECTABLE:
-               return "connectable";
-       case MODE_DISCOVERABLE:
-               return "discoverable";
-       default:
-               return "unknown";
-       }
+       if (adapter->major_class == major && adapter->minor_class == minor)
+               return;
+
+       DBG("class: major %u minor %u", major, minor);
+
+       adapter->major_class = major;
+       adapter->minor_class = minor;
+
+       set_dev_class(adapter);
 }
 
-static uint8_t get_mode(const bdaddr_t *bdaddr, const char *mode)
+static uint8_t get_mode(const char *mode)
 {
        if (strcasecmp("off", mode) == 0)
                return MODE_OFF;
@@ -336,721 +456,703 @@ static uint8_t get_mode(const bdaddr_t *bdaddr, const char *mode)
                return MODE_CONNECTABLE;
        else if (strcasecmp("discoverable", mode) == 0)
                return MODE_DISCOVERABLE;
-       else if (strcasecmp("on", mode) == 0) {
-               char onmode[14], srcaddr[18];
-
-               ba2str(bdaddr, srcaddr);
-               if (read_on_mode(srcaddr, onmode, sizeof(onmode)) < 0)
-                       return MODE_CONNECTABLE;
-
-               return get_mode(bdaddr, onmode);
-       } else
+       else
                return MODE_UNKNOWN;
 }
 
-static void adapter_set_limited_discoverable(struct btd_adapter *adapter,
-                                                       gboolean limited)
+static void store_adapter_info(struct btd_adapter *adapter)
 {
-       DBG("%s", limited ? "TRUE" : "FALSE");
+       GKeyFile *key_file;
+       char filename[PATH_MAX];
+       char address[18];
+       char *str;
+       gsize length = 0;
+       gboolean discoverable;
+#ifdef __TIZEN_PATCH__
+       char key_str[35];
+       static const char testblock[MGMT_IRK_SIZE];
+       int i;
+#endif
 
-       adapter_ops->set_limited_discoverable(adapter->dev_id, limited);
-}
+       key_file = g_key_file_new();
 
-static void adapter_remove_discov_timeout(struct btd_adapter *adapter)
-{
-       if (!adapter)
-               return;
+       if (adapter->pairable_timeout != main_opts.pairto)
+               g_key_file_set_integer(key_file, "General", "PairableTimeout",
+                                       adapter->pairable_timeout);
 
-       if (adapter->discov_timeout_id == 0)
-               return;
+       if ((adapter->current_settings & MGMT_SETTING_DISCOVERABLE) &&
+                                               !adapter->discoverable_timeout)
+               discoverable = TRUE;
+       else
+               discoverable = FALSE;
 
-       g_source_remove(adapter->discov_timeout_id);
-       adapter->discov_timeout_id = 0;
-}
+       g_key_file_set_boolean(key_file, "General", "Discoverable",
+                                                       discoverable);
 
-static gboolean discov_timeout_handler(gpointer user_data)
-{
-       struct btd_adapter *adapter = user_data;
+       if (adapter->discoverable_timeout != main_opts.discovto)
+               g_key_file_set_integer(key_file, "General",
+                                       "DiscoverableTimeout",
+                                       adapter->discoverable_timeout);
 
-       adapter->discov_timeout_id = 0;
+       if (adapter->stored_alias)
+               g_key_file_set_string(key_file, "General", "Alias",
+                                                       adapter->stored_alias);
+#ifdef __TIZEN_PATCH__
+       if (memcmp(adapter->local_irk, testblock , MGMT_IRK_SIZE)) {
+               key_str[0] = '0';
+               key_str[1] = 'x';
+               for (i = 0; i < MGMT_IRK_SIZE; i++)
+                       sprintf(key_str + 2 + (i * 2), "%2.2X",
+                       adapter->local_irk[i]);
+               g_key_file_set_string(key_file, "General",
+                       "LocalIrk", key_str);
+       }
+#endif
 
-       adapter_ops->set_discoverable(adapter->dev_id, FALSE);
+       ba2str(&adapter->bdaddr, address);
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/settings", address);
 
-       return FALSE;
-}
+       create_file(filename, S_IRUSR | S_IWUSR);
 
-static void adapter_set_discov_timeout(struct btd_adapter *adapter,
-                                       guint interval)
-{
-       if (adapter->discov_timeout_id) {
-               g_source_remove(adapter->discov_timeout_id);
-               adapter->discov_timeout_id = 0;
-       }
+       str = g_key_file_to_data(key_file, &length, NULL);
+       g_file_set_contents(filename, str, length, NULL);
+       g_free(str);
 
-       if (interval == 0) {
-               adapter_set_limited_discoverable(adapter, FALSE);
-               return;
-       }
+       g_key_file_free(key_file);
+}
 
-       /* Set limited discoverable if pairable and interval between 0 to 60
-          sec */
-       if (adapter->pairable && interval <= 60)
-               adapter_set_limited_discoverable(adapter, TRUE);
-       else
-               adapter_set_limited_discoverable(adapter, FALSE);
+static void trigger_pairable_timeout(struct btd_adapter *adapter);
+static void adapter_start(struct btd_adapter *adapter);
+static void adapter_stop(struct btd_adapter *adapter);
+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_PATCH__
+static bool set_privacy(struct btd_adapter *adapter, bool privacy);
+#endif
 
-       adapter->discov_timeout_id = g_timeout_add_seconds(interval,
-                                                       discov_timeout_handler,
-                                                       adapter);
+#ifdef __TIZEN_PATCH__
+static int compare_slot(gconstpointer a, gconstpointer b)
+{
+       const struct adv_info *adv = a;
+       const int id = *(int*)b;
+
+       return (adv->slot_id == id ? 0 : -1);
 }
 
-static struct session_req *session_ref(struct session_req *req)
+static struct adv_info *find_advertiser(struct btd_adapter *adapter,
+                               int slot_id)
 {
-       req->refcount++;
+       GSList *list;
 
-       DBG("%p: ref=%d", req, req->refcount);
+       list = g_slist_find_custom(adapter->adv_list, &slot_id,
+                                                       compare_slot);
+       if (list)
+               return list->data;
 
-       return req;
+       return NULL;
 }
 
-static struct session_req *create_session(struct btd_adapter *adapter,
-                                       DBusConnection *conn, DBusMessage *msg,
-                                       uint8_t mode, GDBusWatchFunction cb)
+static void create_advertiser(struct btd_adapter *adapter,
+                                       int slot_id)
 {
-       const char *sender = dbus_message_get_sender(msg);
-       struct session_req *req;
+       struct adv_info *adv;
+
+       if (!adapter)
+               return;
 
-       req = g_new0(struct session_req, 1);
-       req->adapter = adapter;
-       req->conn = dbus_connection_ref(conn);
-       req->msg = dbus_message_ref(msg);
-       req->mode = mode;
+       if (find_advertiser(adapter, slot_id) != NULL) {
+               error("Aleady existed [%d]", slot_id);
+               return;
+       }
 
-       if (cb == NULL)
-               return session_ref(req);
+       DBG("Create adv slot id : %d", slot_id);
 
-       req->owner = g_strdup(sender);
-       req->id = g_dbus_add_disconnect_watch(conn, sender, cb, req, NULL);
+       adv = g_new0(struct adv_info, 1);
+       if (adv == NULL)
+               return;
 
-       info("%s session %p with %s activated",
-               req->mode ? "Mode" : "Discovery", req, sender);
+       adv->slot_id = slot_id;
 
-       return session_ref(req);
+       adapter->adv_list= g_slist_append(adapter->adv_list, adv);
+       return;
 }
 
-static int adapter_set_mode(struct btd_adapter *adapter, uint8_t mode)
+#ifndef __TIZEN_PATCH__
+/* There is no caller of this function */
+static void destroy_advertiser(struct btd_adapter *adapter,
+                               int slot_id)
 {
-       int err;
+       struct adv_info *adv;
 
-       if (mode == MODE_CONNECTABLE)
-               err = adapter_ops->set_discoverable(adapter->dev_id, FALSE);
-       else
-               err = adapter_ops->set_discoverable(adapter->dev_id, TRUE);
+       if (!adapter)
+               return;
 
-       if (err < 0)
-               return err;
+       adv = find_advertiser(adapter, slot_id);
+       if (!adv) {
+               DBG("Unable to find advertiser [%d]", slot_id);
+               return;
+       }
 
-       if (mode == MODE_CONNECTABLE)
-               return 0;
+       adapter->adv_list = g_slist_remove(adapter->adv_list,
+                                                               adv);
+}
+#endif
+
+static void advertising_state_changed(struct btd_adapter *adapter,
+                                       int slot_id, bool enabled)
+{
+       struct adv_info *adv;
+       int id = slot_id;
+       int state = enabled;
+
+       if (!adapter)
+               return;
 
-       adapter_remove_discov_timeout(adapter);
+       adv = find_advertiser(adapter, slot_id);
+       if (!adv) {
+               DBG("Unable to find advertiser [%d]", slot_id);
+               return;
+       }
 
-       if (adapter->discov_timeout)
-               adapter_set_discov_timeout(adapter, adapter->discov_timeout);
+       adv->status = enabled;
+       DBG("slot_id %d, status %d", adv->slot_id, adv->status);
 
-       return 0;
+       g_dbus_emit_signal(dbus_conn, adapter->path,
+                       ADAPTER_INTERFACE, "AdvertisingEnabled",
+                       DBUS_TYPE_INT32, &id,
+                       DBUS_TYPE_BOOLEAN, &state,
+                       DBUS_TYPE_INVALID);
 }
 
-static struct session_req *find_session_by_msg(GSList *list, const DBusMessage *msg)
+static void clear_advertiser_cb(gpointer data, gpointer user_data)
 {
-       GSList *l;
+       struct adv_info *adv = data;
+       struct btd_adapter *adapter = user_data;
 
-       for (l = list; l; l = l->next) {
-               struct session_req *req = l->data;
+       if (adv->status)
+               advertising_state_changed(adapter, adv->slot_id, 0);
+}
 
-               if (req->msg == msg)
-                       return req;
-       }
+static void advertiser_cleanup(struct btd_adapter *adapter)
+{
+       if (!adapter->adv_list)
+               return;
 
-       return NULL;
+       g_slist_foreach(adapter->adv_list, clear_advertiser_cb, adapter);
+       g_slist_free(adapter->adv_list);
+       adapter->adv_list = NULL;
 }
+#endif
 
-static int set_mode(struct btd_adapter *adapter, uint8_t new_mode,
-                       DBusMessage *msg)
+static void settings_changed(struct btd_adapter *adapter, uint32_t settings)
 {
-       int err;
-       const char *modestr;
-       gboolean discoverable;
+       uint32_t changed_mask;
 
-       if (adapter->pending_mode != NULL)
-               return -EALREADY;
+       changed_mask = adapter->current_settings ^ settings;
 
-       discoverable = new_mode == MODE_DISCOVERABLE;
+       adapter->current_settings = settings;
 
-       if (!adapter->up && new_mode != MODE_OFF) {
-               err = adapter_ops->set_powered(adapter->dev_id, TRUE);
-               if (err < 0)
-                       return err;
+       DBG("Changed settings: 0x%08x", changed_mask);
 
-               goto done;
-       }
+       if (changed_mask & MGMT_SETTING_POWERED) {
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Powered");
 
-       if (adapter->up && new_mode == MODE_OFF) {
-               err = adapter_ops->set_powered(adapter->dev_id, FALSE);
-               if (err < 0)
-                       return err;
+               if (adapter->current_settings & MGMT_SETTING_POWERED) {
+                       adapter_start(adapter);
+               } else {
+                       adapter_stop(adapter);
 
-               adapter->off_requested = TRUE;
+                       if (powering_down) {
+                               adapter_remaining--;
 
-               goto done;
+                               if (!adapter_remaining)
+                                       btd_exit();
+                       }
+               }
        }
 
-       if (new_mode == adapter->mode)
-               return 0;
-
-       err = adapter_set_mode(adapter, new_mode);
+       if (changed_mask & MGMT_SETTING_LE) {
+               if ((adapter->current_settings & MGMT_SETTING_POWERED) &&
+                               (adapter->current_settings & MGMT_SETTING_LE))
+                       trigger_passive_scanning(adapter);
+       }
 
-       if (err < 0)
-               return err;
+       if (changed_mask & MGMT_SETTING_CONNECTABLE)
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Connectable");
 
-done:
-       modestr = mode2str(new_mode);
-       write_device_mode(&adapter->bdaddr, modestr);
+       if (changed_mask & MGMT_SETTING_DISCOVERABLE) {
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Discoverable");
+               store_adapter_info(adapter);
+       }
 
-       DBG("%s", modestr);
+       if (changed_mask & MGMT_SETTING_BONDABLE) {
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Pairable");
 
-       if (msg != NULL) {
-               struct session_req *req;
+               trigger_pairable_timeout(adapter);
+       }
 
-               req = find_session_by_msg(adapter->mode_sessions, msg);
-               if (req) {
-                       adapter->pending_mode = req;
-                       session_ref(req);
-               } else
-                       /* Wait for mode change to reply */
-                       adapter->pending_mode = create_session(adapter,
-                                       connection, msg, new_mode, NULL);
-       } else
-               /* Nothing to reply just write the new mode */
-               adapter->mode = new_mode;
+#ifdef __TIZEN_PATCH__
+       if (changed_mask & MGMT_SETTING_ADVERTISING) {
+               if ((adapter->current_settings & MGMT_SETTING_ADVERTISING) &&
+                       (adapter->advertising)) {
+                       return;
+               }
 
-       return 0;
+               adapter->advertising = adapter->current_settings & MGMT_SETTING_ADVERTISING;
+               advertising_state_changed(adapter, 0, adapter->advertising);
+       }
+#endif
 }
 
-static DBusMessage *set_discoverable(DBusConnection *conn, DBusMessage *msg,
-                               gboolean discoverable, void *data)
+static void new_settings_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       struct btd_adapter *adapter = data;
-       uint8_t mode;
-       int err;
-
-       mode = discoverable ? MODE_DISCOVERABLE : MODE_CONNECTABLE;
+       struct btd_adapter *adapter = user_data;
+       uint32_t settings;
 
-       if (mode == adapter->mode) {
-               adapter->global_mode = mode;
-               return dbus_message_new_method_return(msg);
+       if (length < sizeof(settings)) {
+               error("Wrong size of new settings parameters");
+               return;
        }
 
-       err = set_mode(adapter, mode, msg);
-       if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
+       settings = get_le32(param);
 
-       return NULL;
-}
+       if (settings == adapter->current_settings)
+               return;
 
-static DBusMessage *set_powered(DBusConnection *conn, DBusMessage *msg,
-                               gboolean powered, void *data)
-{
-       struct btd_adapter *adapter = data;
-       uint8_t mode;
-       int err;
+       DBG("Settings: 0x%08x", settings);
 
-#ifdef __TIZEN_PATCH__
-       if (powered)
-       {
-               mode = adapter->mode ? adapter->mode : get_mode(&adapter->bdaddr, "on");
+       settings_changed(adapter, settings);
+}
 
-       }
-       else
-               mode = MODE_OFF;
-#else
-       mode = powered ? get_mode(&adapter->bdaddr, "on") : MODE_OFF;
-#endif
+static void set_mode_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
 
-       if (mode == adapter->mode) {
-               adapter->global_mode = mode;
-               return dbus_message_new_method_return(msg);
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to set mode: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
        }
 
-       err = set_mode(adapter, mode, msg);
-       if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
-
-       return NULL;
+       /*
+        * The parameters are identical and also the task that is
+        * required in both cases. So it is safe to just call the
+        * event handling functions here.
+        */
+       new_settings_callback(adapter->dev_id, length, param, adapter);
 }
 
-void btd_adapter_pairable_changed(struct btd_adapter *adapter,
-                                                       gboolean pairable)
+static bool set_mode(struct btd_adapter *adapter, uint16_t opcode,
+                                                       uint8_t mode)
 {
-       adapter->pairable = pairable;
+       struct mgmt_mode cp;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.val = mode;
 
-       write_device_pairable(&adapter->bdaddr, pairable);
+       DBG("sending set mode command for index %u", adapter->dev_id);
 
-       emit_property_changed(connection, adapter->path,
-                               ADAPTER_INTERFACE, "Pairable",
-                               DBUS_TYPE_BOOLEAN, &pairable);
+       if (mgmt_send(adapter->mgmt, opcode,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               set_mode_complete, adapter, NULL) > 0)
+               return true;
 
-       if (pairable && adapter->pairable_timeout)
-               adapter_set_pairable_timeout(adapter,
-                                               adapter->pairable_timeout);
+       error("Failed to set mode for index %u", adapter->dev_id);
+
+       return false;
 }
 
-static DBusMessage *set_pairable(DBusConnection *conn, DBusMessage *msg,
-                               gboolean pairable, void *data)
+static bool set_discoverable(struct btd_adapter *adapter, uint8_t mode,
+                                                       uint16_t timeout)
 {
-       struct btd_adapter *adapter = data;
-       int err;
+       struct mgmt_cp_set_discoverable cp;
 
-       if (adapter->scan_mode == SCAN_DISABLED)
-               return btd_error_not_ready(msg);
+       memset(&cp, 0, sizeof(cp));
+       cp.val = mode;
+       cp.timeout = htobs(timeout);
 
-       if (pairable == adapter->pairable)
-               goto done;
+       DBG("sending set mode command for index %u", adapter->dev_id);
 
-       if (!(adapter->scan_mode & SCAN_INQUIRY))
-               goto store;
+       if (kernel_conn_control) {
+               if (mode)
+                       set_mode(adapter, MGMT_OP_SET_CONNECTABLE, mode);
+               else
+                       /* This also disables discoverable so we're done */
+                       return set_mode(adapter, MGMT_OP_SET_CONNECTABLE,
+                                                                       mode);
+       }
 
-#ifndef __TIZEN_PATCH__
-       err = set_mode(adapter, MODE_DISCOVERABLE, NULL);
-       if (err < 0 && msg)
-               return btd_error_failed(msg, strerror(-err));
-#endif
+       if (mgmt_send(adapter->mgmt, MGMT_OP_SET_DISCOVERABLE,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               set_mode_complete, adapter, NULL) > 0)
+               return true;
 
-store:
-       adapter_ops->set_pairable(adapter->dev_id, pairable);
+       error("Failed to set mode for index %u", adapter->dev_id);
 
-done:
-       return msg ? dbus_message_new_method_return(msg) : NULL;
+       return false;
 }
 
-static gboolean pairable_timeout_handler(void *data)
+static gboolean pairable_timeout_handler(gpointer user_data)
 {
-       set_pairable(NULL, NULL, FALSE, data);
+       struct btd_adapter *adapter = user_data;
+
+       adapter->pairable_timeout_id = 0;
+
+       set_mode(adapter, MGMT_OP_SET_BONDABLE, 0x00);
 
        return FALSE;
 }
 
-static void adapter_set_pairable_timeout(struct btd_adapter *adapter,
-                                       guint interval)
+static void trigger_pairable_timeout(struct btd_adapter *adapter)
 {
-       if (adapter->pairable_timeout_id) {
+       if (adapter->pairable_timeout_id > 0) {
                g_source_remove(adapter->pairable_timeout_id);
                adapter->pairable_timeout_id = 0;
        }
 
-       if (interval == 0)
+       if (!(adapter->current_settings & MGMT_SETTING_BONDABLE))
                return;
 
-       adapter->pairable_timeout_id = g_timeout_add_seconds(interval,
-                                               pairable_timeout_handler,
-                                               adapter);
+       if (adapter->pairable_timeout > 0)
+               g_timeout_add_seconds(adapter->pairable_timeout,
+                                       pairable_timeout_handler, adapter);
 }
 
-static struct session_req *find_session(GSList *list, const char *sender)
+static void local_name_changed_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       GSList *l;
-
-       for (l = list; l; l = l->next) {
-               struct session_req *req = l->data;
+       struct btd_adapter *adapter = user_data;
+       const struct mgmt_cp_set_local_name *rp = param;
 
-               if (g_str_equal(req->owner, sender))
-                       return req;
+       if (length < sizeof(*rp)) {
+               error("Wrong size of local name changed parameters");
+               return;
        }
 
-       return NULL;
-}
+       if (!g_strcmp0(adapter->short_name, (const char *) rp->short_name) &&
+                       !g_strcmp0(adapter->name, (const char *) rp->name))
+               return;
 
-static uint8_t get_needed_mode(struct btd_adapter *adapter, uint8_t mode)
-{
-       GSList *l;
+       DBG("Name: %s", rp->name);
+       DBG("Short name: %s", rp->short_name);
 
-       if (adapter->global_mode > mode)
-               mode = adapter->global_mode;
+       g_free(adapter->name);
+       adapter->name = g_strdup((const char *) rp->name);
 
-       for (l = adapter->mode_sessions; l; l = l->next) {
-               struct session_req *req = l->data;
+       g_free(adapter->short_name);
+       adapter->short_name = g_strdup((const char *) rp->short_name);
 
-               if (req->mode > mode)
-                       mode = req->mode;
+       /*
+        * Changing the name (even manually via HCI) will update the
+        * current alias property.
+        *
+        * In case the name is empty, use the short name.
+        *
+        * There is a difference between the stored alias (which is
+        * configured by the user) and the current alias. The current
+        * alias is temporary for the lifetime of the daemon.
+        */
+       if (adapter->name && adapter->name[0] != '\0') {
+               g_free(adapter->current_alias);
+               adapter->current_alias = g_strdup(adapter->name);
+       } else {
+               g_free(adapter->current_alias);
+               adapter->current_alias = g_strdup(adapter->short_name);
        }
 
-       return mode;
-}
-
-static GSList *remove_bredr(GSList *all)
-{
-       GSList *l, *le;
-
-       for (l = all, le = NULL; l; l = l->next) {
-               struct remote_dev_info *dev = l->data;
-               if (dev->le == FALSE) {
-                       dev_info_free(dev);
-                       continue;
-               }
+       DBG("Current alias: %s", adapter->current_alias);
 
-               le = g_slist_append(le, dev);
-       }
+       if (!adapter->current_alias)
+               return;
 
-       g_slist_free(all);
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "Alias");
 
-       return le;
+       attrib_gap_set(adapter, GATT_CHARAC_DEVICE_NAME,
+                               (const uint8_t *) adapter->current_alias,
+                                       strlen(adapter->current_alias));
 }
 
-static void stop_discovery(struct btd_adapter *adapter, gboolean suspend)
+static void set_local_name_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       pending_remote_name_cancel(adapter);
-
-       if (suspend == FALSE)
-               adapter->found_devices = remove_bredr(adapter->found_devices);
-
-       if (adapter->oor_devices) {
-               g_slist_free(adapter->oor_devices);
-               adapter->oor_devices = NULL;
-       }
-
-       /* Reset if suspended, otherwise remove timer (software scheduler)
-          or request inquiry to stop */
-       if (adapter->state & STATE_SUSPENDED) {
-               adapter->state &= ~STATE_SUSPENDED;
-               return;
-       }
+       struct btd_adapter *adapter = user_data;
 
-       if (adapter->scheduler_id) {
-               g_source_remove(adapter->scheduler_id);
-               adapter->scheduler_id = 0;
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to set local name: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
                return;
        }
 
-       if (adapter->state & STATE_LE_SCAN)
-               adapter_ops->stop_scanning(adapter->dev_id);
-       else
-               adapter_ops->stop_inquiry(adapter->dev_id);
+       /*
+        * The parameters are identical and also the task that is
+        * required in both cases. So it is safe to just call the
+        * event handling functions here.
+        */
+       local_name_changed_callback(adapter->dev_id, length, param, adapter);
 }
 
-static void session_remove(struct session_req *req)
+static int set_name(struct btd_adapter *adapter, const char *name)
 {
-       struct btd_adapter *adapter = req->adapter;
-
-       /* Ignore set_mode session */
-       if (req->owner == NULL)
-               return;
-
-       DBG("%s session %p with %s deactivated",
-               req->mode ? "Mode" : "Discovery", req, req->owner);
-
-       if (req->mode) {
-               uint8_t mode;
-
-               adapter->mode_sessions = g_slist_remove(adapter->mode_sessions,
-                                                       req);
+       struct mgmt_cp_set_local_name cp;
+       char maxname[MAX_NAME_LENGTH + 1];
 
-               mode = get_needed_mode(adapter, adapter->global_mode);
+       memset(maxname, 0, sizeof(maxname));
+       strncpy(maxname, name, MAX_NAME_LENGTH);
 
-               if (mode == adapter->mode)
-                       return;
+       if (!g_utf8_validate(maxname, -1, NULL)) {
+               error("Name change failed: supplied name isn't valid UTF-8");
+               return -EINVAL;
+       }
 
-               DBG("Switching to '%s' mode", mode2str(mode));
+       memset(&cp, 0, sizeof(cp));
+       strncpy((char *) cp.name, maxname, sizeof(cp.name) - 1);
 
-               set_mode(adapter, mode, NULL);
-       } else {
-               adapter->disc_sessions = g_slist_remove(adapter->disc_sessions,
-                                                       req);
+       DBG("sending set local name command for index %u", adapter->dev_id);
 
-               if (adapter->disc_sessions)
-                       return;
+       if (mgmt_send(adapter->mgmt, MGMT_OP_SET_LOCAL_NAME,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               set_local_name_complete, adapter, NULL) > 0)
+               return 0;
 
-               DBG("Stopping discovery");
+       error("Failed to set local name for index %u", adapter->dev_id);
 
-               stop_discovery(adapter, FALSE);
-       }
+       return -EIO;
 }
 
-static void session_free(struct session_req *req)
+int adapter_set_name(struct btd_adapter *adapter, const char *name)
 {
-       if (req->id)
-               g_dbus_remove_watch(req->conn, req->id);
-
-       session_remove(req);
-
-       if (req->msg) {
-               dbus_message_unref(req->msg);
-               if (!req->got_reply && req->mode && req->adapter->agent)
-                       agent_cancel(req->adapter->agent);
-       }
-
-       if (req->conn)
-               dbus_connection_unref(req->conn);
-       g_free(req->owner);
-       g_free(req);
-}
+       if (g_strcmp0(adapter->system_name, name) == 0)
+               return 0;
 
-static void session_owner_exit(DBusConnection *conn, void *user_data)
-{
-       struct session_req *req = user_data;
+       DBG("name: %s", name);
 
-       req->id = 0;
+       g_free(adapter->system_name);
+       adapter->system_name = g_strdup(name);
 
-       session_free(req);
-}
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "Name");
 
-static void session_unref(struct session_req *req)
-{
-       req->refcount--;
+       /* alias is preferred over system name */
+       if (adapter->stored_alias)
+               return 0;
 
-       DBG("%p: ref=%d", req, req->refcount);
+       DBG("alias: %s", name);
 
-       if (req->refcount)
-               return;
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "Alias");
 
-       session_free(req);
+       return set_name(adapter, name);
 }
 
-static void confirm_mode_cb(struct agent *agent, DBusError *derr, void *data)
+struct btd_device *btd_adapter_find_device(struct btd_adapter *adapter,
+                                                       const bdaddr_t *dst,
+                                                       uint8_t bdaddr_type)
 {
-       struct session_req *req = data;
-       int err;
-       DBusMessage *reply;
+       struct device_addr_type addr;
+       struct btd_device *device;
+       GSList *list;
 
-       req->got_reply = TRUE;
+       if (!adapter)
+               return NULL;
 
-       if (derr && dbus_error_is_set(derr)) {
-               reply = dbus_message_new_error(req->msg, derr->name,
-                                               derr->message);
-               g_dbus_send_message(req->conn, reply);
-               session_unref(req);
-               return;
-       }
+       bacpy(&addr.bdaddr, dst);
+       addr.bdaddr_type = bdaddr_type;
 
-       err = set_mode(req->adapter, req->mode, req->msg);
-       if (err < 0)
-               reply = btd_error_failed(req->msg, strerror(-err));
-       else if (!req->adapter->pending_mode)
-               reply = dbus_message_new_method_return(req->msg);
-       else
-               reply = NULL;
+       list = g_slist_find_custom(adapter->devices, &addr,
+                                                       device_addr_type_cmp);
+       if (!list)
+               return NULL;
 
-       if (reply) {
-               /*
-                * Send reply immediately only if there was an error changing
-                * mode, or change is not needed. Otherwise, reply is sent in
-                * set_mode_complete.
-                */
-               g_dbus_send_message(req->conn, reply);
+       device = list->data;
 
-               dbus_message_unref(req->msg);
-               req->msg = NULL;
-       }
+       /*
+        * If we're looking up based on public address and the address
+        * was not previously used over this bearer we may need to
+        * update LE or BR/EDR support information.
+        */
+       if (bdaddr_type == BDADDR_BREDR)
+               device_set_bredr_support(device);
+       else
+               device_set_le_support(device, bdaddr_type);
 
-       if (!find_session(req->adapter->mode_sessions, req->owner))
-               session_unref(req);
+       return device;
 }
 
-static DBusMessage *set_discoverable_timeout(DBusConnection *conn,
-                                                       DBusMessage *msg,
-                                                       uint32_t timeout,
-                                                       void *data)
+static void uuid_to_uuid128(uuid_t *uuid128, const uuid_t *uuid)
 {
-       struct btd_adapter *adapter = data;
-       const char *path;
-
-       if (adapter->discov_timeout == timeout && timeout == 0)
-               return dbus_message_new_method_return(msg);
-
-       if (adapter->scan_mode & SCAN_INQUIRY)
-               adapter_set_discov_timeout(adapter, timeout);
-
-       adapter->discov_timeout = timeout;
-
-       write_discoverable_timeout(&adapter->bdaddr, timeout);
-
-       path = dbus_message_get_path(msg);
-
-       emit_property_changed(conn, path,
-                               ADAPTER_INTERFACE, "DiscoverableTimeout",
-                               DBUS_TYPE_UINT32, &timeout);
-
-       return dbus_message_new_method_return(msg);
+       if (uuid->type == SDP_UUID16)
+               sdp_uuid16_to_uuid128(uuid128, uuid);
+       else if (uuid->type == SDP_UUID32)
+               sdp_uuid32_to_uuid128(uuid128, uuid);
+       else
+               memcpy(uuid128, uuid, sizeof(*uuid));
 }
 
-static DBusMessage *set_pairable_timeout(DBusConnection *conn,
-                                               DBusMessage *msg,
-                                               uint32_t timeout,
-                                               void *data)
+static bool is_supported_uuid(const uuid_t *uuid)
 {
-       struct btd_adapter *adapter = data;
-       const char *path;
-
-       if (adapter->pairable_timeout == timeout && timeout == 0)
-               return dbus_message_new_method_return(msg);
-
-       if (adapter->pairable)
-               adapter_set_pairable_timeout(adapter, timeout);
+       uuid_t tmp;
 
-       adapter->pairable_timeout = timeout;
+       /* mgmt versions from 1.3 onwards support all types of UUIDs */
+       if (MGMT_VERSION(mgmt_version, mgmt_revision) >= MGMT_VERSION(1, 3))
+               return true;
 
-       write_pairable_timeout(&adapter->bdaddr, timeout);
+       uuid_to_uuid128(&tmp, uuid);
 
-       path = dbus_message_get_path(msg);
+       if (!sdp_uuid128_to_uuid(&tmp))
+               return false;
 
-       emit_property_changed(conn, path,
-                               ADAPTER_INTERFACE, "PairableTimeout",
-                               DBUS_TYPE_UINT32, &timeout);
+       if (tmp.type != SDP_UUID16)
+               return false;
 
-       return dbus_message_new_method_return(msg);
+       return true;
 }
 
-void btd_adapter_class_changed(struct btd_adapter *adapter, uint32_t new_class)
+static void add_uuid_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       uint8_t class[3];
-
-       class[2] = (new_class >> 16) & 0xff;
-       class[1] = (new_class >> 8) & 0xff;
-       class[0] = new_class & 0xff;
-
-       write_local_class(&adapter->bdaddr, class);
-
-       adapter->dev_class = new_class;
+       struct btd_adapter *adapter = user_data;
 
-       if (main_opts.attrib_server) {
-               /* Removes service class */
-               class[1] = class[1] & 0x1f;
-               attrib_gap_set(GATT_CHARAC_APPEARANCE, class, 2);
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to add UUID: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
        }
 
-       emit_property_changed(connection, adapter->path,
-                               ADAPTER_INTERFACE, "Class",
-                               DBUS_TYPE_UINT32, &new_class);
+       /*
+        * The parameters are identical and also the task that is
+        * required in both cases. So it is safe to just call the
+        * event handling functions here.
+        */
+       dev_class_changed_callback(adapter->dev_id, length, param, adapter);
+
+       if (adapter->initialized)
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "UUIDs");
 }
 
-void adapter_update_local_name(struct btd_adapter *adapter, const char *name)
+static int add_uuid(struct btd_adapter *adapter, uuid_t *uuid, uint8_t svc_hint)
 {
-       struct hci_dev *dev = &adapter->dev;
+       struct mgmt_cp_add_uuid cp;
+       uuid_t uuid128;
+       uint128_t uint128;
 
-       if (strncmp(name, dev->name, MAX_NAME_LENGTH) == 0)
-               return;
+       if (!is_supported_uuid(uuid)) {
+               warn("Ignoring unsupported UUID for addition");
+               return 0;
+       }
 
-       strncpy(dev->name, name, MAX_NAME_LENGTH);
+       uuid_to_uuid128(&uuid128, uuid);
 
-       if (main_opts.attrib_server)
-               attrib_gap_set(GATT_CHARAC_DEVICE_NAME,
-                       (const uint8_t *) dev->name, strlen(dev->name));
+       ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128);
+       htob128(&uint128, (uint128_t *) cp.uuid);
+       cp.svc_hint = svc_hint;
 
-       if (!adapter->name_stored) {
-               char *name_ptr = dev->name;
+       DBG("sending add uuid command for index %u", adapter->dev_id);
 
-               write_local_name(&adapter->bdaddr, dev->name);
+       if (mgmt_send(adapter->mgmt, MGMT_OP_ADD_UUID,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               add_uuid_complete, adapter, NULL) > 0)
+               return 0;
 
-               if (connection)
-                       emit_property_changed(connection, adapter->path,
-                                               ADAPTER_INTERFACE, "Name",
-                                               DBUS_TYPE_STRING, &name_ptr);
-       }
+       error("Failed to add UUID for index %u", adapter->dev_id);
 
-       adapter->name_stored = FALSE;
+       return -EIO;
 }
 
-static DBusMessage *set_name(DBusConnection *conn, DBusMessage *msg,
-                                       const char *name, void *data)
+static void remove_uuid_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       struct btd_adapter *adapter = data;
-       struct hci_dev *dev = &adapter->dev;
-       char *name_ptr = dev->name;
+       struct btd_adapter *adapter = user_data;
 
-       if (!g_utf8_validate(name, -1, NULL)) {
-               error("Name change failed: supplied name isn't valid UTF-8");
-               return btd_error_invalid_args(msg);
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to remove UUID: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
        }
 
-       if (strncmp(name, dev->name, MAX_NAME_LENGTH) == 0)
-               goto done;
+       /*
+        * The parameters are identical and also the task that is
+        * required in both cases. So it is safe to just call the
+        * event handling functions here.
+        */
+       dev_class_changed_callback(adapter->dev_id, length, param, adapter);
 
-       strncpy(dev->name, name, MAX_NAME_LENGTH);
-       write_local_name(&adapter->bdaddr, name);
-       emit_property_changed(connection, adapter->path,
-                                       ADAPTER_INTERFACE, "Name",
-                                       DBUS_TYPE_STRING, &name_ptr);
+       if (adapter->initialized)
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "UUIDs");
+}
 
-       if (adapter->up) {
-               int err = adapter_ops->set_name(adapter->dev_id, name);
-               if (err < 0)
-                       return btd_error_failed(msg, strerror(-err));
+static int remove_uuid(struct btd_adapter *adapter, uuid_t *uuid)
+{
+       struct mgmt_cp_remove_uuid cp;
+       uuid_t uuid128;
+       uint128_t uint128;
 
-               adapter->name_stored = TRUE;
+       if (!is_supported_uuid(uuid)) {
+               warn("Ignoring unsupported UUID for removal");
+               return 0;
        }
 
-done:
-       return dbus_message_new_method_return(msg);
-}
+       uuid_to_uuid128(&uuid128, uuid);
 
-struct btd_device *adapter_find_device(struct btd_adapter *adapter,
-                                                       const char *dest)
-{
-       struct btd_device *device;
-       GSList *l;
+       ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128);
+       htob128(&uint128, (uint128_t *) cp.uuid);
 
-       if (!adapter)
-               return NULL;
+       DBG("sending remove uuid command for index %u", adapter->dev_id);
 
-       l = g_slist_find_custom(adapter->devices, dest,
-                                       (GCompareFunc) device_address_cmp);
-       if (!l)
-               return NULL;
+       if (mgmt_send(adapter->mgmt, MGMT_OP_REMOVE_UUID,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               remove_uuid_complete, adapter, NULL) > 0)
+               return 0;
 
-       device = l->data;
+       error("Failed to remove UUID for index %u", adapter->dev_id);
 
-       return device;
+       return -EIO;
 }
 
-static void adapter_update_devices(struct btd_adapter *adapter)
+static void clear_uuids_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       char **devices;
-       int i;
-       GSList *l;
+       struct btd_adapter *adapter = user_data;
 
-       /* Devices */
-       devices = g_new0(char *, g_slist_length(adapter->devices) + 1);
-       for (i = 0, l = adapter->devices; l; l = l->next, i++) {
-               struct btd_device *dev = l->data;
-               devices[i] = (char *) device_get_path(dev);
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to clear UUIDs: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
        }
 
-       emit_array_property_changed(connection, adapter->path,
-                                       ADAPTER_INTERFACE, "Devices",
-                                       DBUS_TYPE_OBJECT_PATH, &devices, i);
-       g_free(devices);
+       /*
+        * The parameters are identical and also the task that is
+        * required in both cases. So it is safe to just call the
+        * event handling functions here.
+        */
+       dev_class_changed_callback(adapter->dev_id, length, param, adapter);
 }
 
-static void adapter_emit_uuids_updated(struct btd_adapter *adapter)
+static int clear_uuids(struct btd_adapter *adapter)
 {
-       char **uuids;
-       int i;
-       sdp_list_t *list;
+       struct mgmt_cp_remove_uuid cp;
 
-       uuids = g_new0(char *, sdp_list_len(adapter->services) + 1);
+       memset(&cp, 0, sizeof(cp));
 
-       for (i = 0, list = adapter->services; list; list = list->next) {
-               char *uuid;
-               sdp_record_t *rec = list->data;
+       DBG("sending clear uuids command for index %u", adapter->dev_id);
 
-               uuid = bt_uuid2string(&rec->svclass);
-               if (uuid)
-                       uuids[i++] = uuid;
-       }
+       if (mgmt_send(adapter->mgmt, MGMT_OP_REMOVE_UUID,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               clear_uuids_complete, adapter, NULL) > 0)
+               return 0;
 
-       emit_array_property_changed(connection, adapter->path,
-                       ADAPTER_INTERFACE, "UUIDs", DBUS_TYPE_STRING, &uuids, i);
+       error("Failed to clear UUIDs for index %u", adapter->dev_id);
 
-       g_strfreev(uuids);
+       return -EIO;
 }
 
 static uint8_t get_uuid_mask(uuid_t *uuid)
@@ -1106,11 +1208,26 @@ static int uuid_cmp(const void *a, const void *b)
        return sdp_uuid_cmp(&rec->svclass, uuid);
 }
 
-void adapter_service_insert(struct btd_adapter *adapter, void *r)
+static void adapter_service_insert(struct btd_adapter *adapter, sdp_record_t *rec)
 {
-       sdp_record_t *rec = r;
+       sdp_list_t *browse_list = NULL;
+       uuid_t browse_uuid;
        gboolean new_uuid;
 
+       DBG("%s", adapter->path);
+
+       /* skip record without a browse group */
+       if (sdp_get_browse_groups(rec, &browse_list) < 0) {
+               DBG("skipping record without browse group");
+               return;
+       }
+
+       sdp_uuid16_create(&browse_uuid, PUBLIC_BROWSE_GROUP);
+
+       /* skip record without public browse group */
+       if (!sdp_list_find(browse_list, &browse_uuid, sdp_uuid_cmp))
+               goto done;
+
        if (sdp_list_find(adapter->services, &rec->svclass, uuid_cmp) == NULL)
                new_uuid = TRUE;
        else
@@ -1121,2825 +1238,9444 @@ void adapter_service_insert(struct btd_adapter *adapter, void *r)
 
        if (new_uuid) {
                uint8_t svc_hint = get_uuid_mask(&rec->svclass);
-               adapter_ops->add_uuid(adapter->dev_id, &rec->svclass, svc_hint);
+               add_uuid(adapter, &rec->svclass, svc_hint);
        }
 
-       adapter_emit_uuids_updated(adapter);
+done:
+       sdp_list_free(browse_list, free);
 }
 
-void adapter_service_remove(struct btd_adapter *adapter, void *r)
+int adapter_service_add(struct btd_adapter *adapter, sdp_record_t *rec)
 {
-       sdp_record_t *rec = r;
+       int ret;
 
-       adapter->services = sdp_list_remove(adapter->services, rec);
+       DBG("%s", adapter->path);
 
-       if (sdp_list_find(adapter->services, &rec->svclass, uuid_cmp) == NULL)
-               adapter_ops->remove_uuid(adapter->dev_id, &rec->svclass);
+       ret = add_record_to_server(&adapter->bdaddr, rec);
+       if (ret < 0)
+               return ret;
+
+       adapter_service_insert(adapter, rec);
 
-       adapter_emit_uuids_updated(adapter);
+       return 0;
 }
-#ifdef __TIZEN_PATCH__
-sdp_list_t *adapter_get_services(struct btd_adapter *adapter)
+
+void adapter_service_remove(struct btd_adapter *adapter, uint32_t handle)
 {
-       return adapter->services;
+       sdp_record_t *rec = sdp_record_find(handle);
+
+       DBG("%s", adapter->path);
+
+       if (!rec)
+               return;
+
+       adapter->services = sdp_list_remove(adapter->services, rec);
+
+       if (sdp_list_find(adapter->services, &rec->svclass, uuid_cmp) == NULL)
+               remove_uuid(adapter, &rec->svclass);
+
+       remove_record_from_server(rec->handle);
 }
 
-#endif
-static struct btd_device *adapter_create_device(DBusConnection *conn,
-                                               struct btd_adapter *adapter,
-                                               const char *address,
-                                               device_type_t type)
+static struct btd_device *adapter_create_device(struct btd_adapter *adapter,
+                                               const bdaddr_t *bdaddr,
+                                               uint8_t bdaddr_type)
 {
        struct btd_device *device;
-       const char *path;
-
-       DBG("%s", address);
 
-       device = device_create(conn, adapter, address, type);
+       device = device_create(adapter, bdaddr, bdaddr_type);
        if (!device)
                return NULL;
 
-       device_set_temporary(device, TRUE);
-
        adapter->devices = g_slist_append(adapter->devices, device);
 
-       path = device_get_path(device);
-       g_dbus_emit_signal(conn, adapter->path,
-                       ADAPTER_INTERFACE, "DeviceCreated",
-                       DBUS_TYPE_OBJECT_PATH, &path,
-                       DBUS_TYPE_INVALID);
-
-       adapter_update_devices(adapter);
-
        return device;
 }
 
-void adapter_remove_device(DBusConnection *conn, struct btd_adapter *adapter,
-                                               struct btd_device *device,
-                                               gboolean remove_storage)
+static void service_auth_cancel(struct service_auth *auth)
 {
-       const gchar *dev_path = device_get_path(device);
-       struct agent *agent;
+       DBusError derr;
 
-       adapter->devices = g_slist_remove(adapter->devices, device);
-       adapter->connections = g_slist_remove(adapter->connections, device);
+       if (auth->svc_id > 0)
+               device_remove_svc_complete_callback(auth->device,
+                                                               auth->svc_id);
 
-       adapter_update_devices(adapter);
+       dbus_error_init(&derr);
+       dbus_set_error_const(&derr, ERROR_INTERFACE ".Canceled", NULL);
 
-       g_dbus_emit_signal(conn, adapter->path,
-                       ADAPTER_INTERFACE, "DeviceRemoved",
-                       DBUS_TYPE_OBJECT_PATH, &dev_path,
-                       DBUS_TYPE_INVALID);
+       auth->cb(&derr, auth->user_data);
 
-       agent = device_get_agent(device);
+       dbus_error_free(&derr);
 
-       if (agent && device_is_authorizing(device))
-               agent_cancel(agent);
+       if (auth->agent != NULL) {
+               agent_cancel(auth->agent);
+               agent_unref(auth->agent);
+       }
 
-       device_remove(device, remove_storage);
+       g_free(auth);
 }
-
-struct btd_device *adapter_get_device(DBusConnection *conn,
-                                               struct btd_adapter *adapter,
-                                               const gchar *address)
+#ifdef __TIZEN_PATCH__
+void btd_adapter_unpair_device(struct btd_adapter *adapter,
+                               struct btd_device *dev)
 {
-       struct btd_device *device;
+       DBG("+");
+       GList *l;
 
-       DBG("%s", address);
+       adapter->connect_list = g_slist_remove(adapter->connect_list, dev);
 
-       if (!adapter)
-               return NULL;
+//     adapter->devices = g_slist_remove(adapter->devices, dev);
+//
+//     adapter->discovery_found = g_slist_remove(adapter->discovery_found,
+//                                                                     dev);
 
-       device = adapter_find_device(adapter, address);
-       if (device)
-               return device;
+       adapter->connections = g_slist_remove(adapter->connections, dev);
 
-       return adapter_create_device(conn, adapter, address,
-                                               DEVICE_TYPE_BREDR);
-}
+       if (adapter->connect_le == dev)
+               adapter->connect_le = NULL;
 
-static gboolean stop_scanning(gpointer user_data)
-{
-       struct btd_adapter *adapter = user_data;
+       l = adapter->auths->head;
+       while (l != NULL) {
+               struct service_auth *auth = l->data;
+               GList *next = g_list_next(l);
 
-       adapter_ops->stop_scanning(adapter->dev_id);
+               if (auth->device != dev) {
+                       l = next;
+                       continue;
+               }
 
-       return FALSE;
+               g_queue_delete_link(adapter->auths, l);
+               l = next;
+
+               service_auth_cancel(auth);
+       }
+
+       device_unpair(dev, TRUE);
+       DBG("-");
 }
 
-static int start_discovery(struct btd_adapter *adapter)
+gboolean adapter_clear_le_white_list(struct btd_adapter *adapter)
 {
-       int err, type;
+       if (mgmt_send(adapter->mgmt, MGMT_OP_CLEAR_DEV_WHITE_LIST,
+                                  adapter->dev_id, 0, NULL,
+                                  NULL, NULL, NULL) > 0)
+               return TRUE;
+       else
+               return FALSE;
+}
 
-       /* Do not start if suspended */
-       if (adapter->state & STATE_SUSPENDED)
-               return 0;
+gboolean adapter_add_le_white_list(struct btd_adapter *adapter, struct btd_device *device)
+{
+       struct mgmt_cp_add_dev_white_list cp;
+       const bdaddr_t *dst;
+       char device_addr[18];
 
-       /* Postpone discovery if still resolving names */
-       if (adapter->state & STATE_RESOLVNAME)
-               return 1;
+       memset(&cp, 0, sizeof(cp));
 
-       pending_remote_name_cancel(adapter);
+       dst = device_get_address(device);
 
-       type = adapter_get_discover_type(adapter) & ~DISC_RESOLVNAME;
+       ba2str(device_get_address(device), device_addr);
+       DBG("addr %s  bdaddr type  %d", device_addr, btd_device_get_bdaddr_type(device));
 
-       switch (type) {
-       case DISC_STDINQ:
-       case DISC_INTERLEAVE:
-               err = adapter_ops->start_inquiry(adapter->dev_id,
-                                                       0x08, FALSE);
-               break;
-       case DISC_PINQ:
-               err = adapter_ops->start_inquiry(adapter->dev_id,
-                                                       0x08, TRUE);
-               break;
-       case DISC_LE:
-               err = adapter_ops->start_scanning(adapter->dev_id);
-               break;
-       default:
-               err = -EINVAL;
-       }
+       if ( btd_device_get_bdaddr_type(device) == BDADDR_LE_PUBLIC)
+               cp.bdaddr_type =  0x0;
+       else
+               cp.bdaddr_type =  0x1;
 
-       return err;
+       memcpy(&cp.bdaddr, dst, sizeof(bdaddr_t));
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_ADD_DEV_WHITE_LIST,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       NULL, NULL, NULL) > 0)
+                       return TRUE;
+
+       DBG("Unable to add white list");
+
+       return FALSE;
 }
 
-static DBusMessage *adapter_start_discovery(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
+gboolean btd_adapter_is_le_auto_connect(struct btd_adapter *adapter)
 {
-       struct session_req *req;
-       struct btd_adapter *adapter = data;
-       const char *sender = dbus_message_get_sender(msg);
-       int err;
-       info("adapter_start_discovery");
-       if (!adapter->up)
-               return btd_error_not_ready(msg);
+       return adapter->le_auto_connect;
+}
 
-       req = find_session(adapter->disc_sessions, sender);
-       if (req) {
-               session_ref(req);
-               return dbus_message_new_method_return(msg);
+void btd_adapter_set_le_auto_connect(struct btd_adapter *adapter, gboolean auto_connect)
+{
+       adapter->le_auto_connect = auto_connect;
+}
+
+gboolean btd_adapter_disable_le_auto_connect(struct btd_adapter *adapter)
+{
+       if (btd_adapter_is_le_auto_connect(adapter) == FALSE) {
+               error("le auto connection is not going on");
+               return FALSE;
        }
 
-       if (adapter->disc_sessions)
-               goto done;
+       DBG("disable le auto connect : %u", adapter->dev_id);
 
-       g_slist_foreach(adapter->found_devices, (GFunc) dev_info_free, NULL);
-       g_slist_free(adapter->found_devices);
-       adapter->found_devices = NULL;
+       if (mgmt_send(adapter->mgmt, MGMT_OP_DISABLE_LE_AUTO_CONNECT,
+                               adapter->dev_id, 0, NULL,
+                               NULL, NULL, NULL) > 0) {
+               btd_adapter_set_le_auto_connect(adapter, FALSE);
+               return TRUE;
+       }
 
-       g_slist_free(adapter->oor_devices);
-       adapter->oor_devices = NULL;
+       error("Failed to disable le auto conn : %u", adapter->dev_id);
 
-       err = start_discovery(adapter);
-       if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
+       return FALSE;
+}
+#endif
 
-done:
-       req = create_session(adapter, conn, msg, 0,
-                               session_owner_exit);
+void btd_adapter_remove_device(struct btd_adapter *adapter,
+                               struct btd_device *dev)
+{
+       GList *l;
 
-       adapter->disc_sessions = g_slist_append(adapter->disc_sessions, req);
+       adapter->connect_list = g_slist_remove(adapter->connect_list, dev);
 
-       return dbus_message_new_method_return(msg);
-}
+       adapter->devices = g_slist_remove(adapter->devices, dev);
 
-static DBusMessage *adapter_stop_discovery(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       struct btd_adapter *adapter = data;
-       struct session_req *req;
-       const char *sender = dbus_message_get_sender(msg);
+       adapter->discovery_found = g_slist_remove(adapter->discovery_found,
+                                                                       dev);
 
-       if (!adapter->up)
-               return btd_error_not_ready(msg);
+       adapter->connections = g_slist_remove(adapter->connections, dev);
 
-       req = find_session(adapter->disc_sessions, sender);
-       if (!req)
-               return btd_error_failed(msg, "Invalid discovery session");
+       if (adapter->connect_le == dev)
+               adapter->connect_le = NULL;
 
-       session_unref(req);
-       info("Stopping discovery");
-       return dbus_message_new_method_return(msg);
-}
+       l = adapter->auths->head;
+       while (l != NULL) {
+               struct service_auth *auth = l->data;
+               GList *next = g_list_next(l);
 
-struct remote_device_list_t {
-       GSList *list;
-       time_t time;
-};
+               if (auth->device != dev) {
+                       l = next;
+                       continue;
+               }
 
-static DBusMessage *get_properties(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
+               g_queue_delete_link(adapter->auths, l);
+               l = next;
+
+               service_auth_cancel(auth);
+       }
+
+       device_remove(dev, TRUE);
+}
+
+struct btd_device *btd_adapter_get_device(struct btd_adapter *adapter,
+                                       const bdaddr_t *addr,
+                                       uint8_t addr_type)
+{
+       struct btd_device *device;
+
+       if (!adapter)
+               return NULL;
+
+       device = btd_adapter_find_device(adapter, addr, addr_type);
+       if (device)
+               return device;
+
+       return adapter_create_device(adapter, addr, addr_type);
+}
+
+sdp_list_t *btd_adapter_get_services(struct btd_adapter *adapter)
+{
+       return adapter->services;
+}
+
+static void passive_scanning_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const struct mgmt_cp_start_discovery *rp = param;
+
+       DBG("status 0x%02x", status);
+
+       if (length < sizeof(*rp)) {
+               error("Wrong size of start scanning return parameters");
+               return;
+       }
+
+       if (status == MGMT_STATUS_SUCCESS) {
+               adapter->discovery_type = rp->type;
+               adapter->discovery_enable = 0x01;
+       }
+}
+
+static gboolean passive_scanning_timeout(gpointer user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       struct mgmt_cp_start_discovery cp;
+
+       adapter->passive_scan_timeout = 0;
+
+       cp.type = (1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM);
+#ifdef __TIZEN_PATCH__
+       mgmt_send(adapter->mgmt, MGMT_OP_START_LE_DISCOVERY,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               passive_scanning_complete, adapter, NULL);
+#else
+       mgmt_send(adapter->mgmt, MGMT_OP_START_DISCOVERY,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               passive_scanning_complete, adapter, NULL);
+#endif
+       return FALSE;
+}
+
+static void trigger_passive_scanning(struct btd_adapter *adapter)
+{
+       if (!(adapter->current_settings & MGMT_SETTING_LE))
+               return;
+
+       DBG("");
+
+       if (adapter->passive_scan_timeout > 0) {
+               g_source_remove(adapter->passive_scan_timeout);
+               adapter->passive_scan_timeout = 0;
+       }
+
+       /*
+        * When the kernel background scanning is available, there is
+        * no need to start any discovery. The kernel will keep scanning
+        * as long as devices are in its auto-connection list.
+        */
+       if (kernel_conn_control)
+               return;
+
+       /*
+        * If any client is running a discovery right now, then do not
+        * even try to start passive scanning.
+        *
+        * The discovery procedure is using interleaved scanning and
+        * thus will discover Low Energy devices as well.
+        */
+#ifdef __TIZEN_PATCH__
+       if (adapter->discovery_list || adapter->le_discovery_list)
+               return;
+#else
+       if (adapter->discovery_list)
+               return;
+#endif
+
+       if (adapter->discovery_enable == 0x01)
+               return;
+
+       /*
+        * In case the discovery is suspended (for example for an ongoing
+        * pairing attempt), then also do not start passive scanning.
+        */
+       if (adapter->discovery_suspended)
+               return;
+
+       /*
+        * If the list of connectable Low Energy devices is empty,
+        * then do not start passive scanning.
+        */
+       if (!adapter->connect_list)
+               return;
+
+       adapter->passive_scan_timeout = g_timeout_add_seconds(CONN_SCAN_TIMEOUT,
+                                       passive_scanning_timeout, adapter);
+}
+
+static void stop_passive_scanning_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *dev;
+       int err;
+
+       DBG("status 0x%02x (%s)", status, mgmt_errstr(status));
+
+       dev = adapter->connect_le;
+       adapter->connect_le = NULL;
+
+       /*
+        * When the kernel background scanning is available, there is
+        * no need to stop any discovery. The kernel will handle the
+        * auto-connection by itself.
+        */
+       if (kernel_conn_control)
+               return;
+
+       /*
+        * MGMT_STATUS_REJECTED may be returned from kernel because the passive
+        * scan timer had expired in kernel and passive scan was disabled just
+        * around the time we called stop_passive_scanning().
+        */
+       if (status != MGMT_STATUS_SUCCESS && status != MGMT_STATUS_REJECTED) {
+               error("Stopping passive scanning failed: %s",
+                                                       mgmt_errstr(status));
+               return;
+       }
+
+       adapter->discovery_type = 0x00;
+       adapter->discovery_enable = 0x00;
+
+       if (!dev) {
+               DBG("Device removed while stopping passive scanning");
+               trigger_passive_scanning(adapter);
+               return;
+       }
+
+       err = device_connect_le(dev);
+       if (err < 0) {
+               error("LE auto connection failed: %s (%d)",
+                                               strerror(-err), -err);
+               trigger_passive_scanning(adapter);
+       }
+}
+
+static void stop_passive_scanning(struct btd_adapter *adapter)
+{
+       struct mgmt_cp_stop_discovery cp;
+#ifdef __TIZEN_PATCH__
+       struct mgmt_cp_stop_discovery le_cp;
+#endif
+
+       DBG("");
+
+       /* If there are any normal discovery clients passive scanning
+        * wont be running */
+#ifdef __TIZEN_PATCH__
+       if (adapter->discovery_list || adapter->le_discovery_list)
+               return;
+#else
+       if (adapter->discovery_list)
+               return;
+#endif
+
+       if (adapter->discovery_enable == 0x00)
+               return;
+
+#ifdef __TIZEN_PATCH__
+       if ((adapter->discovery_type & 0x01) > 0)
+               cp.type = 0x01;
+               mgmt_send(adapter->mgmt, MGMT_OP_STOP_DISCOVERY,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               stop_passive_scanning_complete, adapter, NULL);
+       if ((adapter->discovery_type & 0x06) > 0)
+               le_cp.type = 0x06;
+               mgmt_send(adapter->mgmt, MGMT_OP_STOP_LE_DISCOVERY,
+                               adapter->dev_id, sizeof(le_cp), &le_cp,
+                               stop_passive_scanning_complete, adapter, NULL);
+#else
+       cp.type = adapter->discovery_type;
+
+       mgmt_send(adapter->mgmt, MGMT_OP_STOP_DISCOVERY,
+                       adapter->dev_id, sizeof(cp), &cp,
+                       stop_passive_scanning_complete, adapter, NULL);
+#endif
+}
+
+static void cancel_passive_scanning(struct btd_adapter *adapter)
+{
+       if (!(adapter->current_settings & MGMT_SETTING_LE))
+               return;
+
+       DBG("");
+
+       if (adapter->passive_scan_timeout > 0) {
+               g_source_remove(adapter->passive_scan_timeout);
+               adapter->passive_scan_timeout = 0;
+       }
+}
+
+static void trigger_start_discovery(struct btd_adapter *adapter, guint delay);
+
+static void start_discovery_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const struct mgmt_cp_start_discovery *rp = param;
+
+       DBG("status 0x%02x", status);
+#ifndef __TIZEN_PATCH__
+       DBG("Discovery Type 0x%02x", rp->type);
+#endif
+
+       if (length < sizeof(*rp)) {
+               error("Wrong size of start discovery return parameters");
+               return;
+       }
+
+       if (status == MGMT_STATUS_SUCCESS) {
+#ifdef __TIZEN_PATCH__
+               DBG("Return param discovery type 0x%02x", rp->type);
+               adapter->discovery_type |= rp->type;
+#else
+               adapter->discovery_type = rp->type;
+#endif
+               adapter->discovery_enable = 0x01;
+               DBG("Discovery Type 0x%02x", adapter->discovery_type);
+
+               if (adapter->discovering)
+                       return;
+
+               adapter->discovering = true;
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Discovering");
+               return;
+
+#ifdef __TIZEN_PATCH__
+       } else {
+               adapter->discovering = false;
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Discovering");
+#endif
+
+       }
+
+       /*
+        * In case the restart of the discovery failed, then just trigger
+        * it for the next idle timeout again.
+        */
+#ifndef __TIZEN_PATCH__
+       trigger_start_discovery(adapter, IDLE_DISCOV_TIMEOUT * 2);
+#endif
+}
+
+#ifdef __TIZEN_PATCH__
+static void start_le_discovery_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const struct mgmt_cp_start_discovery *rp = param;
+
+       DBG("status 0x%02x", status);
+       DBG("Discovery Type 0x%02x", rp->type);
+       if (length < sizeof(*rp)) {
+               error("Wrong size of start discovery return parameters");
+               return;
+       }
+
+       if (status == MGMT_STATUS_SUCCESS) {
+               adapter->discovery_type |= rp->type;
+               adapter->discovery_enable = 0x01;
+
+               if (adapter->le_discovering)
+                       return;
+
+               adapter->le_discovering = true;
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "LEDiscovering");
+
+               return;
+       } else {
+               adapter->discovering = false;
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "LEDiscovering");
+
+       }
+
+       /*
+        * In case the restart of the discovery failed, then just trigger
+        * it for the next idle timeout again.
+        */
+//     trigger_start_discovery(adapter, IDLE_LE_DISCOV_TIMEOUT * 2);
+}
+#endif
+
+static gboolean start_discovery_timeout(gpointer user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       struct mgmt_cp_start_discovery cp;
+#ifdef __TIZEN_PATCH__
+       uint8_t new_type = 0;
+#else
+       uint8_t new_type;
+#endif
+
+       DBG("");
+
+       adapter->discovery_idle_timeout = 0;
+
+#ifdef __TIZEN_PATCH__
+       if (adapter->disc_type == BT_DISC_TYPE_BREDR_ONLY) {
+
+               if (adapter->current_settings & MGMT_SETTING_BREDR)
+                       new_type = (1 << BDADDR_BREDR);
+               else
+                       new_type = 0;
+
+       } else if (adapter->disc_type == BT_DISC_TYPE_LE_ONLY) {
+
+               if (adapter->current_settings & MGMT_SETTING_LE)
+                       new_type = (1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM);
+
+       } else if (adapter->disc_type == BT_DISC_TYPE_LE_BREDR) {
+
+               if (adapter->current_settings & MGMT_SETTING_BREDR)
+                       new_type = (1 << BDADDR_BREDR);
+               else
+                       new_type = 0;
+               if (adapter->current_settings & MGMT_SETTING_LE)
+                       new_type |= (1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM);
+       }
+
+
+       if (adapter->discovery_enable == 0x01) {
+               /*
+                * If there is an already running discovery and it has the
+                * same type, then just keep it.
+                */
+               if (adapter->disc_type == BT_DISC_TYPE_BREDR_ONLY) {
+                       if ((adapter->discovery_type & new_type) == 0x01) {
+                               if (adapter->discovering)
+                                       return FALSE;
+
+                               adapter->discovering = true;
+                               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "Discovering");
+
+                               return FALSE;
+                       }
+
+               }  else if (adapter->disc_type == BT_DISC_TYPE_LE_ONLY) {
+                       if ((adapter->discovery_type & new_type) == 0x06) {
+                               if (adapter->le_discovering)
+                                       return FALSE;
+
+                               adapter->le_discovering = true;
+                               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "LEDiscovering");
+
+                               return FALSE;
+                       }
+
+               }
+       }
+
+       DBG("adapter->disc_type [%d]", adapter->disc_type);
+       if (adapter->disc_type == BT_DISC_TYPE_BREDR_ONLY) {
+               cp.type = 0x01;
+               mgmt_send(adapter->mgmt, MGMT_OP_START_DISCOVERY,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       start_discovery_complete, adapter, NULL);
+
+       } else if (adapter->disc_type == BT_DISC_TYPE_LE_ONLY) {
+               cp.type = 0x06;
+               mgmt_send(adapter->mgmt, MGMT_OP_START_LE_DISCOVERY,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       start_le_discovery_complete, adapter, NULL);
+       }
+#else
+       if (adapter->current_settings & MGMT_SETTING_BREDR)
+               new_type = (1 << BDADDR_BREDR);
+       else
+               new_type = 0;
+
+       if (adapter->current_settings & MGMT_SETTING_LE)
+               new_type |= (1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM);
+
+       if (adapter->discovery_enable == 0x01) {
+               /*
+                * If there is an already running discovery and it has the
+                * same type, then just keep it.
+                */
+               if (adapter->discovery_type == new_type) {
+                       if (adapter->discovering)
+                               return FALSE;
+
+                       adapter->discovering = true;
+                       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Discovering");
+                       return FALSE;
+               }
+
+               /*
+                * Otherwise the current discovery must be stopped. So
+                * queue up a stop discovery command.
+                *
+                * This can happen if a passive scanning for Low Energy
+                * devices is ongoing.
+                */
+               cp.type = adapter->discovery_type;
+
+               mgmt_send(adapter->mgmt, MGMT_OP_STOP_DISCOVERY,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       NULL, NULL, NULL);
+       }
+
+       cp.type = new_type;
+
+       mgmt_send(adapter->mgmt, MGMT_OP_START_DISCOVERY,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               start_discovery_complete, adapter, NULL);
+#endif  //end of __TIZEN_PATCH__
+
+       return FALSE;
+}
+
+static void trigger_start_discovery(struct btd_adapter *adapter, guint delay)
+{
+
+       DBG("");
+
+       cancel_passive_scanning(adapter);
+
+       if (adapter->discovery_idle_timeout > 0) {
+               g_source_remove(adapter->discovery_idle_timeout);
+               adapter->discovery_idle_timeout = 0;
+       }
+
+       /*
+        * If the controller got powered down in between, then ensure
+        * that we do not keep trying to restart discovery.
+        *
+        * This is safe-guard and should actually never trigger.
+        */
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return;
+
+#ifdef __TIZEN_PATCH__
+       if (delay == 0) {
+               start_discovery_timeout((gpointer)adapter);
+               return;
+       }
+#endif
+       adapter->discovery_idle_timeout = g_timeout_add_seconds(delay,
+                                       start_discovery_timeout, adapter);
+}
+
+#ifndef __TIZEN_PATCH__
+static void suspend_discovery_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       DBG("status 0x%02x", status);
+
+       if (status == MGMT_STATUS_SUCCESS) {
+#ifdef __TIZEN_PATCH__
+               adapter->discovery_type &= (~0x01);
+#else
+               adapter->discovery_type = 0x00;
+#endif
+               adapter->discovery_enable = 0x00;
+               return;
+       }
+}
+
+#ifdef __TIZEN_PATCH__
+static void suspend_le_discovery_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       DBG("status 0x%02x", status);
+
+       if (status == MGMT_STATUS_SUCCESS) {
+               adapter->discovery_type &= (~0x06);
+               adapter->discovery_enable = 0x00;
+               return;
+       }
+}
+#endif
+
+static void suspend_discovery(struct btd_adapter *adapter)
+{
+       struct mgmt_cp_stop_discovery cp;
+#ifdef __TIZEN_PATCH__
+       struct mgmt_cp_stop_le_discovery le_cp;
+#endif
+
+       DBG("");
+
+       adapter->discovery_suspended = true;
+
+       /*
+        * If there are no clients discovering right now, then there is
+        * also nothing to suspend.
+        */
+#ifdef __TIZEN_PATCH__
+       if (adapter->discovery_list == NULL && adapter->le_discovery_list == NULL )
+               return;
+#else
+       if (!adapter->discovery_list)
+               return;
+#endif
+
+
+       /*
+        * In case of being inside the idle phase, make sure to remove
+        * the timeout to not trigger a restart.
+        *
+        * The restart will be triggered when the discovery is resumed.
+        */
+       if (adapter->discovery_idle_timeout > 0) {
+               g_source_remove(adapter->discovery_idle_timeout);
+               adapter->discovery_idle_timeout = 0;
+       }
+
+       if (adapter->discovery_enable == 0x00)
+               return;
+
+#ifdef __TIZEN_PATCH__
+       if (adapter->discovery_list) {
+               cp.type = 0x01;
+               mgmt_send(adapter->mgmt, MGMT_OP_STOP_DISCOVERY,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       suspend_discovery_complete, adapter, NULL);
+       }
+       if (adapter->le_discovery_list) {
+               le_cp.type = 0x06;
+               mgmt_send(adapter->mgmt, MGMT_OP_STOP_LE_DISCOVERY,
+                               adapter->dev_id, sizeof(le_cp), &le_cp,
+                               suspend_le_discovery_complete, adapter, NULL);
+       }
+#else
+       cp.type = adapter->discovery_type;
+
+       mgmt_send(adapter->mgmt, MGMT_OP_STOP_DISCOVERY,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               suspend_discovery_complete, adapter, NULL);
+#endif
+}
+
+static void resume_discovery(struct btd_adapter *adapter)
+{
+       DBG("");
+
+       adapter->discovery_suspended = false;
+
+       /*
+        * If there are no clients discovering right now, then there is
+        * also nothing to resume.
+        */
+       if (!adapter->discovery_list)
+               return;
+
+       /*
+        * Treat a suspended discovery session the same as extra long
+        * idle time for a normal discovery. So just trigger the default
+        * restart procedure.
+        */
+#ifdef __TIZEN_PATCH__
+       adapter->disc_type = BT_DISC_TYPE_BREDR_ONLY;
+#endif
+       trigger_start_discovery(adapter, IDLE_DISCOV_TIMEOUT);
+}
+
+#ifdef __TIZEN_PATCH__
+static void resume_le_discovery(struct btd_adapter *adapter)
+{
+       DBG("");
+
+       adapter->discovery_suspended = false;
+
+       /*
+        * If there are no clients discovering right now, then there is
+        * also nothing to resume.
+        */
+       if (adapter->le_discovery_list == NULL)
+               return;
+
+       /*
+        * Treat a suspended discovery session the same as extra long
+        * idle time for a normal discovery. So just trigger the default
+        * restart procedure.
+        */
+       adapter->disc_type = BT_DISC_TYPE_LE_ONLY;
+       trigger_start_discovery(adapter, IDLE_LE_DISCOV_TIMEOUT);
+}
+#endif
+#endif
+static void discovering_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_discovering *ev = param;
+       struct btd_adapter *adapter = user_data;
+
+       if (length < sizeof(*ev)) {
+               error("Too small discovering event");
+               return;
+       }
+
+       DBG("hci%u type %u discovering %u", adapter->dev_id,
+                                       ev->type, ev->discovering);
+
+#ifdef __TIZEN_PATCH__
+       DBG("info discov_type %d", adapter->discovery_type);
+       if (ev->type == DISCOV_TYPE_BREDR) {
+               if (ev->discovering == FALSE) {
+                       hci_clear_bit(BDADDR_BREDR, &adapter->discovery_type);
+                       adapter->discovering = FALSE;
+               } else {
+                       hci_set_bit(BDADDR_BREDR, &adapter->discovery_type);
+                       adapter->discovering = TRUE;
+               }
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Discovering");
+
+       } else if (ev->type == DISCOV_TYPE_LE) {
+               if (ev->discovering == FALSE) {
+                       hci_clear_bit(BDADDR_LE_PUBLIC, &adapter->discovery_type);
+                       hci_clear_bit(BDADDR_LE_RANDOM, &adapter->discovery_type);
+                       adapter->le_discovering = FALSE;
+               } else {
+                       hci_set_bit(BDADDR_LE_PUBLIC, &adapter->discovery_type);
+                       hci_set_bit(BDADDR_LE_RANDOM, &adapter->discovery_type);
+                       adapter->le_discovering = TRUE;
+               }
+
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "LEDiscovering");
+       }
+#else
+       if (adapter->discovery_enable == ev->discovering)
+               return;
+
+       adapter->discovery_type = ev->type;
+       adapter->discovery_enable = ev->discovering;
+#endif
+       /*
+        * Check for existing discoveries triggered by client applications
+        * and ignore all others.
+        *
+        * If there are no clients, then it is good idea to trigger a
+        * passive scanning attempt.
+        */
+#ifdef __TIZEN_PATCH__
+       if (adapter->discovery_list == NULL && adapter->le_discovery_list == NULL) {
+               if (!adapter->connect_le)
+                       trigger_passive_scanning(adapter);
+               return;
+       }
+#else
+       if (!adapter->discovery_list) {
+               if (!adapter->connect_le)
+                       trigger_passive_scanning(adapter);
+               return;
+       }
+#endif
+
+       if (adapter->discovery_suspended)
+               return;
+
+       switch (adapter->discovery_enable) {
+       case 0x00:
+               trigger_start_discovery(adapter, IDLE_DISCOV_TIMEOUT);
+               break;
+
+       case 0x01:
+               if (adapter->discovery_idle_timeout > 0) {
+                       g_source_remove(adapter->discovery_idle_timeout);
+                       adapter->discovery_idle_timeout = 0;
+               }
+               break;
+       }
+}
+
+#ifdef __TIZEN_PATCH__
+static void stop_discovery_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       DBG("status 0x%02x", status);
+
+       if (status == MGMT_STATUS_SUCCESS) {
+               adapter->discovery_type &= (~0x01);
+               DBG("Discovery Type 0x%02x", adapter->discovery_type);
+
+               adapter->discovering = false;
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Discovering");
+
+               if (adapter->discovery_list == NULL && adapter->le_discovery_list == NULL) {
+                       adapter->discovery_enable = 0x00;
+                       trigger_passive_scanning(adapter);
+               }
+       }
+}
+
+static void stop_le_discovery_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       DBG("status 0x%02x", status);
+
+       if (status == MGMT_STATUS_SUCCESS) {
+               adapter->discovery_type &= (~0x06);
+               DBG("Discovery Type 0x%02x", adapter->discovery_type);
+
+               adapter->le_discovering = false;
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "LEDiscovering");
+
+               if (adapter->discovery_list == NULL && adapter->le_discovery_list == NULL) {
+                       adapter->discovery_enable = 0x00;
+                       trigger_passive_scanning(adapter);
+               }
+       }
+}
+
+#else
+
+static void stop_discovery_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       DBG("status 0x%02x", status);
+
+       if (status == MGMT_STATUS_SUCCESS) {
+               adapter->discovery_type = 0x00;
+               adapter->discovery_enable = 0x00;
+               DBG("Discovery Type 0x%02x", adapter->discovery_type);
+
+               adapter->discovering = false;
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Discovering");
+
+               trigger_passive_scanning(adapter);
+       }
+}
+#endif
+
+
+static int compare_sender(gconstpointer a, gconstpointer b)
+{
+       const struct watch_client *client = a;
+       const char *sender = b;
+
+       return g_strcmp0(client->owner, sender);
+}
+
+static void invalidate_rssi(gpointer a)
+{
+       struct btd_device *dev = a;
+
+       device_set_rssi(dev, 0);
+}
+
+static void discovery_cleanup(struct btd_adapter *adapter)
+{
+       g_slist_free_full(adapter->discovery_found, invalidate_rssi);
+       adapter->discovery_found = NULL;
+}
+
+#ifndef __TIZEN_PATCH__
+static gboolean remove_temp_devices(gpointer user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       GSList *l, *next;
+
+       DBG("%s", adapter->path);
+
+       adapter->temp_devices_timeout = 0;
+
+       for (l = adapter->devices; l != NULL; l = next) {
+               struct btd_device *dev = l->data;
+
+               next = g_slist_next(l);
+
+               if (device_is_temporary(dev))
+                       btd_adapter_remove_device(adapter, dev);
+       }
+
+       return FALSE;
+}
+#endif
+
+static void discovery_destroy(void *user_data)
+{
+       struct watch_client *client = user_data;
+       struct btd_adapter *adapter = client->adapter;
+
+       DBG("owner %s", client->owner);
+
+       adapter->discovery_list = g_slist_remove(adapter->discovery_list,
+                                                               client);
+
+       g_free(client->owner);
+       g_free(client);
+
+       /*
+        * If there are other client discoveries in progress, then leave
+        * it active. If not, then make sure to stop the restart timeout.
+        */
+
+#ifdef __TIZEN_PATCH__
+       if (adapter->discovery_list || adapter->le_discovery_list)
+               return;
+#else
+       if (adapter->discovery_list)
+               return;
+#endif
+
+       adapter->discovery_type = 0x00;
+
+       if (adapter->discovery_idle_timeout > 0) {
+               g_source_remove(adapter->discovery_idle_timeout);
+               adapter->discovery_idle_timeout = 0;
+       }
+
+       if (adapter->temp_devices_timeout > 0) {
+               g_source_remove(adapter->temp_devices_timeout);
+               adapter->temp_devices_timeout = 0;
+       }
+
+       discovery_cleanup(adapter);
+#ifndef __TIZEN_PATCH__
+       adapter->temp_devices_timeout = g_timeout_add_seconds(TEMP_DEV_TIMEOUT,
+                                               remove_temp_devices, adapter);
+#endif
+}
+
+#ifdef __TIZEN_PATCH__
+static void le_discovery_destroy(void *user_data)
+{
+       struct watch_client *client = user_data;
+       struct btd_adapter *adapter = client->adapter;
+
+       DBG("owner %s", client->owner);
+
+       adapter->le_discovery_list = g_slist_remove(adapter->le_discovery_list,
+                                                               client);
+
+       g_free(client->owner);
+       g_free(client);
+
+       /*
+        * If there are other client discoveries in progress, then leave
+        * it active. If not, then make sure to stop the restart timeout.
+        */
+       DBG("adapter->discovery_list[%p] adapter->le_discovery_list[%p]",
+                       adapter->discovery_list, adapter->le_discovery_list);
+       if (adapter->discovery_list || adapter->le_discovery_list)
+               return;
+
+       adapter->discovery_type = 0x00;
+       DBG("Restart Timer... adapter->discovery_type[%d]", adapter->discovery_type);
+       if (adapter->discovery_idle_timeout > 0) {
+               g_source_remove(adapter->discovery_idle_timeout);
+               adapter->discovery_idle_timeout = 0;
+       }
+
+       if (adapter->temp_devices_timeout > 0) {
+               g_source_remove(adapter->temp_devices_timeout);
+               adapter->temp_devices_timeout = 0;
+       }
+
+       discovery_cleanup(adapter);
+#ifndef __TIZEN_PATCH__
+       adapter->temp_devices_timeout = g_timeout_add_seconds(TEMP_DEV_TIMEOUT,
+                                               remove_temp_devices, adapter);
+#endif
+}
+#endif
+
+static void discovery_disconnect(DBusConnection *conn, void *user_data)
+{
+       struct watch_client *client = user_data;
+       struct btd_adapter *adapter = client->adapter;
+       struct mgmt_cp_stop_discovery cp;
+
+       DBG("owner %s", client->owner);
+
+       adapter->discovery_list = g_slist_remove(adapter->discovery_list,
+                                                               client);
+
+       /*
+        * There is no need for extra cleanup of the client since that
+        * will be done by the destroy callback.
+        *
+        * However in case this is the last client, the discovery in
+        * the kernel needs to be disabled.
+        */
+       if (adapter->discovery_list)
+               return;
+
+       /*
+        * In the idle phase of a discovery, there is no need to stop it
+        * and so it is enough to send out the signal and just return.
+        */
+       if (adapter->discovery_enable == 0x00) {
+               adapter->discovering = false;
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Discovering");
+
+#ifdef __TIZEN_PATCH__
+               if (adapter->discovering == false  && adapter->le_discovering == false) {
+                       trigger_passive_scanning(adapter);
+                       return;
+               }
+#else
+               trigger_passive_scanning(adapter);
+               return;
+#endif
+       }
+
+#ifdef __TIZEN_PATCH__
+       cp.type = 0x01;
+#else
+       cp.type = adapter->discovery_type;
+#endif
+
+       mgmt_send(adapter->mgmt, MGMT_OP_STOP_DISCOVERY,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               stop_discovery_complete, adapter, NULL);
+}
+
+#ifdef __TIZEN_PATCH__
+static void le_discovery_disconnect(DBusConnection *conn, void *user_data)
+{
+       struct watch_client *client = user_data;
+       struct btd_adapter *adapter = client->adapter;
+       struct mgmt_cp_stop_le_discovery cp;
+
+       DBG("owner %s", client->owner);
+
+       adapter->le_discovery_list = g_slist_remove(adapter->le_discovery_list,
+                                                               client);
+
+       /*
+        * There is no need for extra cleanup of the client since that
+        * will be done by the destroy callback.
+        *
+        * However in case this is the last client, the discovery in
+        * the kernel needs to be disabled.
+        */
+       if (adapter->le_discovery_list)
+               return;
+
+       /*
+        * In the idle phase of a discovery, there is no need to stop it
+        * and so it is enough to send out the signal and just return.
+        */
+       if (adapter->discovery_enable == 0x00) {
+               adapter->le_discovering = false;
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "LEDiscovering");
+
+               if (adapter->discovering == false  && adapter->le_discovering == false) {
+                       trigger_passive_scanning(adapter);
+                       return;
+               }
+       }
+
+       cp.type = 0x06;
+
+       mgmt_send(adapter->mgmt, MGMT_OP_STOP_LE_DISCOVERY,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               stop_discovery_complete, adapter, NULL);
+}
+#endif
+
+static DBusMessage *start_discovery(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const char *sender = dbus_message_get_sender(msg);
+       struct watch_client *client;
+       GSList *list;
+
+       DBG("sender %s", sender);
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       /*
+        * Every client can only start one discovery, if the client
+        * already started a discovery then return an error.
+        */
+#ifdef __TIZEN_PATCH__
+       adapter->disc_type = BT_DISC_TYPE_BREDR_ONLY;
+#endif
+
+       list = g_slist_find_custom(adapter->discovery_list, sender,
+                                               compare_sender);
+       if (list)
+               return btd_error_busy(msg);
+
+       client = g_new0(struct watch_client, 1);
+
+       client->adapter = adapter;
+       client->owner = g_strdup(sender);
+       client->watch = g_dbus_add_disconnect_watch(dbus_conn, sender,
+                                               discovery_disconnect, client,
+                                               discovery_destroy);
+
+       adapter->discovery_list = g_slist_prepend(adapter->discovery_list,
+                                                               client);
+
+       /*
+        * Just trigger the discovery here. In case an already running
+        * discovery in idle phase exists, it will be restarted right
+        * away.
+        */
+       trigger_start_discovery(adapter, 0);
+
+       return dbus_message_new_method_return(msg);
+}
+
+#ifdef __TIZEN_PATCH__
+static int set_adv_data_flag(uint8_t *adv_data, uint8_t *data, int data_len)
+{
+       adv_data[0] = 2;
+       adv_data[1] = EIR_FLAGS;
+       adv_data[2] = EIR_GEN_DISC;
+
+       memcpy(adv_data + 3, data, data_len);
+       return data_len + 3;
+}
+
+static int set_adv_data_device_name(uint8_t *adv_data, int adv_len, char *name)
+{
+       int ad_type;
+       int ad_len;
+       int i, j;
+       int name_len;
+       uint8_t *data = NULL;
+
+       data = g_memdup(adv_data, adv_len);
+
+       if (!data || !name)
+               return adv_len;
+
+       name_len = strlen(name);
+
+       for (i = 0; i <adv_len ; i++) {
+               ad_len = data[i];
+               ad_type = data[i + 1];
+
+               if (ad_type == EIR_NAME_COMPLETE) {
+                       /* Move to last position and update local name */
+                       for (j = i; j < adv_len - 2; j++)
+                               adv_data[j] = data[j + 2];
+
+                       adv_data[j] = name_len + 1;
+                       if (name_len > ADV_DATA_MAX_LENGTH - adv_len) {
+                               adv_data[j + 1] = EIR_NAME_SHORT;
+                               memcpy(adv_data + j + 2, name, ADV_DATA_MAX_LENGTH - adv_len);
+                       } else {
+                               adv_data[j + 1] = EIR_NAME_COMPLETE;
+                               memcpy(adv_data + j + 2, name, name_len);
+                       }
+
+                       g_free(data);
+                       return adv_len + name_len;
+               } else {
+                       memcpy(adv_data + i, &data[i], ad_len + 1);
+                       i = i + data[i];
+               }
+       }
+
+       g_free(data);
+       return adv_len;
+}
+
+static int set_adv_data_tx_power(uint8_t *adv_data, int adv_len, int8_t tx_power)
+{
+       int ad_type;
+       int ad_len;
+       int i, j;
+       uint8_t *data = NULL;
+
+       data = g_memdup(adv_data, adv_len);
+       if (!data)
+               return adv_len;
+
+       for (i = 0; i <adv_len ; i++) {
+               ad_len = data[i];
+               ad_type = data[i + 1];
+
+               if (ad_type == EIR_TX_POWER) {
+                       adv_data[i] = 2;
+                       adv_data[i + 1] = EIR_TX_POWER;
+                       adv_data[i + 2] = tx_power;
+
+                       for(j = i + 2; j < adv_len; j++)
+                               adv_data[j + 1] = data[j];
+
+                       g_free(data);
+                       return adv_len + 1;
+               } else {
+                       memcpy(adv_data + i, &data[i], ad_len + 1);
+                       i = i + data[i];
+               }
+       }
+
+       g_free(data);
+       return adv_len;
+}
+
+static gboolean adapter_le_set_missed_adv_data(uint8_t *p_data, uint8_t data_len,
+               gboolean is_scan_rsp, char *adapter_name, int8_t tx_power, uint8_t **adv_data, int *adv_len)
+{
+       uint8_t *data;
+       int len;
+
+       data = g_malloc0(ADV_DATA_MAX_LENGTH);
+       /* Fix : NULL_RETURNS */
+       if (data == NULL) {
+               return FALSE;
+       }
+       memcpy(data, p_data, data_len);
+       len = data_len;
+
+       /* In case multi advertising, need to update the below AD type
+               since it handled into kernel */
+       if (!is_scan_rsp) {
+               len = set_adv_data_flag(data, p_data, data_len);
+       }
+
+       len = set_adv_data_tx_power(data, len, tx_power);
+
+       len = set_adv_data_device_name(data, len, adapter_name);
+
+       *adv_data = data;
+       *adv_len = len;
+       return TRUE;
+}
+
+static DBusMessage *adapter_start_custom_discovery(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const char *sender = dbus_message_get_sender(msg);
+       struct watch_client *client;
+       GSList *list;
+       const gchar *disc_type;
+
+       DBG("sender %s", sender);
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &disc_type,
+                                                       DBUS_TYPE_INVALID)) {
+               return btd_error_invalid_args(msg);
+       }
+
+       DBG("discovery type = %s", disc_type);
+
+       /*Valid strings: "BREDR", "LE", "LE_BREDR" */
+       if (g_strcmp0(disc_type, "BREDR") == 0)
+               adapter->disc_type = BT_DISC_TYPE_BREDR_ONLY;
+       else if (g_strcmp0(disc_type, "LE") == 0)
+               adapter->disc_type =  BT_DISC_TYPE_LE_ONLY;
+       else if (g_strcmp0(disc_type, "LE_BREDR") == 0)
+               adapter->disc_type =  BT_DISC_TYPE_LE_BREDR;
+       else
+               return btd_error_invalid_args(msg);
+
+       /*
+        * Every client can only start one discovery, if the client
+        * already started a discovery then return an error.
+        */
+       list = g_slist_find_custom(adapter->discovery_list, sender,
+                                               compare_sender);
+       if (list)
+               return btd_error_busy(msg);
+
+       client = g_new0(struct watch_client, 1);
+
+       client->adapter = adapter;
+       client->owner = g_strdup(sender);
+       client->watch = g_dbus_add_disconnect_watch(dbus_conn, sender,
+                                               discovery_disconnect, client,
+                                               discovery_destroy);
+
+       adapter->discovery_list = g_slist_prepend(adapter->discovery_list,
+                                                               client);
+
+       /*
+        * Just trigger the discovery here. In case an already running
+        * discovery in idle phase exists, it will be restarted right
+        * away.
+        */
+       trigger_start_discovery(adapter, 0);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *adapter_start_le_discovery(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const char *sender = dbus_message_get_sender(msg);
+       struct watch_client *client;
+       GSList *list;
+
+       DBG("sender %s", sender);
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       /*
+        * Every client can only start one discovery, if the client
+        * already started a discovery then return an error.
+        */
+
+       adapter->disc_type = BT_DISC_TYPE_LE_ONLY;
+       DBG("adapter->disc_type[%d]", adapter->disc_type);
+       DBG("adapter->discovery_type [%d]", adapter->discovery_type);
+
+       list = g_slist_find_custom(adapter->le_discovery_list, sender,
+                                               compare_sender);
+       if (list)
+               return btd_error_busy(msg);
+
+       client = g_new0(struct watch_client, 1);
+
+       client->adapter = adapter;
+       client->owner = g_strdup(sender);
+       client->watch = g_dbus_add_disconnect_watch(dbus_conn, sender,
+                                               le_discovery_disconnect, client,
+                                               le_discovery_destroy);
+
+       adapter->le_discovery_list = g_slist_prepend(adapter->le_discovery_list,
+                                                               client);
+
+       /*
+        * Just trigger the discovery here. In case an already running
+        * discovery in idle phase exists, it will be restarted right
+        * away.
+        */
+       trigger_start_discovery(adapter, 0);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *adapter_stop_le_discovery(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const char *sender = dbus_message_get_sender(msg);
+       struct mgmt_cp_stop_le_discovery cp;
+       struct watch_client *client;
+       GSList *list;
+
+       DBG("sender %s", sender);
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       list = g_slist_find_custom(adapter->le_discovery_list, sender,
+                                               compare_sender);
+       if (!list)
+               return btd_error_failed(msg, "No discovery started");
+
+       client = list->data;
+
+       adapter->disc_type = BT_DISC_TYPE_LE_ONLY;
+       DBG("adapter->disc_type[%d]", adapter->disc_type);
+       DBG("adapter->discovery_type [%d]", adapter->discovery_type);
+
+       cp.type = adapter->discovery_type;
+       DBG("cp.type %d", cp.type);
+
+       /*
+        * The destroy function will cleanup the client information and
+        * also remove it from the list of discovery clients.
+        */
+       g_dbus_remove_watch(dbus_conn, client->watch);
+
+       /*
+        * As long as other discovery clients are still active, just
+        * return success.
+        */
+       DBG("cp.type %d", cp.type);
+       DBG("adapter->le_discovery_list %d", adapter->discovery_type);
+       if (adapter->le_discovery_list)
+               return dbus_message_new_method_return(msg);
+
+       /*
+        * In the idle phase of a discovery, there is no need to stop it
+        * and so it is enough to send out the signal and just return.
+        */
+       DBG("cp.type %d", cp.type);
+       DBG("adapter->discovery_enable %d", adapter->discovery_enable);
+       if (adapter->discovery_enable == 0x00) {
+               adapter->le_discovering = false;
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "LEDiscovering");
+
+               trigger_passive_scanning(adapter);
+
+               return dbus_message_new_method_return(msg);
+       }
+       DBG("adapter->discovery_type %d", adapter->discovery_type);
+       cp.type = 0x06;
+       DBG("cp.type %d", cp.type);
+       mgmt_send(adapter->mgmt, MGMT_OP_STOP_LE_DISCOVERY,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               stop_le_discovery_complete, adapter, NULL);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *adapter_set_advertising(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       dbus_bool_t err;
+       dbus_bool_t enable = FALSE;
+       dbus_int32_t slot_id;
+
+       DBG("adapter_set_advertising");
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &enable,
+                                               DBUS_TYPE_INT32, &slot_id,
+                                               DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       if (adapter_le_is_supported_multi_advertising() && slot_id > 0)
+               err = adapter_le_enable_multi_adv(enable, slot_id);
+       else
+               err = set_mode(adapter, MGMT_OP_SET_ADVERTISING, enable);
+
+       if (!err)
+               return btd_error_failed(msg, "Set Advertising failed");
+
+       if (enable)
+               create_advertiser(adapter, slot_id);
+
+       if (err && slot_id > 0)
+               advertising_state_changed(adapter, slot_id, enable);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *adapter_set_advertising_params(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       struct mgmt_cp_set_advertising_params cp;
+       dbus_uint32_t interval_min;
+       dbus_uint32_t interval_max;
+       dbus_uint32_t filter_policy;
+       dbus_uint32_t type;
+       dbus_int32_t slot_id;
+       gboolean ret;
+
+       DBG("Set customised advertising parameters");
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       if (!dbus_message_get_args(msg, NULL,
+                               DBUS_TYPE_UINT32, &interval_min,
+                               DBUS_TYPE_UINT32, &interval_max,
+                               DBUS_TYPE_UINT32, &filter_policy,
+                               DBUS_TYPE_UINT32, &type,
+                               DBUS_TYPE_INT32, &slot_id,
+                               DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       memset(&cp, 0, sizeof(cp));
+
+       DBG("advertising interval min %x, max %x, filter %x type %x",
+                               interval_min, interval_max, filter_policy, type);
+
+       if (filter_policy > 0x03)
+               return btd_error_invalid_args(msg);
+
+       if (type > 0x04)
+               return btd_error_invalid_args(msg);
+
+       if (adapter_le_is_supported_multi_advertising() && slot_id > 0) {
+               adapter_le_adv_inst_info_t *p_inst;
+               adapter_le_adv_param_t *p_params;
+
+               p_inst = malloc(sizeof(adapter_le_adv_inst_info_t));
+               p_params = malloc(sizeof(adapter_le_adv_param_t));
+               memset(p_inst, 0, sizeof(adapter_le_adv_inst_info_t));
+               memset(p_params, 0, sizeof(adapter_le_adv_param_t));
+               p_inst->inst_id = slot_id;
+               p_params->adv_int_min = interval_min;
+               p_params->adv_int_max = interval_max;
+               p_params->adv_type = type;
+               p_params->channel_map = 0x07;   /* fixed channel :: will be used all */
+               p_params->adv_filter_policy = filter_policy;
+               p_params->tx_power = BLE_ADV_TX_POWER_MID;      /* TODO:need to optimize */
+               p_inst->bdaddr_type = 0x00;
+               bacpy(&p_inst->bdaddr, &adapter->bdaddr);
+
+               ret = adapter_le_set_multi_adv_params(p_inst, p_params);
+
+               free(p_inst);
+               free(p_params);
+
+               if (ret)
+                       return dbus_message_new_method_return(msg);
+               else
+                       return btd_error_failed(msg, "set advertising param failed");
+       } else {
+               cp.interval_max = interval_max;
+               cp.interval_min = interval_min;
+               cp.filter_policy = filter_policy;
+               cp.type = type;
+
+               if (mgmt_send(adapter->mgmt, MGMT_OP_SET_ADVERTISING_PARAMS,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       NULL, NULL, NULL) > 0)
+                       return dbus_message_new_method_return(msg);
+
+               return btd_error_failed(msg, "set advertising param failed");
+       }
+}
+
+static DBusMessage *adapter_set_advertising_data(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       struct mgmt_cp_set_advertising_data cp;
+       uint8_t *value;
+       int32_t len = 0;
+       dbus_int32_t slot_id;
+       uint8_t *adv_data = NULL;
+       int adv_len = 0;
+
+       DBG("Set advertising data");
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       if (!dbus_message_get_args(msg, NULL,
+                       DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &value, &len,
+                       DBUS_TYPE_INT32, &slot_id,
+                       DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       if (len > ADV_DATA_MAX_LENGTH - 3)
+               return btd_error_invalid_args(msg);
+
+       if (adapter_le_set_missed_adv_data(value, len, FALSE,
+                       adapter->name, adapter->adv_tx_power, &adv_data, &adv_len) != TRUE)
+                       return btd_error_failed(msg, "set advertising data failed");
+
+       if (adapter_le_is_supported_multi_advertising() && slot_id > 0) {
+               if (adapter_le_set_multi_adv_data(slot_id, FALSE, adv_len, adv_data)) {
+                       g_free(adv_data);
+                       return dbus_message_new_method_return(msg);
+               } else {
+                       g_free(adv_data);
+                       return btd_error_failed(msg, "set advertising data failed");
+               }
+       } else {
+               if(adv_len > sizeof(cp)) {
+                       g_free(adv_data);
+                       DBG("Error: overrun advertising data length");
+                       return btd_error_failed(msg, "Overrun advertising data length");
+               }
+
+               memcpy(&cp, adv_data, adv_len);
+
+               if (mgmt_send(adapter->mgmt, MGMT_OP_SET_ADVERTISING_DATA,
+                                               adapter->dev_id, adv_len,
+                                               &cp, NULL, NULL, NULL) > 0) {
+                       g_free(adv_data);
+                       return dbus_message_new_method_return(msg);
+               }
+
+               g_free(adv_data);
+               return btd_error_failed(msg, "set advertising data failed");
+       }
+}
+
+static DBusMessage *adapter_le_scan_filter_param_setup(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       dbus_bool_t err;
+       dbus_int32_t client_if, action, filt_index;
+       dbus_int32_t feat_seln, list_logic_type, filt_logic_type;
+       dbus_int32_t rssi_high_thres, rssi_low_thres, dely_mode;
+       dbus_int32_t found_timeout, lost_timeout, found_timeout_cnt;
+       adapter_le_scan_filter_param_t params;
+
+       DBG("adapter_le_scan_filter_param_setup");
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       if (adapter_le_get_scan_filter_size() == 0)
+               return btd_error_not_supported(msg);
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &client_if,
+                                               DBUS_TYPE_INT32, &action,
+                                               DBUS_TYPE_INT32, &filt_index,
+                                               DBUS_TYPE_INT32, &feat_seln,
+                                               DBUS_TYPE_INT32, &list_logic_type,
+                                               DBUS_TYPE_INT32, &filt_logic_type,
+                                               DBUS_TYPE_INT32, &rssi_high_thres,
+                                               DBUS_TYPE_INT32, &rssi_low_thres,
+                                               DBUS_TYPE_INT32, &dely_mode,
+                                               DBUS_TYPE_INT32, &found_timeout,
+                                               DBUS_TYPE_INT32, &lost_timeout,
+                                               DBUS_TYPE_INT32, &found_timeout_cnt,
+                                               DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       memset(&params, 0, sizeof(params));
+
+       params.action = action;
+       params.index = filt_index;
+       params.feature = feat_seln;
+       params.filter_logic_type = filt_logic_type;
+       params.list_logic_type = list_logic_type;
+       params.delivery_mode = dely_mode;
+       params.rssi_high_threshold = rssi_high_thres;
+
+       if (params.delivery_mode == ON_FOUND) {
+               params.rssi_low_threshold = rssi_low_thres;
+               params.onfound_timeout = found_timeout;
+               params.onfound_timeout_cnt = found_timeout_cnt;
+               params.onlost_timeout = lost_timeout;
+       }
+
+       err = adapter_le_set_scan_filter_params(&params);
+
+       if (!err)
+               return btd_error_failed(msg, "Failed to scan filter param setup");
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *adapter_le_scan_filter_add_remove(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       dbus_bool_t err;
+       dbus_int32_t client_if, action, filt_type, filt_index;
+       dbus_int32_t company_id, company_id_mask;
+       gchar *string;
+       dbus_uint32_t address_type;
+       uint8_t *p_uuid, *p_uuid_mask, *p_data, *p_mask;
+       int32_t uuid_len = 0, uuid_mask_len = 0, data_len = 0, mask_len = 0;
+
+       DBG("adapter_le_scan_filter_add_remove");
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       if (adapter_le_get_scan_filter_size() == 0)
+               return btd_error_not_supported(msg);
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &client_if,
+                                               DBUS_TYPE_INT32, &action,
+                                               DBUS_TYPE_INT32, &filt_type,
+                                               DBUS_TYPE_INT32, &filt_index,
+                                               DBUS_TYPE_INT32, &company_id,
+                                               DBUS_TYPE_INT32, &company_id_mask,
+                                               DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &p_uuid, &uuid_len,
+                                               DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &p_uuid_mask, &uuid_mask_len,
+                                               DBUS_TYPE_STRING, &string,
+                                               DBUS_TYPE_UINT32, &address_type,
+                                               DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &p_data, &data_len,
+                                               DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &p_mask, &mask_len,
+                                               DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       err = adapter_le_set_scan_filter_data(client_if, action, filt_type,
+                       filt_index, company_id, company_id_mask,
+                       uuid_len, p_uuid, uuid_mask_len, p_uuid_mask,
+                       string, address_type, data_len, p_data, mask_len, p_mask);
+
+       if (!err)
+               return btd_error_failed(msg, "Failed to add/remove filter");
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *adapter_le_scan_filter_clear(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       dbus_bool_t err;
+       dbus_int32_t client_if;
+       dbus_int32_t filt_index;
+
+       DBG("adapter_le_scan_filter_clear");
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       if (adapter_le_get_scan_filter_size() == 0)
+               return btd_error_not_supported(msg);
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &client_if,
+                                               DBUS_TYPE_INT32, &filt_index,
+                                               DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       err = adapter_le_clear_scan_filter_data(client_if, filt_index);
+
+       if (!err)
+               return btd_error_failed(msg, "Failed to clear filter");
+
+       return dbus_message_new_method_return(msg);
+}
+
+
+static DBusMessage *adapter_le_scan_filter_enable(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       dbus_bool_t err;
+       dbus_bool_t enable = FALSE;
+       dbus_int32_t client_if;
+
+       DBG("adapter_le_scan_filter_enable");
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       if (adapter_le_get_scan_filter_size() == 0)
+               return btd_error_not_supported(msg);
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &client_if,
+                                               DBUS_TYPE_BOOLEAN, &enable,
+                                               DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       err = adapter_le_enable_scan_filtering(enable);
+
+       if (!err)
+               return btd_error_failed(msg, "Failed to enable scan filtering");
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *adapter_le_set_scan_params(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       struct mgmt_cp_le_set_scan_params cp;
+       uint32_t type;
+       uint32_t interval;
+       uint32_t window;
+
+       DBG("Set scan parameters");
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       if (!dbus_message_get_args(msg, NULL,
+                               DBUS_TYPE_UINT32, &type,
+                               DBUS_TYPE_UINT32, &interval,
+                               DBUS_TYPE_UINT32, &window,
+                               DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       DBG("scan type %x, interval %x, window %x",
+                               type, interval, window);
+       memset(&cp, 0, sizeof(cp));
+
+       cp.type = type;
+       cp.interval = interval;
+       cp.window = window;
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_LE_SET_SCAN_PARAMS,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       NULL, NULL, NULL) > 0)
+               return dbus_message_new_method_return(msg);
+
+       return btd_error_failed(msg, "set scan parameters failed");
+}
+
+static DBusMessage *adapter_set_scan_rsp_data(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       struct mgmt_cp_set_scan_rsp_data cp;
+       uint8_t *value;
+       int32_t len = 0;
+       dbus_int32_t slot_id;
+       uint8_t *adv_data = NULL;
+       int adv_len = 0;
+
+       DBG("Set scan response data");
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       if (!dbus_message_get_args(msg, NULL,
+                       DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &value, &len,
+                       DBUS_TYPE_INT32, &slot_id,
+                       DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       if (len > SCAN_RESPONSE_DATA_LENGTH_MAX)
+               return btd_error_invalid_args(msg);
+
+       if (adapter_le_set_missed_adv_data(value, len, TRUE,
+                       adapter->name, adapter->adv_tx_power, &adv_data, &adv_len) != TRUE)
+                       return btd_error_failed(msg, "set advertising data failed");
+
+       if (adapter_le_is_supported_multi_advertising() && slot_id > 0) {
+               if (adapter_le_set_multi_adv_data(slot_id, TRUE, adv_len, (uint8_t *)adv_data)) {
+                       g_free(adv_data);
+                       return dbus_message_new_method_return(msg);
+               } else {
+                       g_free(adv_data);
+                       return btd_error_failed(msg, "set advertising data failed");
+               }
+       } else {
+               if(adv_len > sizeof(cp)) {
+                       g_free(adv_data);
+                       DBG("Error: overrun scan response data length");
+                       return btd_error_failed(msg, "Overrun scan response data length");
+               }
+
+               memcpy(&cp, adv_data, adv_len);
+
+               if (mgmt_send(adapter->mgmt, MGMT_OP_SET_SCAN_RSP_DATA,
+                                               adapter->dev_id, adv_len, &cp,
+                                               NULL, NULL, NULL) > 0) {
+                       g_free(adv_data);
+                       return dbus_message_new_method_return(msg);
+               }
+
+               g_free(adv_data);
+               return btd_error_failed(msg, "set scan reponse data failed");
+       }
+}
+
+static DBusMessage *adapter_add_device_white_list(DBusConnection *conn,
+                                       DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       struct mgmt_cp_add_dev_white_list cp;
+       const gchar *address;
+       bdaddr_t bdaddr;
+       dbus_uint32_t address_type;
+
+       DBG("Add device whie list");
+       if (dbus_message_get_args(msg, NULL,
+                                       DBUS_TYPE_STRING, &address,
+                                       DBUS_TYPE_UINT32, &address_type,
+                                       DBUS_TYPE_INVALID) == FALSE)
+               return btd_error_invalid_args(msg);
+
+       if (check_address(address) < 0)
+               return btd_error_invalid_args(msg);
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       DBG("addr %s, type %d", address, address_type);
+       str2ba(address, &bdaddr);
+
+       memset(&cp, 0, sizeof(cp));
+
+       cp.bdaddr_type = address_type;
+       memcpy(&cp.bdaddr, &bdaddr, sizeof(bdaddr_t));
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_ADD_DEV_WHITE_LIST,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       NULL, NULL, NULL) > 0)
+               return dbus_message_new_method_return(msg);
+
+       return btd_error_failed(msg, "add device white list failed");
+}
+
+static DBusMessage *adapter_remove_device_white_list(DBusConnection *conn,
+                                       DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       struct mgmt_cp_remove_dev_white_list cp;
+       const gchar *address;
+       bdaddr_t bdaddr;
+       dbus_uint32_t address_type;
+
+       DBG("Remove device whie list");
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       if (dbus_message_get_args(msg, NULL,
+                                       DBUS_TYPE_STRING, &address,
+                                       DBUS_TYPE_UINT32, &address_type,
+                                       DBUS_TYPE_INVALID) == FALSE)
+               return btd_error_invalid_args(msg);
+
+       if (check_address(address) < 0)
+               return btd_error_invalid_args(msg);
+
+       DBG("addr %s, type %d", address, address_type);
+       str2ba(address, &bdaddr);
+
+       memset(&cp, 0, sizeof(cp));
+
+       cp.bdaddr_type = address_type;
+       memcpy(&cp.bdaddr, &bdaddr, sizeof(bdaddr_t));
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_REMOVE_DEV_FROM_WHITE_LIST,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       NULL, NULL, NULL) > 0)
+               return dbus_message_new_method_return(msg);
+
+       return btd_error_failed(msg, "remove device white list failed");
+}
+
+static DBusMessage *adapter_clear_device_white_list(DBusConnection *conn,
+                                       DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+
+       DBG("Clear device whie list");
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_CLEAR_DEV_WHITE_LIST,
+                                       adapter->dev_id, 0, NULL,
+                                       NULL, NULL, NULL) > 0)
+               return dbus_message_new_method_return(msg);
+
+       return btd_error_failed(msg, "clear white list failed");
+}
+
+static DBusMessage *adapter_set_le_privacy(DBusConnection *conn,
+                                       DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       dbus_bool_t err;
+       dbus_bool_t enable_privacy = FALSE;
+
+       if (!(adapter->supported_settings & MGMT_SETTING_PRIVACY))
+               return btd_error_not_supported(msg);
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN,
+                               &enable_privacy, DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       if (enable_privacy) {
+               if (adapter->current_settings & MGMT_SETTING_PRIVACY)
+                       return btd_error_already_exists(msg);
+       } else {
+               if (!(adapter->current_settings & MGMT_SETTING_PRIVACY))
+                       return btd_error_already_exists(msg);
+       }
+
+       err = set_privacy(adapter, enable_privacy);
+
+       if (!err)
+               return btd_error_failed(msg, "Set Le Privacy failed");
+
+       return dbus_message_new_method_return(msg);
+}
+
+#if 0 // Not used
+static void read_sec_conn_host_support_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_rp_read_sec_conn_host_support *rp = param;
+       struct btd_adapter *adapter = user_data;
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to read secure conn parameter: %s (0x%02x)",
+                  mgmt_errstr(status), status);
+               return;
+       }
+
+       if (length < sizeof(*rp)) {
+               error("Wrong size of read secure connections host support");
+               return;
+       }
+
+       if (rp->sec_conn_host_support)
+               adapter->secure_connection = TRUE;
+       else
+               adapter->secure_connection = FALSE;
+
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                       ADAPTER_INTERFACE, "SecureConnection");
+}
+
+static DBusMessage *read_sec_conn_host_support(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       mgmt_send(adapter->mgmt, MGMT_OP_READ_SEC_CONN_HOST_SUPPORT,
+             adapter->dev_id, 0, NULL,
+             read_sec_conn_host_support_complete, adapter, NULL);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static void write_sec_conn_host_support_complete(uint8_t status,
+               uint16_t length, const void *param, void *user_data)
+{
+       const struct mgmt_rp_write_sec_conn_host_support *rp = param;
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to write secure connections host \
+                               support parameter: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
+       }
+
+       if (length < sizeof(*rp)) {
+               error("Wrong size of write secure connections host\
+                                support parameter");
+               return;
+       }
+}
+
+static DBusMessage *write_sec_conn_host_support(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+
+       struct mgmt_cp_write_sec_conn_host_support cp;
+       dbus_bool_t enable = FALSE;
+       struct btd_adapter *adapter = user_data;
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN,
+                                       &enable, DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       memset(&cp, 0, sizeof(cp));
+       cp.secure_connection_host_support = enable;
+       mgmt_send(adapter->mgmt, MGMT_OP_WRITE_SEC_CONN_HOST_SUPPORT,
+                       adapter->dev_id, sizeof(cp), &cp,
+                       write_sec_conn_host_support_complete,
+                       NULL, NULL);
+       return dbus_message_new_method_return(msg);
+}
+#endif
+
+static DBusMessage *adapter_enable_rssi(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       struct mgmt_cp_set_enable_rssi cp;
+       struct mgmt_cp_disable_rssi cp_dis;
+       bdaddr_t bt_addr = { { 0, } };
+       const gchar *address = NULL;
+
+       const char *sender = dbus_message_get_sender(msg);
+       dbus_int32_t link_type;
+       dbus_int32_t low_threshold;
+       dbus_int32_t in_range_threshold;
+       dbus_int32_t high_threshold;
+
+       DBG("Enable RSSI called");
+       DBG("sender %s", sender);
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       if (!dbus_message_get_args(msg, NULL,
+                               DBUS_TYPE_STRING, &address,
+                               DBUS_TYPE_INT32, &link_type,
+                               DBUS_TYPE_INT32, &low_threshold,
+                               DBUS_TYPE_INT32, &in_range_threshold,
+                               DBUS_TYPE_INT32, &high_threshold,
+                               DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       DBG("Enable RSSI: [%s %d %d %d %d]", address, link_type,
+                       low_threshold, in_range_threshold, high_threshold);
+
+       DBG("BT address [%s]", address);
+       memset(&bt_addr, 0, sizeof(bdaddr_t));
+       str2ba(address, &bt_addr);
+       memset(&cp, 0, sizeof(struct mgmt_cp_set_enable_rssi));
+       memset(&cp_dis, 0, sizeof(struct mgmt_cp_disable_rssi));
+
+       if (check_address(address) < 0)
+               return btd_error_invalid_args(msg);
+
+//     if (!btd_adapter_find_device(adapter, address))
+//             return btd_error_not_found(msg);
+
+       if (low_threshold == 0 && in_range_threshold == 0 && high_threshold == 0) {
+               cp_dis.bdaddr = bt_addr;
+               cp_dis.link_type = link_type;
+               DBG("Disable Request");
+               if (mgmt_send(adapter->mgmt, MGMT_OP_SET_RSSI_DISABLE,
+                                       adapter->dev_id, sizeof(cp_dis), &cp_dis,
+                                       NULL, NULL, NULL) > 0)
+                                       return dbus_message_new_method_return(msg);
+       } else {
+               cp.low_th = low_threshold;
+               cp.in_range_th = in_range_threshold;
+               cp.high_th = high_threshold;
+               cp.bdaddr = bt_addr;
+               cp.link_type = link_type;
+               DBG("Enable Request");
+               if (mgmt_send(adapter->mgmt, MGMT_OP_SET_RSSI_ENABLE,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       NULL, NULL, NULL) > 0)
+                       return dbus_message_new_method_return(msg);
+       }
+       return btd_error_failed(msg, "Enable/Disable RSSI Failed");
+}
+
+static DBusMessage *adapter_get_rssi(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       struct mgmt_cp_get_raw_rssi cp;
+       bdaddr_t bt_addr;
+       const gchar *address = NULL;
+       dbus_int32_t link_type;
+       const char *sender = dbus_message_get_sender(msg);
+
+       DBG("Get RSSI called");
+       DBG("sender %s", sender);
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       if (!dbus_message_get_args(msg, NULL,
+                               DBUS_TYPE_STRING, &address,
+                               DBUS_TYPE_INT32, &link_type,
+                               DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       DBG("BT address [%s] link type [%d]", address, link_type);
+       memset(&bt_addr, 0, sizeof(bdaddr_t));
+       str2ba(address, &bt_addr);
+       memset(&cp, 0, sizeof(struct mgmt_cp_get_raw_rssi));
+
+       if (check_address(address) < 0)
+               return btd_error_invalid_args(msg);
+
+//     if (!btd_adapter_find_device(adapter, address))
+//             return btd_error_not_found(msg);
+
+       memcpy(&(cp.bt_address), &bt_addr, sizeof(bdaddr_t));
+       cp.link_type = link_type;
+       DBG("RAW RSSI Request");
+       if (mgmt_send(adapter->mgmt, MGMT_OP_GET_RAW_RSSI,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       NULL, NULL, NULL) > 0)
+                       return dbus_message_new_method_return(msg);
+
+       return btd_error_failed(msg, "Get Raw RSSI Failed");
+}
+
+static void get_adv_tx_power_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const struct mgmt_rp_get_adv_tx_power *rp = param;
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to get adv tx power: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
+       }
+
+       if (length < sizeof(*rp)) {
+               error("Wrong size of get adv tx power");
+               return;
+       }
+
+       adapter->adv_tx_power = rp->adv_tx_power;
+       return;
+}
+
+static  void adapter_get_adv_tx_power(void *data)
+{
+       struct btd_adapter *adapter = data;
+
+       mgmt_send(adapter->mgmt, MGMT_OP_GET_ADV_TX_POWER,
+                                       adapter->dev_id, 0, NULL,
+                                       get_adv_tx_power_complete, adapter, NULL);
+       return;
+}
+
+#ifdef __BROADCOM_PATCH__
+static DBusMessage *set_wbs_parameters(DBusConnection *conn,
+                               DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       const gchar *role = NULL;
+       const gchar *address = NULL;
+       struct mgmt_cp_set_voice_setting cp;
+       bdaddr_t bt_addr = { { 0, } };
+
+       DBG("+");
+
+       if (!dbus_message_get_args(msg, NULL,
+                               DBUS_TYPE_STRING, &role,
+                               DBUS_TYPE_STRING, &address,
+                               DBUS_TYPE_INVALID)) {
+               return btd_error_invalid_args(msg);
+       }
+
+       DBG("Role = %s", role);
+       DBG("Address = %s", address);
+
+       memset(&cp, 0, sizeof(cp));
+
+       cp.voice_setting = BT_VOICE_TRANSPARENT | BT_VOICE_CVSD_16BIT;
+
+       if (g_strcmp0(role, "Handsfree") == 0)
+               cp.sco_role = MGMT_SCO_ROLE_HANDSFREE;
+       else if (g_strcmp0(role, "Gateway") == 0)
+               cp.sco_role = MGMT_SCO_ROLE_AUDIO_GATEWAY;
+
+       str2ba(address, &bt_addr);
+       memcpy(&(cp.bdaddr), &bt_addr, sizeof(bdaddr_t));
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_SET_VOICE_SETTING,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               NULL, NULL, NULL) == 0)
+               error("mgmt_send failed for voice setting");
+
+       DBG("-");
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *set_nb_parameters(DBusConnection *conn,
+                               DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       const gchar *role;
+       const gchar *address = NULL;
+       struct mgmt_cp_set_voice_setting cp;
+       bdaddr_t bt_addr = { { 0, } };
+
+       DBG("+");
+
+       if (!dbus_message_get_args(msg, NULL,
+                               DBUS_TYPE_STRING, &role,
+                               DBUS_TYPE_STRING, &address,
+                               DBUS_TYPE_INVALID)) {
+               return btd_error_invalid_args(msg);
+       }
+
+       DBG("Role = %s", role);
+       DBG("Address = %s", address);
+
+       memset(&cp, 0, sizeof(cp));
+
+       cp.voice_setting = BT_VOICE_CVSD_16BIT;
+
+       if (g_strcmp0(role, "Handsfree") == 0)
+               cp.sco_role = MGMT_SCO_ROLE_HANDSFREE;
+       else if (g_strcmp0(role, "Gateway") == 0)
+               cp.sco_role = MGMT_SCO_ROLE_AUDIO_GATEWAY;
+
+       str2ba(address, &bt_addr);
+       memcpy(&(cp.bdaddr), &bt_addr, sizeof(bdaddr_t));
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_SET_VOICE_SETTING,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               NULL, NULL, NULL) == 0)
+               error("mgmt_send failed for voice setting");
+
+       DBG("-");
+
+       return dbus_message_new_method_return(msg);
+}
+static DBusMessage *adapter_set_manufacturer_data(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       struct mgmt_cp_set_manufacturer_data cp;
+       uint8_t *value;
+       int32_t len = 0;
+
+       DBG("Set manufacturer data");
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       if (!dbus_message_get_args(msg, NULL,
+                       DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &value, &len,
+                       DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       if (len > MANUFACTURER_DATA_LENGTH_MAX)
+               return btd_error_invalid_args(msg);
+
+       memcpy(&cp, value, len);
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_SET_MANUFACTURER_DATA,
+                                       adapter->dev_id, MANUFACTURER_DATA_LENGTH_MAX,
+                                       &cp, NULL, NULL, NULL) > 0)
+               return dbus_message_new_method_return(msg);
+
+       return btd_error_failed(msg, "Set manufacturer data failed");
+}
+#endif /* __BROADCOM_PATCH__ */
+#endif /* __TIZEN_PATCH__ */
+
+static DBusMessage *stop_discovery(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const char *sender = dbus_message_get_sender(msg);
+       struct mgmt_cp_stop_discovery cp;
+       struct watch_client *client;
+       GSList *list;
+
+       DBG("sender %s", sender);
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       list = g_slist_find_custom(adapter->discovery_list, sender,
+                                               compare_sender);
+       if (!list)
+               return btd_error_failed(msg, "No discovery started");
+
+       client = list->data;
+
+#ifdef __TIZEN_PATCH__
+       adapter->disc_type = BT_DISC_TYPE_BREDR_ONLY;
+#endif
+       cp.type = adapter->discovery_type;
+
+       /*
+        * The destroy function will cleanup the client information and
+        * also remove it from the list of discovery clients.
+        */
+       g_dbus_remove_watch(dbus_conn, client->watch);
+
+       /*
+        * As long as other discovery clients are still active, just
+        * return success.
+        */
+       if (adapter->discovery_list)
+               return dbus_message_new_method_return(msg);
+
+       /*
+        * In the idle phase of a discovery, there is no need to stop it
+        * and so it is enough to send out the signal and just return.
+        */
+       if (adapter->discovery_enable == 0x00) {
+               adapter->discovering = false;
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Discovering");
+
+               trigger_passive_scanning(adapter);
+
+               return dbus_message_new_method_return(msg);
+       }
+#ifdef __TIZEN_PATCH__
+       cp.type = 0x01;
+#endif
+       mgmt_send(adapter->mgmt, MGMT_OP_STOP_DISCOVERY,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               stop_discovery_complete, adapter, NULL);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static gboolean property_get_address(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       char addr[18];
+       const char *str = addr;
+
+       ba2str(&adapter->bdaddr, addr);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
+
+       return TRUE;
+}
+
+static gboolean property_get_name(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const char *str = adapter->system_name ? : "";
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
+
+       return TRUE;
+}
+
+static gboolean property_get_alias(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const char *str;
+
+       if (adapter->current_alias)
+               str = adapter->current_alias;
+       else if (adapter->stored_alias)
+               str = adapter->stored_alias;
+       else
+               str = adapter->system_name ? : "";
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
+
+       return TRUE;
+}
+
+static void property_set_alias(const GDBusPropertyTable *property,
+                               DBusMessageIter *iter,
+                               GDBusPendingPropertySet id, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const char *name;
+       int ret;
+
+       dbus_message_iter_get_basic(iter, &name);
+
+       if (g_str_equal(name, "")  == TRUE) {
+               if (adapter->stored_alias == NULL) {
+                       /* no alias set, nothing to restore */
+                       g_dbus_pending_property_success(id);
+                       return;
+               }
+
+               /* restore to system name */
+               ret = set_name(adapter, adapter->system_name);
+       } else {
+               if (g_strcmp0(adapter->stored_alias, name) == 0) {
+                       /* alias already set, nothing to do */
+                       g_dbus_pending_property_success(id);
+                       return;
+               }
+
+               /* set to alias */
+               ret = set_name(adapter, name);
+       }
+
+       if (ret >= 0) {
+               g_free(adapter->stored_alias);
+
+               if (g_str_equal(name, "")  == TRUE)
+                       adapter->stored_alias = NULL;
+               else
+                       adapter->stored_alias = g_strdup(name);
+
+               store_adapter_info(adapter);
+
+               g_dbus_pending_property_success(id);
+               return;
+       }
+
+       if (ret == -EINVAL)
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments in method call");
+       else
+               g_dbus_pending_property_error(id, ERROR_INTERFACE ".Failed",
+                                                       strerror(-ret));
+}
+
+static gboolean property_get_class(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       dbus_uint32_t val = adapter->dev_class;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &val);
+
+       return TRUE;
+}
+
+static gboolean property_get_mode(struct btd_adapter *adapter,
+                               uint32_t setting, DBusMessageIter *iter)
+{
+       dbus_bool_t enable;
+
+       enable = (adapter->current_settings & setting) ? TRUE : FALSE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &enable);
+
+       return TRUE;
+}
+
+struct property_set_data {
+       struct btd_adapter *adapter;
+       GDBusPendingPropertySet id;
+};
+
+static void property_set_mode_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct property_set_data *data = user_data;
+       struct btd_adapter *adapter = data->adapter;
+
+       DBG("%s (0x%02x)", mgmt_errstr(status), status);
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               const char *dbus_err;
+
+               error("Failed to set mode: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+
+               if (status == MGMT_STATUS_RFKILLED)
+                       dbus_err = ERROR_INTERFACE ".Blocked";
+               else
+                       dbus_err = ERROR_INTERFACE ".Failed";
+
+               g_dbus_pending_property_error(data->id, dbus_err,
+                                                       mgmt_errstr(status));
+               return;
+       }
+
+       g_dbus_pending_property_success(data->id);
+
+       /*
+        * The parameters are identical and also the task that is
+        * required in both cases. So it is safe to just call the
+        * event handling functions here.
+        */
+       new_settings_callback(adapter->dev_id, length, param, adapter);
+}
+
+static void property_set_mode(struct btd_adapter *adapter, uint32_t setting,
+                                               DBusMessageIter *value,
+                                               GDBusPendingPropertySet id)
+{
+       struct property_set_data *data;
+       struct mgmt_cp_set_discoverable cp;
+       void *param;
+       dbus_bool_t enable, current_enable;
+       uint16_t opcode, len;
+       uint8_t mode;
+
+       dbus_message_iter_get_basic(value, &enable);
+
+       if (adapter->current_settings & setting)
+               current_enable = TRUE;
+       else
+               current_enable = FALSE;
+
+       if (enable == current_enable) {
+               g_dbus_pending_property_success(id);
+               return;
+       }
+
+       mode = (enable == TRUE) ? 0x01 : 0x00;
+
+       switch (setting) {
+       case MGMT_SETTING_POWERED:
+               opcode = MGMT_OP_SET_POWERED;
+               param = &mode;
+               len = sizeof(mode);
+               break;
+       case MGMT_SETTING_DISCOVERABLE:
+#ifndef __TIZEN_PATCH__
+               if (kernel_conn_control) {
+                       if (mode) {
+                               set_mode(adapter, MGMT_OP_SET_CONNECTABLE,
+                                                                       mode);
+                       } else {
+                               opcode = MGMT_OP_SET_CONNECTABLE;
+                               param = &mode;
+                               len = sizeof(mode);
+                               break;
+                       }
+               }
+#endif
+
+               memset(&cp, 0, sizeof(cp));
+               cp.val = mode;
+               if (cp.val)
+                       cp.timeout = htobs(adapter->discoverable_timeout);
+
+               opcode = MGMT_OP_SET_DISCOVERABLE;
+               param = &cp;
+               len = sizeof(cp);
+               break;
+       case MGMT_SETTING_BONDABLE:
+               opcode = MGMT_OP_SET_BONDABLE;
+               param = &mode;
+               len = sizeof(mode);
+               break;
+#ifdef __TIZEN_PATCH__
+       case MGMT_SETTING_CONNECTABLE:
+               opcode = MGMT_OP_SET_CONNECTABLE;
+               param = &mode;
+               len = sizeof(mode);
+               break;
+#endif
+       default:
+               goto failed;
+       }
+
+       DBG("sending %s command for index %u", mgmt_opstr(opcode),
+                                                       adapter->dev_id);
+
+       data = g_try_new0(struct property_set_data, 1);
+       if (!data)
+               goto failed;
+
+       data->adapter = adapter;
+       data->id = id;
+
+#ifdef __TIZEN_PATCH__
+       /*
+        * Use mgmt_reply to avoid dbus timeout in a state of bonding.
+        */
+       if (mgmt_reply(adapter->mgmt, opcode, adapter->dev_id, len, param,
+                               property_set_mode_complete, data, g_free) > 0)
+#else
+       if (mgmt_send(adapter->mgmt, opcode, adapter->dev_id, len, param,
+                               property_set_mode_complete, data, g_free) > 0)
+#endif
+               return;
+
+       g_free(data);
+
+failed:
+       error("Failed to set mode for index %u", adapter->dev_id);
+
+       g_dbus_pending_property_error(id, ERROR_INTERFACE ".Failed", NULL);
+}
+
+static gboolean property_get_powered(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       return property_get_mode(adapter, MGMT_SETTING_POWERED, iter);
+}
+
+static void property_set_powered(const GDBusPropertyTable *property,
+                               DBusMessageIter *iter,
+                               GDBusPendingPropertySet id, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       if (powering_down) {
+               g_dbus_pending_property_error(id, ERROR_INTERFACE ".Failed",
+                                                       "Powering down");
+               return;
+       }
+
+#ifdef __TIZEN_PATCH__
+       if (adapter_le_read_ble_feature_info())
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                       ADAPTER_INTERFACE, "SupportedLEFeatures");
+
+       adapter_get_adv_tx_power(adapter);
+#endif
+
+       property_set_mode(adapter, MGMT_SETTING_POWERED, iter, id);
+}
+
+static gboolean property_get_discoverable(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       return property_get_mode(adapter, MGMT_SETTING_DISCOVERABLE, iter);
+}
+
+static void property_set_discoverable(const GDBusPropertyTable *property,
+                               DBusMessageIter *iter,
+                               GDBusPendingPropertySet id, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       if (adapter->discoverable_timeout > 0 &&
+                       !(adapter->current_settings & MGMT_SETTING_POWERED)) {
+               g_dbus_pending_property_error(id, ERROR_INTERFACE ".Failed",
+                                                               "Not Powered");
+               return;
+       }
+
+       property_set_mode(adapter, MGMT_SETTING_DISCOVERABLE, iter, id);
+}
+
+static gboolean property_get_discoverable_timeout(
+                                       const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       dbus_uint32_t value = adapter->discoverable_timeout;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &value);
+
+       return TRUE;
+}
+
+static void property_set_discoverable_timeout(
+                               const GDBusPropertyTable *property,
+                               DBusMessageIter *iter,
+                               GDBusPendingPropertySet id, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       dbus_uint32_t value;
+
+       dbus_message_iter_get_basic(iter, &value);
+
+       adapter->discoverable_timeout = value;
+
+       g_dbus_pending_property_success(id);
+
+       store_adapter_info(adapter);
+
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                               ADAPTER_INTERFACE, "DiscoverableTimeout");
+
+
+       if (adapter->current_settings & MGMT_SETTING_DISCOVERABLE)
+               set_discoverable(adapter, 0x01, adapter->discoverable_timeout);
+}
+
+static gboolean property_get_pairable(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       return property_get_mode(adapter, MGMT_SETTING_BONDABLE, iter);
+}
+
+static void property_set_pairable(const GDBusPropertyTable *property,
+                               DBusMessageIter *iter,
+                               GDBusPendingPropertySet id, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       property_set_mode(adapter, MGMT_SETTING_BONDABLE, iter, id);
+}
+
+static gboolean property_get_pairable_timeout(
+                                       const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       dbus_uint32_t value = adapter->pairable_timeout;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &value);
+
+       return TRUE;
+}
+
+static void property_set_pairable_timeout(const GDBusPropertyTable *property,
+                               DBusMessageIter *iter,
+                               GDBusPendingPropertySet id, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       dbus_uint32_t value;
+
+       dbus_message_iter_get_basic(iter, &value);
+
+       adapter->pairable_timeout = value;
+
+       g_dbus_pending_property_success(id);
+
+       store_adapter_info(adapter);
+
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "PairableTimeout");
+
+       trigger_pairable_timeout(adapter);
+}
+
+static gboolean property_get_discovering(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       dbus_bool_t discovering = adapter->discovering;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &discovering);
+
+       return TRUE;
+}
+
+static void add_gatt_uuid(struct gatt_db_attribute *attrib, void *user_data)
+{
+       GHashTable *uuids = user_data;
+       bt_uuid_t uuid, u128;
+       char uuidstr[MAX_LEN_UUID_STR + 1];
+
+       if (!gatt_db_service_get_active(attrib))
+               return;
+
+       if (!gatt_db_attribute_get_service_uuid(attrib, &uuid))
+               return;
+
+       bt_uuid_to_uuid128(&uuid, &u128);
+       bt_uuid_to_string(&u128, uuidstr, sizeof(uuidstr));
+
+       g_hash_table_add(uuids, strdup(uuidstr));
+}
+
+static void iter_append_uuid(gpointer key, gpointer value, gpointer user_data)
+{
+       DBusMessageIter *iter = user_data;
+       const char *uuid = key;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);
+}
+
+#ifdef __TIZEN_PATCH__
+
+static gboolean property_get_le_discovering(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       dbus_bool_t discovering = adapter->le_discovering;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &discovering);
+
+       return TRUE;
+}
+
+#if 0 // Not used
+static gboolean property_get_secure_connection(const GDBusPropertyTable
+                         *property, DBusMessageIter *iter, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       dbus_bool_t secure_connection = adapter->secure_connection;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN,
+                                 &secure_connection);
+
+       return TRUE;
+}
+#endif
+
+static gboolean property_get_connectable(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       return property_get_mode(adapter, MGMT_SETTING_CONNECTABLE, iter);
+}
+
+static void property_set_connectable(const GDBusPropertyTable *property,
+                               DBusMessageIter *iter,
+                               GDBusPendingPropertySet id, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       property_set_mode(adapter, MGMT_SETTING_CONNECTABLE, iter, id);
+}
+
+static gboolean property_get_version(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const char *str = adapter->version ? : "";
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
+
+       return TRUE;
+}
+
+static gboolean property_get_supported_le_features(
+                                       const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       const char *str, *val;
+       int value;
+       DBusMessageIter entry;
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_TYPE_STRING_AS_STRING, &entry);
+
+       value = adapter_le_get_max_adv_instance();
+       if (value > 0) {
+               str = g_strdup("adv_inst_max");
+               dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &str);
+
+               val = g_strdup_printf("%d", value);
+               dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &val);
+
+               free((void *)str);
+               free((void *)val);
+       }
+
+       value = adapter_le_is_supported_offloading();
+       if (value > 0) {
+               str = g_strdup("rpa_offloading");
+               dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &str);
+
+               val = g_strdup_printf("%d", value);
+               dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &val);
+
+               free((void *)str);
+               free((void *)val);
+       }
+
+       value = adapter_le_get_scan_filter_size();
+       if (value > 0) {
+               str = g_strdup("max_filter");
+               dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &str);
+
+               val = g_strdup_printf("%d", value);
+               dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &val);
+
+               free((void *)str);
+               free((void *)val);
+       }
+
+       dbus_message_iter_close_container(iter, &entry);
+
+       return TRUE;
+}
+
+#endif
+
+static gboolean property_get_uuids(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       DBusMessageIter entry;
+       sdp_list_t *l;
+       struct gatt_db *db;
+       GHashTable *uuids;
+
+       uuids = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL);
+       if (!uuids)
+               return FALSE;
+
+       /* SDP records */
+       for (l = adapter->services; l != NULL; l = l->next) {
+               sdp_record_t *rec = l->data;
+               char *uuid;
+
+               uuid = bt_uuid2string(&rec->svclass);
+               if (uuid == NULL)
+                       continue;
+
+               g_hash_table_add(uuids, uuid);
+       }
+
+       /* GATT services */
+       db = btd_gatt_database_get_db(adapter->database);
+       if (db)
+               gatt_db_foreach_service(db, NULL, add_gatt_uuid, uuids);
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_TYPE_STRING_AS_STRING, &entry);
+       g_hash_table_foreach(uuids, iter_append_uuid, &entry);
+       dbus_message_iter_close_container(iter, &entry);
+
+       g_hash_table_destroy(uuids);
+
+       return TRUE;
+}
+
+static gboolean property_exists_modalias(const GDBusPropertyTable *property,
+                                                       void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       return adapter->modalias ? TRUE : FALSE;
+}
+
+static gboolean property_get_modalias(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const char *str = adapter->modalias ? : "";
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
+
+       return TRUE;
+}
+
+static int device_path_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct btd_device *device = a;
+       const char *path = b;
+       const char *dev_path = device_get_path(device);
+
+       return strcasecmp(dev_path, path);
+}
+
+#ifdef __TIZEN_PATCH__
+static DBusMessage *adapter_unpair_device(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       DBG("+");
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       const char *path;
+       GSList *list;
+
+       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+                                               DBUS_TYPE_INVALID) == FALSE)
+               return btd_error_invalid_args(msg);
+
+       list = g_slist_find_custom(adapter->devices, path, device_path_cmp);
+       if (!list)
+               return btd_error_does_not_exist(msg);
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       device = list->data;
+
+       btd_device_set_temporary(device, TRUE);
+
+       if (!btd_device_is_connected(device)) {
+               btd_adapter_unpair_device(adapter, device);
+               return dbus_message_new_method_return(msg);
+       }
+
+       device_request_disconnect(device, msg);
+
+       DBG("-");
+       return NULL;
+}
+
+static DBusMessage *create_device(DBusConnection *conn,
+                                       DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter = data;
+       const gchar *address;
+       bdaddr_t addr;
+       DBG("+");
+
+       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
+                                               DBUS_TYPE_INVALID) == FALSE)
+               return btd_error_invalid_args(msg);
+
+       if (check_address(address) < 0)
+               return btd_error_invalid_args(msg);
+
+       DBG("%s", address);
+
+       str2ba(address, &addr);
+       btd_adapter_get_device(adapter, &addr, BDADDR_BREDR);
+
+       DBG("-");
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *find_device(DBusConnection *conn, DBusMessage *msg,
+                                       void *data)
+{
+       struct btd_adapter *adapter = data;
+       struct btd_device *device;
+       DBusMessage *reply;
+       const gchar *address;
+       GSList *l;
+       const gchar *dev_path;
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
+                                                                                       DBUS_TYPE_INVALID))
+                       return btd_error_invalid_args(msg);
+
+       l = g_slist_find_custom(adapter->devices,
+                                       address, (GCompareFunc) device_address_cmp);
+       if (!l)
+                       return btd_error_does_not_exist(msg);
+
+       device = l->data;
+
+       reply = dbus_message_new_method_return(msg);
+       if (!reply)
+                       return NULL;
+
+       dev_path = device_get_path(device);
+
+       dbus_message_append_args(reply,
+                                                       DBUS_TYPE_OBJECT_PATH, &dev_path,
+                                                       DBUS_TYPE_INVALID);
+
+       return reply;
+}
+#endif
+
+static DBusMessage *remove_device(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       const char *path;
+       GSList *list;
+
+       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+                                               DBUS_TYPE_INVALID) == FALSE)
+               return btd_error_invalid_args(msg);
+
+       list = g_slist_find_custom(adapter->devices, path, device_path_cmp);
+       if (!list)
+               return btd_error_does_not_exist(msg);
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       device = list->data;
+
+       btd_device_set_temporary(device, TRUE);
+
+       if (!btd_device_is_connected(device)) {
+               btd_adapter_remove_device(adapter, device);
+               return dbus_message_new_method_return(msg);
+       }
+
+       device_request_disconnect(device, msg);
+
+       return NULL;
+}
+
+static const GDBusMethodTable adapter_methods[] = {
+       { GDBUS_METHOD("StartDiscovery", NULL, NULL, start_discovery) },
+       { GDBUS_METHOD("StopDiscovery", NULL, NULL, stop_discovery) },
+#ifdef __TIZEN_PATCH__
+       { GDBUS_METHOD("StartCustomDiscovery",
+                       GDBUS_ARGS({ "type", "s" }), NULL,
+                       adapter_start_custom_discovery) },
+       { GDBUS_METHOD("StartLEDiscovery", NULL, NULL,
+                       adapter_start_le_discovery) },
+       { GDBUS_ASYNC_METHOD("StopLEDiscovery", NULL, NULL,
+                       adapter_stop_le_discovery) },
+#if 0 // Not used
+       { GDBUS_METHOD("EnableSecureConnection",
+                       GDBUS_ARGS({"enable", "b"}), NULL,
+                       write_sec_conn_host_support)},
+
+       { GDBUS_METHOD("ReadSecureConnection", NULL,
+                                       NULL, read_sec_conn_host_support)},
+#endif
+
+       { GDBUS_METHOD("SetAdvertising",
+                       GDBUS_ARGS({ "enable", "b" },
+                               { "slot_id", "i" }), NULL,
+                       adapter_set_advertising) },
+       { GDBUS_METHOD("SetAdvertisingParameters",
+                       GDBUS_ARGS({ "interval_min", "u" },
+                               { "interval_max", "u" },
+                               { "filter_policy", "u" },
+                               { "type", "u" },
+                               { "slot_id", "i" }), NULL,
+                       adapter_set_advertising_params) },
+       { GDBUS_METHOD("SetAdvertisingData",
+                       GDBUS_ARGS({ "value", "ay" },
+                               { "slot_id", "i" }), NULL,
+                       adapter_set_advertising_data) },
+       { GDBUS_METHOD("SetScanParameters",
+                       GDBUS_ARGS({ "type", "u" },
+                               { "interval", "u" },
+                               { "window", "u" }), NULL,
+                       adapter_le_set_scan_params) },
+#ifdef __TIZEN_PATCH__ /* scan filter method - refered bt_gatt_client.h */
+       { GDBUS_ASYNC_METHOD("scan_filter_param_setup",
+                       GDBUS_ARGS({ "client_if", "i" }, { "action", "i" },
+                               { "filt_index", "i" }, { "feat_seln", "i"},
+                               { "list_logic_type", "i" }, { "filt_logic_type", "i"},
+                               { "rssi_high_thres", "i" }, { "rssi_low_thres", "i"},
+                               { "dely_mode", "i" }, { "found_timeout", "i"},
+                               { "lost_timeout", "i" }, { "found_timeout_cnt", "i"}), NULL,
+                       adapter_le_scan_filter_param_setup) },
+       { GDBUS_ASYNC_METHOD("scan_filter_add_remove",
+                       GDBUS_ARGS({ "client_if", "i" }, { "action", "i" },
+                               { "filt_type", "i" }, { "filt_index", "i"},
+                               { "company_id", "i" }, { "company_id_mask", "i"},
+                               { "p_uuid", "ay" }, { "p_uuid_mask", "ay" },
+                               { "string", "s" }, { "address_type", "u" },
+                               /*{ "data_len", "i" },*/ { "p_data", "ay" },
+                               /*{ "mask_len", "i" },*/ { "p_mask", "ay" }), NULL,
+                       adapter_le_scan_filter_add_remove) },
+       { GDBUS_ASYNC_METHOD("scan_filter_clear",
+                       GDBUS_ARGS({ "client_if", "i" }, { "filt_index", "i" }), NULL,
+                       adapter_le_scan_filter_clear) },
+       { GDBUS_ASYNC_METHOD("scan_filter_enable",
+                       GDBUS_ARGS({ "client_if", "i" }, { "enable", "b" }), NULL,
+                       adapter_le_scan_filter_enable) },
+#endif /* scan filter method */
+       { GDBUS_METHOD("SetScanRespData",
+                       GDBUS_ARGS({ "value", "ay" },
+                               { "slot_id", "i" }), NULL,
+                       adapter_set_scan_rsp_data) },
+       { GDBUS_METHOD("AddDeviceWhiteList",
+                       GDBUS_ARGS({ "address", "s" },
+                               { "address_type", "u" }), NULL,
+                       adapter_add_device_white_list) },
+       { GDBUS_METHOD("RemoveDeviceWhiteList",
+                       GDBUS_ARGS({ "address", "s" },
+                               { "address_type", "u" }), NULL,
+                       adapter_remove_device_white_list) },
+       { GDBUS_METHOD("ClearDeviceWhiteList",
+                       NULL, NULL,
+                       adapter_clear_device_white_list) },
+       { GDBUS_METHOD("SetLePrivacy",
+                       GDBUS_ARGS({ "enable", "b" }), NULL,
+                       adapter_set_le_privacy) },
+       { GDBUS_ASYNC_METHOD("EnableRssi",
+                       GDBUS_ARGS({ "bt_address", "s" },
+                               { "link_type", "i" },
+                               { "low_th", "i" },
+                               { "in_range_th", "i" },
+                               { "high_th", "i"}),
+                       NULL,
+                       adapter_enable_rssi) },
+       { GDBUS_ASYNC_METHOD("GetRssiStrength",
+                       GDBUS_ARGS({ "bt_address", "s" }, { "link_type", "i" }),
+                       NULL,
+                       adapter_get_rssi) },
+       { GDBUS_ASYNC_METHOD("UnpairDevice",
+                       GDBUS_ARGS({ "device", "o" }), NULL, adapter_unpair_device) },
+       { GDBUS_METHOD("FindDevice",
+                       GDBUS_ARGS({ "address", "s" }),
+                       GDBUS_ARGS({ "device", "o" }),
+                       find_device) },
+#ifdef __BROADCOM_PATCH__
+       { GDBUS_METHOD("SetWbsParameters",
+                       GDBUS_ARGS({ "role", "s" }, { "bt_address", "s" }),
+                       NULL,
+                       set_wbs_parameters) },
+       { GDBUS_METHOD("SetNbParameters",
+                       GDBUS_ARGS({ "role", "s" }, { "bt_address", "s" }),
+                       NULL,
+                       set_nb_parameters) },
+       { GDBUS_METHOD("SetManufacturerData",
+                       GDBUS_ARGS({ "value", "ay" }), NULL,
+                       adapter_set_manufacturer_data) },
+#endif
+       { GDBUS_ASYNC_METHOD("CreateDevice",
+                       GDBUS_ARGS({ "address", "s" }), NULL,
+                       create_device) },
+#endif
+       { GDBUS_ASYNC_METHOD("RemoveDevice",
+                       GDBUS_ARGS({ "device", "o" }), NULL, remove_device) },
+       { }
+};
+
+#ifdef __TIZEN_PATCH__
+static const GDBusSignalTable adapter_signals[] = {
+       { GDBUS_SIGNAL("AdvertisingEnabled",
+                       GDBUS_ARGS({ "slot_id", "i" },
+                                       { "enabled", "b"})) },
+       { GDBUS_SIGNAL("RssiEnabled",
+                       GDBUS_ARGS({"address","s"},
+                                       { "link_type", "i" },
+                                       { "enabled", "b"})) },
+       { GDBUS_SIGNAL("RssiAlert",
+                       GDBUS_ARGS({"address","s"},
+                                       { "link_type", "i" },
+                                       { "alert_type", "i" },
+                                       { "rssi_dbm", "i"})) },
+       { GDBUS_SIGNAL("RawRssi",
+                       GDBUS_ARGS({"address","s"},
+                                       { "link_type", "i" },
+                                       { "rssi_dbm", "i"})) },
+       { GDBUS_SIGNAL("HardwareError", NULL) },
+       { GDBUS_SIGNAL("TxTimeoutError", NULL) },
+       { }
+};
+#endif
+
+static const GDBusPropertyTable adapter_properties[] = {
+       { "Address", "s", property_get_address },
+       { "Name", "s", property_get_name },
+       { "Alias", "s", property_get_alias, property_set_alias },
+       { "Class", "u", property_get_class },
+       { "Powered", "b", property_get_powered, property_set_powered },
+       { "Discoverable", "b", property_get_discoverable,
+                                       property_set_discoverable },
+       { "DiscoverableTimeout", "u", property_get_discoverable_timeout,
+                                       property_set_discoverable_timeout },
+       { "Pairable", "b", property_get_pairable, property_set_pairable },
+       { "PairableTimeout", "u", property_get_pairable_timeout,
+                                       property_set_pairable_timeout },
+       { "Discovering", "b", property_get_discovering },
+#ifdef __TIZEN_PATCH__
+       { "LEDiscovering", "b", property_get_le_discovering },
+#endif
+       { "UUIDs", "as", property_get_uuids },
+       { "Modalias", "s", property_get_modalias, NULL,
+                                       property_exists_modalias },
+#ifdef __TIZEN_PATCH__
+#if 0 // Not used
+       { "SecureConnection", "b", property_get_secure_connection },
+#endif
+       { "Connectable", "b", property_get_connectable,
+                                       property_set_connectable },
+       { "Version", "s", property_get_version },
+       { "SupportedLEFeatures", "as", property_get_supported_le_features},
+#endif
+
+       { }
+};
+
+static int str2buf(const char *str, uint8_t *buf, size_t blen)
+{
+       int i, dlen;
+
+       if (str == NULL)
+               return -EINVAL;
+
+       memset(buf, 0, blen);
+
+       dlen = MIN((strlen(str) / 2), blen);
+
+       for (i = 0; i < dlen; i++)
+               sscanf(str + (i * 2), "%02hhX", &buf[i]);
+
+       return 0;
+}
+
+static struct link_key_info *get_key_info(GKeyFile *key_file, const char *peer)
+{
+       struct link_key_info *info = NULL;
+       char *str;
+
+       str = g_key_file_get_string(key_file, "LinkKey", "Key", NULL);
+       if (!str || strlen(str) < 32)
+               goto failed;
+
+       info = g_new0(struct link_key_info, 1);
+
+       str2ba(peer, &info->bdaddr);
+
+       if (!strncmp(str, "0x", 2))
+               str2buf(&str[2], info->key, sizeof(info->key));
+       else
+               str2buf(&str[0], info->key, sizeof(info->key));
+
+       info->type = g_key_file_get_integer(key_file, "LinkKey", "Type", NULL);
+       info->pin_len = g_key_file_get_integer(key_file, "LinkKey", "PINLength",
+                                               NULL);
+
+failed:
+       g_free(str);
+
+       return info;
+}
+
+static struct smp_ltk_info *get_ltk(GKeyFile *key_file, const char *peer,
+                                       uint8_t peer_type, const char *group)
+{
+       struct smp_ltk_info *ltk = NULL;
+       GError *gerr = NULL;
+       bool master;
+       char *key;
+       char *rand = NULL;
+
+       key = g_key_file_get_string(key_file, group, "Key", NULL);
+       if (!key || strlen(key) < 32)
+               goto failed;
+
+       rand = g_key_file_get_string(key_file, group, "Rand", NULL);
+       if (!rand)
+               goto failed;
+
+       ltk = g_new0(struct smp_ltk_info, 1);
+
+       /* Default to assuming a master key */
+       ltk->master = true;
+
+       str2ba(peer, &ltk->bdaddr);
+       ltk->bdaddr_type = peer_type;
+
+       /*
+        * Long term keys should respond to an identity address which can
+        * either be a public address or a random static address. Keys
+        * stored for resolvable random and unresolvable random addresses
+        * are ignored.
+        *
+        * This is an extra sanity check for older kernel versions or older
+        * daemons that might have been instructed to store long term keys
+        * for these temporary addresses.
+        */
+       if (ltk->bdaddr_type == BDADDR_LE_RANDOM &&
+                                       (ltk->bdaddr.b[5] & 0xc0) != 0xc0) {
+               g_free(ltk);
+               ltk = NULL;
+               goto failed;
+       }
+
+       if (!strncmp(key, "0x", 2))
+               str2buf(&key[2], ltk->val, sizeof(ltk->val));
+       else
+               str2buf(&key[0], ltk->val, sizeof(ltk->val));
+
+       if (!strncmp(rand, "0x", 2)) {
+               uint64_t rand_le;
+               str2buf(&rand[2], (uint8_t *) &rand_le, sizeof(rand_le));
+               ltk->rand = le64_to_cpu(rand_le);
+       } else {
+               sscanf(rand, "%" PRIu64, &ltk->rand);
+       }
+
+       ltk->authenticated = g_key_file_get_integer(key_file, group,
+                                                       "Authenticated", NULL);
+       ltk->enc_size = g_key_file_get_integer(key_file, group, "EncSize",
+                                                                       NULL);
+       ltk->ediv = g_key_file_get_integer(key_file, group, "EDiv", NULL);
+
+       master = g_key_file_get_boolean(key_file, group, "Master", &gerr);
+       if (gerr)
+               g_error_free(gerr);
+       else
+               ltk->master = master;
+
+failed:
+       g_free(key);
+       g_free(rand);
+
+       return ltk;
+}
+
+static GSList *get_ltk_info(GKeyFile *key_file, const char *peer,
+                                                       uint8_t bdaddr_type)
+{
+       struct smp_ltk_info *ltk;
+       GSList *l = NULL;
+
+       DBG("%s", peer);
+
+       ltk = get_ltk(key_file, peer, bdaddr_type, "LongTermKey");
+       if (ltk)
+               l = g_slist_append(l, ltk);
+
+       ltk = get_ltk(key_file, peer, bdaddr_type, "SlaveLongTermKey");
+       if (ltk) {
+               ltk->master = false;
+               l = g_slist_append(l, ltk);
+       }
+
+       return l;
+}
+
+static struct irk_info *get_irk_info(GKeyFile *key_file, const char *peer,
+                                                       uint8_t bdaddr_type)
+{
+       struct irk_info *irk;
+       char *str;
+
+       str = g_key_file_get_string(key_file, "IdentityResolvingKey", "Key", NULL);
+       if (!str || strlen(str) < 32)
+               return NULL;
+
+       irk = g_new0(struct irk_info, 1);
+
+       str2ba(peer, &irk->bdaddr);
+       irk->bdaddr_type = bdaddr_type;
+
+       if (!strncmp(str, "0x", 2))
+               str2buf(&str[2], irk->val, sizeof(irk->val));
+       else
+               str2buf(&str[0], irk->val, sizeof(irk->val));
+
+       g_free(str);
+
+       return irk;
+}
+
+static struct conn_param *get_conn_param(GKeyFile *key_file, const char *peer,
+                                                       uint8_t bdaddr_type)
+{
+       struct conn_param *param;
+
+       if (!g_key_file_has_group(key_file, "ConnectionParameters"))
+               return NULL;
+
+       param = g_new0(struct conn_param, 1);
+
+       param->min_interval = g_key_file_get_integer(key_file,
+                                                       "ConnectionParameters",
+                                                       "MinInterval", NULL);
+       param->max_interval = g_key_file_get_integer(key_file,
+                                                       "ConnectionParameters",
+                                                       "MaxInterval", NULL);
+       param->latency = g_key_file_get_integer(key_file,
+                                                       "ConnectionParameters",
+                                                       "Latency", NULL);
+       param->timeout = g_key_file_get_integer(key_file,
+                                                       "ConnectionParameters",
+                                                       "Timeout", NULL);
+       str2ba(peer, &param->bdaddr);
+       param->bdaddr_type = bdaddr_type;
+
+       return param;
+}
+
+static void load_link_keys_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to load link keys for hci%u: %s (0x%02x)",
+                               adapter->dev_id, mgmt_errstr(status), status);
+               return;
+       }
+
+       DBG("link keys loaded for hci%u", adapter->dev_id);
+}
+
+static void load_link_keys(struct btd_adapter *adapter, GSList *keys,
+                                                       bool debug_keys)
+{
+       struct mgmt_cp_load_link_keys *cp;
+       struct mgmt_link_key_info *key;
+       size_t key_count, cp_size;
+       unsigned int id;
+       GSList *l;
+
+       /*
+        * If the controller does not support BR/EDR operation,
+        * there is no point in trying to load the link keys into
+        * the kernel.
+        *
+        * This is an optimization for Low Energy only controllers.
+        */
+       if (!(adapter->supported_settings & MGMT_SETTING_BREDR))
+               return;
+
+       key_count = g_slist_length(keys);
+
+       DBG("hci%u keys %zu debug_keys %d", adapter->dev_id, key_count,
+                                                               debug_keys);
+
+       cp_size = sizeof(*cp) + (key_count * sizeof(*key));
+
+       cp = g_try_malloc0(cp_size);
+       if (cp == NULL) {
+               error("No memory for link keys for hci%u", adapter->dev_id);
+               return;
+       }
+
+       /*
+        * Even if the list of stored keys is empty, it is important to
+        * load an empty list into the kernel. That way it is ensured
+        * that no old keys from a previous daemon are present.
+        *
+        * In addition it is also the only way to toggle the different
+        * behavior for debug keys.
+        */
+       cp->debug_keys = debug_keys;
+       cp->key_count = htobs(key_count);
+
+       for (l = keys, key = cp->keys; l != NULL; l = g_slist_next(l), key++) {
+               struct link_key_info *info = l->data;
+
+               bacpy(&key->addr.bdaddr, &info->bdaddr);
+               key->addr.type = BDADDR_BREDR;
+               key->type = info->type;
+               memcpy(key->val, info->key, 16);
+               key->pin_len = info->pin_len;
+       }
+
+       id = mgmt_send(adapter->mgmt, MGMT_OP_LOAD_LINK_KEYS,
+                               adapter->dev_id, cp_size, cp,
+                               load_link_keys_complete, adapter, NULL);
+
+       g_free(cp);
+
+       if (id == 0)
+               error("Failed to load link keys for hci%u", adapter->dev_id);
+}
+
+static gboolean load_ltks_timeout(gpointer user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       error("Loading LTKs timed out for hci%u", adapter->dev_id);
+
+       adapter->load_ltks_timeout = 0;
+
+       mgmt_cancel(adapter->mgmt, adapter->load_ltks_id);
+       adapter->load_ltks_id = 0;
+
+       return FALSE;
+}
+
+static void load_ltks_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to load LTKs for hci%u: %s (0x%02x)",
+                               adapter->dev_id, mgmt_errstr(status), status);
+       }
+
+       adapter->load_ltks_id = 0;
+
+       g_source_remove(adapter->load_ltks_timeout);
+       adapter->load_ltks_timeout = 0;
+
+       DBG("LTKs loaded for hci%u", adapter->dev_id);
+}
+
+static void load_ltks(struct btd_adapter *adapter, GSList *keys)
+{
+       struct mgmt_cp_load_long_term_keys *cp;
+       struct mgmt_ltk_info *key;
+       size_t key_count, cp_size;
+       GSList *l;
+
+       /*
+        * If the controller does not support Low Energy operation,
+        * there is no point in trying to load the long term keys
+        * into the kernel.
+        *
+        * While there is no harm in loading keys into the kernel,
+        * this is an optimization to avoid a confusing warning
+        * message when the loading of the keys timed out due to
+        * a kernel bug (see comment below).
+        */
+       if (!(adapter->supported_settings & MGMT_SETTING_LE))
+               return;
+
+       key_count = g_slist_length(keys);
+
+       DBG("hci%u keys %zu", adapter->dev_id, key_count);
+
+       cp_size = sizeof(*cp) + (key_count * sizeof(*key));
+
+       cp = g_try_malloc0(cp_size);
+       if (cp == NULL) {
+               error("No memory for LTKs for hci%u", adapter->dev_id);
+               return;
+       }
+
+       /*
+        * Even if the list of stored keys is empty, it is important to
+        * load an empty list into the kernel. That way it is ensured
+        * that no old keys from a previous daemon are present.
+        */
+       cp->key_count = htobs(key_count);
+
+       for (l = keys, key = cp->keys; l != NULL; l = g_slist_next(l), key++) {
+               struct smp_ltk_info *info = l->data;
+
+               bacpy(&key->addr.bdaddr, &info->bdaddr);
+               key->addr.type = info->bdaddr_type;
+               memcpy(key->val, info->val, sizeof(info->val));
+               key->rand = cpu_to_le64(info->rand);
+               key->ediv = cpu_to_le16(info->ediv);
+               key->type = info->authenticated;
+               key->master = info->master;
+               key->enc_size = info->enc_size;
+       }
+
+       adapter->load_ltks_id = mgmt_send(adapter->mgmt,
+                                       MGMT_OP_LOAD_LONG_TERM_KEYS,
+                                       adapter->dev_id, cp_size, cp,
+                                       load_ltks_complete, adapter, NULL);
+
+       g_free(cp);
+
+       if (adapter->load_ltks_id == 0) {
+               error("Failed to load LTKs for hci%u", adapter->dev_id);
+               return;
+       }
+
+       /*
+        * This timeout handling is needed since the kernel is stupid
+        * and forgets to send a command complete response. However in
+        * case of failures it does send a command status.
+        */
+       adapter->load_ltks_timeout = g_timeout_add_seconds(2,
+                                               load_ltks_timeout, adapter);
+}
+
+static void load_irks_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       if (status == MGMT_STATUS_UNKNOWN_COMMAND) {
+               info("Load IRKs failed: Kernel doesn't support LE Privacy");
+               return;
+       }
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to load IRKs for hci%u: %s (0x%02x)",
+                               adapter->dev_id, mgmt_errstr(status), status);
+               return;
+       }
+
+       DBG("IRKs loaded for hci%u", adapter->dev_id);
+}
+
+static void load_irks(struct btd_adapter *adapter, GSList *irks)
+{
+       struct mgmt_cp_load_irks *cp;
+       struct mgmt_irk_info *irk;
+       size_t irk_count, cp_size;
+       unsigned int id;
+       GSList *l;
+
+       /*
+        * If the controller does not support LE Privacy operation,
+        * there is no support for loading identity resolving keys
+        * into the kernel.
+        */
+       if (!(adapter->supported_settings & MGMT_SETTING_PRIVACY))
+               return;
+
+       irk_count = g_slist_length(irks);
+
+       DBG("hci%u irks %zu", adapter->dev_id, irk_count);
+
+       cp_size = sizeof(*cp) + (irk_count * sizeof(*irk));
+
+       cp = g_try_malloc0(cp_size);
+       if (cp == NULL) {
+               error("No memory for IRKs for hci%u", adapter->dev_id);
+               return;
+       }
+
+       /*
+        * Even if the list of stored keys is empty, it is important to
+        * load an empty list into the kernel. That way we tell the
+        * kernel that we are able to handle New IRK events.
+        */
+       cp->irk_count = htobs(irk_count);
+
+       for (l = irks, irk = cp->irks; l != NULL; l = g_slist_next(l), irk++) {
+               struct irk_info *info = l->data;
+
+               bacpy(&irk->addr.bdaddr, &info->bdaddr);
+               irk->addr.type = info->bdaddr_type;
+               memcpy(irk->val, info->val, sizeof(irk->val));
+       }
+
+       id = mgmt_send(adapter->mgmt, MGMT_OP_LOAD_IRKS, adapter->dev_id,
+                       cp_size, cp, load_irks_complete, adapter, NULL);
+
+       g_free(cp);
+
+       if (id == 0)
+               error("Failed to IRKs for hci%u", adapter->dev_id);
+}
+
+static void load_conn_params_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("hci%u Load Connection Parameters failed: %s (0x%02x)",
+                               adapter->dev_id, mgmt_errstr(status), status);
+               return;
+       }
+
+       DBG("Connection Parameters loaded for hci%u", adapter->dev_id);
+}
+
+static void load_conn_params(struct btd_adapter *adapter, GSList *params)
+{
+       struct mgmt_cp_load_conn_param *cp;
+       struct mgmt_conn_param *param;
+       size_t param_count, cp_size;
+       unsigned int id;
+       GSList *l;
+
+       /*
+        * If the controller does not support Low Energy operation,
+        * there is no point in trying to load the connection
+        * parameters into the kernel.
+        */
+       if (!(adapter->supported_settings & MGMT_SETTING_LE))
+               return;
+
+       param_count = g_slist_length(params);
+
+       DBG("hci%u conn params %zu", adapter->dev_id, param_count);
+
+       cp_size = sizeof(*cp) + (param_count * sizeof(*param));
+
+       cp = g_try_malloc0(cp_size);
+       if (cp == NULL) {
+               error("Failed to allocate memory for connection parameters");
+               return;
+       }
+
+       cp->param_count = htobs(param_count);
+
+       for (l = params, param = cp->params; l; l = g_slist_next(l), param++) {
+               struct conn_param *info = l->data;
+
+               bacpy(&param->addr.bdaddr, &info->bdaddr);
+               param->addr.type = info->bdaddr_type;
+               param->min_interval = htobs(info->min_interval);
+               param->max_interval = htobs(info->max_interval);
+               param->latency = htobs(info->latency);
+               param->timeout = htobs(info->timeout);
+       }
+
+       id = mgmt_send(adapter->mgmt, MGMT_OP_LOAD_CONN_PARAM, adapter->dev_id,
+                       cp_size, cp, load_conn_params_complete, adapter, NULL);
+
+       g_free(cp);
+
+       if (id == 0)
+               error("Load connection parameters failed");
+}
+
+static uint8_t get_le_addr_type(GKeyFile *keyfile)
+{
+       uint8_t addr_type;
+       char *type;
+
+       type = g_key_file_get_string(keyfile, "General", "AddressType", NULL);
+       if (!type)
+               return BDADDR_LE_PUBLIC;
+
+       if (g_str_equal(type, "public"))
+               addr_type = BDADDR_LE_PUBLIC;
+       else if (g_str_equal(type, "static"))
+               addr_type = BDADDR_LE_RANDOM;
+       else
+               addr_type = BDADDR_LE_PUBLIC;
+
+       g_free(type);
+
+       return addr_type;
+}
+
+static void load_devices(struct btd_adapter *adapter)
+{
+       char dirname[PATH_MAX];
+       char srcaddr[18];
+       GSList *keys = NULL;
+       GSList *ltks = NULL;
+       GSList *irks = NULL;
+       GSList *params = NULL;
+       DIR *dir;
+       struct dirent *entry;
+
+       ba2str(&adapter->bdaddr, srcaddr);
+
+       snprintf(dirname, PATH_MAX, STORAGEDIR "/%s", srcaddr);
+
+       dir = opendir(dirname);
+       if (!dir) {
+               error("Unable to open adapter storage directory: %s", dirname);
+               return;
+       }
+
+       while ((entry = readdir(dir)) != NULL) {
+               struct btd_device *device;
+               char filename[PATH_MAX];
+               GKeyFile *key_file;
+               struct link_key_info *key_info;
+               GSList *list, *ltk_info;
+               struct irk_info *irk_info;
+               struct conn_param *param;
+               uint8_t bdaddr_type;
+
+               if (entry->d_type == DT_UNKNOWN)
+                       entry->d_type = util_get_dt(dirname, entry->d_name);
+
+               if (entry->d_type != DT_DIR || bachk(entry->d_name) < 0)
+                       continue;
+
+               snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", srcaddr,
+                               entry->d_name);
+
+               key_file = g_key_file_new();
+               g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+               key_info = get_key_info(key_file, entry->d_name);
+               if (key_info)
+                       keys = g_slist_append(keys, key_info);
+
+               bdaddr_type = get_le_addr_type(key_file);
+
+               ltk_info = get_ltk_info(key_file, entry->d_name, bdaddr_type);
+               ltks = g_slist_concat(ltks, ltk_info);
+
+               irk_info = get_irk_info(key_file, entry->d_name, bdaddr_type);
+               if (irk_info)
+                       irks = g_slist_append(irks, irk_info);
+
+               param = get_conn_param(key_file, entry->d_name, bdaddr_type);
+               if (param)
+                       params = g_slist_append(params, param);
+
+               list = g_slist_find_custom(adapter->devices, entry->d_name,
+                                                       device_address_cmp);
+               if (list) {
+                       device = list->data;
+                       goto device_exist;
+               }
+
+               device = device_create_from_storage(adapter, entry->d_name,
+                                                       key_file);
+               if (!device)
+                       goto free;
+
+               btd_device_set_temporary(device, FALSE);
+               adapter->devices = g_slist_append(adapter->devices, device);
+
+               /* TODO: register services from pre-loaded list of primaries */
+
+               list = btd_device_get_uuids(device);
+               if (list)
+                       device_probe_profiles(device, list);
+
+device_exist:
+               if (key_info) {
+                       device_set_paired(device, BDADDR_BREDR);
+                       device_set_bonded(device, BDADDR_BREDR);
+               }
+
+               if (ltk_info) {
+                       device_set_paired(device, bdaddr_type);
+                       device_set_bonded(device, bdaddr_type);
+               }
+
+free:
+               g_key_file_free(key_file);
+       }
+
+       closedir(dir);
+
+       load_link_keys(adapter, keys, main_opts.debug_keys);
+       g_slist_free_full(keys, g_free);
+
+       load_ltks(adapter, ltks);
+       g_slist_free_full(ltks, g_free);
+       load_irks(adapter, irks);
+       g_slist_free_full(irks, g_free);
+       load_conn_params(adapter, params);
+       g_slist_free_full(params, g_free);
+}
+
+int btd_adapter_block_address(struct btd_adapter *adapter,
+                               const bdaddr_t *bdaddr, uint8_t bdaddr_type)
+{
+       struct mgmt_cp_block_device cp;
+       char addr[18];
+
+       ba2str(bdaddr, addr);
+       DBG("hci%u %s", adapter->dev_id, addr);
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       cp.addr.type = bdaddr_type;
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_BLOCK_DEVICE,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               NULL, NULL, NULL) > 0)
+               return 0;
+
+       return -EIO;
+}
+
+int btd_adapter_unblock_address(struct btd_adapter *adapter,
+                               const bdaddr_t *bdaddr, uint8_t bdaddr_type)
+{
+       struct mgmt_cp_unblock_device cp;
+       char addr[18];
+
+       ba2str(bdaddr, addr);
+       DBG("hci%u %s", adapter->dev_id, addr);
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       cp.addr.type = bdaddr_type;
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_UNBLOCK_DEVICE,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               NULL, NULL, NULL) > 0)
+               return 0;
+
+       return -EIO;
+}
+
+static int clear_blocked(struct btd_adapter *adapter)
+{
+       return btd_adapter_unblock_address(adapter, BDADDR_ANY, 0);
+}
+
+static void probe_driver(struct btd_adapter *adapter, gpointer user_data)
+{
+       struct btd_adapter_driver *driver = user_data;
+       int err;
+
+       if (driver->probe == NULL)
+               return;
+
+       err = driver->probe(adapter);
+       if (err < 0) {
+               error("%s: %s (%d)", driver->name, strerror(-err), -err);
+               return;
+       }
+
+       adapter->drivers = g_slist_prepend(adapter->drivers, driver);
+}
+
+static void load_drivers(struct btd_adapter *adapter)
+{
+       GSList *l;
+
+       for (l = adapter_drivers; l; l = l->next)
+               probe_driver(adapter, l->data);
+}
+
+static void probe_profile(struct btd_profile *profile, void *data)
+{
+       struct btd_adapter *adapter = data;
+       int err;
+
+       if (profile->adapter_probe == NULL)
+               return;
+
+       err = profile->adapter_probe(profile, adapter);
+       if (err < 0) {
+               error("%s: %s (%d)", profile->name, strerror(-err), -err);
+               return;
+       }
+
+       adapter->profiles = g_slist_prepend(adapter->profiles, profile);
+}
+
+void adapter_add_profile(struct btd_adapter *adapter, gpointer p)
+{
+       struct btd_profile *profile = p;
+
+       if (!adapter->initialized)
+               return;
+
+       probe_profile(profile, adapter);
+
+       g_slist_foreach(adapter->devices, device_probe_profile, profile);
+}
+
+void adapter_remove_profile(struct btd_adapter *adapter, gpointer p)
+{
+       struct btd_profile *profile = p;
+
+       if (!adapter->initialized)
+               return;
+
+       if (profile->device_remove)
+               g_slist_foreach(adapter->devices, device_remove_profile, p);
+
+       adapter->profiles = g_slist_remove(adapter->profiles, profile);
+
+       if (profile->adapter_remove)
+               profile->adapter_remove(profile, adapter);
+}
+
+static void adapter_add_connection(struct btd_adapter *adapter,
+                                               struct btd_device *device,
+                                               uint8_t bdaddr_type)
+{
+       device_add_connection(device, bdaddr_type);
+
+       if (g_slist_find(adapter->connections, device)) {
+               error("Device is already marked as connected");
+               return;
+       }
+
+       adapter->connections = g_slist_append(adapter->connections, device);
+}
+
+static void get_connections_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const struct mgmt_rp_get_connections *rp = param;
+       uint16_t i, conn_count;
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to get connections: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
+       }
+
+       if (length < sizeof(*rp)) {
+               error("Wrong size of get connections response");
+               return;
+       }
+
+       conn_count = btohs(rp->conn_count);
+
+       DBG("Connection count: %d", conn_count);
+
+       if (conn_count * sizeof(struct mgmt_addr_info) +
+                                               sizeof(*rp) != length) {
+               error("Incorrect packet size for get connections response");
+               return;
+       }
+
+       for (i = 0; i < conn_count; i++) {
+               const struct mgmt_addr_info *addr = &rp->addr[i];
+               struct btd_device *device;
+               char address[18];
+
+               ba2str(&addr->bdaddr, address);
+               DBG("Adding existing connection to %s", address);
+
+               device = btd_adapter_get_device(adapter, &addr->bdaddr,
+                                                               addr->type);
+               if (device)
+                       adapter_add_connection(adapter, device, addr->type);
+       }
+}
+
+static void load_connections(struct btd_adapter *adapter)
+{
+       DBG("sending get connections command for index %u", adapter->dev_id);
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_GET_CONNECTIONS,
+                               adapter->dev_id, 0, NULL,
+                               get_connections_complete, adapter, NULL) > 0)
+               return;
+
+       error("Failed to get connections for index %u", adapter->dev_id);
+}
+
+bool btd_adapter_get_pairable(struct btd_adapter *adapter)
+{
+       if (adapter->current_settings & MGMT_SETTING_BONDABLE)
+               return true;
+
+       return false;
+}
+
+bool btd_adapter_get_powered(struct btd_adapter *adapter)
+{
+       if (adapter->current_settings & MGMT_SETTING_POWERED)
+               return true;
+
+       return false;
+}
+
+bool btd_adapter_get_connectable(struct btd_adapter *adapter)
+{
+       if (adapter->current_settings & MGMT_SETTING_CONNECTABLE)
+               return true;
+
+       return false;
+}
+
+struct btd_gatt_database *btd_adapter_get_database(struct btd_adapter *adapter)
+{
+       if (!adapter)
+               return NULL;
+
+       return adapter->database;
+}
+
+uint32_t btd_adapter_get_class(struct btd_adapter *adapter)
+{
+       return adapter->dev_class;
+}
+
+const char *btd_adapter_get_name(struct btd_adapter *adapter)
+{
+       if (adapter->stored_alias)
+               return adapter->stored_alias;
+
+       if (adapter->system_name)
+               return adapter->system_name;
+
+       return NULL;
+}
+
+int adapter_connect_list_add(struct btd_adapter *adapter,
+                                       struct btd_device *device)
+{
+       /*
+        * If the adapter->connect_le device is getting added back to
+        * the connect list it probably means that the connect attempt
+        * failed and hence we should clear this pointer
+        */
+       if (device == adapter->connect_le)
+               adapter->connect_le = NULL;
+
+       /*
+        * If kernel background scanning is supported then the
+        * adapter_auto_connect_add() function is used to maintain what to
+        * connect.
+        */
+       if (kernel_conn_control)
+               return 0;
+
+       if (g_slist_find(adapter->connect_list, device)) {
+               DBG("ignoring already added device %s",
+                                               device_get_path(device));
+               goto done;
+       }
+
+       if (!(adapter->supported_settings & MGMT_SETTING_LE)) {
+               error("Can't add %s to non-LE capable adapter connect list",
+                                               device_get_path(device));
+               return -ENOTSUP;
+       }
+
+       adapter->connect_list = g_slist_append(adapter->connect_list, device);
+       DBG("%s added to %s's connect_list", device_get_path(device),
+                                                       adapter->system_name);
+
+done:
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return 0;
+
+       trigger_passive_scanning(adapter);
+
+       return 0;
+}
+
+void adapter_connect_list_remove(struct btd_adapter *adapter,
+                                       struct btd_device *device)
+{
+       /*
+        * If the adapter->connect_le device is being removed from the
+        * connect list it means the connection was successful and hence
+        * the pointer should be cleared
+        */
+       if (device == adapter->connect_le)
+               adapter->connect_le = NULL;
+
+       if (kernel_conn_control)
+               return;
+
+       if (!g_slist_find(adapter->connect_list, device)) {
+               DBG("device %s is not on the list, ignoring",
+                                               device_get_path(device));
+               return;
+       }
+
+       adapter->connect_list = g_slist_remove(adapter->connect_list, device);
+       DBG("%s removed from %s's connect_list", device_get_path(device),
+                                                       adapter->system_name);
+
+       if (!adapter->connect_list) {
+               stop_passive_scanning(adapter);
+               return;
+       }
+
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return;
+
+       trigger_passive_scanning(adapter);
+}
+
+static void add_whitelist_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_rp_add_device *rp = param;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *dev;
+       char addr[18];
+
+       if (length < sizeof(*rp)) {
+               error("Too small Add Device complete event");
+               return;
+       }
+
+       ba2str(&rp->addr.bdaddr, addr);
+
+       dev = btd_adapter_find_device(adapter, &rp->addr.bdaddr,
+                                                       rp->addr.type);
+       if (!dev) {
+               error("Add Device complete for unknown device %s", addr);
+               return;
+       }
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to add device %s: %s (0x%02x)",
+                                       addr, mgmt_errstr(status), status);
+               return;
+       }
+
+       DBG("%s added to kernel whitelist", addr);
+}
+
+void adapter_whitelist_add(struct btd_adapter *adapter, struct btd_device *dev)
+{
+       struct mgmt_cp_add_device cp;
+
+       if (!kernel_conn_control)
+               return;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, device_get_address(dev));
+       cp.addr.type = BDADDR_BREDR;
+       cp.action = 0x01;
+
+       mgmt_send(adapter->mgmt, MGMT_OP_ADD_DEVICE,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               add_whitelist_complete, adapter, NULL);
+}
+
+static void remove_whitelist_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_rp_remove_device *rp = param;
+       char addr[18];
+
+       if (length < sizeof(*rp)) {
+               error("Too small Remove Device complete event");
+               return;
+       }
+
+       ba2str(&rp->addr.bdaddr, addr);
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to remove device %s: %s (0x%02x)",
+                                       addr, mgmt_errstr(status), status);
+               return;
+       }
+
+       DBG("%s removed from kernel whitelist", addr);
+}
+
+void adapter_whitelist_remove(struct btd_adapter *adapter, struct btd_device *dev)
+{
+       struct mgmt_cp_remove_device cp;
+
+       if (!kernel_conn_control)
+               return;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, device_get_address(dev));
+       cp.addr.type = BDADDR_BREDR;
+
+       mgmt_send(adapter->mgmt, MGMT_OP_REMOVE_DEVICE,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               remove_whitelist_complete, adapter, NULL);
+}
+
+static void add_device_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_rp_add_device *rp = param;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *dev;
+       char addr[18];
+
+       if (length < sizeof(*rp)) {
+               error("Too small Add Device complete event");
+               return;
+       }
+
+       ba2str(&rp->addr.bdaddr, addr);
+
+       dev = btd_adapter_find_device(adapter, &rp->addr.bdaddr,
+                                                       rp->addr.type);
+       if (!dev) {
+               error("Add Device complete for unknown device %s", addr);
+               return;
+       }
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to add device %s (%u): %s (0x%02x)",
+                       addr, rp->addr.type, mgmt_errstr(status), status);
+               adapter->connect_list = g_slist_remove(adapter->connect_list,
+                                                                       dev);
+               return;
+       }
+
+       DBG("%s (%u) added to kernel connect list", addr, rp->addr.type);
+}
+
+void adapter_auto_connect_add(struct btd_adapter *adapter,
+                                       struct btd_device *device)
+{
+       struct mgmt_cp_add_device cp;
+       const bdaddr_t *bdaddr;
+       uint8_t bdaddr_type;
+       unsigned int id;
+
+       if (!kernel_conn_control)
+               return;
+
+       if (g_slist_find(adapter->connect_list, device)) {
+               DBG("ignoring already added device %s",
+                                               device_get_path(device));
+               return;
+       }
+
+       bdaddr = device_get_address(device);
+       bdaddr_type = btd_device_get_bdaddr_type(device);
+
+       if (bdaddr_type == BDADDR_BREDR) {
+               DBG("auto-connection feature is not avaiable for BR/EDR");
+               return;
+       }
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       cp.addr.type = bdaddr_type;
+       cp.action = 0x02;
+
+       id = mgmt_send(adapter->mgmt, MGMT_OP_ADD_DEVICE,
+                       adapter->dev_id, sizeof(cp), &cp, add_device_complete,
+                       adapter, NULL);
+       if (id == 0)
+               return;
+
+       adapter->connect_list = g_slist_append(adapter->connect_list, device);
+}
+
+static void remove_device_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_rp_remove_device *rp = param;
+       char addr[18];
+
+       if (length < sizeof(*rp)) {
+               error("Too small Remove Device complete event");
+               return;
+       }
+
+       ba2str(&rp->addr.bdaddr, addr);
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to remove device %s (%u): %s (0x%02x)",
+                       addr, rp->addr.type, mgmt_errstr(status), status);
+               return;
+       }
+
+       DBG("%s (%u) removed from kernel connect list", addr, rp->addr.type);
+}
+
+void adapter_auto_connect_remove(struct btd_adapter *adapter,
+                                       struct btd_device *device)
+{
+       struct mgmt_cp_remove_device cp;
+       const bdaddr_t *bdaddr;
+       uint8_t bdaddr_type;
+       unsigned int id;
+
+       if (!kernel_conn_control)
+               return;
+
+       if (!g_slist_find(adapter->connect_list, device)) {
+               DBG("ignoring not added device %s", device_get_path(device));
+               return;
+       }
+
+       bdaddr = device_get_address(device);
+       bdaddr_type = btd_device_get_bdaddr_type(device);
+
+       if (bdaddr_type == BDADDR_BREDR) {
+               DBG("auto-connection feature is not avaiable for BR/EDR");
+               return;
+       }
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       cp.addr.type = bdaddr_type;
+
+       id = mgmt_send(adapter->mgmt, MGMT_OP_REMOVE_DEVICE,
+                       adapter->dev_id, sizeof(cp), &cp,
+                       remove_device_complete, adapter, NULL);
+       if (id == 0)
+               return;
+
+       adapter->connect_list = g_slist_remove(adapter->connect_list, device);
+}
+
+static void adapter_start(struct btd_adapter *adapter)
+{
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "Powered");
+
+       DBG("adapter %s has been enabled", adapter->path);
+
+       trigger_passive_scanning(adapter);
+}
+
+static void reply_pending_requests(struct btd_adapter *adapter)
+{
+       GSList *l;
+
+       if (!adapter)
+               return;
+
+       /* pending bonding */
+       for (l = adapter->devices; l; l = l->next) {
+               struct btd_device *device = l->data;
+
+               if (device_is_bonding(device, NULL))
+                       device_bonding_failed(device,
+                                               HCI_OE_USER_ENDED_CONNECTION);
+       }
+}
+
+static void remove_driver(gpointer data, gpointer user_data)
+{
+       struct btd_adapter_driver *driver = data;
+       struct btd_adapter *adapter = user_data;
+
+       if (driver->remove)
+               driver->remove(adapter);
+}
+
+static void remove_profile(gpointer data, gpointer user_data)
+{
+       struct btd_profile *profile = data;
+       struct btd_adapter *adapter = user_data;
+
+       if (profile->adapter_remove)
+               profile->adapter_remove(profile, adapter);
+}
+
+static void unload_drivers(struct btd_adapter *adapter)
+{
+       g_slist_foreach(adapter->drivers, remove_driver, adapter);
+       g_slist_free(adapter->drivers);
+       adapter->drivers = NULL;
+
+       g_slist_foreach(adapter->profiles, remove_profile, adapter);
+       g_slist_free(adapter->profiles);
+       adapter->profiles = NULL;
+}
+
+static void free_service_auth(gpointer data, gpointer user_data)
+{
+       struct service_auth *auth = data;
+
+       g_free(auth);
+}
+
+static void adapter_free(gpointer user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       DBG("%p", adapter);
+
+       if (adapter->load_ltks_timeout > 0)
+               g_source_remove(adapter->load_ltks_timeout);
+
+       if (adapter->confirm_name_timeout > 0)
+               g_source_remove(adapter->confirm_name_timeout);
+
+       if (adapter->pair_device_timeout > 0)
+               g_source_remove(adapter->pair_device_timeout);
+
+       if (adapter->auth_idle_id)
+               g_source_remove(adapter->auth_idle_id);
+
+       g_queue_foreach(adapter->auths, free_service_auth, NULL);
+       g_queue_free(adapter->auths);
+
+       /*
+        * Unregister all handlers for this specific index since
+        * the adapter bound to them is no longer valid.
+        *
+        * This also avoids having multiple instances of the same
+        * handler in case indexes got removed and re-added.
+        */
+       mgmt_unregister_index(adapter->mgmt, adapter->dev_id);
+
+       /*
+        * Cancel all pending commands for this specific index
+        * since the adapter bound to them is no longer valid.
+        */
+       mgmt_cancel_index(adapter->mgmt, adapter->dev_id);
+
+       mgmt_unref(adapter->mgmt);
+
+       sdp_list_free(adapter->services, NULL);
+
+       g_slist_free(adapter->connections);
+
+       g_free(adapter->path);
+       g_free(adapter->name);
+       g_free(adapter->short_name);
+       g_free(adapter->system_name);
+       g_free(adapter->stored_alias);
+       g_free(adapter->current_alias);
+       free(adapter->modalias);
+       g_free(adapter);
+}
+
+struct btd_adapter *btd_adapter_ref(struct btd_adapter *adapter)
+{
+       __sync_fetch_and_add(&adapter->ref_count, 1);
+
+       return adapter;
+}
+
+void btd_adapter_unref(struct btd_adapter *adapter)
+{
+       if (__sync_sub_and_fetch(&adapter->ref_count, 1))
+               return;
+
+       if (!adapter->path) {
+               DBG("Freeing adapter %u", adapter->dev_id);
+
+               adapter_free(adapter);
+               return;
+       }
+
+       DBG("Freeing adapter %s", adapter->path);
+
+       g_dbus_unregister_interface(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE);
+}
+
+static void convert_names_entry(char *key, char *value, void *user_data)
+{
+       char *address = user_data;
+       char *str = key;
+       char filename[PATH_MAX];
+       GKeyFile *key_file;
+       char *data;
+       gsize length = 0;
+
+       if (strchr(key, '#'))
+               str[17] = '\0';
+
+       if (bachk(str) != 0)
+               return;
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", address, str);
+       create_file(filename, S_IRUSR | S_IWUSR);
+
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+       g_key_file_set_string(key_file, "General", "Name", value);
+
+       data = g_key_file_to_data(key_file, &length, NULL);
+       g_file_set_contents(filename, data, length, NULL);
+       g_free(data);
+
+       g_key_file_free(key_file);
+}
+
+struct device_converter {
+       char *address;
+       void (*cb)(GKeyFile *key_file, void *value);
+       gboolean force;
+};
+
+static void set_device_type(GKeyFile *key_file, char type)
+{
+       char *techno;
+       char *addr_type = NULL;
+       char *str;
+
+       switch (type) {
+       case BDADDR_BREDR:
+               techno = "BR/EDR";
+               break;
+       case BDADDR_LE_PUBLIC:
+               techno = "LE";
+               addr_type = "public";
+               break;
+       case BDADDR_LE_RANDOM:
+               techno = "LE";
+               addr_type = "static";
+               break;
+       default:
+               return;
+       }
+
+       str = g_key_file_get_string(key_file, "General",
+                                       "SupportedTechnologies", NULL);
+       if (!str)
+               g_key_file_set_string(key_file, "General",
+                                       "SupportedTechnologies", techno);
+       else if (!strstr(str, techno))
+               g_key_file_set_string(key_file, "General",
+                                       "SupportedTechnologies", "BR/EDR;LE");
+
+       g_free(str);
+
+       if (addr_type)
+               g_key_file_set_string(key_file, "General", "AddressType",
+                                       addr_type);
+}
+
+static void convert_aliases_entry(GKeyFile *key_file, void *value)
+{
+       g_key_file_set_string(key_file, "General", "Alias", value);
+}
+
+static void convert_trusts_entry(GKeyFile *key_file, void *value)
+{
+       g_key_file_set_boolean(key_file, "General", "Trusted", TRUE);
+}
+
+static void convert_classes_entry(GKeyFile *key_file, void *value)
+{
+       g_key_file_set_string(key_file, "General", "Class", value);
+}
+
+static void convert_blocked_entry(GKeyFile *key_file, void *value)
+{
+       g_key_file_set_boolean(key_file, "General", "Blocked", TRUE);
+}
+
+static void convert_did_entry(GKeyFile *key_file, void *value)
+{
+       char *vendor_str, *product_str, *version_str;
+       uint16_t val;
+
+       vendor_str = strchr(value, ' ');
+       if (!vendor_str)
+               return;
+
+       *(vendor_str++) = 0;
+
+       if (g_str_equal(value, "FFFF"))
+               return;
+
+       product_str = strchr(vendor_str, ' ');
+       if (!product_str)
+               return;
+
+       *(product_str++) = 0;
+
+       version_str = strchr(product_str, ' ');
+       if (!version_str)
+               return;
+
+       *(version_str++) = 0;
+
+       val = (uint16_t) strtol(value, NULL, 16);
+       g_key_file_set_integer(key_file, "DeviceID", "Source", val);
+
+       val = (uint16_t) strtol(vendor_str, NULL, 16);
+       g_key_file_set_integer(key_file, "DeviceID", "Vendor", val);
+
+       val = (uint16_t) strtol(product_str, NULL, 16);
+       g_key_file_set_integer(key_file, "DeviceID", "Product", val);
+
+       val = (uint16_t) strtol(version_str, NULL, 16);
+       g_key_file_set_integer(key_file, "DeviceID", "Version", val);
+}
+
+static void convert_linkkey_entry(GKeyFile *key_file, void *value)
+{
+       char *type_str, *length_str, *str;
+       int val;
+
+       type_str = strchr(value, ' ');
+       if (!type_str)
+               return;
+
+       *(type_str++) = 0;
+
+       length_str = strchr(type_str, ' ');
+       if (!length_str)
+               return;
+
+       *(length_str++) = 0;
+
+       str = g_strconcat("0x", value, NULL);
+       g_key_file_set_string(key_file, "LinkKey", "Key", str);
+       g_free(str);
+
+       val = strtol(type_str, NULL, 16);
+       g_key_file_set_integer(key_file, "LinkKey", "Type", val);
+
+       val = strtol(length_str, NULL, 16);
+       g_key_file_set_integer(key_file, "LinkKey", "PINLength", val);
+}
+
+static void convert_ltk_entry(GKeyFile *key_file, void *value)
+{
+       char *auth_str, *rand_str, *str;
+       int i, ret;
+       unsigned char auth, master, enc_size;
+       unsigned short ediv;
+
+       auth_str = strchr(value, ' ');
+       if (!auth_str)
+               return;
+
+       *(auth_str++) = 0;
+
+       for (i = 0, rand_str = auth_str; i < 4; i++) {
+               rand_str = strchr(rand_str, ' ');
+               if (!rand_str || rand_str[1] == '\0')
+                       return;
+
+               rand_str++;
+       }
+
+       ret = sscanf(auth_str, " %hhd %hhd %hhd %hd", &auth, &master,
+                                                       &enc_size, &ediv);
+       if (ret < 4)
+               return;
+
+       str = g_strconcat("0x", value, NULL);
+       g_key_file_set_string(key_file, "LongTermKey", "Key", str);
+       g_free(str);
+
+       g_key_file_set_integer(key_file, "LongTermKey", "Authenticated", auth);
+       g_key_file_set_integer(key_file, "LongTermKey", "Master", master);
+       g_key_file_set_integer(key_file, "LongTermKey", "EncSize", enc_size);
+       g_key_file_set_integer(key_file, "LongTermKey", "EDiv", ediv);
+
+       str = g_strconcat("0x", rand_str, NULL);
+       g_key_file_set_string(key_file, "LongTermKey", "Rand", str);
+       g_free(str);
+}
+
+static void convert_profiles_entry(GKeyFile *key_file, void *value)
+{
+       g_strdelimit(value, " ", ';');
+       g_key_file_set_string(key_file, "General", "Services", value);
+}
+
+static void convert_appearances_entry(GKeyFile *key_file, void *value)
+{
+       g_key_file_set_string(key_file, "General", "Appearance", value);
+}
+
+static void convert_entry(char *key, char *value, void *user_data)
+{
+       struct device_converter *converter = user_data;
+       char type = BDADDR_BREDR;
+       char filename[PATH_MAX];
+       GKeyFile *key_file;
+       char *data;
+       gsize length = 0;
+
+       if (strchr(key, '#')) {
+               key[17] = '\0';
+               type = key[18] - '0';
+       }
+
+       if (bachk(key) != 0)
+               return;
+
+       if (converter->force == FALSE) {
+               struct stat st;
+               int err;
+
+               snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s",
+                               converter->address, key);
+
+               err = stat(filename, &st);
+               if (err || !S_ISDIR(st.st_mode))
+                       return;
+       }
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info",
+                       converter->address, key);
+
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+       set_device_type(key_file, type);
+
+       converter->cb(key_file, value);
+
+       data = g_key_file_to_data(key_file, &length, NULL);
+       if (length > 0) {
+               create_file(filename, S_IRUSR | S_IWUSR);
+               g_file_set_contents(filename, data, length, NULL);
+       }
+
+       g_free(data);
+
+       g_key_file_free(key_file);
+}
+
+static void convert_file(char *file, char *address,
+                               void (*cb)(GKeyFile *key_file, void *value),
+                               gboolean force)
+{
+       char filename[PATH_MAX];
+       struct device_converter converter;
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s", address, file);
+
+       converter.address = address;
+       converter.cb = cb;
+       converter.force = force;
+
+       textfile_foreach(filename, convert_entry, &converter);
+}
+
+static gboolean record_has_uuid(const sdp_record_t *rec,
+                               const char *profile_uuid)
+{
+       sdp_list_t *pat;
+
+       for (pat = rec->pattern; pat != NULL; pat = pat->next) {
+               char *uuid;
+               int ret;
+
+               uuid = bt_uuid2string(pat->data);
+               if (!uuid)
+                       continue;
+
+               ret = strcasecmp(uuid, profile_uuid);
+
+               free(uuid);
+
+               if (ret == 0)
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
+static void store_attribute_uuid(GKeyFile *key_file, uint16_t start,
+                                       uint16_t end, char *att_uuid,
+                                       uuid_t uuid)
+{
+       char handle[6], uuid_str[33];
+       int i;
+
+       switch (uuid.type) {
+       case SDP_UUID16:
+               sprintf(uuid_str, "%4.4X", uuid.value.uuid16);
+               break;
+       case SDP_UUID32:
+               sprintf(uuid_str, "%8.8X", uuid.value.uuid32);
+               break;
+       case SDP_UUID128:
+               for (i = 0; i < 16; i++)
+                       sprintf(uuid_str + (i * 2), "%2.2X",
+                                       uuid.value.uuid128.data[i]);
+               break;
+       default:
+               uuid_str[0] = '\0';
+       }
+
+       sprintf(handle, "%hu", start);
+       g_key_file_set_string(key_file, handle, "UUID", att_uuid);
+       g_key_file_set_string(key_file, handle, "Value", uuid_str);
+       g_key_file_set_integer(key_file, handle, "EndGroupHandle", end);
+}
+
+static void store_sdp_record(char *local, char *peer, int handle, char *value)
+{
+       char filename[PATH_MAX];
+       GKeyFile *key_file;
+       char handle_str[11];
+       char *data;
+       gsize length = 0;
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", local, peer);
+
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+       sprintf(handle_str, "0x%8.8X", handle);
+       g_key_file_set_string(key_file, "ServiceRecords", handle_str, value);
+
+       data = g_key_file_to_data(key_file, &length, NULL);
+       if (length > 0) {
+               create_file(filename, S_IRUSR | S_IWUSR);
+               g_file_set_contents(filename, data, length, NULL);
+       }
+
+       g_free(data);
+
+       g_key_file_free(key_file);
+}
+
+static void convert_sdp_entry(char *key, char *value, void *user_data)
+{
+       char *src_addr = user_data;
+       char dst_addr[18];
+       char type = BDADDR_BREDR;
+       int handle, ret;
+       char filename[PATH_MAX];
+       GKeyFile *key_file;
+       struct stat st;
+       sdp_record_t *rec;
+       uuid_t uuid;
+       char *att_uuid, *prim_uuid;
+       uint16_t start = 0, end = 0, psm = 0;
+       int err;
+       char *data;
+       gsize length = 0;
+
+       ret = sscanf(key, "%17s#%hhu#%08X", dst_addr, &type, &handle);
+       if (ret < 3) {
+               ret = sscanf(key, "%17s#%08X", dst_addr, &handle);
+               if (ret < 2)
+                       return;
+       }
+
+       if (bachk(dst_addr) != 0)
+               return;
+
+       /* Check if the device directory has been created as records should
+        * only be converted for known devices */
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s", src_addr, dst_addr);
+
+       err = stat(filename, &st);
+       if (err || !S_ISDIR(st.st_mode))
+               return;
+
+       /* store device records in cache */
+       store_sdp_record(src_addr, dst_addr, handle, value);
+
+       /* Retrieve device record and check if there is an
+        * attribute entry in it */
+       sdp_uuid16_create(&uuid, ATT_UUID);
+       att_uuid = bt_uuid2string(&uuid);
+
+       sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+       prim_uuid = bt_uuid2string(&uuid);
+
+       rec = record_from_string(value);
+
+       if (record_has_uuid(rec, att_uuid))
+               goto failed;
+
+       /* TODO: Do this through btd_gatt_database */
+       if (!gatt_parse_record(rec, &uuid, &psm, &start, &end))
+               goto failed;
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/attributes", src_addr,
+                                                               dst_addr);
+
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+       store_attribute_uuid(key_file, start, end, prim_uuid, uuid);
+
+       data = g_key_file_to_data(key_file, &length, NULL);
+       if (length > 0) {
+               create_file(filename, S_IRUSR | S_IWUSR);
+               g_file_set_contents(filename, data, length, NULL);
+       }
+
+       g_free(data);
+       g_key_file_free(key_file);
+
+failed:
+       sdp_record_free(rec);
+       free(prim_uuid);
+       free(att_uuid);
+}
+
+static void convert_primaries_entry(char *key, char *value, void *user_data)
+{
+       char *address = user_data;
+       int device_type = -1;
+       uuid_t uuid;
+       char **services, **service, *prim_uuid;
+       char filename[PATH_MAX];
+       GKeyFile *key_file;
+       int ret;
+       uint16_t start, end;
+       char uuid_str[MAX_LEN_UUID_STR + 1];
+       char *data;
+       gsize length = 0;
+
+       if (strchr(key, '#')) {
+               key[17] = '\0';
+               device_type = key[18] - '0';
+       }
+
+       if (bachk(key) != 0)
+               return;
+
+       services = g_strsplit(value, " ", 0);
+       if (services == NULL)
+               return;
+
+       sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+       prim_uuid = bt_uuid2string(&uuid);
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/attributes", address,
+                                                                       key);
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+       for (service = services; *service; service++) {
+               ret = sscanf(*service, "%04hX#%04hX#%s", &start, &end,
+                                                               uuid_str);
+               if (ret < 3)
+                       continue;
+
+               bt_string2uuid(&uuid, uuid_str);
+               sdp_uuid128_to_uuid(&uuid);
+
+               store_attribute_uuid(key_file, start, end, prim_uuid, uuid);
+       }
+
+       g_strfreev(services);
+
+       data = g_key_file_to_data(key_file, &length, NULL);
+       if (length == 0)
+               goto end;
+
+       create_file(filename, S_IRUSR | S_IWUSR);
+       g_file_set_contents(filename, data, length, NULL);
+
+       if (device_type < 0)
+               goto end;
+
+       g_free(data);
+       g_key_file_free(key_file);
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", address, key);
+
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+       set_device_type(key_file, device_type);
+
+       data = g_key_file_to_data(key_file, &length, NULL);
+       if (length > 0) {
+               create_file(filename, S_IRUSR | S_IWUSR);
+               g_file_set_contents(filename, data, length, NULL);
+       }
+
+end:
+       g_free(data);
+       free(prim_uuid);
+       g_key_file_free(key_file);
+}
+
+static void convert_ccc_entry(char *key, char *value, void *user_data)
+{
+       char *src_addr = user_data;
+       char dst_addr[18];
+       char type = BDADDR_BREDR;
+       uint16_t handle;
+       int ret, err;
+       char filename[PATH_MAX];
+       GKeyFile *key_file;
+       struct stat st;
+       char group[6];
+       char *data;
+       gsize length = 0;
+
+       ret = sscanf(key, "%17s#%hhu#%04hX", dst_addr, &type, &handle);
+       if (ret < 3)
+               return;
+
+       if (bachk(dst_addr) != 0)
+               return;
+
+       /* Check if the device directory has been created as records should
+        * only be converted for known devices */
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s", src_addr, dst_addr);
+
+       err = stat(filename, &st);
+       if (err || !S_ISDIR(st.st_mode))
+               return;
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/ccc", src_addr,
+                                                               dst_addr);
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+       sprintf(group, "%hu", handle);
+       g_key_file_set_string(key_file, group, "Value", value);
+
+       data = g_key_file_to_data(key_file, &length, NULL);
+       if (length > 0) {
+               create_file(filename, S_IRUSR | S_IWUSR);
+               g_file_set_contents(filename, data, length, NULL);
+       }
+
+       g_free(data);
+       g_key_file_free(key_file);
+}
+
+static void convert_gatt_entry(char *key, char *value, void *user_data)
+{
+       char *src_addr = user_data;
+       char dst_addr[18];
+       char type = BDADDR_BREDR;
+       uint16_t handle;
+       int ret, err;
+       char filename[PATH_MAX];
+       GKeyFile *key_file;
+       struct stat st;
+       char group[6];
+       char *data;
+       gsize length = 0;
+
+       ret = sscanf(key, "%17s#%hhu#%04hX", dst_addr, &type, &handle);
+       if (ret < 3)
+               return;
+
+       if (bachk(dst_addr) != 0)
+               return;
+
+       /* Check if the device directory has been created as records should
+        * only be converted for known devices */
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s", src_addr, dst_addr);
+
+       err = stat(filename, &st);
+       if (err || !S_ISDIR(st.st_mode))
+               return;
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/gatt", src_addr,
+                                                               dst_addr);
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+       sprintf(group, "%hu", handle);
+       g_key_file_set_string(key_file, group, "Value", value);
+
+       data = g_key_file_to_data(key_file, &length, NULL);
+       if (length > 0) {
+               create_file(filename, S_IRUSR | S_IWUSR);
+               g_file_set_contents(filename, data, length, NULL);
+       }
+
+       g_free(data);
+       g_key_file_free(key_file);
+}
+
+static void convert_proximity_entry(char *key, char *value, void *user_data)
+{
+       char *src_addr = user_data;
+       char *alert;
+       char filename[PATH_MAX];
+       GKeyFile *key_file;
+       struct stat st;
+       int err;
+       char *data;
+       gsize length = 0;
+
+       if (!strchr(key, '#'))
+               return;
+
+       key[17] = '\0';
+       alert = &key[18];
+
+       if (bachk(key) != 0)
+               return;
+
+       /* Check if the device directory has been created as records should
+        * only be converted for known devices */
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s", src_addr, key);
+
+       err = stat(filename, &st);
+       if (err || !S_ISDIR(st.st_mode))
+               return;
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/proximity", src_addr,
+                                                                       key);
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+       g_key_file_set_string(key_file, alert, "Level", value);
+
+       data = g_key_file_to_data(key_file, &length, NULL);
+       if (length > 0) {
+               create_file(filename, S_IRUSR | S_IWUSR);
+               g_file_set_contents(filename, data, length, NULL);
+       }
+
+       g_free(data);
+       g_key_file_free(key_file);
+}
+
+static void convert_device_storage(struct btd_adapter *adapter)
+{
+       char filename[PATH_MAX];
+       char address[18];
+
+       ba2str(&adapter->bdaddr, address);
+
+       /* Convert device's name cache */
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/names", address);
+       textfile_foreach(filename, convert_names_entry, address);
+
+       /* Convert aliases */
+       convert_file("aliases", address, convert_aliases_entry, TRUE);
+
+       /* Convert trusts */
+       convert_file("trusts", address, convert_trusts_entry, TRUE);
+
+       /* Convert blocked */
+       convert_file("blocked", address, convert_blocked_entry, TRUE);
+
+       /* Convert profiles */
+       convert_file("profiles", address, convert_profiles_entry, TRUE);
+
+       /* Convert primaries */
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/primaries", address);
+       textfile_foreach(filename, convert_primaries_entry, address);
+
+       /* Convert linkkeys */
+       convert_file("linkkeys", address, convert_linkkey_entry, TRUE);
+
+       /* Convert longtermkeys */
+       convert_file("longtermkeys", address, convert_ltk_entry, TRUE);
+
+       /* Convert classes */
+       convert_file("classes", address, convert_classes_entry, FALSE);
+
+       /* Convert device ids */
+       convert_file("did", address, convert_did_entry, FALSE);
+
+       /* Convert sdp */
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/sdp", address);
+       textfile_foreach(filename, convert_sdp_entry, address);
+
+       /* Convert ccc */
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/ccc", address);
+       textfile_foreach(filename, convert_ccc_entry, address);
+
+       /* Convert appearances */
+       convert_file("appearances", address, convert_appearances_entry, FALSE);
+
+       /* Convert gatt */
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/gatt", address);
+       textfile_foreach(filename, convert_gatt_entry, address);
+
+       /* Convert proximity */
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/proximity", address);
+       textfile_foreach(filename, convert_proximity_entry, address);
+}
+
+static void convert_config(struct btd_adapter *adapter, const char *filename,
+                                                       GKeyFile *key_file)
+{
+       char address[18];
+       char str[MAX_NAME_LENGTH + 1];
+       char config_path[PATH_MAX];
+       int timeout;
+       uint8_t mode;
+       char *data;
+       gsize length = 0;
+
+       ba2str(&adapter->bdaddr, address);
+       snprintf(config_path, PATH_MAX, STORAGEDIR "/%s/config", address);
+
+       if (read_pairable_timeout(address, &timeout) == 0)
+               g_key_file_set_integer(key_file, "General",
+                                               "PairableTimeout", timeout);
+
+       if (read_discoverable_timeout(address, &timeout) == 0)
+               g_key_file_set_integer(key_file, "General",
+                                               "DiscoverableTimeout", timeout);
+
+       if (read_on_mode(address, str, sizeof(str)) == 0) {
+               mode = get_mode(str);
+               g_key_file_set_boolean(key_file, "General", "Discoverable",
+                                       mode == MODE_DISCOVERABLE);
+       }
+
+       if (read_local_name(&adapter->bdaddr, str) == 0)
+               g_key_file_set_string(key_file, "General", "Alias", str);
+
+       create_file(filename, S_IRUSR | S_IWUSR);
+
+       data = g_key_file_to_data(key_file, &length, NULL);
+       g_file_set_contents(filename, data, length, NULL);
+       g_free(data);
+}
+
+static void fix_storage(struct btd_adapter *adapter)
+{
+       char filename[PATH_MAX];
+       char address[18];
+       char *converted;
+
+       ba2str(&adapter->bdaddr, address);
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/config", address);
+       converted = textfile_get(filename, "converted");
+       if (!converted)
+               return;
+
+       free(converted);
+
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/names", address);
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/aliases", address);
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/trusts", address);
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/blocked", address);
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/profiles", address);
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/primaries", address);
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/linkkeys", address);
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/longtermkeys", address);
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/classes", address);
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/did", address);
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/sdp", address);
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/ccc", address);
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/appearances", address);
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/gatt", address);
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/proximity", address);
+       textfile_del(filename, "converted");
+}
+
+static void load_config(struct btd_adapter *adapter)
+{
+       GKeyFile *key_file;
+       char filename[PATH_MAX];
+       char address[18];
+       struct stat st;
+       GError *gerr = NULL;
+#ifdef __TIZEN_PATCH__
+       char *str;
+#endif
+
+       ba2str(&adapter->bdaddr, address);
+
+       key_file = g_key_file_new();
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/settings", address);
+
+       if (stat(filename, &st) < 0) {
+               convert_config(adapter, filename, key_file);
+               convert_device_storage(adapter);
+       }
+
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+       /* Get alias */
+       adapter->stored_alias = g_key_file_get_string(key_file, "General",
+                                                               "Alias", NULL);
+       if (!adapter->stored_alias) {
+               /* fallback */
+               adapter->stored_alias = g_key_file_get_string(key_file,
+                                               "General", "Name", NULL);
+       }
+
+       /* Get pairable timeout */
+       adapter->pairable_timeout = g_key_file_get_integer(key_file, "General",
+                                               "PairableTimeout", &gerr);
+       if (gerr) {
+               adapter->pairable_timeout = main_opts.pairto;
+               g_error_free(gerr);
+               gerr = NULL;
+       }
+
+       /* Get discoverable mode */
+       adapter->stored_discoverable = g_key_file_get_boolean(key_file,
+                                       "General", "Discoverable", &gerr);
+       if (gerr) {
+               adapter->stored_discoverable = false;
+               g_error_free(gerr);
+               gerr = NULL;
+       }
+
+       /* Get discoverable timeout */
+       adapter->discoverable_timeout = g_key_file_get_integer(key_file,
+                               "General", "DiscoverableTimeout", &gerr);
+       if (gerr) {
+               adapter->discoverable_timeout = main_opts.discovto;
+               g_error_free(gerr);
+               gerr = NULL;
+       }
+
+#ifdef __TIZEN_PATCH__
+       /* Get Le Privacy feature support */
+       adapter->le_privacy_enabled = main_opts.le_privacy;
+       if (adapter->le_privacy_enabled) {
+               /* Get Local IRK */
+               str = g_key_file_get_string(key_file,
+                               "General", "LocalIrk", &gerr);
+               if (gerr || !str || strlen(str) != 34) {
+                       memset(adapter->local_irk, 0, MGMT_IRK_SIZE);
+                       g_error_free(gerr);
+                       gerr = NULL;
+               } else
+                       str2buf(&str[2], (uint8_t *)adapter->local_irk, MGMT_IRK_SIZE);
+       }
+#endif
+
+       g_key_file_free(key_file);
+}
+
+static struct btd_adapter *btd_adapter_new(uint16_t index)
+{
+       struct btd_adapter *adapter;
+
+       adapter = g_try_new0(struct btd_adapter, 1);
+       if (!adapter)
+               return NULL;
+
+       adapter->dev_id = index;
+       adapter->mgmt = mgmt_ref(mgmt_master);
+       adapter->pincode_requested = false;
+
+       /*
+        * Setup default configuration values. These are either adapter
+        * defaults or from a system wide configuration file.
+        *
+        * Some value might be overwritten later on by adapter specific
+        * configuration. This is to make sure that sane defaults are
+        * always present.
+        */
+       adapter->system_name = g_strdup(main_opts.name);
+       adapter->major_class = (main_opts.class & 0x001f00) >> 8;
+       adapter->minor_class = (main_opts.class & 0x0000fc) >> 2;
+       adapter->modalias = bt_modalias(main_opts.did_source,
+                                               main_opts.did_vendor,
+                                               main_opts.did_product,
+                                               main_opts.did_version);
+       adapter->discoverable_timeout = main_opts.discovto;
+       adapter->pairable_timeout = main_opts.pairto;
+#ifdef __TIZEN_PATCH__
+       adapter->advertising = FALSE;
+#endif
+
+       DBG("System name: %s", adapter->system_name);
+       DBG("Major class: %u", adapter->major_class);
+       DBG("Minor class: %u", adapter->minor_class);
+       DBG("Modalias: %s", adapter->modalias);
+       DBG("Discoverable timeout: %u seconds", adapter->discoverable_timeout);
+       DBG("Pairable timeout: %u seconds", adapter->pairable_timeout);
+#ifdef __TIZEN_PATCH__
+       if (main_opts.le_privacy)
+               DBG("LE Privacy is enabled.");
+       else
+               DBG("LE Privacy is disabled.");
+#endif
+       adapter->auths = g_queue_new();
+
+       return btd_adapter_ref(adapter);
+}
+
+static void adapter_remove(struct btd_adapter *adapter)
+{
+       GSList *l;
+#ifndef __TIZEN_PATCH__
+       struct gatt_db *db;
+#endif
+
+       DBG("Removing adapter %s", adapter->path);
+
+       if (adapter->discovery_idle_timeout > 0) {
+               g_source_remove(adapter->discovery_idle_timeout);
+               adapter->discovery_idle_timeout = 0;
+       }
+
+       if (adapter->temp_devices_timeout > 0) {
+               g_source_remove(adapter->temp_devices_timeout);
+               adapter->temp_devices_timeout = 0;
+       }
+
+       discovery_cleanup(adapter);
+
+       g_slist_free(adapter->connect_list);
+       adapter->connect_list = NULL;
+
+       for (l = adapter->devices; l; l = l->next)
+               device_remove(l->data, FALSE);
+
+       g_slist_free(adapter->devices);
+       adapter->devices = NULL;
+
+       unload_drivers(adapter);
+
+#ifndef __TIZEN_PATCH__
+       db = btd_gatt_database_get_db(adapter->database);
+       gatt_db_unregister(db, adapter->db_id);
+       adapter->db_id = 0;
+
+       btd_gatt_database_destroy(adapter->database);
+       adapter->database = NULL;
+#else
+       btd_adapter_gatt_server_stop(adapter);
+#endif
+
+       g_slist_free(adapter->pin_callbacks);
+       adapter->pin_callbacks = NULL;
+
+       g_slist_free(adapter->msd_callbacks);
+       adapter->msd_callbacks = NULL;
+}
+
+const char *adapter_get_path(struct btd_adapter *adapter)
+{
+       if (!adapter)
+               return NULL;
+
+       return adapter->path;
+}
+
+const bdaddr_t *btd_adapter_get_address(struct btd_adapter *adapter)
+{
+       return &adapter->bdaddr;
+}
+
+static gboolean confirm_name_timeout(gpointer user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       error("Confirm name timed out for hci%u", adapter->dev_id);
+
+       adapter->confirm_name_timeout = 0;
+
+       mgmt_cancel(adapter->mgmt, adapter->confirm_name_id);
+       adapter->confirm_name_id = 0;
+
+       return FALSE;
+}
+
+static void confirm_name_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to confirm name for hci%u: %s (0x%02x)",
+                               adapter->dev_id, mgmt_errstr(status), status);
+       }
+
+       adapter->confirm_name_id = 0;
+
+       g_source_remove(adapter->confirm_name_timeout);
+       adapter->confirm_name_timeout = 0;
+
+       DBG("Confirm name complete for hci%u", adapter->dev_id);
+}
+
+static void confirm_name(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
+                                       uint8_t bdaddr_type, bool name_known)
+{
+       struct mgmt_cp_confirm_name cp;
+       char addr[18];
+
+       ba2str(bdaddr, addr);
+       DBG("hci%d bdaddr %s name_known %u", adapter->dev_id, addr,
+                                                               name_known);
+
+       /*
+        * If the kernel does not answer the confirm name command with
+        * a command complete or command status in time, this might
+        * race against another device found event that also requires
+        * to confirm the name. If there is a pending command, just
+        * cancel it to be safe here.
+        */
+       if (adapter->confirm_name_id > 0) {
+               warn("Found pending confirm name for hci%u", adapter->dev_id);
+               mgmt_cancel(adapter->mgmt, adapter->confirm_name_id);
+       }
+
+       if (adapter->confirm_name_timeout > 0) {
+               g_source_remove(adapter->confirm_name_timeout);
+               adapter->confirm_name_timeout = 0;
+       }
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       cp.addr.type = bdaddr_type;
+       cp.name_known = name_known;
+
+       adapter->confirm_name_id = mgmt_reply(adapter->mgmt,
+                                       MGMT_OP_CONFIRM_NAME,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       confirm_name_complete, adapter, NULL);
+
+       if (adapter->confirm_name_id == 0) {
+               error("Failed to confirm name for hci%u", adapter->dev_id);
+               return;
+       }
+
+       /*
+        * This timeout handling is needed since the kernel is stupid
+        * and forgets to send a command complete response. However in
+        * case of failures it does send a command status.
+        */
+       adapter->confirm_name_timeout = g_timeout_add_seconds(2,
+                                               confirm_name_timeout, adapter);
+}
+
+static void adapter_msd_notify(struct btd_adapter *adapter,
+                                                       struct btd_device *dev,
+                                                       GSList *msd_list)
+{
+       GSList *cb_l, *cb_next;
+       GSList *msd_l, *msd_next;
+
+       for (cb_l = adapter->msd_callbacks; cb_l != NULL; cb_l = cb_next) {
+               btd_msd_cb_t cb = cb_l->data;
+
+               cb_next = g_slist_next(cb_l);
+
+               for (msd_l = msd_list; msd_l != NULL; msd_l = msd_next) {
+                       const struct eir_msd *msd = msd_l->data;
+
+                       msd_next = g_slist_next(msd_l);
+
+                       cb(adapter, dev, msd->company, msd->data,
+                                                               msd->data_len);
+               }
+       }
+}
+
+#ifdef __TIZEN_PATCH__
+static void update_found_devices(struct btd_adapter *adapter,
+                                       const bdaddr_t *bdaddr,
+                                       uint8_t bdaddr_type, int8_t rssi,
+                                       bool confirm, bool legacy, uint8_t adv_type,
+                                       const uint8_t *data, uint8_t data_len)
+#else
+static void update_found_devices(struct btd_adapter *adapter,
+                                       const bdaddr_t *bdaddr,
+                                       uint8_t bdaddr_type, int8_t rssi,
+                                       bool confirm, bool legacy,
+                                       const uint8_t *data, uint8_t data_len)
+#endif
+{
+       struct btd_device *dev;
+       struct eir_data eir_data;
+       bool name_known, discoverable;
+       char addr[18];
+
+       memset(&eir_data, 0, sizeof(eir_data));
+       eir_parse(&eir_data, data, data_len);
+
+       if (bdaddr_type == BDADDR_BREDR)
+               discoverable = true;
+       else
+               discoverable = eir_data.flags & (EIR_LIM_DISC | EIR_GEN_DISC);
+
+       ba2str(bdaddr, addr);
+
+       dev = btd_adapter_find_device(adapter, bdaddr, bdaddr_type);
+       if (!dev) {
+               /*
+                * If no client has requested discovery or the device is
+                * not marked as discoverable, then do not create new
+                * device objects.
+                */
+#ifdef __TIZEN_PATCH__
+               /*DBG("List BREDR:%p LE:%p Discoverable:%d", adapter->discovery_list,
+                       adapter->le_discovery_list, discoverable);*/
+               if ((adapter->discovery_list == NULL &&
+                               adapter->le_discovery_list == NULL) || !discoverable) {
+                               DBG("discovery list is NULL");
+                       eir_data_free(&eir_data);
+                       return;
+               }
+#else
+               if (!adapter->discovery_list || !discoverable) {
+                       eir_data_free(&eir_data);
+                       return;
+               }
+#endif
+
+               dev = adapter_create_device(adapter, bdaddr, bdaddr_type);
+       }
+
+       if (!dev) {
+               error("Unable to create object for found device %s", addr);
+               eir_data_free(&eir_data);
+               return;
+       }
+
+       device_update_last_seen(dev, bdaddr_type);
+
+       /*
+        * FIXME: We need to check for non-zero flags first because
+        * older kernels send separate adv_ind and scan_rsp. Newer
+        * kernels send them merged, so once we know which mgmt version
+        * supports this we can make the non-zero check conditional.
+        */
+       if (bdaddr_type != BDADDR_BREDR && eir_data.flags &&
+                                       !(eir_data.flags & EIR_BREDR_UNSUP))
+               device_set_bredr_support(dev);
+
+       if (eir_data.name != NULL && eir_data.name_complete)
+               device_store_cached_name(dev, eir_data.name);
+
+       /*
+        * If no client has requested discovery, then only update
+        * already paired devices (skip temporary ones).
+        */
+#ifdef __TIZEN_PATCH__
+       if (device_is_temporary(dev) && adapter->discovery_list == NULL &&
+                       adapter->le_discovery_list == NULL) {
+               DBG("discovery list is NULL");
+               eir_data_free(&eir_data);
+               return;
+       }
+
+       device_set_last_addr_type(dev, bdaddr_type);
+#else
+       if (device_is_temporary(dev) && !adapter->discovery_list) {
+               eir_data_free(&eir_data);
+               return;
+       }
+#endif
+
+       device_set_legacy(dev, legacy);
+       device_set_rssi(dev, rssi);
+
+       if (eir_data.appearance != 0)
+               device_set_appearance(dev, eir_data.appearance);
+
+       /* Report an unknown name to the kernel even if there is a short name
+        * known, but still update the name with the known short name. */
+#ifdef __TIZEN_PATCH__
+       if (eir_data.name_complete)
+               name_known = device_name_known(dev);
+       else
+               name_known = false;
+#else
+       name_known = device_name_known(dev);
+#endif
+
+       if (eir_data.name && (eir_data.name_complete || !name_known))
+               btd_device_device_set_name(dev, eir_data.name);
+
+       if (eir_data.class != 0)
+               device_set_class(dev, eir_data.class);
+
+       if (eir_data.did_source || eir_data.did_vendor ||
+                       eir_data.did_product || eir_data.did_version)
+               btd_device_set_pnpid(dev, eir_data.did_source,
+                                                       eir_data.did_vendor,
+                                                       eir_data.did_product,
+                                                       eir_data.did_version);
+
+       device_add_eir_uuids(dev, eir_data.services);
+
+#ifdef __TIZEN_PATCH__
+       if (eir_data.flags != 0)
+               device_set_remote_feature_flag(dev, eir_data.flags);
+
+       if (bdaddr_type == BDADDR_BREDR)
+               device_set_manufacturer_info(dev, &eir_data);
+       else
+               device_set_adv_report_info(dev, (void*)data, data_len, adv_type);
+#endif
+
+       if (eir_data.msd_list)
+               adapter_msd_notify(adapter, dev, eir_data.msd_list);
+
+       eir_data_free(&eir_data);
+
+       /*
+        * Only if at least one client has requested discovery, maintain
+        * list of found devices and name confirming for legacy devices.
+        * Otherwise, this is an event from passive discovery and we
+        * should check if the device needs connecting to.
+        */
+#ifdef __TIZEN_PATCH__
+       if (!adapter->discovery_list && !adapter->le_discovery_list)
+#else
+       if (!adapter->discovery_list)
+#endif
+               goto connect_le;
+
+       if (g_slist_find(adapter->discovery_found, dev))
+               return;
+
+       if (confirm)
+               confirm_name(adapter, bdaddr, bdaddr_type, name_known);
+
+       adapter->discovery_found = g_slist_prepend(adapter->discovery_found,
+                                                                       dev);
+
+       return;
+
+connect_le:
+       /*
+        * If we're in the process of stopping passive scanning and
+        * connecting another (or maybe even the same) LE device just
+        * ignore this one.
+        */
+       if (adapter->connect_le)
+               return;
+
+       /*
+        * If kernel background scan is used then the kernel is
+        * responsible for connecting.
+        */
+       if (kernel_conn_control)
+               return;
+
+       /*
+        * If this is an LE device that's not connected and part of the
+        * connect_list stop passive scanning so that a connection
+        * attempt to it can be made
+        */
+       if (bdaddr_type != BDADDR_BREDR && !btd_device_is_connected(dev) &&
+                               g_slist_find(adapter->connect_list, dev)) {
+               adapter->connect_le = dev;
+               stop_passive_scanning(adapter);
+       }
+}
+
+static void device_found_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_device_found *ev = param;
+       struct btd_adapter *adapter = user_data;
+       const uint8_t *eir;
+       uint16_t eir_len;
+       uint32_t flags;
+       bool confirm_name;
+       bool legacy;
+       char addr[18];
+
+       if (length < sizeof(*ev)) {
+               error("Too short device found event (%u bytes)", length);
+               return;
+       }
+
+       eir_len = btohs(ev->eir_len);
+       if (length != sizeof(*ev) + eir_len) {
+               error("Device found event size mismatch (%u != %zu)",
+                                       length, sizeof(*ev) + eir_len);
+               return;
+       }
+
+       if (eir_len == 0)
+               eir = NULL;
+       else
+               eir = ev->eir;
+
+       flags = btohl(ev->flags);
+
+       ba2str(&ev->addr.bdaddr, addr);
+       DBG("hci%u addr %s, rssi %d flags 0x%04x eir_len %u",
+                       index, addr, ev->rssi, flags, eir_len);
+
+#ifndef __TIZEN_PATCH__
+       /* Ignore non-connectable events for now */
+       if (flags & MGMT_DEV_FOUND_NOT_CONNECTABLE)
+               return;
+#endif
+
+       confirm_name = (flags & MGMT_DEV_FOUND_CONFIRM_NAME);
+       legacy = (flags & MGMT_DEV_FOUND_LEGACY_PAIRING);
+
+#ifdef __TIZEN_PATCH__
+       update_found_devices(adapter, &ev->addr.bdaddr, ev->addr.type,
+                                       ev->rssi, confirm_name, legacy, 0,
+                                       eir, eir_len);
+#else
+       update_found_devices(adapter, &ev->addr.bdaddr, ev->addr.type,
+                                       ev->rssi, confirm_name, legacy,
+                                       eir, eir_len);
+#endif
+}
+
+#ifdef __TIZEN_PATCH__
+static void le_device_found_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_le_device_found *ev = param;
+       struct btd_adapter *adapter = user_data;
+       const uint8_t *eir;
+       uint16_t eir_len;
+       uint32_t flags;
+       bool confirm_name;
+       bool legacy;
+       char addr[18];
+
+       if (length < sizeof(*ev)) {
+               error("Too short device found event (%u bytes)", length);
+               return;
+       }
+
+       eir_len = btohs(ev->eir_len);
+       if (length != sizeof(*ev) + eir_len) {
+               error("Device found event size mismatch (%u != %zu)",
+                                       length, sizeof(*ev) + eir_len);
+               return;
+       }
+
+       if (eir_len == 0)
+               eir = NULL;
+       else
+               eir = ev->eir;
+
+       flags = btohl(ev->flags);
+
+       ba2str(&ev->addr.bdaddr, addr);
+       DBG("hci%u addr %s, rssi %d flags 0x%04x eir_len %u",
+                       index, addr, ev->rssi, flags, eir_len);
+
+       confirm_name = (flags & MGMT_DEV_FOUND_CONFIRM_NAME);
+       legacy = (flags & MGMT_DEV_FOUND_LEGACY_PAIRING);
+
+       /*DBG("hci%u addr %s, addr_type %d rssi %d flags 0x%04x eir_len %u confirm_name %d legacy %d, adv_type %02x",
+                       index, addr, ev->addr.type, ev->rssi, flags, eir_len, confirm_name, legacy, ev->adv_type);*/
+
+       update_found_devices(adapter, &ev->addr.bdaddr, ev->addr.type,
+                                       ev->rssi, confirm_name, legacy, ev->adv_type,
+                                       eir, eir_len);
+}
+#endif
+
+struct agent *adapter_get_agent(struct btd_adapter *adapter)
+{
+       return agent_get(NULL);
+}
+
+static void adapter_remove_connection(struct btd_adapter *adapter,
+                                               struct btd_device *device,
+                                               uint8_t bdaddr_type)
+{
+       DBG("");
+
+       if (!g_slist_find(adapter->connections, device)) {
+               error("No matching connection for device");
+               return;
+       }
+
+       device_remove_connection(device, bdaddr_type);
+
+       if (device_is_authenticating(device))
+               device_cancel_authentication(device, TRUE);
+
+       /* If another bearer is still connected */
+       if (btd_device_is_connected(device))
+               return;
+
+       adapter->connections = g_slist_remove(adapter->connections, device);
+
+       if (device_is_temporary(device) && !device_is_retrying(device)) {
+               const char *path = device_get_path(device);
+
+               DBG("Removing temporary device %s", path);
+#ifdef __TIZEN_PATCH__
+               /* device_is_paired is added incase of tempoary bonded
+                * oop file transfer in that device is not bonded it's paired.
+                */
+               if (!(device_is_bonded(device, bdaddr_type) ||
+                               device_is_paired(device, bdaddr_type))) {
+                       DBG("addr type %d, bonded", bdaddr_type);
+                       return;
+               }
+
+               btd_adapter_unpair_device(adapter, device);
+#else
+               btd_adapter_remove_device(adapter, device);
+#endif
+       }
+}
+
+static void adapter_stop(struct btd_adapter *adapter)
+{
+       /* check pending requests */
+       reply_pending_requests(adapter);
+
+       cancel_passive_scanning(adapter);
+
+       while (adapter->discovery_list) {
+               struct watch_client *client;
+
+               client = adapter->discovery_list->data;
+
+               /* g_dbus_remove_watch will remove the client from the
+                * adapter's list and free it using the discovery_destroy
+                * function.
+                */
+               g_dbus_remove_watch(dbus_conn, client->watch);
+       }
+
+       adapter->discovering = false;
+
+#ifdef __TIZEN_PATCH__
+       while (adapter->le_discovery_list) {
+               struct watch_client *client;
+
+               client = adapter->le_discovery_list->data;
+
+               /* g_dbus_remove_watch will remove the client from the
+                * adapter's list and free it using the discovery_destroy
+                * function.
+                */
+               g_dbus_remove_watch(dbus_conn, client->watch);
+       }
+
+       adapter->le_discovering = false;
+#endif
+
+       while (adapter->connections) {
+               struct btd_device *device = adapter->connections->data;
+               uint8_t addr_type = btd_device_get_bdaddr_type(device);
+
+               adapter_remove_connection(adapter, device, BDADDR_BREDR);
+               if (addr_type != BDADDR_BREDR)
+                       adapter_remove_connection(adapter, device, addr_type);
+       }
+
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Discovering");
+#ifdef __TIZEN_PATCH__
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "LEDiscovering");
+#endif
+
+       if (adapter->dev_class) {
+               /* the kernel should reset the class of device when powering
+                * down, but it does not. So force it here ... */
+               adapter->dev_class = 0;
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "Class");
+       }
+
+#ifdef __TIZEN_PATCH__
+       advertiser_cleanup(adapter);
+#endif
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "Powered");
+
+       DBG("adapter %s has been disabled", adapter->path);
+}
+
+int btd_register_adapter_driver(struct btd_adapter_driver *driver)
+{
+       adapter_drivers = g_slist_append(adapter_drivers, driver);
+
+       if (driver->probe == NULL)
+               return 0;
+
+       adapter_foreach(probe_driver, driver);
+
+       return 0;
+}
+
+static void unload_driver(struct btd_adapter *adapter, gpointer data)
 {
-       struct btd_adapter *adapter = data;
-       const char *property;
-       DBusMessage *reply;
-       DBusMessageIter iter;
-       DBusMessageIter dict;
-       char str[MAX_NAME_LENGTH + 1], srcaddr[18];
-       gboolean value;
-       char **devices, **uuids;
-       int i;
-       GSList *l;
-       sdp_list_t *list;
-               info("Get properties 1\n");
-       ba2str(&adapter->bdaddr, srcaddr);
+       struct btd_adapter_driver *driver = data;
 
-       if (check_address(srcaddr) < 0)
-               return btd_error_invalid_args(msg);
+       if (driver->remove)
+               driver->remove(adapter);
 
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
+       adapter->drivers = g_slist_remove(adapter->drivers, data);
+}
+
+void btd_unregister_adapter_driver(struct btd_adapter_driver *driver)
+{
+       adapter_drivers = g_slist_remove(adapter_drivers, driver);
+
+       adapter_foreach(unload_driver, driver);
+}
 
-       dbus_message_iter_init_append(reply, &iter);
+static void agent_auth_cb(struct agent *agent, DBusError *derr,
+                                                       void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       struct service_auth *auth = g_queue_pop_head(adapter->auths);
 
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+       if (!auth) {
+               DBG("No pending authorization");
+               return;
+       }
 
-       /* Address */
-       property = srcaddr;
-       dict_append_entry(&dict, "Address", DBUS_TYPE_STRING, &property);
+       auth->cb(derr, auth->user_data);
 
-       /* Name */
-       memset(str, 0, sizeof(str));
-       strncpy(str, (char *) adapter->dev.name, MAX_NAME_LENGTH);
-       property = str;
+       if (auth->agent)
+               agent_unref(auth->agent);
 
-       dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &property);
+       g_free(auth);
 
-       /* Class */
-       dict_append_entry(&dict, "Class",
-                               DBUS_TYPE_UINT32, &adapter->dev_class);
+       /* Stop processing if queue is empty */
+       if (g_queue_is_empty(adapter->auths)) {
+               if (adapter->auth_idle_id > 0)
+                       g_source_remove(adapter->auth_idle_id);
+               return;
+       }
 
-       /* Powered */
-       value = (adapter->up && !adapter->off_requested) ? TRUE : FALSE;
-       dict_append_entry(&dict, "Powered", DBUS_TYPE_BOOLEAN, &value);
+       if (adapter->auth_idle_id > 0)
+               return;
 
-       /* Discoverable */
-       value = adapter->scan_mode & SCAN_INQUIRY ? TRUE : FALSE;
-       dict_append_entry(&dict, "Discoverable", DBUS_TYPE_BOOLEAN, &value);
-#ifdef __TIZEN_PATCH__
-       // Adding limited property for setting limited discoverable mode
-       /* Limited */
-       dict_append_entry(&dict, "Limited", DBUS_TYPE_BOOLEAN,
-                               &adapter->limited);
-#endif
+       adapter->auth_idle_id = g_idle_add(process_auth_queue, adapter);
+}
 
-       /* Pairable */
-       dict_append_entry(&dict, "Pairable", DBUS_TYPE_BOOLEAN,
-                               &adapter->pairable);
+static gboolean process_auth_queue(gpointer user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       DBusError err;
 
-       /* DiscoverableTimeout */
-       dict_append_entry(&dict, "DiscoverableTimeout",
-                               DBUS_TYPE_UINT32, &adapter->discov_timeout);
+       adapter->auth_idle_id = 0;
 
-       /* PairableTimeout */
-       dict_append_entry(&dict, "PairableTimeout",
-                               DBUS_TYPE_UINT32, &adapter->pairable_timeout);
+       dbus_error_init(&err);
+       dbus_set_error_const(&err, ERROR_INTERFACE ".Rejected", NULL);
 
+       while (!g_queue_is_empty(adapter->auths)) {
+               struct service_auth *auth = adapter->auths->head->data;
+               struct btd_device *device = auth->device;
+               const char *dev_path;
 
-       if (adapter->state & (STATE_PINQ | STATE_STDINQ | STATE_LE_SCAN))
-               value = TRUE;
-       else
-               value = FALSE;
+               /* Wait services to be resolved before asking authorization */
+               if (auth->svc_id > 0)
+                       return FALSE;
 
-       /* Discovering */
-       dict_append_entry(&dict, "Discovering", DBUS_TYPE_BOOLEAN, &value);
+/* The below patch should be removed after we provide the API
+ * to control autorization for the specific UUID.
+ */
+               if (device_is_trusted(device) == TRUE) {
+                       auth->cb(NULL, auth->user_data);
+                       goto next;
+               }
 
-       /* Devices */
-       devices = g_new0(char *, g_slist_length(adapter->devices) + 1);
-       for (i = 0, l = adapter->devices; l; l = l->next, i++) {
-               struct btd_device *dev = l->data;
-               devices[i] = (char *) device_get_path(dev);
-       }
-       dict_append_array(&dict, "Devices", DBUS_TYPE_OBJECT_PATH,
-                                                               &devices, i);
-       g_free(devices);
+               /* If agent is set authorization is already ongoing */
+               if (auth->agent)
+                       return FALSE;
 
-       /* UUIDs */
-       uuids = g_new0(char *, sdp_list_len(adapter->services) + 1);
+               auth->agent = agent_get(NULL);
+               if (auth->agent == NULL) {
+                       warn("Authentication attempt without agent");
+                       auth->cb(&err, auth->user_data);
+                       goto next;
+               }
 
-       for (i = 0, list = adapter->services; list; list = list->next) {
-               sdp_record_t *rec = list->data;
-               char *uuid;
+               dev_path = device_get_path(device);
 
-               uuid = bt_uuid2string(&rec->svclass);
-               if (uuid)
-                       uuids[i++] = uuid;
-       }
+               if (agent_authorize_service(auth->agent, dev_path, auth->uuid,
+                                       agent_auth_cb, adapter, NULL) < 0) {
+                       auth->cb(&err, auth->user_data);
+                       goto next;
+               }
+
+               break;
 
-       dict_append_array(&dict, "UUIDs", DBUS_TYPE_STRING, &uuids, i);
+next:
+               if (auth->agent)
+                       agent_unref(auth->agent);
 
-       g_strfreev(uuids);
+               g_free(auth);
+
+               g_queue_pop_head(adapter->auths);
+       }
 
-       dbus_message_iter_close_container(&iter, &dict);
+       dbus_error_free(&err);
 
-       return reply;
+       return FALSE;
 }
 
-static DBusMessage *set_property(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
+static void svc_complete(struct btd_device *dev, int err, void *user_data)
 {
-       info(" set_property 1 \n");
-       struct btd_adapter *adapter = data;
-       DBusMessageIter iter;
-       DBusMessageIter sub;
-       const char *property;
-       char srcaddr[18];
+       struct service_auth *auth = user_data;
+       struct btd_adapter *adapter = auth->adapter;
 
-       ba2str(&adapter->bdaddr, srcaddr);
+       auth->svc_id = 0;
 
-       if (!dbus_message_iter_init(msg, &iter))
-               return btd_error_invalid_args(msg);
+       if (adapter->auth_idle_id != 0)
+               return;
 
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-               return btd_error_invalid_args(msg);
+       adapter->auth_idle_id = g_idle_add(process_auth_queue, adapter);
+}
+
+static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
+                                       const char *uuid, service_auth_cb cb,
+                                       void *user_data)
+{
+       struct service_auth *auth;
+       struct btd_device *device;
+       static guint id = 0;
 
-       dbus_message_iter_get_basic(&iter, &property);
-       dbus_message_iter_next(&iter);
+       device = btd_adapter_find_device(adapter, dst, BDADDR_BREDR);
+       if (!device)
+               return 0;
 
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
-               return btd_error_invalid_args(msg);
-       dbus_message_iter_recurse(&iter, &sub);
+       /* Device connected? */
+       if (!g_slist_find(adapter->connections, device))
+               error("Authorization request for non-connected device!?");
 
-       if (g_str_equal("Name", property)) {
-               const char *name;
+       auth = g_try_new0(struct service_auth, 1);
+       if (!auth)
+               return 0;
 
-               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)
-                       return btd_error_invalid_args(msg);
-               dbus_message_iter_get_basic(&sub, &name);
+       auth->cb = cb;
+       auth->user_data = user_data;
+       auth->uuid = uuid;
+       auth->device = device;
+       auth->adapter = adapter;
+       auth->id = ++id;
+       auth->svc_id = device_wait_for_svc_complete(device, svc_complete, auth);
 
-               return set_name(conn, msg, name, data);
-       } else if (g_str_equal("Powered", property)) {
-               gboolean powered;
+       g_queue_push_tail(adapter->auths, auth);
 
-               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
-                       return btd_error_invalid_args(msg);
+       return auth->id;
+}
 
-               dbus_message_iter_get_basic(&sub, &powered);
+guint btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
+                                       const char *uuid, service_auth_cb cb,
+                                       void *user_data)
+{
+       struct btd_adapter *adapter;
+       GSList *l;
 
-               return set_powered(conn, msg, powered, data);
-       } else if (g_str_equal("Discoverable", property)) {
-               gboolean discoverable;
+       if (bacmp(src, BDADDR_ANY) != 0) {
+               adapter = adapter_find(src);
+               if (!adapter)
+                       return 0;
 
-               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
-                       return btd_error_invalid_args(msg);
+               return adapter_authorize(adapter, dst, uuid, cb, user_data);
+       }
 
-               dbus_message_iter_get_basic(&sub, &discoverable);
+       for (l = adapters; l != NULL; l = g_slist_next(l)) {
+               guint id;
 
-               return set_discoverable(conn, msg, discoverable, data);
-#ifdef __TIZEN_PATCH__
-       // Adding limited property for setting limited discoverable mode
-       } else if (g_str_equal("Limited", property)) {
-               gboolean limited;
+               adapter = l->data;
 
-               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
-                       return btd_error_invalid_args(msg);
+               id = adapter_authorize(adapter, dst, uuid, cb, user_data);
+               if (id != 0)
+                       return id;
+       }
 
-               dbus_message_iter_get_basic(&sub, &limited);
+       return 0;
+}
 
-///            return set_limited(conn, msg, limited, data);
-       return btd_error_invalid_args(msg);
-#endif
-       } else if (g_str_equal("DiscoverableTimeout", property)) {
-               uint32_t timeout;
+static struct service_auth *find_authorization(guint id)
+{
+       GSList *l;
+       GList *l2;
 
-               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT32)
-                       return btd_error_invalid_args(msg);
+       for (l = adapters; l != NULL; l = g_slist_next(l)) {
+               struct btd_adapter *adapter = l->data;
 
-               dbus_message_iter_get_basic(&sub, &timeout);
+               for (l2 = adapter->auths->head; l2 != NULL; l2 = l2->next) {
+                       struct service_auth *auth = l2->data;
 
-               return set_discoverable_timeout(conn, msg, timeout, data);
-       } else if (g_str_equal("Pairable", property)) {
-               gboolean pairable;
+                       if (auth->id == id)
+                               return auth;
+               }
+       }
 
-               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
-                       return btd_error_invalid_args(msg);
+       return NULL;
+}
 
-               dbus_message_iter_get_basic(&sub, &pairable);
+int btd_cancel_authorization(guint id)
+{
+       struct service_auth *auth;
 
-               return set_pairable(conn, msg, pairable, data);
-       } else if (g_str_equal("PairableTimeout", property)) {
-               uint32_t timeout;
+       auth = find_authorization(id);
+       if (auth == NULL)
+               return -EPERM;
 
-               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT32)
-                       return btd_error_invalid_args(msg);
+       if (auth->svc_id > 0)
+               device_remove_svc_complete_callback(auth->device,
+                                                               auth->svc_id);
 
-               dbus_message_iter_get_basic(&sub, &timeout);
+       g_queue_remove(auth->adapter->auths, auth);
 
-               return set_pairable_timeout(conn, msg, timeout, data);
+       if (auth->agent) {
+               agent_cancel(auth->agent);
+               agent_unref(auth->agent);
        }
 
-       return btd_error_invalid_args(msg);
+       g_free(auth);
+
+       return 0;
 }
 
-static DBusMessage *request_session(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
+int btd_adapter_restore_powered(struct btd_adapter *adapter)
 {
-       struct btd_adapter *adapter = data;
-       struct session_req *req;
-       const char *sender = dbus_message_get_sender(msg);
-       uint8_t new_mode;
-       int err;
+       if (adapter->current_settings & MGMT_SETTING_POWERED)
+               return 0;
 
-       if (!adapter->agent)
-               return btd_error_agent_not_available(msg);
+       set_mode(adapter, MGMT_OP_SET_POWERED, 0x01);
 
-       if (!adapter->mode_sessions)
-               adapter->global_mode = adapter->mode;
+       return 0;
+}
 
-       new_mode = get_mode(&adapter->bdaddr, "on");
+void btd_adapter_register_pin_cb(struct btd_adapter *adapter,
+                                                       btd_adapter_pin_cb_t cb)
+{
+       adapter->pin_callbacks = g_slist_prepend(adapter->pin_callbacks, cb);
+}
 
-       req = find_session(adapter->mode_sessions, sender);
-       if (req) {
-               session_ref(req);
-               return dbus_message_new_method_return(msg);
-       } else {
-               req = create_session(adapter, conn, msg, new_mode,
-                                       session_owner_exit);
-               adapter->mode_sessions = g_slist_append(adapter->mode_sessions,
-                                                       req);
-       }
+void btd_adapter_unregister_pin_cb(struct btd_adapter *adapter,
+                                                       btd_adapter_pin_cb_t cb)
+{
+       adapter->pin_callbacks = g_slist_remove(adapter->pin_callbacks, cb);
+}
 
-       /* No need to change mode */
-       if (adapter->mode >= new_mode)
-               return dbus_message_new_method_return(msg);
+void btd_adapter_unregister_msd_cb(struct btd_adapter *adapter,
+                                                       btd_msd_cb_t cb)
+{
+       adapter->msd_callbacks = g_slist_remove(adapter->msd_callbacks, cb);
+}
 
-       err = agent_confirm_mode_change(adapter->agent, mode2str(new_mode),
-                                       confirm_mode_cb, req, NULL);
-       if (err < 0) {
-               session_unref(req);
-               return btd_error_failed(msg, strerror(-err));
-       }
+void btd_adapter_register_msd_cb(struct btd_adapter *adapter,
+                                                       btd_msd_cb_t cb)
+{
+       adapter->msd_callbacks = g_slist_prepend(adapter->msd_callbacks, cb);
+}
 
-       return NULL;
+int btd_adapter_set_fast_connectable(struct btd_adapter *adapter,
+                                                       gboolean enable)
+{
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return -EINVAL;
+
+       set_mode(adapter, MGMT_OP_SET_FAST_CONNECTABLE, enable ? 0x01 : 0x00);
+
+       return 0;
 }
 
-static DBusMessage *release_session(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
+int btd_adapter_read_clock(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
+                               int which, int timeout, uint32_t *clock,
+                               uint16_t *accuracy)
 {
-       struct btd_adapter *adapter = data;
-       struct session_req *req;
-       const char *sender = dbus_message_get_sender(msg);
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return -EINVAL;
 
-       req = find_session(adapter->mode_sessions, sender);
-       if (!req)
-               return btd_error_failed(msg, "Invalid Session");
+       return -ENOSYS;
+}
 
-       session_unref(req);
+int btd_adapter_remove_bonding(struct btd_adapter *adapter,
+                               const bdaddr_t *bdaddr, uint8_t bdaddr_type)
+{
+       struct mgmt_cp_unpair_device cp;
 
-       return dbus_message_new_method_return(msg);
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       cp.addr.type = bdaddr_type;
+       cp.disconnect = 1;
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_UNPAIR_DEVICE,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               NULL, NULL, NULL) > 0)
+               return 0;
+
+       return -EIO;
 }
 
-static DBusMessage *list_devices(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
+static void pincode_reply_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       struct btd_adapter *adapter = data;
-       DBusMessage *reply;
-       GSList *l;
-       DBusMessageIter iter;
-       DBusMessageIter array_iter;
-       const gchar *dev_path;
+       struct btd_device *device = user_data;
 
-       if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
-               return btd_error_invalid_args(msg);
+       /* If the MGMT_OP_PIN_CODE_REPLY command is acknowledged, move the
+        * starting time to that point. This give a better sense of time
+        * evaluating the pincode. */
+       device_bonding_restart_timer(device);
+}
 
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
+int btd_adapter_pincode_reply(struct btd_adapter *adapter,
+                                       const bdaddr_t *bdaddr,
+                                       const char *pin, size_t pin_len)
+{
+       struct btd_device *device;
+       unsigned int id;
+       char addr[18];
 
-       dbus_message_iter_init_append(reply, &iter);
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                               DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter);
+       ba2str(bdaddr, addr);
+       DBG("hci%u addr %s pinlen %zu", adapter->dev_id, addr, pin_len);
 
-       for (l = adapter->devices; l; l = l->next) {
-               struct btd_device *device = l->data;
+       if (pin == NULL) {
+               struct mgmt_cp_pin_code_neg_reply cp;
 
-               dev_path = device_get_path(device);
+               memset(&cp, 0, sizeof(cp));
+               bacpy(&cp.addr.bdaddr, bdaddr);
+               cp.addr.type = BDADDR_BREDR;
+
+               id = mgmt_reply(adapter->mgmt, MGMT_OP_PIN_CODE_NEG_REPLY,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       NULL, NULL, NULL);
+       } else {
+               struct mgmt_cp_pin_code_reply cp;
 
-               dbus_message_iter_append_basic(&array_iter,
-                               DBUS_TYPE_OBJECT_PATH, &dev_path);
+               if (pin_len > 16)
+                       return -EINVAL;
+
+               memset(&cp, 0, sizeof(cp));
+               bacpy(&cp.addr.bdaddr, bdaddr);
+               cp.addr.type = BDADDR_BREDR;
+               cp.pin_len = pin_len;
+               memcpy(cp.pin_code, pin, pin_len);
+
+               /* Since a pincode was requested, update the starting time to
+                * the point where the pincode is provided. */
+               device = btd_adapter_find_device(adapter, bdaddr, BDADDR_BREDR);
+               device_bonding_restart_timer(device);
+
+               id = mgmt_reply(adapter->mgmt, MGMT_OP_PIN_CODE_REPLY,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       pincode_reply_complete, device, NULL);
        }
 
-       dbus_message_iter_close_container(&iter, &array_iter);
+       if (id == 0)
+               return -EIO;
 
-       return reply;
+       return 0;
 }
 
-static DBusMessage *cancel_device_creation(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
+int btd_adapter_confirm_reply(struct btd_adapter *adapter,
+                               const bdaddr_t *bdaddr, uint8_t bdaddr_type,
+                               gboolean success)
 {
-       struct btd_adapter *adapter = data;
-       const gchar *address, *sender = dbus_message_get_sender(msg);
+       struct mgmt_cp_user_confirm_reply cp;
+       uint16_t opcode;
+       char addr[18];
+
+       ba2str(bdaddr, addr);
+       DBG("hci%u addr %s success %d", adapter->dev_id, addr, success);
+
+       if (success)
+               opcode = MGMT_OP_USER_CONFIRM_REPLY;
+       else
+               opcode = MGMT_OP_USER_CONFIRM_NEG_REPLY;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       cp.addr.type = bdaddr_type;
+
+       if (mgmt_reply(adapter->mgmt, opcode, adapter->dev_id, sizeof(cp), &cp,
+                                                       NULL, NULL, NULL) > 0)
+               return 0;
+
+       return -EIO;
+}
+
+static void user_confirm_request_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_user_confirm_request *ev = param;
+       struct btd_adapter *adapter = user_data;
        struct btd_device *device;
+       char addr[18];
+       int err;
 
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
-                                               DBUS_TYPE_INVALID) == FALSE)
-               return btd_error_invalid_args(msg);
+       if (length < sizeof(*ev)) {
+               error("Too small user confirm request event");
+               return;
+       }
 
-       if (check_address(address) < 0)
-               return btd_error_invalid_args(msg);
+       ba2str(&ev->addr.bdaddr, addr);
+       DBG("hci%u %s confirm_hint %u", adapter->dev_id, addr,
+                                                       ev->confirm_hint);
+       device = btd_adapter_get_device(adapter, &ev->addr.bdaddr,
+                                                               ev->addr.type);
+       if (!device) {
+               error("Unable to get device object for %s", addr);
+               return;
+       }
 
-       device = adapter_find_device(adapter, address);
-       if (!device || !device_is_creating(device, NULL))
-               return btd_error_does_not_exist(msg);
+       err = device_confirm_passkey(device, btohl(ev->value),
+                                                       ev->confirm_hint);
+       if (err < 0) {
+               error("device_confirm_passkey: %s", strerror(-err));
+               btd_adapter_confirm_reply(adapter, &ev->addr.bdaddr,
+                                                       ev->addr.type, FALSE);
+       }
+}
+
+int btd_adapter_passkey_reply(struct btd_adapter *adapter,
+                               const bdaddr_t *bdaddr, uint8_t bdaddr_type,
+                               uint32_t passkey)
+{
+       unsigned int id;
+       char addr[18];
 
-       if (!device_is_creating(device, sender))
-               return btd_error_not_authorized(msg);
+       ba2str(bdaddr, addr);
+       DBG("hci%u addr %s passkey %06u", adapter->dev_id, addr, passkey);
 
-       device_set_temporary(device, TRUE);
+       if (passkey == INVALID_PASSKEY) {
+               struct mgmt_cp_user_passkey_neg_reply cp;
 
-       if (device_is_connected(device)) {
-               device_request_disconnect(device, msg);
-               return NULL;
+               memset(&cp, 0, sizeof(cp));
+               bacpy(&cp.addr.bdaddr, bdaddr);
+               cp.addr.type = bdaddr_type;
+
+               id = mgmt_reply(adapter->mgmt, MGMT_OP_USER_PASSKEY_NEG_REPLY,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       NULL, NULL, NULL);
+       } else {
+               struct mgmt_cp_user_passkey_reply cp;
+
+               memset(&cp, 0, sizeof(cp));
+               bacpy(&cp.addr.bdaddr, bdaddr);
+               cp.addr.type = bdaddr_type;
+               cp.passkey = htobl(passkey);
+
+               id = mgmt_reply(adapter->mgmt, MGMT_OP_USER_PASSKEY_REPLY,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       NULL, NULL, NULL);
        }
 
-       adapter_remove_device(conn, adapter, device, TRUE);
+       if (id == 0)
+               return -EIO;
 
-       return dbus_message_new_method_return(msg);
+       return 0;
 }
 
-static device_type_t flags2type(uint8_t flags)
+static void user_passkey_request_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       /* Inferring the remote type based on the EIR Flags field */
+       const struct mgmt_ev_user_passkey_request *ev = param;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       char addr[18];
+       int err;
 
-       /* For LE only and dual mode the following flags must be zero */
-       if (flags & (EIR_SIM_CONTROLLER | EIR_SIM_HOST))
-               return DEVICE_TYPE_UNKNOWN;
+       if (length < sizeof(*ev)) {
+               error("Too small passkey request event");
+               return;
+       }
 
-       /* Limited or General discoverable mode bit must be enabled */
-       if (!(flags & (EIR_LIM_DISC | EIR_GEN_DISC)))
-               return DEVICE_TYPE_UNKNOWN;
+       ba2str(&ev->addr.bdaddr, addr);
+       DBG("hci%u %s", index, addr);
 
-       if (flags & EIR_BREDR_UNSUP)
-               return DEVICE_TYPE_LE;
-       else
-               return DEVICE_TYPE_DUALMODE;
+       device = btd_adapter_get_device(adapter, &ev->addr.bdaddr,
+                                                               ev->addr.type);
+       if (!device) {
+               error("Unable to get device object for %s", addr);
+               return;
+       }
+
+       err = device_request_passkey(device);
+       if (err < 0) {
+               error("device_request_passkey: %s", strerror(-err));
+               btd_adapter_passkey_reply(adapter, &ev->addr.bdaddr,
+                                       ev->addr.type, INVALID_PASSKEY);
+       }
 }
 
-static gboolean event_is_connectable(uint8_t type)
+static void user_passkey_notify_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       switch (type) {
-       case ADV_TYPE_IND:
-       case ADV_TYPE_DIRECT_IND:
-               return TRUE;
-       default:
-               return FALSE;
+       const struct mgmt_ev_passkey_notify *ev = param;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       uint32_t passkey;
+       char addr[18];
+       int err;
+
+       if (length < sizeof(*ev)) {
+               error("Too small passkey notify event");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, addr);
+       DBG("hci%u %s", index, addr);
+
+       device = btd_adapter_get_device(adapter, &ev->addr.bdaddr,
+                                                               ev->addr.type);
+       if (!device) {
+               error("Unable to get device object for %s", addr);
+               return;
+       }
+
+       passkey = get_le32(&ev->passkey);
+
+       DBG("passkey %06u entered %u", passkey, ev->entered);
+
+       err = device_notify_passkey(device, passkey, ev->entered);
+       if (err < 0)
+               error("device_notify_passkey: %s", strerror(-err));
+}
+
+#ifdef __TIZEN_PATCH__
+static void rssi_alert_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_vendor_specific_rssi_alert *ev = param;
+       struct btd_adapter *adapter = user_data;
+       char addr[18];
+       char *bt_addr =  NULL;
+       int link_type = -1;
+       int alert_type = -1;
+       int rssi_dbm = 0;
+
+       if (length < sizeof(*ev)) {
+               error("Too small rssi alert event");
+               return;
        }
+
+       ba2str(&ev->bdaddr, addr);
+       DBG("hci%u %s %d", index, addr, ev->link_type);
+       DBG("RSSI Alert Params [%d %d]", ev->alert_type, ev->rssi_dbm);
+
+       bt_addr = (char *)&addr;
+       link_type = ev->link_type;
+       alert_type = ev->alert_type;
+       rssi_dbm = ev->rssi_dbm;
+       g_dbus_emit_signal(dbus_conn, adapter->path,
+                       ADAPTER_INTERFACE, "RssiAlert",
+                       DBUS_TYPE_STRING, &bt_addr,
+                       DBUS_TYPE_INT32, &link_type,
+                       DBUS_TYPE_INT32, &alert_type,
+                       DBUS_TYPE_INT32, &rssi_dbm,
+                       DBUS_TYPE_INVALID);
 }
 
-static struct btd_device *create_device_internal(DBusConnection *conn,
-                                               struct btd_adapter *adapter,
-                                               const gchar *address,
-                                               gboolean force, int *err)
+static void get_raw_rssi_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       struct remote_dev_info *dev, match;
-       struct btd_device *device;
-       device_type_t type;
-
-       memset(&match, 0, sizeof(struct remote_dev_info));
-       str2ba(address, &match.bdaddr);
-       match.name_status = NAME_ANY;
-
-       dev = adapter_search_found_devices(adapter, &match);
-       if (dev && dev->flags)
-               type = flags2type(dev->flags);
-       else
-               type = DEVICE_TYPE_BREDR;
-
-       if (!force && type == DEVICE_TYPE_LE &&
-                                       !event_is_connectable(dev->evt_type)) {
-               if (err)
-                       *err = -ENOTCONN;
+       const struct mgmt_cc_rp_get_raw_rssi *ev = param;
+       struct btd_adapter *adapter = user_data;
+       char addr[18];
+       char *bt_addr =  NULL;
+       int link_type = -1;
+       int rssi_dbm = 0;
 
-               return NULL;
+       if (length < sizeof(*ev)) {
+               error("Too small raw RSSI event");
+               return;
        }
 
-       device = adapter_create_device(conn, adapter, address, type);
-       if (!device && err)
-               *err = -ENOMEM;
+       ba2str(&ev->bt_address, addr);
+       DBG("hci%u %s", index, addr);
+       DBG("Raw RSSI Params [%d %d]", ev->link_type, ev->rssi_dbm);
 
-       return device;
+       bt_addr = (char *)&addr;
+       link_type = ev->link_type;
+       rssi_dbm = ev->rssi_dbm;
+
+       g_dbus_emit_signal(dbus_conn, adapter->path,
+                       ADAPTER_INTERFACE, "RawRssi",
+                       DBUS_TYPE_STRING, &bt_addr,
+                       DBUS_TYPE_INT32, &link_type,
+                       DBUS_TYPE_INT32, &rssi_dbm,
+                       DBUS_TYPE_INVALID);
 }
 
-static DBusMessage *create_device(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
+static void rssi_enabled_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       struct btd_adapter *adapter = data;
-       struct btd_device *device;
-       const gchar *address;
-       DBusMessage *reply;
-       int err;
-
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
-                                               DBUS_TYPE_INVALID) == FALSE)
-               return btd_error_invalid_args(msg);
-
-       if (check_address(address) < 0)
-               return btd_error_invalid_args(msg);
+       const struct mgmt_cc_rsp_enable_rssi *ev = param;
+       struct btd_adapter *adapter = user_data;
+       char addr[18];
+       char *bt_addr =  NULL;
+       int enabled = TRUE;
+       int link_type = -1;
 
-       if (!adapter->up)
-               return btd_error_not_ready(msg);
+       if (length < sizeof(*ev)) {
+               error("Too small rssi enabled event");
+               return;
+       }
 
-       if (adapter_find_device(adapter, address))
-               return btd_error_already_exists(msg);
+       ba2str(&ev->bt_address, addr);
+       DBG("hci%u %s %d", index, addr, ev->link_type);
+       DBG("RSSI Enabled [%d %d]", ev->le_ext_opcode, ev->status);
 
-       DBG("%s", address);
+       bt_addr = (char *)&addr;
+       link_type = ev->link_type;
 
-       device = create_device_internal(conn, adapter, address, TRUE, &err);
-       if (!device)
-               goto failed;
+       g_dbus_emit_signal(dbus_conn, adapter->path,
+                       ADAPTER_INTERFACE, "RssiEnabled",
+                       DBUS_TYPE_STRING, &bt_addr,
+                       DBUS_TYPE_INT32, &link_type,
+                       DBUS_TYPE_BOOLEAN, &enabled,
+                       DBUS_TYPE_INVALID);
+}
 
-       if (device_get_type(device) != DEVICE_TYPE_LE)
-               err = device_browse_sdp(device, conn, msg, NULL, FALSE);
-       else
-               err = device_browse_primary(device, conn, msg, FALSE);
+static void rssi_disabled_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_cc_rp_disable_rssi *ev = param;
+       struct btd_adapter *adapter = user_data;
+       char addr[18];
+       char *bt_addr =  NULL;
+       int disabled = FALSE;
+       int link_type = -1;
 
-       if (err < 0) {
-               adapter_remove_device(conn, adapter, device, TRUE);
-               return btd_error_failed(msg, strerror(-err));
+       if (length < sizeof(*ev)) {
+               error("Too small RSSI disabled event");
+               return;
        }
 
-       return NULL;
-
-failed:
-       if (err == -ENOTCONN) {
-               /* Device is not connectable */
-               const char *path = device_get_path(device);
+       ba2str(&ev->bt_address, addr);
+       DBG("hci%u %s %d", index, addr, ev->link_type);
+       DBG("RSSI Disabled Params [%d %d]", ev->le_ext_opcode, ev->status);
 
-               reply = dbus_message_new_method_return(msg);
+       bt_addr = (char *)&addr;
+       link_type = ev->link_type;
 
-               dbus_message_append_args(reply,
-                               DBUS_TYPE_OBJECT_PATH, &path,
-                               DBUS_TYPE_INVALID);
-       } else
-               reply = btd_error_failed(msg, strerror(-err));
-
-       return reply;
+       g_dbus_emit_signal(dbus_conn, adapter->path,
+                       ADAPTER_INTERFACE, "RssiEnabled",
+                       DBUS_TYPE_STRING, &bt_addr,
+                       DBUS_TYPE_INT32, &link_type,
+                       DBUS_TYPE_BOOLEAN, &disabled,
+                       DBUS_TYPE_INVALID);
 }
 
-static uint8_t parse_io_capability(const char *capability)
+void adapter_check_version(struct btd_adapter *adapter, uint8_t hci_ver)
 {
-       if (g_str_equal(capability, ""))
-               return IO_CAPABILITY_DISPLAYYESNO;
-       if (g_str_equal(capability, "DisplayOnly"))
-               return IO_CAPABILITY_DISPLAYONLY;
-       if (g_str_equal(capability, "DisplayYesNo"))
-               return IO_CAPABILITY_DISPLAYYESNO;
-       if (g_str_equal(capability, "KeyboardOnly"))
-               return IO_CAPABILITY_KEYBOARDONLY;
-       if (g_str_equal(capability, "NoInputNoOutput"))
-               return IO_CAPABILITY_NOINPUTNOOUTPUT;
-       return IO_CAPABILITY_INVALID;
+       char *ver;
+
+       switch (hci_ver) {
+       case 0:
+               ver = "Bluetooth 1.0b";
+               break;
+       case 1:
+               ver = "Bluetooth 1.1";
+               break;
+       case 2:
+               ver = "Bluetooth 1.2";
+               break;
+       case 3:
+               ver = "Bluetooth 2.0 + EDR";
+               break;
+       case 4:
+               ver = "Bluetooth 2.1 + EDR";
+               break;
+       case 5:
+               ver = "Bluetooth 3.0 + HS";
+               break;
+       case 6:
+               ver = "Bluetooth 4.0";
+               break;
+       case 7:
+               ver = "Bluetooth 4.1";
+               break;
+       default:
+               ver = "Unknown";
+               break;
+       }
+
+       if (adapter->version)
+               g_free(adapter->version);
+
+       adapter->version = g_strdup(ver);
 }
-#ifdef __TIZEN_PATCH__
-DBusMessage *adapter_encrypt_link(DBusConnection *conn,
-                                       DBusMessage *msg,
-                                       const char *address,
-                                       dbus_bool_t encrypt,
-                                       void* data)
 
+#if 0 // Not used
+static void new_local_irk_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       struct btd_adapter *adapter = data;
-       struct btd_device *device;
-       char filename[PATH_MAX + 1];
-       bdaddr_t bdaddr;
-       struct hci_conn_info_req *cr;
-       int opt, dd;
-       int dev_id = 0;
+       const struct mgmt_ev_new_local_irk *ev = param;
+       struct btd_adapter *adapter = user_data;
 
-       DBG("handle_authenticate_link_request1");
-        device = adapter_get_device(conn, adapter, address);
+       if (length < sizeof(*ev)) {
+               error("Too small size of Local IRK generated");
+               return;
+       }
 
-       str2ba(address, &bdaddr);
-       /* check if there is a pending discover: requested by D-Bus/non clients */
-       if (0)//todo
+       DBG("Local IRK generated for hci%u", index);
 
-               return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress", "Discover in progress");
+       memset(adapter->local_irk, 0, sizeof(adapter->local_irk));
+       memcpy(adapter->local_irk, (char *)ev->irk, sizeof(adapter->local_irk));
+       store_adapter_info(adapter);
+}
+#endif
 
-       pending_remote_name_cancel(adapter);
+static void hardware_error_callback(uint16_t index, uint16_t length,
+               const void *param, void *user_data)
+{
+       const struct mgmt_ev_hardware_error *ev = param;
+       struct btd_adapter *adapter = user_data;
 
-       if (device_get_bonding(device))
-               return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress", "Bonding in progress");
+       if (length < sizeof(*ev)) {
+               error("Too small Hardware error event");
+               return;
+       }
 
+       error("Hardware error occurred : %d", ev->error_code);
+       g_dbus_emit_signal(dbus_conn, adapter->path,
+                       ADAPTER_INTERFACE, "HardwareError",
+                       DBUS_TYPE_INVALID);
+}
 
-       /*if (adapter_find_auth_request(adapter, &bdaddr))
-               return in_progress(msg, "Bonding in progress");*/
+static void tx_timeout_error_callback(uint16_t index, uint16_t length,
+               const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
 
-       /* check if a link key already exists */
-       create_name(filename, PATH_MAX, STORAGEDIR,address,
-                       "linkkeys");
+       error("Tx Timeout error occurred");
+       g_dbus_emit_signal(dbus_conn, adapter->path,
+                       ADAPTER_INTERFACE, "TxTimeoutError",
+                       DBUS_TYPE_INVALID);
+}
 
-       dd = hci_open_dev(dev_id);
-       if (dd < 0) {
-               return g_dbus_create_error(msg,
-                               ERROR_INTERFACE ".Failed",
-                               "Device open failed");
-       }
+static void device_name_update_callback(uint16_t index, uint16_t length,
+               const void *param, void *user_data)
+{
+       const struct mgmt_ev_device_name_update *ev = param;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       char addr[18];
+       const uint8_t *eir_name;
+       struct eir_data eir_data;
 
-       cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
-       if (!cr) {
-               return NULL;
+       if (length < sizeof(*ev)) {
+               error("Name update error event");
+               return;
        }
 
-       bacpy(&cr->bdaddr, &bdaddr);
-       cr->type = ACL_LINK;
-       if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
-               free(cr);
-               return g_dbus_create_error(msg,
-                               ERROR_INTERFACE ".Failed",
-                               "Getting connection info failed");
-       }
+       ba2str(&ev->addr.bdaddr, addr);
+       DBG("hci%u %s", index, addr);
 
-#if 0
-       if (hci_authenticate_link(dd, htobs(cr->conn_info->handle), 25000) < 0) {
-               free(cr);
-               return g_dbus_create_error(msg,
-                               ERROR_INTERFACE ".Failed",
-                               "Authentication request failed");
+       device = btd_adapter_get_device(adapter, &ev->addr.bdaddr,
+                                                               ev->addr.type);
+       if (!device) {
+               error("Unable to get device object for %s", addr);
+               return;
        }
 
-#endif
-       info("Encrypt value   %d",encrypt);
-       if (hci_encrypt_link(dd, htobs(cr->conn_info->handle), encrypt, 25000) < 0) {
-               free(cr);
-               return g_dbus_create_error(msg,
-                               ERROR_INTERFACE ".Failed",
-                               "Encryption request failed");
-       }
+       if (ev->eir_len == 0)
+               return;
 
-       DBG("handle_authenticate_link_request2");
-       free(cr);
+       eir_name = ev->eir;
 
-       hci_close_dev(dd);
+       memset(&eir_data, 0, sizeof(eir_data));
+       eir_parse(&eir_data, eir_name, ev->eir_len);
 
-       return dbus_message_new_method_return(msg);
+       if (eir_data.name)
+               btd_device_device_set_name(device, eir_data.name);
 
+       eir_data_free(&eir_data);
 }
-#endif
 
+static void multi_adv_state_change_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_vendor_specific_multi_adv_state_changed *ev = param;
 
+       if (length < sizeof(*ev)) {
+               error("Too small adv state change event");
+               return;
+       }
 
+       DBG("adv id %d, state change reason %d, connection_handle %x",
+               ev->adv_instance, ev->state_change_reason, ev->connection_handle);
 
-#ifdef __TIZEN_PATCH__
-static DBusMessage *authenticate_link(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       struct btd_adapter *adapter = data;
-       struct btd_device *device;
-       const gchar *address, *agent_path, *capability, *sender;
-       uint8_t cap;
-       info("authenticate_link 1\n");
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
-                                       DBUS_TYPE_OBJECT_PATH, &agent_path,
-                                       DBUS_TYPE_STRING, &capability,
-                                               DBUS_TYPE_INVALID) == FALSE)
-               return btd_error_invalid_args(msg);
-      info("authenticate_link 2\n");
-       if (check_address(address) < 0)
-               return btd_error_invalid_args(msg);
-       info("authenticate_link 3\n");
-       sender = dbus_message_get_sender(msg);
-       if (adapter->agent &&
-                       agent_matches(adapter->agent, sender, agent_path)) {
-               error("Refusing adapter agent usage as device specific one");
-               return btd_error_invalid_args(msg);
-       }
-       info("authenticate_link 4\n");
-       cap = parse_io_capability(capability);
-       if (cap == IO_CAPABILITY_INVALID)
-               return btd_error_invalid_args(msg);
-       info("authenticate_link 5\n");
-       device = adapter_get_device(conn, adapter, address);
-       if (!device)
-               return g_dbus_create_error(msg,
-                               ERROR_INTERFACE ".Failed",
-                               "Unable to create a new device object");
-       info("authenticate_link 5\n");
-       return device_jsr82_authenticate_link(device, conn, msg, agent_path, cap);
+       if ((ev->adv_instance > 0 && ev->adv_instance < adapter_le_get_max_adv_instance()) &&
+                       ev->state_change_reason == 0)
+               adapter_le_enable_multi_adv(TRUE, ev->adv_instance);
 }
 #endif
 
-#ifdef __TIZEN_PATCH__
-static DBusMessage *encrypt_connection(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
+struct btd_adapter_pin_cb_iter *btd_adapter_pin_cb_iter_new(
+                                               struct btd_adapter *adapter)
 {
-       struct btd_adapter *adapter = data;
-       gboolean encrypt = FALSE;
-       DBG("encrypt_link");
-       info("encrypt_connection value  1   %d",encrypt);
-       if (!adapter->up)
-               return btd_error_not_ready(msg);
-       DBusMessageIter iter;
-       DBusMessageIter sub;
-       const char *address;
-
-
-       if (!dbus_message_iter_init(msg, &iter))
-               return btd_error_invalid_args(msg);
+       struct btd_adapter_pin_cb_iter *iter =
+                               g_new0(struct btd_adapter_pin_cb_iter, 1);
 
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-               return btd_error_invalid_args(msg);
+       iter->it = adapter->pin_callbacks;
+       iter->attempt = 1;
 
-       dbus_message_iter_get_basic(&iter, &address);
-       dbus_message_iter_next(&iter);
+       return iter;
+}
 
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
-               return btd_error_invalid_args(msg);
-       dbus_message_iter_recurse(&iter, &sub);
+void btd_adapter_pin_cb_iter_free(struct btd_adapter_pin_cb_iter *iter)
+{
+       g_free(iter);
+}
 
-       if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
-               return btd_error_invalid_args(msg);
+bool btd_adapter_pin_cb_iter_end(struct btd_adapter_pin_cb_iter *iter)
+{
+       return iter->it == NULL && iter->attempt == 0;
+}
 
-       dbus_message_iter_get_basic(&sub, &encrypt);
-/*     if (!dbus_message_get_args(msg, NULL,
-                               DBUS_TYPE_STRING, &address, DBUS_TYPE_BOOLEAN,&encrypt,
-                               DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);*/
+static ssize_t btd_adapter_pin_cb_iter_next(
+                                       struct btd_adapter_pin_cb_iter *iter,
+                                       struct btd_adapter *adapter,
+                                       struct btd_device *device,
+                                       char *pin_buf, bool *display)
+{
+       btd_adapter_pin_cb_t cb;
+       ssize_t ret;
 
-       info("encrypt_connection value  2   %d",encrypt);
-       return adapter_encrypt_link(conn, msg, address, encrypt, data);
+       while (iter->it != NULL) {
+               cb = iter->it->data;
+               ret = cb(adapter, device, pin_buf, display, iter->attempt);
+               iter->attempt++;
+               if (ret > 0)
+                       return ret;
+               iter->attempt = 1;
+               iter->it = g_slist_next(iter->it);
+       }
+       iter->attempt = 0;
 
+       return 0;
 }
-#endif
-static DBusMessage *create_paired_device(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
+
+static void pin_code_request_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       struct btd_adapter *adapter = data;
+       const struct mgmt_ev_pin_code_request *ev = param;
+       struct btd_adapter *adapter = user_data;
        struct btd_device *device;
-       const gchar *address, *agent_path, *capability, *sender;
-       uint8_t cap;
+       bool display = false;
+       char pin[17];
+       ssize_t pinlen;
+       char addr[18];
        int err;
+       struct btd_adapter_pin_cb_iter *iter;
 
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
-                                       DBUS_TYPE_OBJECT_PATH, &agent_path,
-                                       DBUS_TYPE_STRING, &capability,
-                                       DBUS_TYPE_INVALID) == FALSE)
-               return btd_error_invalid_args(msg);
-
-       if (check_address(address) < 0)
-               return btd_error_invalid_args(msg);
-
-       if (!adapter->up)
-               return btd_error_not_ready(msg);
-
-       sender = dbus_message_get_sender(msg);
-       if (adapter->agent &&
-                       agent_matches(adapter->agent, sender, agent_path)) {
-               error("Refusing adapter agent usage as device specific one");
-               return btd_error_invalid_args(msg);
+       if (length < sizeof(*ev)) {
+               error("Too small PIN code request event");
+               return;
        }
 
-       cap = parse_io_capability(capability);
-       if (cap == IO_CAPABILITY_INVALID)
-               return btd_error_invalid_args(msg);
+       ba2str(&ev->addr.bdaddr, addr);
 
-       device = adapter_find_device(adapter, address);
+       DBG("hci%u %s", adapter->dev_id, addr);
+
+       device = btd_adapter_get_device(adapter, &ev->addr.bdaddr,
+                                                               ev->addr.type);
        if (!device) {
-               device = create_device_internal(conn, adapter, address,
-                                                               FALSE, &err);
-               if (!device)
-                       return btd_error_failed(msg, strerror(-err));
+               error("Unable to get device object for %s", addr);
+               return;
        }
 
-       if (device_get_type(device) != DEVICE_TYPE_LE)
-               return device_create_bonding(device, conn, msg,
-                                                       agent_path, cap);
+       /* Flag the request of a pincode to allow a bonding retry. */
+       adapter->pincode_requested = true;
+#ifdef __TIZEN_PATCH__
+       btd_device_set_legacy_pairing(device, true);
+#endif
 
-       err = device_browse_primary(device, conn, msg, TRUE);
-       if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
+       memset(pin, 0, sizeof(pin));
 
-       return NULL;
+       iter = device_bonding_iter(device);
+       if (iter == NULL)
+               pinlen = 0;
+       else
+               pinlen = btd_adapter_pin_cb_iter_next(iter, adapter, device,
+                                                               pin, &display);
+
+       if (pinlen > 0 && (!ev->secure || pinlen == 16)) {
+               if (display && device_is_bonding(device, NULL)) {
+                       err = device_notify_pincode(device, ev->secure, pin);
+                       if (err < 0) {
+                               error("device_notify_pin: %s", strerror(-err));
+                               btd_adapter_pincode_reply(adapter,
+                                                       &ev->addr.bdaddr,
+                                                       NULL, 0);
+                       }
+               } else {
+                       btd_adapter_pincode_reply(adapter, &ev->addr.bdaddr,
+                                                               pin, pinlen);
+               }
+               return;
+       }
+
+       err = device_request_pincode(device, ev->secure);
+       if (err < 0) {
+               error("device_request_pin: %s", strerror(-err));
+               btd_adapter_pincode_reply(adapter, &ev->addr.bdaddr, NULL, 0);
+       }
 }
 
-static gint device_path_cmp(struct btd_device *device, const gchar *path)
+int adapter_cancel_bonding(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
+                                                       uint8_t addr_type)
 {
-       const gchar *dev_path = device_get_path(device);
+       struct mgmt_addr_info cp;
+       char addr[18];
 
-       return strcasecmp(dev_path, path);
+       ba2str(bdaddr, addr);
+       DBG("hci%u bdaddr %s type %u", adapter->dev_id, addr, addr_type);
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.bdaddr, bdaddr);
+       cp.type = addr_type;
+
+       if (mgmt_reply(adapter->mgmt, MGMT_OP_CANCEL_PAIR_DEVICE,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               NULL, NULL, NULL) > 0)
+               return 0;
+
+       return -EIO;
 }
 
-static DBusMessage *remove_device(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
+static void check_oob_bonding_complete(struct btd_adapter *adapter,
+                                       const bdaddr_t *bdaddr, uint8_t status)
 {
-       struct btd_adapter *adapter = data;
-       struct btd_device *device;
-       const char *path;
-       GSList *l;
+       if (!adapter->oob_handler || !adapter->oob_handler->bonding_cb)
+               return;
 
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-                                               DBUS_TYPE_INVALID) == FALSE)
-               return btd_error_invalid_args(msg);
+       if (bacmp(bdaddr, &adapter->oob_handler->remote_addr) != 0)
+               return;
 
-       l = g_slist_find_custom(adapter->devices,
-                       path, (GCompareFunc) device_path_cmp);
-       if (!l)
-               return btd_error_does_not_exist(msg);
+       adapter->oob_handler->bonding_cb(adapter, bdaddr, status,
+                                       adapter->oob_handler->user_data);
 
-       device = l->data;
+       g_free(adapter->oob_handler);
+       adapter->oob_handler = NULL;
+}
 
-       if (device_is_temporary(device) || device_is_busy(device))
-               return g_dbus_create_error(msg,
-                               ERROR_INTERFACE ".DoesNotExist",
-                               "Device creation in progress");
+static void bonding_complete(struct btd_adapter *adapter,
+                                       const bdaddr_t *bdaddr,
+                                       uint8_t addr_type, uint8_t status)
+{
+       struct btd_device *device;
 
-       device_set_temporary(device, TRUE);
+       if (status == 0)
+               device = btd_adapter_get_device(adapter, bdaddr, addr_type);
+       else
+               device = btd_adapter_find_device(adapter, bdaddr, addr_type);
 
-       if (!device_is_connected(device)) {
-               adapter_remove_device(conn, adapter, device, TRUE);
-               return dbus_message_new_method_return(msg);
-       }
+       if (device != NULL)
+               device_bonding_complete(device, addr_type, status);
 
-       device_request_disconnect(device, msg);
-       return NULL;
+#ifdef __TIZEN_PATCH__
+       //resume_discovery(adapter);
+       //resume_le_discovery(adapter);
+#else
+       resume_discovery(adapter);
+#endif
+       check_oob_bonding_complete(adapter, bdaddr, status);
 }
 
-static DBusMessage *find_device(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
+/* bonding_attempt_complete() handles the end of a "bonding attempt" checking if
+ * it should begin a new attempt or complete the bonding.
+ */
+static void bonding_attempt_complete(struct btd_adapter *adapter,
+                                       const bdaddr_t *bdaddr,
+                                       uint8_t addr_type, uint8_t status)
 {
-       struct btd_adapter *adapter = data;
        struct btd_device *device;
-       DBusMessage *reply;
-       const gchar *address;
-       GSList *l;
-       const gchar *dev_path;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
-                                               DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
-
-       l = g_slist_find_custom(adapter->devices,
-                       address, (GCompareFunc) device_address_cmp);
-       if (!l)
-               return btd_error_does_not_exist(msg);
+       char addr[18];
 
-       device = l->data;
+       ba2str(bdaddr, addr);
+       DBG("hci%u bdaddr %s type %u status 0x%x", adapter->dev_id, addr,
+                                                       addr_type, status);
 
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
+       if (status == 0)
+               device = btd_adapter_get_device(adapter, bdaddr, addr_type);
+       else
+               device = btd_adapter_find_device(adapter, bdaddr, addr_type);
 
-       dev_path = device_get_path(device);
+       if (status == MGMT_STATUS_AUTH_FAILED && adapter->pincode_requested) {
+               /* On faliure, issue a bonding_retry if possible. */
+               if (device != NULL) {
+                       if (device_bonding_attempt_retry(device) == 0)
+                               return;
+               }
+       }
 
-       dbus_message_append_args(reply,
-                               DBUS_TYPE_OBJECT_PATH, &dev_path,
-                               DBUS_TYPE_INVALID);
+       /* Ignore disconnects during retry. */
+       if (status == MGMT_STATUS_DISCONNECTED &&
+                                       device && device_is_retrying(device))
+               return;
 
-       return reply;
+       /* In any other case, finish the bonding. */
+       bonding_complete(adapter, bdaddr, addr_type, status);
 }
 
-static void agent_removed(struct agent *agent, struct btd_adapter *adapter)
+struct pair_device_data {
+       struct btd_adapter *adapter;
+       bdaddr_t bdaddr;
+       uint8_t addr_type;
+};
+
+static void free_pair_device_data(void *user_data)
 {
-       adapter_ops->set_io_capability(adapter->dev_id,
-                                       IO_CAPABILITY_NOINPUTNOOUTPUT);
+       struct pair_device_data *data = user_data;
 
-       adapter->agent = NULL;
+       g_free(data);
 }
 
-static DBusMessage *register_agent(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
+static gboolean pair_device_timeout(gpointer user_data)
 {
-       const char *path, *name, *capability;
-       struct agent *agent;
-       struct btd_adapter *adapter = data;
-       uint8_t cap;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-                       DBUS_TYPE_STRING, &capability, DBUS_TYPE_INVALID))
-               return NULL;
+       struct pair_device_data *data = user_data;
+       struct btd_adapter *adapter = data->adapter;
 
-       if (adapter->agent)
-               return btd_error_already_exists(msg);
+       error("Pair device timed out for hci%u", adapter->dev_id);
 
-       cap = parse_io_capability(capability);
-       if (cap == IO_CAPABILITY_INVALID)
-               return btd_error_invalid_args(msg);
+       adapter->pair_device_timeout = 0;
 
-       name = dbus_message_get_sender(msg);
+       adapter_cancel_bonding(adapter, &data->bdaddr, data->addr_type);
 
-       agent = agent_create(adapter, name, path, cap,
-                               (agent_remove_cb) agent_removed, adapter);
-       if (!agent)
-               return btd_error_failed(msg, "Failed to create a new agent");
+       return FALSE;
+}
 
-       adapter->agent = agent;
+static void pair_device_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_rp_pair_device *rp = param;
+       struct pair_device_data *data = user_data;
+       struct btd_adapter *adapter = data->adapter;
 
-       DBG("Agent registered for hci%d at %s:%s", adapter->dev_id, name,
-                       path);
+       DBG("%s (0x%02x)", mgmt_errstr(status), status);
 
-       adapter_ops->set_io_capability(adapter->dev_id, cap);
+       adapter->pair_device_id = 0;
 
-       return dbus_message_new_method_return(msg);
-}
+       if (adapter->pair_device_timeout > 0) {
+               g_source_remove(adapter->pair_device_timeout);
+               adapter->pair_device_timeout = 0;
+       }
 
-static DBusMessage *unregister_agent(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       const char *path, *name;
-       struct btd_adapter *adapter = data;
+       /* Workaround for a kernel bug
+        *
+        * Broken kernels may reply to device pairing command with command
+        * status instead of command complete event e.g. if adapter was not
+        * powered.
+        */
+       if (status != MGMT_STATUS_SUCCESS && length < sizeof(*rp)) {
+               error("Pair device failed: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
 
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-                                               DBUS_TYPE_INVALID))
-               return NULL;
+               bonding_attempt_complete(adapter, &data->bdaddr,
+                                               data->addr_type, status);
+               return;
+       }
 
-       name = dbus_message_get_sender(msg);
+       if (length < sizeof(*rp)) {
+               error("Too small pair device response");
+               return;
+       }
 
-       if (!adapter->agent || !agent_matches(adapter->agent, name, path))
-               return btd_error_does_not_exist(msg);
+       bonding_attempt_complete(adapter, &rp->addr.bdaddr, rp->addr.type,
+                                                                       status);
+}
 
-       agent_free(adapter->agent);
-       adapter->agent = NULL;
+int adapter_create_bonding(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
+                                       uint8_t addr_type, uint8_t io_cap)
+{
+       if (adapter->pair_device_id > 0) {
+               error("Unable pair since another pairing is in progress");
+               return -EBUSY;
+       }
 
-       return dbus_message_new_method_return(msg);
+#ifndef __TIZEN_PATCH__
+       suspend_discovery(adapter);
+#endif
+       return adapter_bonding_attempt(adapter, bdaddr, addr_type, io_cap);
 }
 
-static GDBusMethodTable adapter_methods[] = {
-       { "GetProperties",      "",     "a{sv}",get_properties          },
-       { "SetProperty",        "sv",   "",     set_property,
-                                               G_DBUS_METHOD_FLAG_ASYNC},
-       { "RequestSession",     "",     "",     request_session,
-                                               G_DBUS_METHOD_FLAG_ASYNC},
-       { "ReleaseSession",     "",     "",     release_session         },
-       { "StartDiscovery",     "",     "",     adapter_start_discovery },
-       { "StopDiscovery",      "",     "",     adapter_stop_discovery,
-                                               G_DBUS_METHOD_FLAG_ASYNC},
-       { "ListDevices",        "",     "ao",   list_devices,
-                                               G_DBUS_METHOD_FLAG_DEPRECATED},
-       { "CreateDevice",       "s",    "o",    create_device,
-                                               G_DBUS_METHOD_FLAG_ASYNC},
-       { "CreatePairedDevice", "sos",  "o",    create_paired_device,
-                                               G_DBUS_METHOD_FLAG_ASYNC},
-       { "CancelDeviceCreation","s",   "",     cancel_device_creation,
-                                               G_DBUS_METHOD_FLAG_ASYNC},
-       { "RemoveDevice",       "o",    "",     remove_device,
-                                               G_DBUS_METHOD_FLAG_ASYNC},
-       { "FindDevice",         "s",    "o",    find_device             },
-       { "RegisterAgent",      "os",   "",     register_agent          },
-       { "UnregisterAgent",    "o",    "",     unregister_agent        },
-
-       #ifdef __TIZEN_PATCH__
-       { "AuthenticateLink","sos",     "o",    authenticate_link, G_DBUS_METHOD_FLAG_ASYNC},
-       { "EncryptLink","sv",   "",     encrypt_connection, G_DBUS_METHOD_FLAG_ASYNC},
-       #endif
-       { }
-};
+/* Starts a new bonding attempt in a fresh new bonding_req or a retried one. */
+int adapter_bonding_attempt(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
+                                       uint8_t addr_type, uint8_t io_cap)
+{
+       struct mgmt_cp_pair_device cp;
+       char addr[18];
+       struct pair_device_data *data;
+       unsigned int id;
+
+       ba2str(bdaddr, addr);
+       DBG("hci%u bdaddr %s type %d io_cap 0x%02x",
+                               adapter->dev_id, addr, addr_type, io_cap);
+
+       /* Reset the pincode_requested flag for a new bonding attempt. */
+       adapter->pincode_requested = false;
 
-static GDBusSignalTable adapter_signals[] = {
-       { "PropertyChanged",            "sv"            },
-       { "DeviceCreated",              "o"             },
-       { "DeviceRemoved",              "o"             },
-       { "DeviceFound",                "sa{sv}"        },
-       { "DeviceDisappeared",          "s"             },
-       { }
-};
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       cp.addr.type = addr_type;
+       cp.io_cap = io_cap;
 
-static void create_stored_device_from_profiles(char *key, char *value,
-                                               void *user_data)
-{
-       struct btd_adapter *adapter = user_data;
-       GSList *uuids = bt_string2list(value);
-       struct btd_device *device;
+       data = g_new0(struct pair_device_data, 1);
+       data->adapter = adapter;
+       bacpy(&data->bdaddr, bdaddr);
+       data->addr_type = addr_type;
 
-       if (g_slist_find_custom(adapter->devices,
-                               key, (GCompareFunc) device_address_cmp))
-               return;
+       id = mgmt_send(adapter->mgmt, MGMT_OP_PAIR_DEVICE,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               pair_device_complete, data,
+                               free_pair_device_data);
 
-       device = device_create(connection, adapter, key, DEVICE_TYPE_BREDR);
-       if (!device)
-               return;
+       if (id == 0) {
+               error("Failed to pair %s for hci%u", addr, adapter->dev_id);
+               free_pair_device_data(data);
+               return -EIO;
+       }
 
-       device_set_temporary(device, FALSE);
-       adapter->devices = g_slist_append(adapter->devices, device);
+       adapter->pair_device_id = id;
 
-       device_probe_drivers(device, uuids);
+       /* Due to a bug in the kernel it is possible that a LE pairing
+        * request never times out. Therefore, add a timer to clean up
+        * if no response arrives
+        */
+       adapter->pair_device_timeout = g_timeout_add_seconds(BONDING_TIMEOUT,
+                                               pair_device_timeout, data);
 
-       g_slist_foreach(uuids, (GFunc) g_free, NULL);
-       g_slist_free(uuids);
+       return 0;
 }
 
-struct adapter_keys {
-       struct btd_adapter *adapter;
-       GSList *keys;
-};
-
-static struct link_key_info *get_key_info(const char *addr, const char *value)
+static void disconnect_notify(struct btd_device *dev, uint8_t reason)
 {
-       struct link_key_info *info;
-       char tmp[3];
-       long int l;
-       int i;
+       GSList *l;
 
-       if (strlen(value) < 36) {
-               error("Unexpectedly short (%zu) link key line", strlen(value));
-               return NULL;
+       for (l = disconnect_list; l; l = g_slist_next(l)) {
+               btd_disconnect_cb disconnect_cb = l->data;
+               disconnect_cb(dev, reason);
        }
+}
 
-       info = g_new0(struct link_key_info, 1);
+static void dev_disconnected(struct btd_adapter *adapter,
+                                       const struct mgmt_addr_info *addr,
+                                       uint8_t reason)
+{
+       struct btd_device *device;
+       char dst[18];
 
-       str2ba(addr, &info->bdaddr);
+       ba2str(&addr->bdaddr, dst);
 
-       memset(tmp, 0, sizeof(tmp));
+       DBG("Device %s disconnected, reason %u", dst, reason);
 
-       for (i = 0; i < 16; i++) {
-               memcpy(tmp, value + (i * 2), 2);
-               info->key[i] = (uint8_t) strtol(tmp, NULL, 16);
-       }
+       device = btd_adapter_find_device(adapter, &addr->bdaddr, addr->type);
 
-       memcpy(tmp, value + 33, 2);
-       info->type = (uint8_t) strtol(tmp, NULL, 10);
+#ifdef __TIZEN_PATCH__
+       if (device) {
+               device_set_disconnect_reason(device, reason);
+               adapter_remove_connection(adapter, device, addr->type);
+               disconnect_notify(device, reason);
+               if (device_is_bonded(device, addr->type)) {
+                       DBG("addr type %d, bonded", addr->type);
+                       return;
+               }
+       }
+#else
+       if (device) {
+               adapter_remove_connection(adapter, device, addr->type);
+               disconnect_notify(device, reason);
+       }
+#endif
 
-       memcpy(tmp, value + 35, 2);
-       l = strtol(tmp, NULL, 10);
-       if (l < 0)
-               l = 0;
-       info->pin_len = l;
+       bonding_attempt_complete(adapter, &addr->bdaddr, addr->type,
+                                               MGMT_STATUS_DISCONNECTED);
+}
 
-       return info;
+void btd_add_disconnect_cb(btd_disconnect_cb func)
+{
+       disconnect_list = g_slist_append(disconnect_list, func);
 }
 
-static void create_stored_device_from_linkkeys(char *key, char *value,
-                                                       void *user_data)
+void btd_remove_disconnect_cb(btd_disconnect_cb func)
 {
-       struct adapter_keys *keys = user_data;
-       struct btd_adapter *adapter = keys->adapter;
-       struct btd_device *device;
-       struct link_key_info *info;
+       disconnect_list = g_slist_remove(disconnect_list, func);
+}
 
-       info = get_key_info(key, value);
-       if (info)
-               keys->keys = g_slist_append(keys->keys, info);
+static void disconnect_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_rp_disconnect *rp = param;
+       struct btd_adapter *adapter = user_data;
 
-       if (g_slist_find_custom(adapter->devices, key,
-                                       (GCompareFunc) device_address_cmp))
+       if (status == MGMT_STATUS_NOT_CONNECTED) {
+               warn("Disconnecting failed: already disconnected");
+       } else if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to disconnect device: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
                return;
+       }
 
-       device = device_create(connection, adapter, key, DEVICE_TYPE_BREDR);
-       if (device) {
-               device_set_temporary(device, FALSE);
-               adapter->devices = g_slist_append(adapter->devices, device);
+       if (length < sizeof(*rp)) {
+               error("Too small device disconnect response");
+               return;
        }
+
+       dev_disconnected(adapter, &rp->addr, MGMT_DEV_DISCONN_LOCAL_HOST);
 }
 
-static void create_stored_device_from_blocked(char *key, char *value,
-                                                       void *user_data)
+int btd_adapter_disconnect_device(struct btd_adapter *adapter,
+                                               const bdaddr_t *bdaddr,
+                                               uint8_t bdaddr_type)
+
 {
-       struct btd_adapter *adapter = user_data;
-       struct btd_device *device;
+       struct mgmt_cp_disconnect cp;
 
-       if (g_slist_find_custom(adapter->devices,
-                               key, (GCompareFunc) device_address_cmp))
-               return;
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       cp.addr.type = bdaddr_type;
 
-       device = device_create(connection, adapter, key, DEVICE_TYPE_BREDR);
-       if (device) {
-               device_set_temporary(device, FALSE);
-               adapter->devices = g_slist_append(adapter->devices, device);
-       }
+       if (mgmt_send(adapter->mgmt, MGMT_OP_DISCONNECT,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               disconnect_complete, adapter, NULL) > 0)
+               return 0;
+
+       return -EIO;
 }
 
-static void create_stored_device_from_types(char *key, char *value,
-                                                       void *user_data)
+static void auth_failed_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       GSList *l;
+       const struct mgmt_ev_auth_failed *ev = param;
        struct btd_adapter *adapter = user_data;
-       struct btd_device *device;
-       uint8_t type;
 
-       type = strtol(value, NULL, 16);
-
-       l = g_slist_find_custom(adapter->devices,
-                               key, (GCompareFunc) device_address_cmp);
-       if (l) {
-               device = l->data;
-               device_set_type(device, type);
+       if (length < sizeof(*ev)) {
+               error("Too small auth failed mgmt event");
                return;
        }
 
-       device = device_create(connection, adapter, key, type);
-       if (device) {
-               device_set_temporary(device, FALSE);
-               adapter->devices = g_slist_append(adapter->devices, device);
-       }
+       bonding_attempt_complete(adapter, &ev->addr.bdaddr, ev->addr.type,
+                                                               ev->status);
 }
 
-static GSList *string_to_primary_list(char *str)
+static void store_link_key(struct btd_adapter *adapter,
+                               struct btd_device *device, const uint8_t *key,
+                               uint8_t type, uint8_t pin_length)
 {
-       GSList *l = NULL;
-       char **services;
+       char adapter_addr[18];
+       char device_addr[18];
+       char filename[PATH_MAX];
+       GKeyFile *key_file;
+       gsize length = 0;
+       char key_str[33];
+       char *str;
        int i;
 
-       if (str == NULL)
-               return NULL;
-
-       services = g_strsplit(str, " ", 0);
-       if (services == NULL)
-               return NULL;
+       ba2str(btd_adapter_get_address(adapter), adapter_addr);
+       ba2str(device_get_address(device), device_addr);
 
-       for (i = 0; services[i]; i++) {
-               struct att_primary *prim;
-               int ret;
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", adapter_addr,
+                                                               device_addr);
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
 
-               prim = g_new0(struct att_primary, 1);
+       for (i = 0; i < 16; i++)
+               sprintf(key_str + (i * 2), "%2.2X", key[i]);
 
-               ret = sscanf(services[i], "%04hX#%04hX#%s", &prim->start,
-                                                       &prim->end, prim->uuid);
+       g_key_file_set_string(key_file, "LinkKey", "Key", key_str);
 
-               if (ret < 3) {
-                       g_free(prim);
-                       continue;
-               }
+       g_key_file_set_integer(key_file, "LinkKey", "Type", type);
+       g_key_file_set_integer(key_file, "LinkKey", "PINLength", pin_length);
 
-               l = g_slist_append(l, prim);
-       }
+       create_file(filename, S_IRUSR | S_IWUSR);
 
-       g_strfreev(services);
+       str = g_key_file_to_data(key_file, &length, NULL);
+       g_file_set_contents(filename, str, length, NULL);
+       g_free(str);
 
-       return l;
+       g_key_file_free(key_file);
 }
 
-static void create_stored_device_from_primary(char *key, char *value,
-                                                       void *user_data)
+static void new_link_key_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
+       const struct mgmt_ev_new_link_key *ev = param;
+       const struct mgmt_addr_info *addr = &ev->key.addr;
        struct btd_adapter *adapter = user_data;
        struct btd_device *device;
-       GSList *services, *uuids, *l;
+       char dst[18];
 
-       l = g_slist_find_custom(adapter->devices,
-                               key, (GCompareFunc) device_address_cmp);
-       if (l)
-               device = l->data;
-       else {
-               device = device_create(connection, adapter, key, DEVICE_TYPE_BREDR);
-               if (!device)
-                       return;
+       if (length < sizeof(*ev)) {
+               error("Too small new link key event");
+               return;
+       }
 
-               device_set_temporary(device, FALSE);
-               adapter->devices = g_slist_append(adapter->devices, device);
+       ba2str(&addr->bdaddr, dst);
+
+       DBG("hci%u new key for %s type %u pin_len %u", adapter->dev_id,
+                                       dst, ev->key.type, ev->key.pin_len);
+
+       if (ev->key.pin_len > 16) {
+               error("Invalid PIN length (%u) in new_key event",
+                                                       ev->key.pin_len);
+               return;
        }
 
-       services = string_to_primary_list(value);
-       if (services == NULL)
+       device = btd_adapter_get_device(adapter, &addr->bdaddr, addr->type);
+       if (!device) {
+               error("Unable to get device object for %s", dst);
                return;
+       }
 
-       for (l = services, uuids = NULL; l; l = l->next) {
-               struct att_primary *prim = l->data;
-               uuids = g_slist_append(uuids, prim->uuid);
+       if (ev->store_hint) {
+               const struct mgmt_link_key_info *key = &ev->key;
 
-               device_add_primary(device, prim);
-       }
+               store_link_key(adapter, device, key->val, key->type,
+                                                               key->pin_len);
+
+               device_set_bonded(device, BDADDR_BREDR);
 
-       device_probe_drivers(device, uuids);
+               if (device_is_temporary(device))
+                       btd_device_set_temporary(device, FALSE);
+       }
 
-       g_slist_free(services);
-       g_slist_free(uuids);
+       bonding_complete(adapter, &addr->bdaddr, addr->type, 0);
 }
 
-static void load_devices(struct btd_adapter *adapter)
+static void store_longtermkey(const bdaddr_t *local, const bdaddr_t *peer,
+                               uint8_t bdaddr_type, const unsigned char *key,
+                               uint8_t master, uint8_t authenticated,
+                               uint8_t enc_size, uint16_t ediv,
+                               uint64_t rand)
 {
-       char filename[PATH_MAX + 1];
-       char srcaddr[18];
-       struct adapter_keys keys = { adapter, NULL };
-       int err;
+       const char *group = master ? "LongTermKey" : "SlaveLongTermKey";
+       char adapter_addr[18];
+       char device_addr[18];
+       char filename[PATH_MAX];
+       GKeyFile *key_file;
+       char key_str[33];
+       gsize length = 0;
+       char *str;
+       int i;
 
-       ba2str(&adapter->bdaddr, srcaddr);
+       if (master != 0x00 && master != 0x01) {
+               error("Unsupported LTK type %u", master);
+               return;
+       }
 
-       create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "profiles");
-       textfile_foreach(filename, create_stored_device_from_profiles,
-                                                               adapter);
+       ba2str(local, adapter_addr);
+       ba2str(peer, device_addr);
 
-       create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "primary");
-       textfile_foreach(filename, create_stored_device_from_primary,
-                                                               adapter);
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", adapter_addr,
+                                                               device_addr);
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
 
-       create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "linkkeys");
-       textfile_foreach(filename, create_stored_device_from_linkkeys, &keys);
+       /* Old files may contain this so remove it in case it exists */
+       g_key_file_remove_key(key_file, "LongTermKey", "Master", NULL);
 
-       err = adapter_ops->load_keys(adapter->dev_id, keys.keys,
-                                                       main_opts.debug_keys);
-       if (err < 0) {
-               error("Unable to load keys to adapter_ops: %s (%d)",
-                                                       strerror(-err), -err);
-               g_slist_foreach(keys.keys, (GFunc) g_free, NULL);
-               g_slist_free(keys.keys);
-       }
+       for (i = 0; i < 16; i++)
+               sprintf(key_str + (i * 2), "%2.2X", key[i]);
 
-       create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "blocked");
-       textfile_foreach(filename, create_stored_device_from_blocked, adapter);
+       g_key_file_set_string(key_file, group, "Key", key_str);
 
-       create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "types");
-       textfile_foreach(filename, create_stored_device_from_types, adapter);
-}
+       g_key_file_set_integer(key_file, group, "Authenticated",
+                                                       authenticated);
+       g_key_file_set_integer(key_file, group, "EncSize", enc_size);
 
-int btd_adapter_block_address(struct btd_adapter *adapter, bdaddr_t *bdaddr)
-{
-       return adapter_ops->block_device(adapter->dev_id, bdaddr);
-}
+       g_key_file_set_integer(key_file, group, "EDiv", ediv);
+       g_key_file_set_uint64(key_file, group, "Rand", rand);
 
-int btd_adapter_unblock_address(struct btd_adapter *adapter, bdaddr_t *bdaddr)
-{
-       return adapter_ops->unblock_device(adapter->dev_id, bdaddr);
-}
+       create_file(filename, S_IRUSR | S_IWUSR);
 
-static void clear_blocked(struct btd_adapter *adapter)
-{
-       int err;
+       str = g_key_file_to_data(key_file, &length, NULL);
+       g_file_set_contents(filename, str, length, NULL);
+       g_free(str);
 
-       err = adapter_ops->unblock_device(adapter->dev_id, BDADDR_ANY);
-       if (err < 0)
-               error("Clearing blocked list failed: %s (%d)",
-                                               strerror(-err), -err);
+       g_key_file_free(key_file);
 }
 
-static void probe_driver(struct btd_adapter *adapter, gpointer user_data)
+static void new_long_term_key_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       struct btd_adapter_driver *driver = user_data;
-       int err;
+       const struct mgmt_ev_new_long_term_key *ev = param;
+       const struct mgmt_addr_info *addr = &ev->key.addr;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       bool persistent;
+       char dst[18];
 
-       if (!adapter->up)
+       if (length < sizeof(*ev)) {
+               error("Too small long term key event");
                return;
+       }
 
-       if (driver->probe == NULL)
-               return;
+       ba2str(&addr->bdaddr, dst);
 
-       err = driver->probe(adapter);
-       if (err < 0) {
-               error("%s: %s (%d)", driver->name, strerror(-err), -err);
+       DBG("hci%u new LTK for %s type %u enc_size %u",
+               adapter->dev_id, dst, ev->key.type, ev->key.enc_size);
+
+       device = btd_adapter_get_device(adapter, &addr->bdaddr, addr->type);
+       if (!device) {
+               error("Unable to get device object for %s", dst);
                return;
        }
 
-       adapter->loaded_drivers = g_slist_prepend(adapter->loaded_drivers,
-                                                                       driver);
-}
-
-static void load_drivers(struct btd_adapter *adapter)
-{
-       GSList *l;
-
-       for (l = adapter_drivers; l; l = l->next)
-               probe_driver(adapter, l->data);
-}
+       /*
+        * Some older kernel versions set store_hint for long term keys
+        * from resolvable and unresolvable random addresses, but there
+        * is no point in storing these. Next time around the device
+        * address will be invalid.
+        *
+        * So only for identity addresses (public and static random) use
+        * the store_hint as an indication if the long term key should
+        * be persistently stored.
+        *
+        */
+       if (addr->type == BDADDR_LE_RANDOM &&
+                               (addr->bdaddr.b[5] & 0xc0) != 0xc0)
+               persistent = false;
+       else
+               persistent = !!ev->store_hint;
 
-static void load_connections(struct btd_adapter *adapter)
-{
-       GSList *l, *conns;
-       int err;
+       if (persistent) {
+               const struct mgmt_ltk_info *key = &ev->key;
+               const bdaddr_t *bdaddr = btd_adapter_get_address(adapter);
+               uint16_t ediv;
+               uint64_t rand;
 
-       err = adapter_ops->get_conn_list(adapter->dev_id, &conns);
-       if (err < 0) {
-               error("Unable to fetch existing connections: %s (%d)",
-                                                       strerror(-err), -err);
-               return;
-       }
+               ediv = le16_to_cpu(key->ediv);
+               rand = le64_to_cpu(key->rand);
 
-       for (l = conns; l != NULL; l = g_slist_next(l)) {
-               bdaddr_t *bdaddr = l->data;
-               struct btd_device *device;
-               char address[18];
+               store_longtermkey(bdaddr, &key->addr.bdaddr,
+                                       key->addr.type, key->val, key->master,
+                                       key->type, key->enc_size, ediv, rand);
 
-               ba2str(bdaddr, address);
-               DBG("Adding existing connection to %s", address);
+               device_set_bonded(device, addr->type);
 
-               device = adapter_get_device(connection, adapter, address);
-               if (device)
-                       adapter_add_connection(adapter, device);
+               if (device_is_temporary(device))
+                       btd_device_set_temporary(device, FALSE);
        }
 
-       g_slist_foreach(conns, (GFunc) g_free, NULL);
-       g_slist_free(conns);
+       bonding_complete(adapter, &addr->bdaddr, addr->type, 0);
 }
 
-static int get_discoverable_timeout(const char *src)
+static void store_csrk(const bdaddr_t *local, const bdaddr_t *peer,
+                               uint8_t bdaddr_type, const unsigned char *key,
+                               uint32_t counter, uint8_t type)
 {
-       int timeout;
+       const char *group;
+       char adapter_addr[18];
+       char device_addr[18];
+       char filename[PATH_MAX];
+       GKeyFile *key_file;
+       char key_str[33];
+       gsize length = 0;
+       gboolean auth;
+       char *str;
+       int i;
 
-       if (read_discoverable_timeout(src, &timeout) == 0)
-               return timeout;
+       switch (type) {
+       case 0x00:
+               group = "LocalSignatureKey";
+               auth = FALSE;
+               break;
+       case 0x01:
+               group = "RemoteSignatureKey";
+               auth = FALSE;
+               break;
+       case 0x02:
+               group = "LocalSignatureKey";
+               auth = TRUE;
+               break;
+       case 0x03:
+               group = "RemoteSignatureKey";
+               auth = TRUE;
+               break;
+       default:
+               warn("Unsupported CSRK type %u", type);
+               return;
+       }
 
-       return main_opts.discovto;
-}
+       ba2str(local, adapter_addr);
+       ba2str(peer, device_addr);
 
-static int get_pairable_timeout(const char *src)
-{
-       int timeout;
+       snprintf(filename, sizeof(filename), STORAGEDIR "/%s/%s/info",
+                                               adapter_addr, device_addr);
 
-       if (read_pairable_timeout(src, &timeout) == 0)
-               return timeout;
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
 
-       return main_opts.pairto;
-}
+       for (i = 0; i < 16; i++)
+               sprintf(key_str + (i * 2), "%2.2X", key[i]);
 
-static void call_adapter_powered_callbacks(struct btd_adapter *adapter,
-                                               gboolean powered)
-{
-       GSList *l;
+       g_key_file_set_string(key_file, group, "Key", key_str);
+       g_key_file_set_integer(key_file, group, "Counter", counter);
+       g_key_file_set_boolean(key_file, group, "Authenticated", auth);
 
-       for (l = adapter->powered_callbacks; l; l = l->next) {
-               btd_adapter_powered_cb cb = l->data;
+       create_file(filename, S_IRUSR | S_IWUSR);
 
-               cb(adapter, powered);
-       }
+       str = g_key_file_to_data(key_file, &length, NULL);
+       g_file_set_contents(filename, str, length, NULL);
+       g_free(str);
+
+       g_key_file_free(key_file);
 }
 
-static void emit_device_disappeared(gpointer data, gpointer user_data)
+static void new_csrk_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       struct remote_dev_info *dev = data;
+       const struct mgmt_ev_new_csrk *ev = param;
+       const struct mgmt_addr_info *addr = &ev->key.addr;
+       const struct mgmt_csrk_info *key = &ev->key;
        struct btd_adapter *adapter = user_data;
-       char address[18];
-       const char *paddr = address;
+       const bdaddr_t *bdaddr = btd_adapter_get_address(adapter);
+       struct btd_device *device;
+       char dst[18];
 
-       ba2str(&dev->bdaddr, address);
+       if (length < sizeof(*ev)) {
+               error("Too small CSRK event");
+               return;
+       }
 
-       g_dbus_emit_signal(connection, adapter->path,
-                       ADAPTER_INTERFACE, "DeviceDisappeared",
-                       DBUS_TYPE_STRING, &paddr,
-                       DBUS_TYPE_INVALID);
+       ba2str(&addr->bdaddr, dst);
 
-       adapter->found_devices = g_slist_remove(adapter->found_devices, dev);
-}
+       DBG("hci%u new CSRK for %s type %u", adapter->dev_id, dst,
+                                                               ev->key.type);
 
-static void update_oor_devices(struct btd_adapter *adapter)
-{
-       g_slist_foreach(adapter->oor_devices, emit_device_disappeared, adapter);
-       g_slist_foreach(adapter->oor_devices, (GFunc) dev_info_free, NULL);
-       g_slist_free(adapter->oor_devices);
-       adapter->oor_devices =  g_slist_copy(adapter->found_devices);
-}
+       device = btd_adapter_get_device(adapter, &addr->bdaddr, addr->type);
+       if (!device) {
+               error("Unable to get device object for %s", dst);
+               return;
+       }
 
-static gboolean bredr_capable(struct btd_adapter *adapter)
-{
-       struct hci_dev *dev = &adapter->dev;
+       if (!ev->store_hint)
+               return;
 
-       return (dev->features[4] & LMP_NO_BREDR) == 0 ? TRUE : FALSE;
+       store_csrk(bdaddr, &key->addr.bdaddr, key->addr.type, key->val, 0,
+                                                               key->type);
+
+       if (device_is_temporary(device))
+               btd_device_set_temporary(device, FALSE);
 }
 
-static gboolean le_capable(struct btd_adapter *adapter)
+static void store_irk(struct btd_adapter *adapter, const bdaddr_t *peer,
+                               uint8_t bdaddr_type, const unsigned char *key)
 {
-       struct hci_dev *dev = &adapter->dev;
+       char adapter_addr[18];
+       char device_addr[18];
+       char filename[PATH_MAX];
+       GKeyFile *key_file;
+       char *store_data;
+       char str[33];
+       size_t length = 0;
+       int i;
 
-       return (dev->features[4] & LMP_LE &&
-                       dev->extfeatures[0] & LMP_HOST_LE) ? TRUE : FALSE;
-}
+       ba2str(&adapter->bdaddr, adapter_addr);
+       ba2str(peer, device_addr);
 
-int adapter_get_discover_type(struct btd_adapter *adapter)
-{
-       gboolean le, bredr;
-       int type;
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", adapter_addr,
+                                                               device_addr);
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
 
-       le = le_capable(adapter);
-       bredr = bredr_capable(adapter);
+       for (i = 0; i < 16; i++)
+               sprintf(str + (i * 2), "%2.2X", key[i]);
 
-       if (le)
-               type = bredr ? DISC_INTERLEAVE : DISC_LE;
-       else
-               type = main_opts.discov_interval ? DISC_STDINQ :
-                                                       DISC_PINQ;
+       g_key_file_set_string(key_file, "IdentityResolvingKey", "Key", str);
+
+       create_file(filename, S_IRUSR | S_IWUSR);
 
-       if (main_opts.name_resolv)
-               type |= DISC_RESOLVNAME;
+       store_data = g_key_file_to_data(key_file, &length, NULL);
+       g_file_set_contents(filename, store_data, length, NULL);
+       g_free(store_data);
 
-       return type;
+       g_key_file_free(key_file);
 }
 
-void btd_adapter_get_mode(struct btd_adapter *adapter, uint8_t *mode,
-                                       uint8_t *on_mode, gboolean *pairable)
+static void new_irk_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       char str[14], address[18];
+       const struct mgmt_ev_new_irk *ev = param;
+       const struct mgmt_addr_info *addr = &ev->key.addr;
+       const struct mgmt_irk_info *irk = &ev->key;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device, *duplicate;
+       bool persistent;
+       char dst[18], rpa[18];
 
-       ba2str(&adapter->bdaddr, address);
+       if (length < sizeof(*ev)) {
+               error("Too small New IRK event");
+               return;
+       }
 
-       if (mode) {
-               if (main_opts.remember_powered == FALSE)
-                       *mode = main_opts.mode;
-               else if (read_device_mode(address, str, sizeof(str)) < 0)
-                       *mode = main_opts.mode;
-               else
-                       *mode = get_mode(&adapter->bdaddr, str);
+       ba2str(&addr->bdaddr, dst);
+       ba2str(&ev->rpa, rpa);
+
+       DBG("hci%u new IRK for %s RPA %s", adapter->dev_id, dst, rpa);
+
+       if (bacmp(&ev->rpa, BDADDR_ANY)) {
+               device = btd_adapter_get_device(adapter, &ev->rpa,
+                                                       BDADDR_LE_RANDOM);
+               duplicate = btd_adapter_find_device(adapter, &addr->bdaddr,
+                                                               addr->type);
+               if (duplicate == device)
+                       duplicate = NULL;
+       } else {
+               device = btd_adapter_get_device(adapter, &addr->bdaddr,
+                                                               addr->type);
+               duplicate = NULL;
        }
 
-       if (on_mode) {
-               if (main_opts.remember_powered == FALSE) {
-                       if (adapter->initialized)
-                               *on_mode = get_mode(&adapter->bdaddr, "on");
-                       else {
-                               *on_mode = main_opts.mode;
-                               adapter->initialized = TRUE;
-                       }
-               } else if (read_on_mode(address, str, sizeof(str)) < 0)
-                       *on_mode = main_opts.mode;
-               else
-                       *on_mode = get_mode(&adapter->bdaddr, str);
+       if (!device) {
+               error("Unable to get device object for %s", dst);
+               return;
        }
 
-       if (pairable)
-               *pairable = adapter->pairable;
-}
+       device_update_addr(device, &addr->bdaddr, addr->type);
 
-void btd_adapter_start(struct btd_adapter *adapter)
-{
-       char address[18];
-       uint8_t cls[3];
-       gboolean powered;
+       if (duplicate)
+               device_merge_duplicate(device, duplicate);
 
-       ba2str(&adapter->bdaddr, address);
+       persistent = !!ev->store_hint;
+       if (!persistent)
+               return;
 
-       adapter->dev_class = 0;
-       adapter->off_requested = FALSE;
-       adapter->up = TRUE;
-       adapter->discov_timeout = get_discoverable_timeout(address);
-       adapter->pairable_timeout = get_pairable_timeout(address);
-       adapter->state = STATE_IDLE;
-       adapter->mode = MODE_CONNECTABLE;
+       store_irk(adapter, &addr->bdaddr, addr->type, irk->val);
 
-       if (main_opts.le)
-               adapter_ops->enable_le(adapter->dev_id);
+       if (device_is_temporary(device))
+               btd_device_set_temporary(device, FALSE);
+}
 
-       adapter_ops->set_name(adapter->dev_id, adapter->dev.name);
+static void store_conn_param(struct btd_adapter *adapter, const bdaddr_t *peer,
+                               uint8_t bdaddr_type, uint16_t min_interval,
+                               uint16_t max_interval, uint16_t latency,
+                               uint16_t timeout)
+{
+       char adapter_addr[18];
+       char device_addr[18];
+       char filename[PATH_MAX];
+       GKeyFile *key_file;
+       char *store_data;
+       size_t length = 0;
 
-       if (read_local_class(&adapter->bdaddr, cls) < 0) {
-               uint32_t class = htobl(main_opts.class);
-               memcpy(cls, &class, 3);
-       }
+       ba2str(&adapter->bdaddr, adapter_addr);
+       ba2str(peer, device_addr);
 
-       btd_adapter_set_class(adapter, cls[1], cls[0]);
+       DBG("");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", adapter_addr,
+                                                               device_addr);
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
 
-       powered = TRUE;
-       emit_property_changed(connection, adapter->path,
-                                       ADAPTER_INTERFACE, "Powered",
-                                       DBUS_TYPE_BOOLEAN, &powered);
+       g_key_file_set_integer(key_file, "ConnectionParameters",
+                                               "MinInterval", min_interval);
+       g_key_file_set_integer(key_file, "ConnectionParameters",
+                                               "MaxInterval", max_interval);
+       g_key_file_set_integer(key_file, "ConnectionParameters",
+                                               "Latency", latency);
+       g_key_file_set_integer(key_file, "ConnectionParameters",
+                                               "Timeout", timeout);
 
-       call_adapter_powered_callbacks(adapter, TRUE);
+       create_file(filename, S_IRUSR | S_IWUSR);
 
-       adapter_ops->disable_cod_cache(adapter->dev_id);
+       store_data = g_key_file_to_data(key_file, &length, NULL);
+       g_file_set_contents(filename, store_data, length, NULL);
+       g_free(store_data);
 
-       info("Adapter %s has been enabled", adapter->path);
+       g_key_file_free(key_file);
 }
 
-static void reply_pending_requests(struct btd_adapter *adapter)
+static void new_conn_param(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       GSList *l;
+       const struct mgmt_ev_new_conn_param *ev = param;
+       struct btd_adapter *adapter = user_data;
+       uint16_t min, max, latency, timeout;
+       struct btd_device *dev;
+       char dst[18];
 
-       if (!adapter)
+
+       if (length < sizeof(*ev)) {
+               error("Too small New Connection Parameter event");
                return;
+       }
 
-       /* pending bonding */
-       for (l = adapter->devices; l; l = l->next) {
-               struct btd_device *device = l->data;
+       ba2str(&ev->addr.bdaddr, dst);
 
-               if (device_is_bonding(device, NULL))
-                       device_cancel_bonding(device,
-                                               HCI_OE_USER_ENDED_CONNECTION);
-       }
-}
+       min = btohs(ev->min_interval);
+       max = btohs(ev->max_interval);
+       latency = btohs(ev->latency);
+       timeout = btohs(ev->timeout);
 
-static void remove_driver(gpointer data, gpointer user_data)
-{
-       struct btd_adapter_driver *driver = data;
-       struct btd_adapter *adapter = user_data;
+       DBG("hci%u %s (%u) min 0x%04x max 0x%04x latency 0x%04x timeout 0x%04x",
+               adapter->dev_id, dst, ev->addr.type, min, max, latency, timeout);
 
-       if (driver->remove)
-               driver->remove(adapter);
-}
+       dev = btd_adapter_get_device(adapter, &ev->addr.bdaddr, ev->addr.type);
+       if (!dev) {
+               error("Unable to get device object for %s", dst);
+               return;
+       }
 
-static void unload_drivers(struct btd_adapter *adapter)
-{
-       g_slist_foreach(adapter->loaded_drivers, remove_driver, adapter);
-       g_slist_free(adapter->loaded_drivers);
-       adapter->loaded_drivers = NULL;
+       if (!ev->store_hint)
+               return;
+
+       store_conn_param(adapter, &ev->addr.bdaddr, ev->addr.type,
+                                       ev->min_interval, ev->max_interval,
+                                       ev->latency, ev->timeout);
 }
 
-static void set_mode_complete(struct btd_adapter *adapter)
+int adapter_set_io_capability(struct btd_adapter *adapter, uint8_t io_cap)
 {
-       struct session_req *pending;
-       const char *modestr;
-       int err;
-
-       DBG("");
-
-       if (adapter->pending_mode == NULL)
-               return;
+       struct mgmt_cp_set_io_capability cp;
 
-       pending = adapter->pending_mode;
-       adapter->pending_mode = NULL;
+       memset(&cp, 0, sizeof(cp));
+       cp.io_capability = io_cap;
 
-       err = (pending->mode != adapter->mode) ? -EINVAL : 0;
+       if (mgmt_send(adapter->mgmt, MGMT_OP_SET_IO_CAPABILITY,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               NULL, NULL, NULL) > 0)
+               return 0;
 
-       if (pending->msg != NULL) {
-               DBusMessage *msg = pending->msg;
-               DBusMessage *reply;
+       return -EIO;
+}
 
-               if (err < 0)
-                       reply = btd_error_failed(msg, strerror(-err));
-               else {
-                       if (strcmp(dbus_message_get_member(msg),
-                                               "SetProperty") == 0)
-                               adapter->global_mode = adapter->mode;
-                       reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
-               }
+int btd_adapter_add_remote_oob_data(struct btd_adapter *adapter,
+                                       const bdaddr_t *bdaddr,
+                                       uint8_t *hash, uint8_t *randomizer)
+{
+       struct mgmt_cp_add_remote_oob_data cp;
+       char addr[18];
 
-               g_dbus_send_message(connection, reply);
-       }
+       ba2str(bdaddr, addr);
+       DBG("hci%d bdaddr %s", adapter->dev_id, addr);
 
-       modestr = mode2str(adapter->mode);
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       memcpy(cp.hash192, hash, 16);
 
-       DBG("%s", modestr);
+       if (randomizer)
+               memcpy(cp.rand192, randomizer, 16);
 
-       /* restore if the mode doesn't matches the pending */
-       if (err != 0) {
-               write_device_mode(&adapter->bdaddr, modestr);
-               error("unable to set mode: %s", mode2str(pending->mode));
-       }
+       if (mgmt_send(adapter->mgmt, MGMT_OP_ADD_REMOTE_OOB_DATA,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               NULL, NULL, NULL) > 0)
+               return 0;
 
-       session_unref(pending);
+       return -EIO;
 }
 
-int btd_adapter_stop(struct btd_adapter *adapter)
+int btd_adapter_remove_remote_oob_data(struct btd_adapter *adapter,
+                                                       const bdaddr_t *bdaddr)
 {
-       gboolean powered, discoverable, pairable;
-#ifdef __TIZEN_PATCH__
-       gboolean limited;
-#endif
-
-       /* cancel pending timeout */
-       if (adapter->discov_timeout_id) {
-               g_source_remove(adapter->discov_timeout_id);
-               adapter->discov_timeout_id = 0;
-       }
+       struct mgmt_cp_remove_remote_oob_data cp;
+       char addr[18];
 
-       /* check pending requests */
-       reply_pending_requests(adapter);
+       ba2str(bdaddr, addr);
+       DBG("hci%d bdaddr %s", adapter->dev_id, addr);
 
-       stop_discovery(adapter, FALSE);
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
 
-       if (adapter->disc_sessions) {
-               g_slist_foreach(adapter->disc_sessions, (GFunc) session_free,
-                               NULL);
-               g_slist_free(adapter->disc_sessions);
-               adapter->disc_sessions = NULL;
-       }
+       if (mgmt_send(adapter->mgmt, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               NULL, NULL, NULL) > 0)
+               return 0;
 
-       while (adapter->connections) {
-               struct btd_device *device = adapter->connections->data;
-               adapter_remove_connection(adapter, device);
-       }
+       return -EIO;
+}
 
-       if (adapter->scan_mode == (SCAN_PAGE | SCAN_INQUIRY)) {
-               discoverable = FALSE;
-               emit_property_changed(connection, adapter->path,
-                                       ADAPTER_INTERFACE, "Discoverable",
-                                       DBUS_TYPE_BOOLEAN, &discoverable);
-       }
+bool btd_adapter_ssp_enabled(struct btd_adapter *adapter)
+{
+       if (adapter->current_settings & MGMT_SETTING_SSP)
+               return true;
 
-       if ((adapter->scan_mode & SCAN_PAGE) && adapter->pairable == TRUE) {
-               pairable = FALSE;
-               emit_property_changed(connection, adapter->path,
-                                       ADAPTER_INTERFACE, "Pairable",
-                                       DBUS_TYPE_BOOLEAN, &pairable);
-       }
+       return false;
+}
 
-       powered = FALSE;
-       emit_property_changed(connection, adapter->path, ADAPTER_INTERFACE,
-                               "Powered", DBUS_TYPE_BOOLEAN, &powered);
+void btd_adapter_set_oob_handler(struct btd_adapter *adapter,
+                                               struct oob_handler *handler)
+{
+       adapter->oob_handler = handler;
+}
 
-       adapter->up = 0;
-       adapter->scan_mode = SCAN_DISABLED;
-       adapter->mode = MODE_OFF;
-       adapter->state = STATE_IDLE;
-       adapter->off_requested = FALSE;
-       adapter->name_stored = FALSE;
+gboolean btd_adapter_check_oob_handler(struct btd_adapter *adapter)
+{
+       return adapter->oob_handler != NULL;
+}
 
-       call_adapter_powered_callbacks(adapter, FALSE);
+static void read_local_oob_data_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_rp_read_local_oob_data *rp = param;
+       struct btd_adapter *adapter = user_data;
+       const uint8_t *hash, *randomizer;
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Read local OOB data failed: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               hash = NULL;
+               randomizer = NULL;
+       } else if (length < sizeof(*rp)) {
+               error("Too small read local OOB data response");
+               return;
+       } else {
+               hash = rp->hash;
+               randomizer = rp->randomizer;
+       }
 
-       info("Adapter %s has been disabled", adapter->path);
+       if (!adapter->oob_handler || !adapter->oob_handler->read_local_cb)
+               return;
 
-       set_mode_complete(adapter);
+       adapter->oob_handler->read_local_cb(adapter, hash, randomizer,
+                                       adapter->oob_handler->user_data);
 
-       return 0;
+       g_free(adapter->oob_handler);
+       adapter->oob_handler = NULL;
 }
 
-int adapter_update_ssp_mode(struct btd_adapter *adapter, uint8_t mode)
+int btd_adapter_read_local_oob_data(struct btd_adapter *adapter)
 {
-       struct hci_dev *dev = &adapter->dev;
+       DBG("hci%u", adapter->dev_id);
 
-       dev->ssp_mode = mode;
+       if (mgmt_send(adapter->mgmt, MGMT_OP_READ_LOCAL_OOB_DATA,
+                       adapter->dev_id, 0, NULL, read_local_oob_data_complete,
+                       adapter, NULL) > 0)
+               return 0;
 
-       return 0;
+       return -EIO;
 }
 
-static void adapter_free(gpointer user_data)
+void btd_adapter_for_each_device(struct btd_adapter *adapter,
+                       void (*cb)(struct btd_device *device, void *data),
+                       void *data)
 {
-       struct btd_adapter *adapter = user_data;
+       g_slist_foreach(adapter->devices, (GFunc) cb, data);
+}
 
-       agent_free(adapter->agent);
-       adapter->agent = NULL;
+static int adapter_cmp(gconstpointer a, gconstpointer b)
+{
+       struct btd_adapter *adapter = (struct btd_adapter *) a;
+       const bdaddr_t *bdaddr = b;
 
-       DBG("%p", adapter);
+       return bacmp(&adapter->bdaddr, bdaddr);
+}
 
-       if (adapter->auth_idle_id)
-               g_source_remove(adapter->auth_idle_id);
+static int adapter_id_cmp(gconstpointer a, gconstpointer b)
+{
+       struct btd_adapter *adapter = (struct btd_adapter *) a;
+       uint16_t id = GPOINTER_TO_UINT(b);
 
-       sdp_list_free(adapter->services, NULL);
+       return adapter->dev_id == id ? 0 : -1;
+}
 
-       g_slist_foreach(adapter->found_devices, (GFunc) dev_info_free, NULL);
-       g_slist_free(adapter->found_devices);
+struct btd_adapter *adapter_find(const bdaddr_t *sba)
+{
+       GSList *match;
 
-       g_slist_free(adapter->oor_devices);
+       match = g_slist_find_custom(adapters, sba, adapter_cmp);
+       if (!match)
+               return NULL;
 
-       g_free(adapter->path);
-       g_free(adapter);
+       return match->data;
 }
 
-struct btd_adapter *btd_adapter_ref(struct btd_adapter *adapter)
+struct btd_adapter *adapter_find_by_id(int id)
 {
-       adapter->ref++;
+       GSList *match;
 
-       DBG("%p: ref=%d", adapter, adapter->ref);
+       match = g_slist_find_custom(adapters, GINT_TO_POINTER(id),
+                                                       adapter_id_cmp);
+       if (!match)
+               return NULL;
 
-       return adapter;
+       return match->data;
 }
 
-void btd_adapter_unref(struct btd_adapter *adapter)
+void adapter_foreach(adapter_cb func, gpointer user_data)
 {
-       gchar *path;
+       g_slist_foreach(adapters, (GFunc) func, user_data);
+}
 
-       adapter->ref--;
+static int set_did(struct btd_adapter *adapter, uint16_t vendor,
+                       uint16_t product, uint16_t version, uint16_t source)
+{
+       struct mgmt_cp_set_device_id cp;
 
-       DBG("%p: ref=%d", adapter, adapter->ref);
+       DBG("hci%u source %x vendor %x product %x version %x",
+                       adapter->dev_id, source, vendor, product, version);
 
-       if (adapter->ref > 0)
-               return;
+       memset(&cp, 0, sizeof(cp));
 
-       path = g_strdup(adapter->path);
+       cp.source = htobs(source);
+       cp.vendor = htobs(vendor);
+       cp.product = htobs(product);
+       cp.version = htobs(version);
 
-       g_dbus_unregister_interface(connection, path, ADAPTER_INTERFACE);
+       if (mgmt_send(adapter->mgmt, MGMT_OP_SET_DEVICE_ID,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               NULL, NULL, NULL) > 0)
+               return 0;
 
-       g_free(path);
+       return -EIO;
 }
 
-gboolean adapter_init(struct btd_adapter *adapter)
+#ifndef __TIZEN_PATCH__
+static void services_modified(struct gatt_db_attribute *attrib, void *user_data)
 {
-       struct hci_version ver;
-       struct hci_dev *dev;
-       int err;
+       struct btd_adapter *adapter = user_data;
 
-       /* adapter_ops makes sure that newly registered adapters always
-        * start off as powered */
-       adapter->up = TRUE;
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "UUIDs");
+}
+#endif
+
+static int adapter_register(struct btd_adapter *adapter)
+{
+       struct agent *agent;
+#ifndef __TIZEN_PATCH__
+       struct gatt_db *db;
+#endif
 
-       adapter_ops->read_bdaddr(adapter->dev_id, &adapter->bdaddr);
+       if (powering_down)
+               return -EBUSY;
 
-       if (bacmp(&adapter->bdaddr, BDADDR_ANY) == 0) {
-               error("No address available for hci%d", adapter->dev_id);
-               return FALSE;
-       }
+       adapter->path = g_strdup_printf("/org/bluez/hci%d", adapter->dev_id);
 
-       err = adapter_ops->read_local_version(adapter->dev_id, &ver);
-       if (err < 0) {
-               error("Can't read version info for hci%d: %s (%d)",
-                                       adapter->dev_id, strerror(-err), -err);
-               return FALSE;
+       if (!g_dbus_register_interface(dbus_conn,
+                                       adapter->path, ADAPTER_INTERFACE,
+#ifdef __TIZEN_PATCH__
+                                       adapter_methods, adapter_signals,
+#else
+                                       adapter_methods, NULL,
+#endif
+                                       adapter_properties, adapter,
+                                       adapter_free)) {
+               error("Adapter interface init failed on path %s",
+                                                       adapter->path);
+               g_free(adapter->path);
+               adapter->path = NULL;
+               return -EINVAL;
        }
 
-       dev = &adapter->dev;
+       if (adapters == NULL)
+               adapter->is_default = true;
 
-       dev->hci_rev = ver.hci_rev;
-       dev->lmp_ver = ver.lmp_ver;
-       dev->lmp_subver = ver.lmp_subver;
-       dev->manufacturer = ver.manufacturer;
+       adapters = g_slist_append(adapters, adapter);
 
-       err = adapter_ops->read_local_features(adapter->dev_id, dev->features);
-       if (err < 0) {
-               error("Can't read features for hci%d: %s (%d)",
-                                       adapter->dev_id, strerror(-err), -err);
-               return FALSE;
+       agent = agent_get(NULL);
+       if (agent) {
+               uint8_t io_cap = agent_get_io_capability(agent);
+               adapter_set_io_capability(adapter, io_cap);
+               agent_unref(agent);
        }
 
-       if (read_local_name(&adapter->bdaddr, adapter->dev.name) < 0)
-               expand_name(adapter->dev.name, MAX_NAME_LENGTH, main_opts.name,
-                                                       adapter->dev_id);
+#ifndef __TIZEN_PATCH__
+       adapter->database = btd_gatt_database_new(adapter);
+       if (!adapter->database) {
+               error("Failed to create GATT database for adapter");
+               adapters = g_slist_remove(adapters, adapter);
+               return -EINVAL;
+       }
 
-       if (main_opts.attrib_server)
-               attrib_gap_set(GATT_CHARAC_DEVICE_NAME,
-                       (const uint8_t *) dev->name, strlen(dev->name));
+       db = btd_gatt_database_get_db(adapter->database);
+       adapter->db_id = gatt_db_register(db, services_modified,
+                                                       services_modified,
+                                                       adapter, NULL);
+#else
+       btd_adapter_gatt_server_start(adapter);
+#endif
 
-       sdp_init_services_list(&adapter->bdaddr);
+       load_config(adapter);
+       fix_storage(adapter);
        load_drivers(adapter);
+       btd_profile_foreach(probe_profile, adapter);
        clear_blocked(adapter);
        load_devices(adapter);
 
-       /* Set pairable mode */
-       if (read_device_pairable(&adapter->bdaddr, &adapter->pairable) < 0)
-               adapter->pairable = TRUE;
+#ifdef __TIZEN_PATCH__
+       if (adapter->le_privacy_enabled &&
+               (adapter->supported_settings & MGMT_SETTING_PRIVACY))
+                               set_privacy(adapter, true);
+       else
+               DBG("LE privacy feature not configured or supported");
+#endif
 
        /* retrieve the active connections: address the scenario where
         * the are active connections before the daemon've started */
-       load_connections(adapter);
-
-       return TRUE;
-}
-
-struct btd_adapter *adapter_create(DBusConnection *conn, int id)
-{
-       char path[MAX_PATH_LENGTH];
-       struct btd_adapter *adapter;
-       const char *base_path = manager_get_base_path();
+       if (adapter->current_settings & MGMT_SETTING_POWERED)
+               load_connections(adapter);
 
-       if (!connection)
-               connection = conn;
+       adapter->initialized = TRUE;
 
-       adapter = g_try_new0(struct btd_adapter, 1);
-       if (!adapter) {
-               error("adapter_create: failed to alloc memory for hci%d", id);
-               return NULL;
+       if (main_opts.did_source) {
+               /* DeviceID record is added by sdpd-server before any other
+                * record is registered. */
+               adapter_service_insert(adapter, sdp_record_find(0x10000));
+               set_did(adapter, main_opts.did_vendor, main_opts.did_product,
+                               main_opts.did_version, main_opts.did_source);
        }
 
-       adapter->dev_id = id;
+       DBG("Adapter %s registered", adapter->path);
 
-       snprintf(path, sizeof(path), "%s/hci%d", base_path, id);
-       adapter->path = g_strdup(path);
-
-       if (!g_dbus_register_interface(conn, path, ADAPTER_INTERFACE,
-                                       adapter_methods, adapter_signals, NULL,
-                                       adapter, adapter_free)) {
-               error("Adapter interface init failed on path %s", path);
-               adapter_free(adapter);
-               return NULL;
-       }
-
-       return btd_adapter_ref(adapter);
+       return 0;
 }
 
-void adapter_remove(struct btd_adapter *adapter)
+static int adapter_unregister(struct btd_adapter *adapter)
 {
-       GSList *l;
+       DBG("Unregister path: %s", adapter->path);
 
-       DBG("Removing adapter %s", adapter->path);
+       adapters = g_slist_remove(adapters, adapter);
 
-       for (l = adapter->devices; l; l = l->next)
-               device_remove(l->data, FALSE);
-       g_slist_free(adapter->devices);
+       if (adapter->is_default && adapters != NULL) {
+               struct btd_adapter *new_default;
 
-       unload_drivers(adapter);
+               new_default = adapter_find_by_id(hci_get_route(NULL));
+               if (new_default == NULL)
+                       new_default = adapters->data;
+
+               new_default->is_default = true;
+       }
 
-       /* Return adapter to down state if it was not up on init */
-       adapter_ops->restore_powered(adapter->dev_id);
+       adapter_list = g_list_remove(adapter_list, adapter);
 
+       adapter_remove(adapter);
        btd_adapter_unref(adapter);
-}
 
-uint16_t adapter_get_dev_id(struct btd_adapter *adapter)
-{
-       return adapter->dev_id;
+       return 0;
 }
 
-const gchar *adapter_get_path(struct btd_adapter *adapter)
+static void disconnected_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       if (!adapter)
-               return NULL;
+       const struct mgmt_ev_device_disconnected *ev = param;
+       struct btd_adapter *adapter = user_data;
+       uint8_t reason;
 
-       return adapter->path;
-}
+       if (length < sizeof(struct mgmt_addr_info)) {
+               error("Too small device disconnected event");
+               return;
+       }
 
-void adapter_get_address(struct btd_adapter *adapter, bdaddr_t *bdaddr)
-{
-       bacpy(bdaddr, &adapter->bdaddr);
+       if (length < sizeof(*ev))
+               reason = MGMT_DEV_DISCONN_UNKNOWN;
+       else
+               reason = ev->reason;
+
+       dev_disconnected(adapter, &ev->addr, reason);
 }
 
-void adapter_set_state(struct btd_adapter *adapter, int state)
+static void connected_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       const char *path = adapter->path;
-       gboolean discov_active;
-       int previous, type;
+       const struct mgmt_ev_device_connected *ev = param;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       struct eir_data eir_data;
+       uint16_t eir_len;
+       char addr[18];
+       bool name_known;
 
-       if (adapter->state == state)
+       if (length < sizeof(*ev)) {
+               error("Too small device connected event");
                return;
+       }
 
-       previous = adapter->state;
-       adapter->state = state;
-
-       type = adapter_get_discover_type(adapter);
-
-       switch (state) {
-       case STATE_STDINQ:
-       case STATE_PINQ:
-               discov_active = TRUE;
-
-               /* Started a new session while resolving names ? */
-               if (previous & STATE_RESOLVNAME)
-                       return;
-               break;
-       case STATE_LE_SCAN:
-               /* Scanning enabled */
-               adapter->stop_discov_id = g_timeout_add(5120,
-                                               stop_scanning, adapter);
-
-               /* For dual mode: don't send "Discovering = TRUE"  */
-               if (bredr_capable(adapter) == TRUE)
-                       return;
-
-               /* LE only */
-               discov_active = TRUE;
-
-               break;
-       case STATE_IDLE:
-               /*
-                * Interleave: from inquiry to scanning. Interleave is not
-                * applicable to requests triggered by external applications.
-                */
-               if (adapter->disc_sessions && (type & DISC_INTERLEAVE) &&
-                                               (previous & STATE_STDINQ)) {
-                       adapter_ops->start_scanning(adapter->dev_id);
-                       return;
-               }
-               /* BR/EDR only: inquiry finished */
-               discov_active = FALSE;
-               break;
-       default:
-               discov_active = FALSE;
-               break;
+       eir_len = btohs(ev->eir_len);
+       if (length < sizeof(*ev) + eir_len) {
+               error("Too small device connected event");
+               return;
        }
 
-       if (discov_active == FALSE) {
-               if (type & DISC_RESOLVNAME) {
-                       if (adapter_resolve_names(adapter) == 0) {
-                               adapter->state |= STATE_RESOLVNAME;
-                               return;
-                       }
-               }
+       ba2str(&ev->addr.bdaddr, addr);
 
-               update_oor_devices(adapter);
-       } else if (adapter->disc_sessions && main_opts.discov_interval)
-                       adapter->scheduler_id = g_timeout_add_seconds(
-                                               main_opts.discov_interval,
-                                               (GSourceFunc) start_discovery,
-                                               adapter);
+       DBG("hci%u device %s connected eir_len %u", index, addr, eir_len);
 
-       emit_property_changed(connection, path,
-                               ADAPTER_INTERFACE, "Discovering",
-                               DBUS_TYPE_BOOLEAN, &discov_active);
-}
+       device = btd_adapter_get_device(adapter, &ev->addr.bdaddr,
+                                                               ev->addr.type);
+       if (!device) {
+               error("Unable to get device object for %s", addr);
+               return;
+       }
 
-int adapter_get_state(struct btd_adapter *adapter)
-{
-       return adapter->state;
-}
+       memset(&eir_data, 0, sizeof(eir_data));
+       if (eir_len > 0)
+               eir_parse(&eir_data, ev->eir, eir_len);
 
-struct remote_dev_info *adapter_search_found_devices(struct btd_adapter *adapter,
-                                               struct remote_dev_info *match)
-{
-       GSList *l;
+       if (eir_data.class != 0)
+               device_set_class(device, eir_data.class);
 
-       l = g_slist_find_custom(adapter->found_devices, match,
-                                       (GCompareFunc) found_device_cmp);
-       if (l)
-               return l->data;
+       adapter_add_connection(adapter, device, ev->addr.type);
 
-       return NULL;
-}
+       name_known = device_name_known(device);
 
-static int dev_rssi_cmp(struct remote_dev_info *d1, struct remote_dev_info *d2)
-{
-       int rssi1, rssi2;
+       if (eir_data.name && (eir_data.name_complete || !name_known)) {
+               device_store_cached_name(device, eir_data.name);
+               btd_device_device_set_name(device, eir_data.name);
+       }
 
-       rssi1 = d1->rssi < 0 ? -d1->rssi : d1->rssi;
-       rssi2 = d2->rssi < 0 ? -d2->rssi : d2->rssi;
+       if (eir_data.msd_list)
+               adapter_msd_notify(adapter, device, eir_data.msd_list);
 
-       return rssi1 - rssi2;
+       eir_data_free(&eir_data);
 }
 
-static void append_dict_valist(DBusMessageIter *iter,
-                                       const char *first_key,
-                                       va_list var_args)
+static void device_blocked_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       DBusMessageIter dict;
-       const char *key;
-       int type;
-       int n_elements;
-       void *val;
+       const struct mgmt_ev_device_blocked *ev = param;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       char addr[18];
 
-       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
-       key = first_key;
-       while (key) {
-               type = va_arg(var_args, int);
-               val = va_arg(var_args, void *);
-               if (type == DBUS_TYPE_ARRAY) {
-                       n_elements = va_arg(var_args, int);
-                       if (n_elements > 0)
-                               dict_append_array(&dict, key, DBUS_TYPE_STRING,
-                                               val, n_elements);
-               } else
-                       dict_append_entry(&dict, key, type, val);
-               key = va_arg(var_args, char *);
+       if (length < sizeof(*ev)) {
+               error("Too small device blocked event");
+               return;
        }
 
-       dbus_message_iter_close_container(iter, &dict);
+       ba2str(&ev->addr.bdaddr, addr);
+       DBG("hci%u %s blocked", index, addr);
+
+       device = btd_adapter_find_device(adapter, &ev->addr.bdaddr,
+                                                               ev->addr.type);
+       if (device)
+               device_block(device, TRUE);
 }
 
-static void emit_device_found(const char *path, const char *address,
-                               const char *first_key, ...)
+static void device_unblocked_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       DBusMessage *signal;
-       DBusMessageIter iter;
-       va_list var_args;
+       const struct mgmt_ev_device_unblocked *ev = param;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       char addr[18];
 
-       signal = dbus_message_new_signal(path, ADAPTER_INTERFACE,
-                                       "DeviceFound");
-       if (!signal) {
-               error("Unable to allocate new %s.DeviceFound signal",
-                               ADAPTER_INTERFACE);
+       if (length < sizeof(*ev)) {
+               error("Too small device unblocked event");
                return;
        }
-       dbus_message_iter_init_append(signal, &iter);
-       dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &address);
 
-       va_start(var_args, first_key);
-       append_dict_valist(&iter, first_key, var_args);
-       va_end(var_args);
+       ba2str(&ev->addr.bdaddr, addr);
+       DBG("hci%u %s unblocked", index, addr);
 
-       g_dbus_send_message(connection, signal);
+       device = btd_adapter_find_device(adapter, &ev->addr.bdaddr,
+                                                               ev->addr.type);
+       if (device)
+               device_unblock(device, FALSE, TRUE);
 }
 
-static char **strlist2array(GSList *list)
+static void conn_fail_notify(struct btd_device *dev, uint8_t status)
 {
        GSList *l;
-       unsigned int i, n;
-       char **array;
-
-       if (list == NULL)
-               return NULL;
 
-       n = g_slist_length(list);
-       array = g_new0(char *, n + 1);
+       for (l = conn_fail_list; l; l = g_slist_next(l)) {
+               btd_conn_fail_cb conn_fail_cb = l->data;
+               conn_fail_cb(dev, status);
+       }
+}
 
-       for (l = list, i = 0; l; l = l->next, i++)
-               array[i] = g_strdup((const gchar *) l->data);
+void btd_add_conn_fail_cb(btd_conn_fail_cb func)
+{
+       conn_fail_list = g_slist_append(conn_fail_list, func);
+}
 
-       return array;
+void btd_remove_conn_fail_cb(btd_conn_fail_cb func)
+{
+       conn_fail_list = g_slist_remove(conn_fail_list, func);
 }
 
-void adapter_emit_device_found(struct btd_adapter *adapter,
-                                               struct remote_dev_info *dev)
+static void connect_failed_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
+       const struct mgmt_ev_connect_failed *ev = param;
+       struct btd_adapter *adapter = user_data;
        struct btd_device *device;
-       char peer_addr[18], local_addr[18];
-       const char *icon, *paddr = peer_addr;
-       dbus_bool_t paired = FALSE;
-       dbus_int16_t rssi = dev->rssi;
-       char *alias;
-       size_t uuid_count;
+       char addr[18];
+
+       if (length < sizeof(*ev)) {
+               error("Too small connect failed event");
+               return;
+       }
 
-       ba2str(&dev->bdaddr, peer_addr);
-       ba2str(&adapter->bdaddr, local_addr);
+       ba2str(&ev->addr.bdaddr, addr);
 
-       device = adapter_find_device(adapter, paddr);
-       if (device)
-               paired = device_is_paired(device);
+       DBG("hci%u %s status %u", index, addr, ev->status);
 
-       /* The uuids string array is updated only if necessary */
-       uuid_count = g_slist_length(dev->services);
-       if (dev->services && dev->uuid_count != uuid_count) {
-               g_strfreev(dev->uuids);
-               dev->uuids = strlist2array(dev->services);
-               dev->uuid_count = uuid_count;
-       }
+       device = btd_adapter_find_device(adapter, &ev->addr.bdaddr,
+                                                               ev->addr.type);
+       if (device) {
+               conn_fail_notify(device, ev->status);
 
-       if (dev->le) {
-               gboolean broadcaster;
+               /* If the device is in a bonding process cancel any auth request
+                * sent to the agent before proceeding, but keep the bonding
+                * request structure. */
+               if (device_is_bonding(device, NULL))
+                       device_cancel_authentication(device, FALSE);
+       }
 
-               if (dev->flags & (EIR_LIM_DISC | EIR_GEN_DISC))
-                       broadcaster = FALSE;
-               else
-                       broadcaster = TRUE;
+       /* In the case of security mode 3 devices */
+       bonding_attempt_complete(adapter, &ev->addr.bdaddr, ev->addr.type,
+                                                               ev->status);
 
-               emit_device_found(adapter->path, paddr,
-                               "Address", DBUS_TYPE_STRING, &paddr,
-                               "RSSI", DBUS_TYPE_INT16, &rssi,
-                               "Name", DBUS_TYPE_STRING, &dev->name,
-                               "Paired", DBUS_TYPE_BOOLEAN, &paired,
-                               "Broadcaster", DBUS_TYPE_BOOLEAN, &broadcaster,
-                               "UUIDs", DBUS_TYPE_ARRAY, &dev->uuids, uuid_count,
-                               NULL);
-               return;
+       /* If the device is scheduled to retry the bonding wait until the retry
+        * happens. In other case, proceed with cancel the bondig.
+        */
+       if (device && device_is_bonding(device, NULL)
+                                       && !device_is_retrying(device)) {
+               device_cancel_authentication(device, TRUE);
+               device_bonding_failed(device, ev->status);
        }
 
-       icon = class_to_icon(dev->class);
+#ifndef __TIZEN_PATCH__
+       /* In the case the bonding was canceled or did exists, remove the device
+        * when it is temporary. */
+       if (device && !device_is_bonding(device, NULL)
+                                               && device_is_temporary(device))
+               btd_adapter_remove_device(adapter, device);
+#endif
+}
 
-       if (!dev->alias) {
-               if (!dev->name) {
-                       alias = g_strdup(peer_addr);
-                       g_strdelimit(alias, ":", '-');
-               } else
-                       alias = g_strdup(dev->name);
-       } else
-               alias = g_strdup(dev->alias);
-
-       emit_device_found(adapter->path, paddr,
-                       "Address", DBUS_TYPE_STRING, &paddr,
-                       "Class", DBUS_TYPE_UINT32, &dev->class,
-                       "Icon", DBUS_TYPE_STRING, &icon,
-                       "RSSI", DBUS_TYPE_INT16, &rssi,
-                       "Name", DBUS_TYPE_STRING, &dev->name,
-                       "Alias", DBUS_TYPE_STRING, &alias,
-                       "LegacyPairing", DBUS_TYPE_BOOLEAN, &dev->legacy,
-                       "Paired", DBUS_TYPE_BOOLEAN, &paired,
-                       "UUIDs", DBUS_TYPE_ARRAY, &dev->uuids, uuid_count,
-                       NULL);
-
-       g_free(alias);
-}
-
-static struct remote_dev_info *get_found_dev(struct btd_adapter *adapter,
-                                               const bdaddr_t *bdaddr,
-                                               gboolean *new_dev)
+static void remove_keys(struct btd_adapter *adapter,
+                                       struct btd_device *device, uint8_t type)
 {
-       struct remote_dev_info *dev, match;
+       char adapter_addr[18];
+       char device_addr[18];
+       char filename[PATH_MAX];
+       GKeyFile *key_file;
+       gsize length = 0;
+       char *str;
 
-       memset(&match, 0, sizeof(struct remote_dev_info));
-       bacpy(&match.bdaddr, bdaddr);
-       match.name_status = NAME_ANY;
+       ba2str(btd_adapter_get_address(adapter), adapter_addr);
+       ba2str(device_get_address(device), device_addr);
 
-       dev = adapter_search_found_devices(adapter, &match);
-       if (dev) {
-               *new_dev = FALSE;
-               /* Out of range list update */
-               adapter->oor_devices = g_slist_remove(adapter->oor_devices,
-                                                       dev);
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", adapter_addr,
+                                                               device_addr);
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+       if (type == BDADDR_BREDR) {
+               g_key_file_remove_group(key_file, "LinkKey", NULL);
        } else {
-               *new_dev = TRUE;
-               dev = g_new0(struct remote_dev_info, 1);
-               bacpy(&dev->bdaddr, bdaddr);
-               adapter->found_devices = g_slist_prepend(adapter->found_devices,
-                                                                       dev);
+               g_key_file_remove_group(key_file, "LongTermKey", NULL);
+               g_key_file_remove_group(key_file, "LocalSignatureKey", NULL);
+               g_key_file_remove_group(key_file, "RemoteSignatureKey", NULL);
+               g_key_file_remove_group(key_file, "IdentityResolvingKey", NULL);
        }
 
-       return dev;
+       str = g_key_file_to_data(key_file, &length, NULL);
+       g_file_set_contents(filename, str, length, NULL);
+       g_free(str);
+
+       g_key_file_free(key_file);
 }
 
-static void remove_same_uuid(gpointer data, gpointer user_data)
+static void unpaired_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       struct remote_dev_info *dev = user_data;
-       GSList *l;
+       const struct mgmt_ev_device_unpaired *ev = param;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       char addr[18];
+
+       if (length < sizeof(*ev)) {
+               error("Too small device unpaired event");
+               return;
+       }
 
-       for (l = dev->services; l; l = l->next) {
-               char *current_uuid = l->data;
-               char *new_uuid = data;
+       ba2str(&ev->addr.bdaddr, addr);
 
-               if (strcmp(current_uuid, new_uuid) == 0) {
-                       g_free(current_uuid);
-                       dev->services = g_slist_delete_link(dev->services, l);
-                       break;
-               }
+       DBG("hci%u addr %s", index, addr);
+
+       device = btd_adapter_find_device(adapter, &ev->addr.bdaddr,
+                                                               ev->addr.type);
+       if (!device) {
+               warn("No device object for unpaired device %s", addr);
+               return;
        }
+
+       remove_keys(adapter, device, ev->addr.type);
+       device_set_unpaired(device, ev->addr.type);
 }
 
-static void dev_prepend_uuid(gpointer data, gpointer user_data)
+#ifdef __TIZEN_PATCH__
+static void set_privacy_complete(uint8_t status, uint16_t length,
+       const void *param, void *user_data)
 {
-       struct remote_dev_info *dev = user_data;
-       char *new_uuid = data;
+       struct btd_adapter *adapter = user_data;
 
-       dev->services = g_slist_prepend(dev->services, g_strdup(new_uuid));
+       if (status != MGMT_STATUS_SUCCESS)
+               error("Setting privacy failed for hci%u: %s (0x%02x)",
+                       adapter->dev_id, mgmt_errstr(status), status);
+       else
+               DBG("Privacy feature is set/unset successfully for hci%u",
+                       adapter->dev_id);
 }
 
-void adapter_update_device_from_info(struct btd_adapter *adapter,
-                                       bdaddr_t bdaddr, int8_t rssi,
-                                       uint8_t evt_type, const char *name,
-                                       GSList *services, int flags)
+static bool set_privacy(struct btd_adapter *adapter, bool privacy)
 {
-       struct remote_dev_info *dev;
-       gboolean new_dev;
-
-       dev = get_found_dev(adapter, &bdaddr, &new_dev);
-
-       if (new_dev) {
-               dev->le = TRUE;
-               dev->evt_type = evt_type;
-       } else if (dev->rssi == rssi)
-               return;
+       struct mgmt_cp_set_privacy cp;
+       static const char testblock[MGMT_IRK_SIZE];
 
-       dev->rssi = rssi;
+       memset(&cp, 0, sizeof(cp));
 
-       adapter->found_devices = g_slist_sort(adapter->found_devices,
-                                               (GCompareFunc) dev_rssi_cmp);
+       if (privacy) {
+               if (!memcmp(adapter->local_irk, testblock, MGMT_IRK_SIZE)) {
+                       cp.privacy = GEN_IRK_THEN_ENABLE_PRIVACY;
+                       memset(cp.irk, 0, MGMT_IRK_SIZE);
+               } else {
+                       cp.privacy = ENABLE_PRIVACY;
+                       memcpy(cp.irk, adapter->local_irk, MGMT_IRK_SIZE);
+               }
+       } else {
+               cp.privacy = DISABLE_PRIVACY;
+               memset(cp.irk, 0, 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;
 
-       g_slist_foreach(services, remove_same_uuid, dev);
-       g_slist_foreach(services, dev_prepend_uuid, dev);
+       error("Failed to set privacy and load local irk for index %u",
+               adapter->dev_id);
 
-       if (flags >= 0)
-               dev->flags = flags;
+       return false;
+}
+#endif
 
-       if (name) {
-               g_free(dev->name);
-               dev->name = g_strdup(name);
+static void clear_devices_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to clear devices: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
        }
-
-       /* FIXME: check if other information was changed before emitting the
-        * signal */
-       adapter_emit_device_found(adapter, dev);
 }
 
-void adapter_update_found_devices(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                               int8_t rssi, uint32_t class, const char *name,
-                               const char *alias, gboolean legacy,
-                               GSList *services, name_status_t name_status)
+static int clear_devices(struct btd_adapter *adapter)
 {
-       struct remote_dev_info *dev;
-       gboolean new_dev;
+       struct mgmt_cp_remove_device cp;
 
-       dev = get_found_dev(adapter, bdaddr, &new_dev);
-
-       if (new_dev) {
-               if (name)
-                       dev->name = g_strdup(name);
-
-               if (alias)
-                       dev->alias = g_strdup(alias);
+       if (!kernel_conn_control)
+               return 0;
 
-               dev->le = FALSE;
-               dev->class = class;
-               dev->legacy = legacy;
-               dev->name_status = name_status;
-       } else if (dev->rssi == rssi)
-               return;
+       memset(&cp, 0, sizeof(cp));
 
-       dev->rssi = rssi;
+       DBG("sending clear devices command for index %u", adapter->dev_id);
 
-       adapter->found_devices = g_slist_sort(adapter->found_devices,
-                                               (GCompareFunc) dev_rssi_cmp);
+       if (mgmt_send(adapter->mgmt, MGMT_OP_REMOVE_DEVICE,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               clear_devices_complete, adapter, NULL) > 0)
+               return 0;
 
-       g_slist_foreach(services, remove_same_uuid, dev);
-       g_slist_foreach(services, dev_prepend_uuid, dev);
+       error("Failed to clear devices for index %u", adapter->dev_id);
 
-       adapter_emit_device_found(adapter, dev);
+       return -EIO;
 }
 
-int adapter_remove_found_device(struct btd_adapter *adapter, bdaddr_t *bdaddr)
+static void read_info_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       struct remote_dev_info *dev, match;
+       struct btd_adapter *adapter = user_data;
+       const struct mgmt_rp_read_info *rp = param;
+       uint32_t missing_settings;
+       int err;
 
-       memset(&match, 0, sizeof(struct remote_dev_info));
-       bacpy(&match.bdaddr, bdaddr);
+       DBG("index %u status 0x%02x", adapter->dev_id, status);
 
-       dev = adapter_search_found_devices(adapter, &match);
-       if (!dev)
-               return -1;
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to read info for index %u: %s (0x%02x)",
+                               adapter->dev_id, mgmt_errstr(status), status);
+               goto failed;
+       }
 
-       dev->name_status = NAME_NOT_REQUIRED;
+       if (length < sizeof(*rp)) {
+               error("Too small read info complete response");
+               goto failed;
+       }
 
-       return 0;
-}
+       if (bacmp(&rp->bdaddr, BDADDR_ANY) == 0) {
+               error("No Bluetooth address for index %u", adapter->dev_id);
+               goto failed;
+       }
 
-void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode)
-{
-       const gchar *path = adapter_get_path(adapter);
-       gboolean discoverable, pairable;
+       /*
+        * Store controller information for device address, class of device,
+        * device name, short name and settings.
+        *
+        * During the lifetime of the controller these will be updated by
+        * events and the information is required to keep the current
+        * state of the controller.
+        */
+       bacpy(&adapter->bdaddr, &rp->bdaddr);
+       adapter->dev_class = rp->dev_class[0] | (rp->dev_class[1] << 8) |
+                                               (rp->dev_class[2] << 16);
+       adapter->name = g_strdup((const char *) rp->name);
+       adapter->short_name = g_strdup((const char *) rp->short_name);
+
+       adapter->supported_settings = btohl(rp->supported_settings);
+       adapter->current_settings = btohl(rp->current_settings);
 
-       DBG("old 0x%02x new 0x%02x", adapter->scan_mode, scan_mode);
 #ifdef __TIZEN_PATCH__
-       gboolean limited;
+       adapter_check_version(adapter, rp->version);
 #endif
 
-       if (adapter->scan_mode == scan_mode)
-               return;
+       clear_uuids(adapter);
+       clear_devices(adapter);
 
-       adapter_remove_discov_timeout(adapter);
+       missing_settings = adapter->current_settings ^
+                                               adapter->supported_settings;
 
-       switch (scan_mode) {
-       case SCAN_DISABLED:
-               adapter->mode = MODE_OFF;
-               discoverable = FALSE;
-               pairable = FALSE;
-#ifdef __TIZEN_PATCH__
-               limited = FALSE;
-#endif
+       switch (main_opts.mode) {
+       case BT_MODE_DUAL:
+               if (missing_settings & MGMT_SETTING_SSP)
+                       set_mode(adapter, MGMT_OP_SET_SSP, 0x01);
+               if (missing_settings & MGMT_SETTING_LE)
+                       set_mode(adapter, MGMT_OP_SET_LE, 0x01);
+               if (missing_settings & MGMT_SETTING_BREDR)
+                       set_mode(adapter, MGMT_OP_SET_BREDR, 0x01);
                break;
-       case SCAN_PAGE:
-               adapter->mode = MODE_CONNECTABLE;
-               discoverable = FALSE;
-               pairable = adapter->pairable;
-#ifdef __TIZEN_PATCH__
-               limited = FALSE;
-#endif
+       case BT_MODE_BREDR:
+               if (!(adapter->supported_settings & MGMT_SETTING_BREDR)) {
+                       error("Ignoring adapter withouth BR/EDR support");
+                       goto failed;
+               }
+
+               if (missing_settings & MGMT_SETTING_SSP)
+                       set_mode(adapter, MGMT_OP_SET_SSP, 0x01);
+               if (missing_settings & MGMT_SETTING_BREDR)
+                       set_mode(adapter, MGMT_OP_SET_BREDR, 0x01);
+               if (adapter->current_settings & MGMT_SETTING_LE)
+                       set_mode(adapter, MGMT_OP_SET_LE, 0x00);
                break;
-       case (SCAN_PAGE | SCAN_INQUIRY):
-               adapter->mode = MODE_DISCOVERABLE;
-               discoverable = TRUE;
-               pairable = adapter->pairable;
-               if (adapter->discov_timeout != 0)
-                       adapter_set_discov_timeout(adapter,
-                                               adapter->discov_timeout);
+       case BT_MODE_LE:
+               if (!(adapter->supported_settings & MGMT_SETTING_LE)) {
+                       error("Ignoring adapter withouth LE support");
+                       goto failed;
+               }
+
+               if (missing_settings & MGMT_SETTING_LE)
+                       set_mode(adapter, MGMT_OP_SET_LE, 0x01);
+               if (adapter->current_settings & MGMT_SETTING_BREDR)
+                       set_mode(adapter, MGMT_OP_SET_BREDR, 0x00);
                break;
-       case SCAN_INQUIRY:
-               /* Address the scenario where a low-level application like
-                * hciconfig changed the scan mode */
-               if (adapter->discov_timeout != 0)
-                       adapter_set_discov_timeout(adapter,
-                                               adapter->discov_timeout);
-
-               /* ignore, this event should not be sent */
-       default:
-               /* ignore, reserved */
-               return;
        }
 
-       /* If page scanning gets toggled emit the Pairable property */
-       if ((adapter->scan_mode & SCAN_PAGE) != (scan_mode & SCAN_PAGE))
-               emit_property_changed(connection, adapter->path,
-                                       ADAPTER_INTERFACE, "Pairable",
-                                       DBUS_TYPE_BOOLEAN, &pairable);
+#if 0
+       if (missing_settings & MGMT_SETTING_SECURE_CONN)
+               set_mode(adapter, MGMT_OP_SET_SECURE_CONN, 0x01);
+#endif
+
+       err = adapter_register(adapter);
+       if (err < 0) {
+               error("Unable to register new adapter");
+               goto failed;
+       }
+
+       /*
+        * Register all event notification handlers for controller.
+        *
+        * The handlers are registered after a succcesful read of the
+        * controller info. From now on they can track updates and
+        * notifications.
+        */
+       mgmt_register(adapter->mgmt, MGMT_EV_NEW_SETTINGS, adapter->dev_id,
+                                       new_settings_callback, adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_CLASS_OF_DEV_CHANGED,
+                                               adapter->dev_id,
+                                               dev_class_changed_callback,
+                                               adapter, NULL);
+       mgmt_register(adapter->mgmt, MGMT_EV_LOCAL_NAME_CHANGED,
+                                               adapter->dev_id,
+                                               local_name_changed_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_DISCOVERING,
+                                               adapter->dev_id,
+                                               discovering_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_DEVICE_FOUND,
+                                               adapter->dev_id,
+                                               device_found_callback,
+                                               adapter, NULL);
+
+#ifdef __TIZEN_PATCH__
+       mgmt_register(adapter->mgmt, MGMT_EV_LE_DEVICE_FOUND,
+                                               adapter->dev_id,
+                                               le_device_found_callback,
+                                               adapter, NULL);
+#endif
+
+       mgmt_register(adapter->mgmt, MGMT_EV_DEVICE_DISCONNECTED,
+                                               adapter->dev_id,
+                                               disconnected_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_DEVICE_CONNECTED,
+                                               adapter->dev_id,
+                                               connected_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_CONNECT_FAILED,
+                                               adapter->dev_id,
+                                               connect_failed_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_DEVICE_UNPAIRED,
+                                               adapter->dev_id,
+                                               unpaired_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_AUTH_FAILED,
+                                               adapter->dev_id,
+                                               auth_failed_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_NEW_LINK_KEY,
+                                               adapter->dev_id,
+                                               new_link_key_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_NEW_LONG_TERM_KEY,
+                                               adapter->dev_id,
+                                               new_long_term_key_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_NEW_CSRK,
+                                               adapter->dev_id,
+                                               new_csrk_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_NEW_IRK,
+                                               adapter->dev_id,
+                                               new_irk_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_NEW_CONN_PARAM,
+                                               adapter->dev_id,
+                                               new_conn_param,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_DEVICE_BLOCKED,
+                                               adapter->dev_id,
+                                               device_blocked_callback,
+                                               adapter, NULL);
+       mgmt_register(adapter->mgmt, MGMT_EV_DEVICE_UNBLOCKED,
+                                               adapter->dev_id,
+                                               device_unblocked_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_PIN_CODE_REQUEST,
+                                               adapter->dev_id,
+                                               pin_code_request_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_USER_CONFIRM_REQUEST,
+                                               adapter->dev_id,
+                                               user_confirm_request_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_USER_PASSKEY_REQUEST,
+                                               adapter->dev_id,
+                                               user_passkey_request_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_PASSKEY_NOTIFY,
+                                               adapter->dev_id,
+                                               user_passkey_notify_callback,
+                                               adapter, NULL);
+
+#ifdef __TIZEN_PATCH__
+       mgmt_register(adapter->mgmt, MGMT_EV_RSSI_ALERT,
+                                               adapter->dev_id,
+                                               rssi_alert_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_RAW_RSSI,
+                                               adapter->dev_id,
+                                               get_raw_rssi_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_RSSI_ENABLED,
+                                                       adapter->dev_id,
+                                                       rssi_enabled_callback,
+                                                       adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_RSSI_DISABLED,
+                                                       adapter->dev_id,
+                                                       rssi_disabled_callback,
+                                                       adapter, NULL);
+
+#if 0 // Not used
+       mgmt_register(adapter->mgmt, MGMT_EV_NEW_LOCAL_IRK,
+                                               adapter->dev_id,
+                                               new_local_irk_callback,
+                                               adapter, NULL);
+#endif
+
+       mgmt_register(adapter->mgmt, MGMT_EV_HARDWARE_ERROR,
+                                               adapter->dev_id,
+                                               hardware_error_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_TX_TIMEOUT_ERROR,
+                                               adapter->dev_id,
+                                               tx_timeout_error_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_DEVICE_NAME_UPDATE,
+                                       adapter->dev_id,
+                                       device_name_update_callback,
+                                       adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_MULTI_ADV_STATE_CHANGED,
+                               adapter->dev_id,
+                               multi_adv_state_change_callback,
+                               adapter, NULL);
+#endif
 
-       if (!discoverable)
-               adapter_set_limited_discoverable(adapter, FALSE);
+       set_dev_class(adapter);
 
-       emit_property_changed(connection, path,
-                               ADAPTER_INTERFACE, "Discoverable",
-                               DBUS_TYPE_BOOLEAN, &discoverable);
+       set_name(adapter, btd_adapter_get_name(adapter));
 
-       adapter->scan_mode = scan_mode;
+       if (!(adapter->current_settings & MGMT_SETTING_BONDABLE))
+               set_mode(adapter, MGMT_OP_SET_BONDABLE, 0x01);
 
-       set_mode_complete(adapter);
-}
+       if (!kernel_conn_control)
+               set_mode(adapter, MGMT_OP_SET_CONNECTABLE, 0x01);
+       else if (adapter->current_settings & MGMT_SETTING_CONNECTABLE)
+               set_mode(adapter, MGMT_OP_SET_CONNECTABLE, 0x00);
 
-struct agent *adapter_get_agent(struct btd_adapter *adapter)
-{
-       if (!adapter || !adapter->agent)
-               return NULL;
+       if (adapter->stored_discoverable && !adapter->discoverable_timeout)
+               set_discoverable(adapter, 0x01, 0);
 
-       return adapter->agent;
-}
+       if (adapter->current_settings & MGMT_SETTING_POWERED)
+               adapter_start(adapter);
+#ifdef __TIZEN_PATCH__
+       else
+               set_mode(adapter, MGMT_OP_SET_POWERED, 0x01);
+#endif
 
-void adapter_add_connection(struct btd_adapter *adapter,
-                                               struct btd_device *device)
-{
-       if (g_slist_find(adapter->connections, device)) {
-               error("Device is already marked as connected");
-               return;
-       }
+       return;
 
-       device_add_connection(device, connection);
+failed:
+       /*
+        * Remove adapter from list in case of a failure.
+        *
+        * Leaving an adapter structure around for a controller that can
+        * not be initilized makes no sense at the moment.
+        *
+        * This is a simplification to avoid constant checks if the
+        * adapter is ready to do anything.
+        */
+       adapter_list = g_list_remove(adapter_list, adapter);
 
-       adapter->connections = g_slist_append(adapter->connections, device);
+       btd_adapter_unref(adapter);
 }
 
-void adapter_remove_connection(struct btd_adapter *adapter,
-                                               struct btd_device *device)
+static void index_added(uint16_t index, uint16_t length, const void *param,
+                                                       void *user_data)
 {
-       bdaddr_t bdaddr;
+       struct btd_adapter *adapter;
 
-       DBG("");
+       DBG("index %u", index);
 
-       if (!g_slist_find(adapter->connections, device)) {
-               error("No matching connection for device");
+       adapter = btd_adapter_lookup(index);
+       if (adapter) {
+               warn("Ignoring index added for an already existing adapter");
                return;
        }
 
-       device_remove_connection(device, connection);
-
-       adapter->connections = g_slist_remove(adapter->connections, device);
-
-       /* clean pending HCI cmds */
-       device_get_address(device, &bdaddr);
-
-       if (device_is_authenticating(device))
-               device_cancel_authentication(device, TRUE);
-
-       if (device_is_temporary(device)) {
-               const char *path = device_get_path(device);
-
-               DBG("Removing temporary device %s", path);
-               adapter_remove_device(connection, adapter, device, TRUE);
+       adapter = btd_adapter_new(index);
+       if (!adapter) {
+               error("Unable to create new adapter for index %u", index);
+               return;
        }
-}
 
-gboolean adapter_has_discov_sessions(struct btd_adapter *adapter)
-{
-       if (!adapter || !adapter->disc_sessions)
-               return FALSE;
+       /*
+        * Protect against potential two executions of read controller info.
+        *
+        * In case the start of the daemon and the action of adding a new
+        * controller coincide this function might be called twice.
+        *
+        * To avoid the double execution of reading the controller info,
+        * add the adapter already to the list. If an adapter is already
+        * present, the second notification will cause a warning. If the
+        * command fails the adapter is removed from the list again.
+        */
+       adapter_list = g_list_append(adapter_list, adapter);
 
-       return TRUE;
-}
+       DBG("sending read info command for index %u", index);
 
-void adapter_suspend_discovery(struct btd_adapter *adapter)
-{
-       if (adapter->disc_sessions == NULL ||
-                       adapter->state & STATE_SUSPENDED)
+       if (mgmt_send(mgmt_master, MGMT_OP_READ_INFO, index, 0, NULL,
+                                       read_info_complete, adapter, NULL) > 0)
                return;
 
-       DBG("Suspending discovery");
-
-       stop_discovery(adapter, TRUE);
-       adapter->state |= STATE_SUSPENDED;
-}
-
-void adapter_resume_discovery(struct btd_adapter *adapter)
-{
-       if (adapter->disc_sessions == NULL)
-               return;
+       error("Failed to read controller info for index %u", index);
 
-       DBG("Resuming discovery");
+       adapter_list = g_list_remove(adapter_list, adapter);
 
-       adapter->state &= ~STATE_SUSPENDED;
-       start_discovery(adapter);
+       btd_adapter_unref(adapter);
 }
 
-int btd_register_adapter_driver(struct btd_adapter_driver *driver)
+static void index_removed(uint16_t index, uint16_t length, const void *param,
+                                                       void *user_data)
 {
-       adapter_drivers = g_slist_append(adapter_drivers, driver);
+       struct btd_adapter *adapter;
 
-       if (driver->probe == NULL)
-               return 0;
+       DBG("index %u", index);
 
-       manager_foreach_adapter(probe_driver, driver);
+       adapter = btd_adapter_lookup(index);
+       if (!adapter) {
+               warn("Ignoring index removal for a non-existent adapter");
+               return;
+       }
 
-       return 0;
+       adapter_unregister(adapter);
 }
 
-static void unload_driver(struct btd_adapter *adapter, gpointer data)
+static void read_index_list_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       adapter->loaded_drivers = g_slist_remove(adapter->loaded_drivers, data);
-}
+       const struct mgmt_rp_read_index_list *rp = param;
+       uint16_t num;
+       int i;
 
-void btd_unregister_adapter_driver(struct btd_adapter_driver *driver)
-{
-       adapter_drivers = g_slist_remove(adapter_drivers, driver);
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to read index list: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
+       }
 
-       manager_foreach_adapter(unload_driver, driver);
-}
+       if (length < sizeof(*rp)) {
+               error("Wrong size of read index list response");
+               return;
+       }
 
-static void agent_auth_cb(struct agent *agent, DBusError *derr,
-                                                       void *user_data)
-{
-       struct service_auth *auth = user_data;
+       num = btohs(rp->num_controllers);
 
-       device_set_authorizing(auth->device, FALSE);
+       DBG("Number of controllers: %d", num);
 
-       auth->cb(derr, auth->user_data);
-}
+       if (num * sizeof(uint16_t) + sizeof(*rp) != length) {
+               error("Incorrect packet size for index list response");
+               return;
+       }
 
-static gboolean auth_idle_cb(gpointer user_data)
-{
-       struct service_auth *auth = user_data;
-       struct btd_adapter *adapter = auth->adapter;
+       for (i = 0; i < num; i++) {
+               uint16_t index;
 
-       adapter->auth_idle_id = 0;
+               index = btohs(rp->index[i]);
 
-       auth->cb(NULL, auth->user_data);
+               DBG("Found index %u", index);
 
-       return FALSE;
+               /*
+                * Pretend to be index added event notification.
+                *
+                * It is safe to just trigger the procedure for index
+                * added notification. It does check against itself.
+                */
+               index_added(index, 0, NULL, NULL);
+       }
 }
 
-static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
-                                       const char *uuid, service_auth_cb cb,
-                                       void *user_data)
+static void read_commands_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       struct service_auth *auth;
-       struct btd_device *device;
-       struct agent *agent;
-       char address[18];
-       const gchar *dev_path;
-       int err;
-
-       ba2str(dst, address);
-       device = adapter_find_device(adapter, address);
-       if (!device)
-               return -EPERM;
+       const struct mgmt_rp_read_commands *rp = param;
+       uint16_t num_commands, num_events;
+       const uint16_t *opcode;
+       size_t expected_len;
+       int i;
 
-       /* Device connected? */
-       if (!g_slist_find(adapter->connections, device))
-               return -ENOTCONN;
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to read supported commands: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
+       }
 
-       if (adapter->auth_idle_id)
-               return -EBUSY;
+       if (length < sizeof(*rp)) {
+               error("Wrong size of read commands response");
+               return;
+       }
 
-       auth = g_try_new0(struct service_auth, 1);
-       if (!auth)
-               return -ENOMEM;
+       num_commands = btohs(rp->num_commands);
+       num_events = btohs(rp->num_events);
 
-       auth->cb = cb;
-       auth->user_data = user_data;
-       auth->device = device;
-       auth->adapter = adapter;
+       DBG("Number of commands: %d", num_commands);
+       DBG("Number of events: %d", num_events);
 
-       if (device_is_trusted(device) == TRUE) {
-               adapter->auth_idle_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
-                                                       auth_idle_cb, auth,
-                                                       g_free);
-               return 0;
-       }
+       expected_len = sizeof(*rp) + num_commands * sizeof(uint16_t) +
+                                               num_events * sizeof(uint16_t);
 
-       agent = device_get_agent(device);
-       if (!agent) {
-               g_free(auth);
-               return -EPERM;
+       if (length < expected_len) {
+               error("Too small reply for supported commands: (%u != %zu)",
+                                                       length, expected_len);
+               return;
        }
 
-       dev_path = device_get_path(device);
+       opcode = rp->opcodes;
 
-       err = agent_authorize(agent, dev_path, uuid, agent_auth_cb, auth, g_free);
-       if (err < 0)
-               g_free(auth);
-       else
-               device_set_authorizing(device, TRUE);
+       for (i = 0; i < num_commands; i++) {
+               uint16_t op = get_le16(opcode++);
 
-       return err;
+               if (op == MGMT_OP_ADD_DEVICE) {
+                       DBG("enabling kernel-side connection control");
+                       kernel_conn_control = true;
+               }
+       }
 }
 
-int btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
-                                       const char *uuid, service_auth_cb cb,
-                                       void *user_data)
+static void read_version_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       struct btd_adapter *adapter;
-       GSList *l;
+       const struct mgmt_rp_read_version *rp = param;
 
-       if (bacmp(src, BDADDR_ANY) != 0) {
-               adapter = manager_find_adapter(src);
-               if (!adapter)
-                       return -EPERM;
-
-               return adapter_authorize(adapter, dst, uuid, cb, user_data);
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to read version information: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
        }
 
-       for (l = manager_get_adapters(); l != NULL; l = g_slist_next(l)) {
-               int err;
-
-               adapter = l->data;
-
-               err = adapter_authorize(adapter, dst, uuid, cb, user_data);
-               if (err == 0)
-                       return 0;
+       if (length < sizeof(*rp)) {
+               error("Wrong size of read version response");
+               return;
        }
 
-       return -EPERM;
-}
-
-int btd_cancel_authorization(const bdaddr_t *src, const bdaddr_t *dst)
-{
-       struct btd_adapter *adapter = manager_find_adapter(src);
-       struct btd_device *device;
-       struct agent *agent;
-       char address[18];
-       int err;
-
-       if (!adapter)
-               return -EPERM;
+       mgmt_version = rp->version;
+       mgmt_revision = btohs(rp->revision);
 
-       ba2str(dst, address);
-       device = adapter_find_device(adapter, address);
-       if (!device)
-               return -EPERM;
+       info("Bluetooth management interface %u.%u initialized",
+                                               mgmt_version, mgmt_revision);
 
-       if (adapter->auth_idle_id) {
-               g_source_remove(adapter->auth_idle_id);
-               adapter->auth_idle_id = 0;
-               return 0;
+       if (mgmt_version < 1) {
+               error("Version 1.0 or later of management interface required");
+               abort();
        }
 
+       DBG("sending read supported commands command");
+
        /*
-        * FIXME: Cancel fails if authorization is requested to adapter's
-        * agent and in the meanwhile CreatePairedDevice is called.
+        * It is irrelevant if this command succeeds or fails. In case of
+        * failure safe settings are assumed.
         */
+       mgmt_send(mgmt_master, MGMT_OP_READ_COMMANDS,
+                               MGMT_INDEX_NONE, 0, NULL,
+                               read_commands_complete, NULL, NULL);
 
-       agent = device_get_agent(device);
-       if (!agent)
-               return -EPERM;
+       mgmt_register(mgmt_master, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
+                                               index_added, NULL, NULL);
+       mgmt_register(mgmt_master, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE,
+                                               index_removed, NULL, NULL);
 
-       err = agent_cancel(agent);
+       DBG("sending read index list command");
 
-       if (err == 0)
-               device_set_authorizing(device, FALSE);
+       if (mgmt_send(mgmt_master, MGMT_OP_READ_INDEX_LIST,
+                               MGMT_INDEX_NONE, 0, NULL,
+                               read_index_list_complete, NULL, NULL) > 0)
+               return;
 
-       return err;
+       error("Failed to read controller index list");
 }
 
-static gchar *adapter_any_path = NULL;
-static int adapter_any_refcount = 0;
-
-const char *adapter_any_get_path(void)
+static void mgmt_debug(const char *str, void *user_data)
 {
-       return adapter_any_path;
+       const char *prefix = user_data;
+
+       info("%s%s", prefix, str);
 }
 
-const char *btd_adapter_any_request_path(void)
+int adapter_init(void)
 {
-       if (adapter_any_refcount++ > 0)
-               return adapter_any_path;
+       dbus_conn = btd_get_dbus_connection();
 
-       adapter_any_path = g_strdup_printf("%s/any", manager_get_base_path());
-
-       return adapter_any_path;
-}
+       mgmt_master = mgmt_new_default();
+       if (!mgmt_master) {
+               error("Failed to access management interface");
+               return -EIO;
+       }
 
-void btd_adapter_any_release_path(void)
-{
-       adapter_any_refcount--;
+       if (getenv("MGMT_DEBUG"))
+               mgmt_set_debug(mgmt_master, mgmt_debug, "mgmt: ", NULL);
 
-       if (adapter_any_refcount > 0)
-               return;
+       DBG("sending read version command");
 
-       g_free(adapter_any_path);
-       adapter_any_path = NULL;
-}
+       if (mgmt_send(mgmt_master, MGMT_OP_READ_VERSION,
+                               MGMT_INDEX_NONE, 0, NULL,
+                               read_version_complete, NULL, NULL) > 0)
+               return 0;
 
-gboolean adapter_is_pairable(struct btd_adapter *adapter)
-{
-       return adapter->pairable;
-}
+       error("Failed to read management version information");
 
-gboolean adapter_powering_down(struct btd_adapter *adapter)
-{
-       return adapter->off_requested;
+       return -EIO;
 }
 
-int btd_adapter_restore_powered(struct btd_adapter *adapter)
+void adapter_cleanup(void)
 {
-       char mode[14], address[18];
-       gboolean discoverable;
+       g_list_free(adapter_list);
 
-       if (!adapter_ops)
-               return -EINVAL;
+       while (adapters) {
+               struct btd_adapter *adapter = adapters->data;
 
-       if (!main_opts.remember_powered)
-               return -EINVAL;
+               adapter_remove(adapter);
+               adapters = g_slist_remove(adapters, adapter);
+               btd_adapter_unref(adapter);
+       }
 
-       if (adapter->up)
-               return 0;
+       /*
+        * In case there is another reference active, clear out
+        * registered handlers for index added and index removed.
+        *
+        * This is just an extra precaution to be safe, and in
+        * reality should not make a difference.
+        */
+       mgmt_unregister_index(mgmt_master, MGMT_INDEX_NONE);
 
-       ba2str(&adapter->bdaddr, address);
-       if (read_device_mode(address, mode, sizeof(mode)) == 0 &&
-                                               g_str_equal(mode, "off"))
-               return 0;
+       /*
+        * In case there is another reference active, cancel
+        * all pending global commands.
+        *
+        * This is just an extra precaution to avoid callbacks
+        * that potentially then could leak memory or access
+        * an invalid structure.
+        */
+       mgmt_cancel_index(mgmt_master, MGMT_INDEX_NONE);
 
-       discoverable = get_mode(&adapter->bdaddr, mode) == MODE_DISCOVERABLE;
+       mgmt_unref(mgmt_master);
+       mgmt_master = NULL;
 
-       return adapter_ops->set_powered(adapter->dev_id, TRUE);
+       dbus_conn = NULL;
 }
 
-int btd_adapter_switch_online(struct btd_adapter *adapter)
+void adapter_shutdown(void)
 {
-       if (!adapter_ops)
-               return -EINVAL;
-
-       if (adapter->up)
-               return 0;
+       GList *list;
 
-       return adapter_ops->set_powered(adapter->dev_id, TRUE);
-}
+       DBG("");
 
-int btd_adapter_switch_offline(struct btd_adapter *adapter)
-{
-       if (!adapter_ops)
-               return -EINVAL;
+       powering_down = true;
 
-       if (!adapter->up)
-               return 0;
+       for (list = g_list_first(adapter_list); list;
+                                               list = g_list_next(list)) {
+               struct btd_adapter *adapter = list->data;
 
-       return adapter_ops->set_powered(adapter->dev_id, FALSE);
-}
+               if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+                       continue;
 
-int btd_register_adapter_ops(struct btd_adapter_ops *ops, gboolean priority)
-{
-       if (ops->setup == NULL)
-               return -EINVAL;
+               set_mode(adapter, MGMT_OP_SET_POWERED, 0x00);
 
-       if (priority)
-               ops_candidates = g_slist_prepend(ops_candidates, ops);
-       else
-               ops_candidates = g_slist_append(ops_candidates, ops);
+               adapter_remaining++;
+       }
 
-       return 0;
+       if (!adapter_remaining)
+               btd_exit();
 }
 
-void btd_adapter_cleanup_ops(struct btd_adapter_ops *ops)
+/*
+ * Check if workaround for broken ATT server socket behavior is needed
+ * where we need to connect an ATT client socket before pairing to get
+ * early access to the ATT channel.
+ */
+bool btd_le_connect_before_pairing(void)
 {
-       ops_candidates = g_slist_remove(ops_candidates, ops);
-       ops->cleanup();
+       if (MGMT_VERSION(mgmt_version, mgmt_revision) < MGMT_VERSION(1, 4))
+               return true;
 
-       if (adapter_ops == ops)
-               adapter_ops = NULL;
+       return false;
 }
 
-int adapter_ops_setup(void)
+#ifdef __TIZEN_PATCH__
+#if 0 // Not used
+static void read_rssi_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       GSList *l;
-       int ret;
+       const struct mgmt_rp_read_rssi *rp = param;
+       struct btd_device *device = user_data;
 
-       if (!ops_candidates)
-               return -EINVAL;
-
-       for (l = ops_candidates; l != NULL; l = g_slist_next(l)) {
-               struct btd_adapter_ops *ops = l->data;
-
-               ret = ops->setup();
-               if (ret < 0)
-                       continue;
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("read RSSI failed: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
+       }
 
-               adapter_ops = ops;
-               break;
+       if (length < sizeof(*rp)) {
+               error("Too small read rssi response");
+               return;
        }
 
-       return ret;
+       if (!rp->status) {
+               device_set_rssi(device, rp->rssi);
+       }
+       return;
 }
 
-void btd_adapter_register_powered_callback(struct btd_adapter *adapter,
-                                               btd_adapter_powered_cb cb)
+int btd_adapter_read_rssi(struct btd_adapter *adapter, bdaddr_t *bdaddr,
+                                       struct btd_device *device)
 {
-       adapter->powered_callbacks =
-                       g_slist_append(adapter->powered_callbacks, cb);
-}
+       struct mgmt_cp_read_rssi cp;
 
-void btd_adapter_unregister_powered_callback(struct btd_adapter *adapter,
-                                               btd_adapter_powered_cb cb)
-{
-       adapter->powered_callbacks =
-                       g_slist_remove(adapter->powered_callbacks, cb);
+       DBG("btd_adapter_read_rssi");
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.bdaddr, bdaddr);
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_READ_RSSI,
+                       adapter->dev_id, sizeof(cp), &cp,
+                       read_rssi_complete, device, NULL) > 0)
+               return 0;
+       return -EIO;
 }
 
-int btd_adapter_set_fast_connectable(struct btd_adapter *adapter,
-                                                       gboolean enable)
+int btd_adapter_l2cap_conn_param_update(struct btd_adapter *adapter,
+                               bdaddr_t *bdaddr, uint16_t interval_min,
+                               uint16_t interval_max, uint16_t latency,
+                               uint16_t supervision_time_out)
 {
-       if (!adapter_ops)
-               return -EINVAL;
+       struct mgmt_cp_l2cap_conn_param_update cp;
 
-       if (!adapter->up)
-               return -EINVAL;
+       memset(&cp, 0, sizeof(cp));
+       if (bdaddr)
+               bacpy(&cp.bdaddr, bdaddr);
+       else
+               return -EIO;
+
+       cp.interval_min = interval_min;
+       cp.interval_max = interval_max;
+       cp.latency = latency;
+       cp.supervision_time_out = supervision_time_out;
+       if (mgmt_send(adapter->mgmt, MGMT_OP_L2CAP_CONN_PARAM_UPDATE,
+                       adapter->dev_id, sizeof(cp), &cp,
+                       NULL, NULL, NULL) > 0)
+               return 0;
 
-       return adapter_ops->set_fast_connectable(adapter->dev_id, enable);
+       return -EIO;
 }
 
-int btd_adapter_read_clock(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                               int which, int timeout, uint32_t *clock,
-                               uint16_t *accuracy)
+static void write_auth_payload_timeout_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       if (!adapter_ops)
-               return -EINVAL;
+       const struct mgmt_rp_write_auth_payload_timeout *rp = param;
 
-       if (!adapter->up)
-               return -EINVAL;
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to write auth payload timeout: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
+       }
 
-       return adapter_ops->read_clock(adapter->dev_id, bdaddr, which,
-                                               timeout, clock, accuracy);
+       if (length < sizeof(*rp)) {
+               error("Wrong size of write auth payload timeout parameter");
+               return;
+       }
 }
 
-int btd_adapter_disconnect_device(struct btd_adapter *adapter, bdaddr_t *bdaddr)
+int btd_adapter_write_auth_payload_timeout(struct btd_adapter *adapter,
+                               bdaddr_t *bdaddr, uint32_t payload_timeout,
+                               struct btd_device *device)
 {
-       return adapter_ops->disconnect(adapter->dev_id, bdaddr);
-}
+       struct mgmt_cp_write_auth_payload_timeout cp;
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.bdaddr, bdaddr);
 
-int btd_adapter_remove_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr)
-{
-       return adapter_ops->remove_bonding(adapter->dev_id, bdaddr);
-}
+       if (payload_timeout > 65536)
+               return -EIO;
+       else
+               cp.auth_payload_timeout = payload_timeout;
 
-int btd_adapter_pincode_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                                       const char *pin)
-{
-       return adapter_ops->pincode_reply(adapter->dev_id, bdaddr, pin);
+       if (mgmt_send(adapter->mgmt, MGMT_OP_WRITE_AUTH_PAYLOAD_TIMEOUT,
+                       adapter->dev_id, sizeof(cp), &cp,
+                       write_auth_payload_timeout_complete, device, NULL) > 0)
+                       return 0;
+       return -EIO;
 }
 
-int btd_adapter_confirm_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                                       gboolean success)
+static void read_auth_payload_timeout_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       return adapter_ops->confirm_reply(adapter->dev_id, bdaddr, success);
-}
+       const struct mgmt_rp_read_auth_payload_timeout *rp = param;
+       struct btd_device *device = user_data;
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("read auth payload timeout failed: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
+       }
 
-int btd_adapter_passkey_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                                       uint32_t passkey)
-{
-       return adapter_ops->passkey_reply(adapter->dev_id, bdaddr, passkey);
+       if (length < sizeof(*rp)) {
+               error("Too small read payload response");
+               return;
+       }
+
+       if (!rp->status) {
+               device_set_payload_timeout(device, rp->auth_payload_timeout);
+       }
+       return;
 }
 
-void btd_adapter_update_local_ext_features(struct btd_adapter *adapter,
-                                               const uint8_t *features)
+int btd_adapter_read_auth_payload_timeout(struct btd_adapter *adapter,
+                               bdaddr_t *bdaddr, struct btd_device *device)
 {
-       struct hci_dev *dev = &adapter->dev;
+       struct mgmt_cp_read_auth_payload_timeout cp;
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.bdaddr, bdaddr);
 
-       memcpy(dev->extfeatures, features, 8);
+       if (mgmt_send(adapter->mgmt, MGMT_OP_READ_AUTH_PAYLOAD_TIMEOUT,
+                       adapter->dev_id, sizeof(cp), &cp,
+                       read_auth_payload_timeout_complete, device, NULL) > 0)
+                       return 0;
+       return -EIO;
 }
+#endif
 
-int btd_adapter_encrypt_link(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                       bt_hci_result_t cb, gpointer user_data)
+int btd_adapter_le_conn_update(struct btd_adapter *adapter, bdaddr_t *bdaddr,
+                               uint16_t interval_min, uint16_t interval_max,
+                               uint16_t latency, uint16_t supervision_time_out)
 {
-       return adapter_ops->encrypt_link(adapter->dev_id, bdaddr, cb, user_data);
-}
+       struct mgmt_cp_le_conn_update cp;
 
-int btd_adapter_set_did(struct btd_adapter *adapter, uint16_t vendor,
-                                       uint16_t product, uint16_t version)
-{
-       return adapter_ops->set_did(adapter->dev_id, vendor, product, version);
-}
+       memset(&cp, 0, sizeof(cp));
 
-int adapter_create_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                                               uint8_t io_cap)
-{
-       return adapter_ops->create_bonding(adapter->dev_id, bdaddr, io_cap);
+       if (NULL != bdaddr)
+               bacpy(&cp.bdaddr, bdaddr);
+       else
+               return -EIO;
+
+       cp.interval_min = interval_min;
+       cp.interval_max = interval_max;
+       cp.latency = latency;
+       cp.supervision_time_out = supervision_time_out;
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_LE_CONN_UPDATE,
+                       adapter->dev_id, sizeof(cp), &cp,
+                       NULL, NULL, NULL) > 0)
+               return 0;
+
+       return -EIO;
 }
 
-int adapter_cancel_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr)
+GSList *btd_adapter_get_connections(struct btd_adapter *adapter)
 {
-       return adapter_ops->cancel_bonding(adapter->dev_id, bdaddr);
+       /* Return the connected device list */
+       return adapter->connections;
 }
+#endif /* __TIZEN_PATCH__ */