Handle GATT client app's termination
[platform/core/connectivity/bluetooth-frwk.git] / bt-oal / bluez_hal / src / bt-hal-gatt-client.c
index b87a352..17ccddb 100644 (file)
 #include <errno.h>
 #include <string.h>
 #include <dlog.h>
+#include <gio/gio.h>
+#include <glib.h>
+#include <gio/gunixfdlist.h>
+
 
 #include "bt-hal-log.h"
 #include "bt-hal-msg.h"
@@ -33,6 +37,8 @@
 #include "bt-hal-adapter-le.h"
 
 #include "bt-hal-gatt-client.h"
+#include "bt-hal-dbus-common-utils.h"
+#include "bt-hal-utils.h"
 
 /************************************************************************************
  **  Static variables
@@ -46,17 +52,185 @@ extern const btgatt_callbacks_t *bt_gatt_callbacks;
        DBG("%s", __FUNCTION__);\
 }
 
-typedef struct {
-       uint32_t client_if;
-       bt_uuid_t uuid;
-} hal_registered_client_t;
-
 #ifdef TIZEN_BT_HAL
 int le_scan_type = BT_GATTC_LE_SCAN_TYPE_PASSIVE;
 #endif
 
 static handle_stack_msg event_cb = NULL;
 
+#define GATT_SERV_INTERFACE             "org.bluez.GattService1"
+#define MAX_HAL_OBJECT_PATH_LEN                100
+
+typedef enum {
+       HAL_GATT_CHARACTERISTIC_PROPERTY_BROADCAST = 0x01,
+       HAL_GATT_CHARACTERISTIC_PROPERTY_READ = 0x02,
+       HAL_GATT_CHARACTERISTIC_PROPERTY_WRITE_NO_RESPONSE = 0x04,
+       HAL_GATT_CHARACTERISTIC_PROPERTY_WRITE = 0x08,
+       HAL_GATT_CHARACTERISTIC_PROPERTY_NOTIFY = 0x10,
+       HAL_GATT_CHARACTERISTIC_PROPERTY_INDICATE = 0x20,
+       HAL_GATT_CHARACTERISTIC_PROPERTY_SIGNED_WRITE = 0x40,
+       HAL_GATT_CHARACTERISTIC_PROPERTY_RELIABLE_WRITE = 0x80,
+       HAL_GATT_CHARACTERISTIC_PROPERTY_WRITABLE_AUXILIARIES = 0x100,
+       HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_READ = 0x200,
+       HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_WRITE = 0x400,
+       HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_READ = 0x800,
+       HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_WRITE = 0x1000,
+       HAL_GATT_CHARACTERISTIC_PROPERTY_EXTENDED_PROPS = 0xffff,
+} bt_gatt_characteristic_property_t;
+
+
+typedef enum {
+       HAL_GATT_WRITE_TYPE_WRITE_NO_RESPONSE = 1,
+       HAL_GATT_WRITE_TYPE_WRITE ,
+} hal_gatt_write_type_t;
+
+
+typedef enum {
+       HAL_GATT_PROPERTY_BROADCAST = 0x01,  /**< Broadcast property */
+       HAL_GATT_PROPERTY_READ = 0x02,  /**< Read property */
+       HAL_GATT_PROPERTY_WRITE_WITHOUT_RESPONSE = 0x04,  /**< Write without response property */
+       HAL_GATT_PROPERTY_WRITE = 0x08,  /**< Write property */
+       HAL_GATT_PROPERTY_NOTIFY = 0x10,  /**< Notify property */
+       HAL_GATT_PROPERTY_INDICATE = 0x20,  /**< Indicate property */
+       HAL_GATT_PROPERTY_AUTHENTICATED_SIGNED_WRITES = 0x40,  /**< Authenticated signed writes property */
+       HAL_GATT_PROPERTY_EXTENDED_PROPERTIES = 0x80,  /**< Extended properties */
+} hal_gatt_property_e;
+
+typedef struct {
+       int client_if;
+       bt_bdaddr_t bd_addr;
+       gboolean auto_connect;
+} bt_pending_le_conn_info_s;
+
+typedef struct {
+       char *desc_path;
+       bt_uuid_t desc_uuid;
+} hal_gattc_desc_t;
+
+typedef struct {
+       char *chr_path;
+       bt_uuid_t chr_uuid;
+       unsigned int permission;
+       GSList *gatt_list_descs;
+} hal_gattc_char_t;
+
+typedef struct {
+       gchar *svc_path;
+       bt_uuid_t svc_uuid;
+       int is_primary;
+       GSList *gatt_list_chars;
+} hal_gattc_service_t;
+
+typedef struct {
+       bt_bdaddr_t bd_addr;    /*remote server address*/
+       int conn_id;
+       int inst_id;            /*server instance id*/
+       GSList *gatt_list_services;
+} hal_gattc_server_info_t;
+
+/* Linked List of connected GATT server */
+static GSList *hal_gattc_server_info_list = NULL;
+
+typedef struct {
+       int client_if;
+       bt_bdaddr_t bd_addr;    /*remote server address*/
+       int conn_id;
+       int inst_id;
+} hal_gattc_client_info_t;
+
+/* Linked list of connected GATT client connection */
+static GSList * hal_gattc_client_info_list = NULL;
+
+static bt_pending_le_conn_info_s *pending_le_conn_info = NULL;
+static guint pending_le_conn_timer_id = 0;
+static int bt_conn_id = 0;
+static int bt_inst_id = 0;
+
+/* Should match the range with bt-service-gatt.c's MAX_APPS_SUPPORTED */
+/* TODO: Adjust MAX Client after modifying MAX app handle logic */
+#define BT_GATTC_CL_MAX 11
+
+static int assigned_if = 0;
+static gboolean client_if_used[BT_GATTC_CL_MAX];
+
+typedef struct {
+       int conn_id;
+       int result;
+       btgatt_srvc_id_t srvc_id;
+       btgatt_gatt_id_t char_id;
+       btgatt_gatt_id_t desc_id;
+} hal_gatt_resp_data_t;
+
+typedef struct {
+       int client_if;
+       bt_uuid_t app_uuid;
+} hal_gatt_client_app;
+
+static GSList * hal_gattc_client_app_list = NULL;
+
+struct conn_mtu_s {
+       int conn_id;
+       int mtu;
+};
+
+static bt_status_t __bt_connect_le_device_internal(int client_if, const bt_bdaddr_t *bd_addr,
+               gboolean auto_connect);
+static bt_status_t _bt_hold_current_advertising();
+static gboolean __bt_hold_current_advertising_timeout_cb(gpointer user_data);
+static gboolean __bt_connect_le_timer_cb(gpointer user_data);
+static void __le_connection_req_cb(GDBusProxy *proxy, GAsyncResult *res,
+               gpointer user_data);
+static hal_gattc_server_info_t *__bt_find_gatt_conn_info_from_conn_id(int  conn_id);
+static void _bt_hal_send_search_service_result_event(int conn_id, int is_primary,
+                                               const char* uuid_str, int inst_id);
+static void _bt_hal_send_search_service_complete_event(int conn_id, int status);
+static hal_gattc_server_info_t *__bt_find_gatt_conn_info(const bt_bdaddr_t *serv_addr);
+static hal_gattc_client_info_t *__bt_find_gatt_client_info(bt_bdaddr_t *serv_addr);
+static hal_gattc_client_info_t *__bt_find_gatt_client_info_from_conn_id(int conn_id);
+
+void _bt_hal_gatt_client_init(void)
+{
+       assigned_if = 0;
+       memset(client_if_used, 0x00, sizeof(client_if_used));
+}
+
+static int __bt_hal_gatt_assign_if(void)
+{
+       int index;
+
+       index = assigned_if + 1;
+
+       if (index >= BT_GATTC_CL_MAX)
+               index = 1;
+
+       while (client_if_used[index] == TRUE) {
+               if (index == assigned_if) {
+                       /* No available ID */
+                       ERR("All interface ID is used");
+                       return -1;
+               }
+
+               index++;
+
+               if (index >= BT_GATTC_CL_MAX)
+                       index = 1;
+       }
+
+       assigned_if = index;
+       client_if_used[index] = TRUE;
+
+       return assigned_if;
+}
+
+static void __bt_hal_gatt_delete_if(int client_if)
+{
+       if (client_if >= BT_GATTC_CL_MAX || client_if < 0)
+               return;
+
+       client_if_used[client_if] = FALSE;
+}
+
+
 /* To send stack event to hal-av handler */
 void _bt_hal_register_gatt_client_handler_cb(handle_stack_msg cb)
 {
@@ -78,13 +252,13 @@ int _bt_hal_gatt_client_get_le_scan_type(void)
 static gboolean __bt_hal_register_client_cb(gpointer user_data)
 {
        struct hal_ev_gatt_client_registered ev;
-       hal_registered_client_t *client_info = user_data;
+       hal_gatt_client_app *client_info = user_data;
 
        /* Prepare to send AV connecting event */
        memset(&ev, 0, sizeof(ev));
        ev.status = BT_STATUS_SUCCESS;
        ev.client_if = client_info->client_if;
-       memcpy(ev.app_uuid, client_info->uuid.uu, sizeof(ev.app_uuid));
+       memcpy(ev.app_uuid, client_info->app_uuid.uu, sizeof(ev.app_uuid));
 
        if (!event_cb)
                ERR("GATT Callback not registered");
@@ -97,35 +271,137 @@ static gboolean __bt_hal_register_client_cb(gpointer user_data)
        return FALSE;
 }
 
+static hal_gatt_client_app *__hal_gattc_add_client_app(bt_uuid_t *app_uuid)
+{
+       GSList *l;
+       int client_if = 0;
+       hal_gatt_client_app *info = NULL;
+       hal_gatt_client_app *gattc_app = NULL;
+
+       //check if client app is already registered
+       for (l = hal_gattc_client_app_list; l != NULL; l = g_slist_next(l)) {
+               info = (hal_gatt_client_app*)l->data;
+               if (info == NULL)
+                       continue;
+
+               if (memcmp(&info->app_uuid, app_uuid, sizeof(bt_uuid_t)) == 0) {
+                       DBG("gatt client app already registered");
+                       return info;
+               }
+       }
+
+       client_if = __bt_hal_gatt_assign_if();
+       if (client_if == -1) {
+               ERR("Fail to allocate the client if");
+               return NULL;
+       }
+
+       DBG("adding the gatt client app");
+
+       //add client app
+       gattc_app = g_malloc0(sizeof(hal_gatt_client_app));
+       gattc_app->client_if = client_if;
+       memcpy(&gattc_app->app_uuid, app_uuid, sizeof(bt_uuid_t));
+
+       hal_gattc_client_app_list = g_slist_append(hal_gattc_client_app_list, gattc_app);
+
+       return gattc_app;
+}
+
+static bt_status_t __hal_gattc_register_client_app(bt_uuid_t *app_uuid)
+{
+       hal_gatt_client_app *gattc_app = NULL;
+       hal_gatt_client_app *client_app_info = NULL;
+
+       /* add gatt client in list */
+       gattc_app = __hal_gattc_add_client_app(app_uuid);
+       if (gattc_app == NULL) {
+               ERR("Failed to register gatt client app");
+               return BT_STATUS_FAIL;
+       }
+
+       /*send event */
+       client_app_info = g_malloc0(sizeof(hal_gatt_client_app));
+       client_app_info->client_if = gattc_app->client_if;
+       memcpy(&client_app_info->app_uuid, app_uuid, sizeof(bt_uuid_t));
+       g_idle_add(__bt_hal_register_client_cb, (gpointer)client_app_info);
+
+       DBG("registered client client_if [%d]", client_app_info->client_if);
+
+       return BT_STATUS_SUCCESS;
+}
+
 /** Registers a GATT client application with the stack */
-bt_status_t register_client(bt_uuid_t *uuid)
+bt_status_t btif_gattc_register_client(bt_uuid_t *uuid)
+{
+       CHECK_BTGATT_INIT();
+
+       return __hal_gattc_register_client_app(uuid);
+}
+
+bt_status_t btif_gattc_add_connection_info(const bt_bdaddr_t *bd_addr, int conn_id, int server_inst_id)
+{
+       hal_gattc_client_info_t *client_info = NULL;
+       hal_gattc_server_info_t *server_info = NULL;
+
+       /* Add client connection info in list */
+       client_info = g_malloc0(sizeof(hal_gattc_client_info_t));
+       client_info->client_if = -1;
+       memcpy(client_info->bd_addr.address, bd_addr->address, BT_HAL_ADDRESS_LENGTH_MAX);
+       client_info->conn_id = conn_id;
+       client_info->inst_id = server_inst_id;
+       hal_gattc_client_info_list = g_slist_append(hal_gattc_client_info_list, client_info);
+       DBG("Added client connection info in list");
+
+       /* Add server connection info in list */
+       server_info = __bt_find_gatt_conn_info(bd_addr);
+       if (server_info == NULL) {
+               server_info = g_malloc0(sizeof(hal_gattc_server_info_t));
+               memcpy(server_info->bd_addr.address, bd_addr->address, BT_HAL_ADDRESS_LENGTH_MAX);
+               server_info->conn_id = conn_id;
+               server_info->inst_id = server_inst_id;
+               hal_gattc_server_info_list = g_slist_append(hal_gattc_server_info_list, server_info);
+               DBG("Added server connection info in list");
+       }
+
+       return BT_STATUS_SUCCESS;
+}
+
+bt_status_t __hal_gattc_unregister_client(int client_if)
 {
-       hal_registered_client_t *client_info = NULL;
+       GSList *l;
+       hal_gatt_client_app *info = NULL;
+
+       DBG("registered client count: [%d]", g_slist_length(hal_gattc_client_app_list));
 
-       client_info = g_malloc0(sizeof(hal_registered_client_t));
-       /*
-        * TODO: Actual client_if will be used here later when GATT register_client
-        * is implemented compeltely. For now return 1 as client_if.
-        */
-       client_info->client_if = 1;
-       memcpy(client_info->uuid.uu, uuid->uu, sizeof(bt_uuid_t));
+       /* remove the gatt client app */
+       for (l = hal_gattc_client_app_list; l != NULL; ) {
+               info = (hal_gatt_client_app*)l->data;
+               l = g_slist_next(l);
 
-       /*
-        * As we need to provide async callback to user from HAL, simply schedule a
-        * callback method which will carry actual result
-        */
-       g_idle_add(__bt_hal_register_client_cb, (gpointer)client_info);
+               if (info == NULL)
+                       continue;
 
-       /* If available, then return success, else return error */
+               if (info->client_if == client_if) {
+                       DBG("gatt client app found");
+
+                       __bt_hal_gatt_delete_if(client_if);
+
+                       hal_gattc_client_app_list = g_slist_remove(hal_gattc_client_app_list, info);
+                       g_free(info);
+               }
+       }
+
+       DBG("registered client count: [%d]", g_slist_length(hal_gattc_client_app_list));
        return BT_STATUS_SUCCESS;
 }
 
-/* TODO: APIs will be implemented in subsequent patches whenever required */
 /** Unregister a client application from the stack */
-bt_status_t unregister_client(int client_if)
+bt_status_t btif_gattc_unregister_client(int client_if)
 {
        CHECK_BTGATT_INIT();
-       return BT_STATUS_UNSUPPORTED;
+
+       return __hal_gattc_unregister_client(client_if);
 }
 
 /** Start or stop LE device scanning */
@@ -144,19 +420,154 @@ bt_status_t scan(int client_if, bool start)
 }
 
 /** Create a connection to a remote LE or dual-mode device */
-bt_status_t connect(int client_if, const bt_bdaddr_t *bd_addr,
+bt_status_t btif_gattc_client_connect(int client_if, const bt_bdaddr_t *bd_addr,
                bool is_direct)
 {
+       int ret = BT_STATUS_SUCCESS;
+
        CHECK_BTGATT_INIT();
-       return BT_STATUS_UNSUPPORTED;
+
+       if (NULL == bd_addr)
+               return BT_STATUS_PARM_INVALID;
+
+       ret = _bt_hold_current_advertising();
+       if (ret == BT_STATUS_SUCCESS) {
+               DBG("Current advertising is held");
+               pending_le_conn_info = g_malloc0(sizeof(bt_pending_le_conn_info_s));
+               pending_le_conn_info->client_if = client_if;
+               memcpy(pending_le_conn_info->bd_addr.address, bd_addr->address,
+                               BT_HAL_ADDRESS_LENGTH_MAX);
+               pending_le_conn_info->auto_connect = is_direct;
+
+               pending_le_conn_timer_id =
+                       g_timeout_add(1000, __bt_connect_le_timer_cb, NULL);
+
+               return BT_STATUS_SUCCESS;
+       } else {
+               ERR("advertising is not stopped");
+       }
+
+       return __bt_connect_le_device_internal(client_if, bd_addr, is_direct);
+}
+
+
+static void __le_disconnection_req_cb(GDBusProxy *proxy, GAsyncResult *res,
+               gpointer user_data)
+{
+       GError *g_error = NULL;
+       GVariant *reply = NULL;
+       hal_gattc_client_info_t *gatt_conn_info  = user_data;
+       int result = BT_STATUS_SUCCESS;
+       struct hal_ev_gatt_client_connected ev;
+
+       DBG("+");
+
+       reply = g_dbus_proxy_call_finish(proxy, res, &g_error);
+       g_object_unref(proxy);
+       if (reply == NULL) {
+               ERR("Connect LE Dbus Call Error");
+               if (g_error) {
+                       ERR("Error: %s\n", g_error->message);
+                       g_clear_error(&g_error);
+               }
+               result = BT_STATUS_FAIL;
+       }
+       g_variant_unref(reply);
+
+       if (NULL == gatt_conn_info) {
+               ERR("server_data is NULL");
+               return;
+       }
+
+       /*send fail event*/
+       if (result == BT_STATUS_FAIL) {
+               memset(&ev, 0, sizeof(ev));
+               ev.conn_id = gatt_conn_info->conn_id;
+               ev.status = result;
+               ev.client_if = gatt_conn_info->client_if;
+               memcpy(ev.bdaddr, gatt_conn_info->bd_addr.address,
+                                               BT_HAL_ADDRESS_LENGTH_MAX);
+
+               if (!event_cb) {
+                       ERR("gatt client callback not registered");
+               } else {
+                       DBG("sending gatt client disconnected event");
+                       event_cb(HAL_EV_GATT_CLIENT_DISCONNECTED, (void *)&ev, sizeof(ev));
+               }
+       }
+
+       /*remove conn_info*/
+       if (gatt_conn_info)
+               g_free(gatt_conn_info);
+
+       DBG("-");
+}
+
+bt_status_t _hal_gattc_disconnect(int client_if, const bt_bdaddr_t *bd_addr,
+                       int conn_id)
+{
+       char device_address[BT_HAL_ADDRESS_STRING_SIZE] = { 0 };
+       gchar *device_path;
+       GDBusProxy *device_proxy;
+       GDBusConnection *conn;
+       int ret = BT_STATUS_SUCCESS;
+       hal_gattc_client_info_t *gattc_data;
+
+       if (NULL == bd_addr) {
+               ERR("bd_addr is NULL");
+               return BT_STATUS_PARM_INVALID;
+       }
+
+       conn = _bt_hal_get_system_gconn();
+       if (NULL == conn) {
+               ERR("_bt_gdbus_get_system_gconn returned NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       _bt_hal_convert_addr_type_to_string(device_address,
+                       (unsigned char *)bd_addr->address);
+       device_path = _bt_hal_get_device_object_path(device_address);
+       if (device_path == NULL) {
+               DBG("device_path NULL");
+               ret =  BT_STATUS_FAIL;
+               return ret;
+       }
+
+       ERR("device_path:%s", device_path);
+
+       device_proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
+                       NULL, BT_HAL_BLUEZ_NAME,
+                       device_path, BT_HAL_DEVICE_INTERFACE,  NULL, NULL);
+       g_free(device_path);
+       if (NULL == device_proxy) {
+               ERR("device_proxy returned NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       gattc_data = g_malloc0(sizeof(hal_gattc_client_info_t));
+       memcpy(gattc_data->bd_addr.address, bd_addr->address,
+                       BT_HAL_ADDRESS_LENGTH_MAX);
+       gattc_data->client_if = client_if;
+       gattc_data->conn_id = conn_id;
+
+       DBG("DisconnectLE [%s]", device_address);
+
+       g_dbus_proxy_call(device_proxy, "DisconnectLE",
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE,
+                       BT_HAL_MAX_DBUS_TIMEOUT,
+                       NULL,
+                       (GAsyncReadyCallback)__le_disconnection_req_cb, gattc_data);
+       return ret;
 }
 
 /** Disconnect a remote device or cancel a pending connection */
-bt_status_t disconnect(int client_if, const bt_bdaddr_t *bd_addr,
+bt_status_t btif_gattc_client_disconnect(int client_if, const bt_bdaddr_t *bd_addr,
                int conn_id)
 {
        CHECK_BTGATT_INIT();
-       return BT_STATUS_UNSUPPORTED;
+
+       return _hal_gattc_disconnect(client_if, bd_addr, conn_id);
 }
 
 /** Clear the attribute cache for a given device */
@@ -166,123 +577,2030 @@ bt_status_t refresh(int client_if, const bt_bdaddr_t *bd_addr)
        return BT_STATUS_UNSUPPORTED;
 }
 
-/**
- * Enumerate all GATT services on a connected device.
- * Optionally, the results can be filtered for a given UUID.
- */
-bt_status_t search_service(int conn_id, bt_uuid_t *filter_uuid)
+static hal_gattc_service_t* _gattc_find_service_from_uuid(hal_gattc_server_info_t *conn_info, bt_uuid_t *svc_uuid)
 {
-       CHECK_BTGATT_INIT();
-       return BT_STATUS_UNSUPPORTED;
+       GSList *l;
+       hal_gattc_service_t *info = NULL;
+
+       for (l = conn_info->gatt_list_services; l != NULL; l = g_slist_next(l)) {
+               info = (hal_gattc_service_t*)l->data;
+               if (info == NULL)
+                       continue;
+
+               if (!memcmp(&info->svc_uuid, svc_uuid, sizeof(bt_uuid_t)))
+                       return info;
+               }
+
+       return NULL;
 }
 
-/**
- * Enumerate included services for a given service.
- * Set start_incl_srvc_id to NULL to get the first included service.
- */
-bt_status_t get_included_service(int conn_id, btgatt_srvc_id_t *srvc_id,
-               btgatt_srvc_id_t *start_incl_srvc_id)
+
+static hal_gattc_char_t* _gattc_find_char_from_uuid(hal_gattc_service_t *gattc_svc, bt_uuid_t *char_uuid,
+                               bt_gatt_characteristic_property_t prop)
 {
-       CHECK_BTGATT_INIT();
-       return BT_STATUS_UNSUPPORTED;
+       GSList *l;
+       hal_gattc_char_t *info = NULL;
+
+       for (l = gattc_svc->gatt_list_chars; l != NULL; l = g_slist_next(l)) {
+               info = (hal_gattc_char_t*)l->data;
+               if (info == NULL)
+                       continue;
+
+               if (!memcmp(&info->chr_uuid, char_uuid, sizeof(bt_uuid_t)) &&
+                       (info->permission & prop)) {
+                       return info;
+               }
+       }
+       return NULL;
 }
 
-/**
- * Enumerate characteristics for a given service.
- * Set start_char_id to NULL to get the first characteristic.
- */
-bt_status_t get_characteristic(int conn_id,
-               btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *start_char_id)
+static hal_gattc_char_t* _gattc_find_char_from_uuid_for_notify(hal_gattc_service_t *gattc_svc, bt_uuid_t *char_uuid)
 {
-       CHECK_BTGATT_INIT();
-       return BT_STATUS_UNSUPPORTED;
+       GSList *l;
+       hal_gattc_char_t *info = NULL;
+
+       for (l = gattc_svc->gatt_list_chars; l != NULL; l = g_slist_next(l)) {
+               info = (hal_gattc_char_t*)l->data;
+               if (info == NULL)
+                       continue;
+
+               if (!memcmp(&info->chr_uuid, char_uuid, sizeof(bt_uuid_t)) &&
+                       ((info->permission & HAL_GATT_CHARACTERISTIC_PROPERTY_NOTIFY) ||
+                               (info->permission & HAL_GATT_CHARACTERISTIC_PROPERTY_INDICATE))) {
+                       return info;
+               }
+       }
+       return NULL;
 }
 
-/**
- * Enumerate descriptors for a given characteristic.
- * Set start_descr_id to NULL to get the first descriptor.
- */
-bt_status_t get_descriptor(int conn_id,
-               btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
-               btgatt_gatt_id_t *start_descr_id)
+static hal_gattc_desc_t* _gattc_find_desc_from_uuid(hal_gattc_char_t *gattc_char, bt_uuid_t *desc_uuid)
 {
-       CHECK_BTGATT_INIT();
-       return BT_STATUS_UNSUPPORTED;
+       GSList *l;
+       hal_gattc_desc_t *info = NULL;
+
+       for (l = gattc_char->gatt_list_descs; l != NULL; l = g_slist_next(l)) {
+               info = (hal_gattc_desc_t*)l->data;
+               if (info == NULL)
+                       continue;
+
+               if (!memcmp(&info->desc_uuid, desc_uuid, sizeof(bt_uuid_t)))
+                       return info;
+               }
+       return NULL;
 }
 
-/** Read a characteristic on a remote device */
-bt_status_t read_characteristic(int conn_id,
-               btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
-               int auth_req)
+
+static hal_gattc_service_t* _hal_gatt_client_add_service(hal_gattc_server_info_t *conn_info,
+               const char *uuid_str, const char *object_path, int is_primary)
 {
-       CHECK_BTGATT_INIT();
-       return BT_STATUS_UNSUPPORTED;
+       hal_gattc_service_t *gattc_service = NULL;
+
+       gattc_service = g_malloc0(sizeof(hal_gattc_service_t));
+       gattc_service->svc_path = g_strdup(object_path);
+       _bt_hal_convert_uuid_string_to_type(gattc_service->svc_uuid.uu, uuid_str);
+       gattc_service->is_primary = is_primary;
+
+       INFO("[%d] [%s] [%s]", g_slist_length(conn_info->gatt_list_services), object_path + 15, uuid_str);
+
+       conn_info->gatt_list_services = g_slist_append(conn_info->gatt_list_services, gattc_service);
+
+       return gattc_service;
 }
 
-/** Write a remote characteristic */
-bt_status_t write_characteristic(int conn_id,
-               btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
-               int write_type, int len, int auth_req,
-               char* p_value)
+static void _hal_gattc_add_characteristic(hal_gattc_service_t *gatt_svc, char *char_handle)
 {
-       CHECK_BTGATT_INIT();
-       return BT_STATUS_UNSUPPORTED;
+       hal_gattc_char_t *gattc_char = NULL;
+
+       gattc_char = g_malloc0(sizeof(hal_gattc_char_t));
+       gattc_char->chr_path = g_strdup(char_handle);
+
+       DBG("svc path: [%s]", gatt_svc->svc_path);
+       DBG("char path: [%s]", gattc_char->chr_path);
+
+       gatt_svc->gatt_list_chars = g_slist_append(gatt_svc->gatt_list_chars, gattc_char);
 }
 
-/** Read the descriptor for a given characteristic */
-bt_status_t read_descriptor(int conn_id,
-               btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
-               btgatt_gatt_id_t *descr_id, int auth_req)
+static void _gattc_create_new_service(hal_gattc_server_info_t *conn_info, gboolean is_primary,
+               const char* uuid_str, const char *object_path, GPtrArray *gp_char_array)
 {
-       CHECK_BTGATT_INIT();
-       return BT_STATUS_UNSUPPORTED;
+       hal_gattc_service_t* gatt_svc = NULL;
+       int i;
+       gchar *gp_char_path = NULL;
+
+       /* add the service */
+       gatt_svc = _hal_gatt_client_add_service(conn_info, uuid_str, object_path, is_primary);
+       if (gatt_svc == NULL) {
+               ERR("Failed to add service");
+               return;
+       }
+
+       /* add the characteristic */
+       for (i = 0; i < gp_char_array->len; i++) {
+               gp_char_path = g_ptr_array_index(gp_char_array, i);
+               _hal_gattc_add_characteristic(gatt_svc, gp_char_path);
+       }
+
+       g_ptr_array_free(gp_char_array, TRUE);
 }
-/** Write a remote descriptor for a given characteristic */
-bt_status_t write_descriptor(int conn_id,
-               btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
-               btgatt_gatt_id_t *descr_id, int write_type, int len,
-               int auth_req, char* p_value)
+
+static void _hal_gattc_add_descriptor(hal_gattc_char_t *gattc_char, char *desc_path)
 {
-       CHECK_BTGATT_INIT();
-       return BT_STATUS_UNSUPPORTED;
+       hal_gattc_desc_t *gattc_desc = NULL;
+
+       gattc_desc = g_malloc0(sizeof(hal_gattc_desc_t));
+       gattc_desc->desc_path = g_strdup(desc_path);
+
+       gattc_char->gatt_list_descs = g_slist_append(gattc_char->gatt_list_descs, gattc_desc);
 }
 
-/** Execute a prepared write operation */
-bt_status_t execute_write(int conn_id, int execute)
+static void _hal_gattc_update_char_property(hal_gattc_char_t *gattc_char, const char* char_uuid_str,
+               GPtrArray *gp_desc_array, unsigned int char_permission)
 {
-       CHECK_BTGATT_INIT();
-       return BT_STATUS_UNSUPPORTED;
+       gchar *gp_desc_path = NULL;
+       int i;
+
+       if (char_uuid_str == NULL) {
+               DBG("char_uuid_str is NULL");
+               return;
+       }
+
+       //update the char uuid
+       _bt_hal_convert_uuid_string_to_type(gattc_char->chr_uuid.uu, char_uuid_str);
+
+       //update char permission
+       gattc_char->permission = char_permission;
+
+       //add the descriptor
+       for (i = 0; i < gp_desc_array->len; i++) {
+               gp_desc_path = g_ptr_array_index(gp_desc_array, i);
+               _hal_gattc_add_descriptor(gattc_char, gp_desc_path);
+       }
 }
 
-/**
- * Register to receive notifications or indications for a given
- * characteristic
- */
-bt_status_t register_for_notification(int client_if,
-               const bt_bdaddr_t *bd_addr, btgatt_srvc_id_t *srvc_id,
-               btgatt_gatt_id_t *char_id)
+static void _hal_gattc_update_desc_property(hal_gattc_desc_t *gattc_desc, const char* desc_uuid_str)
 {
-       CHECK_BTGATT_INIT();
-       return BT_STATUS_UNSUPPORTED;
+       if (desc_uuid_str == NULL) {
+               DBG("char_uuid_str is NULL");
+               return;
+       }
+
+       //update the descriptor uuid
+       DBG("desc UUID: [%s] ", desc_uuid_str);
+       DBG("desc path: [%s]", gattc_desc->desc_path);
+
+       _bt_hal_convert_uuid_string_to_type(gattc_desc->desc_uuid.uu, desc_uuid_str);
 }
 
-/** Deregister a previous request for notifications/indications */
-bt_status_t deregister_for_notification(int client_if,
-               const bt_bdaddr_t *bd_addr, btgatt_srvc_id_t *srvc_id,
-               btgatt_gatt_id_t *char_id)
+static void browse_service_char(int conn_id)
 {
-       CHECK_BTGATT_INIT();
-       return BT_STATUS_UNSUPPORTED;
+       hal_gattc_server_info_t *conn_info = NULL;
+       GSList *l;
+       GSList *k;
+       GSList *m;
+       hal_gattc_service_t *svc_info = NULL;
+       hal_gattc_char_t *char_info = NULL;
+       hal_gattc_desc_t *desc_info = NULL;
+
+       conn_info = __bt_find_gatt_conn_info_from_conn_id(conn_id);
+       if (conn_info == NULL) {
+               ERR("Failed to get the conn_info for conn_id [%d]", conn_id);
+               return;
+       }
+
+       for (l = conn_info->gatt_list_services; l != NULL; l = g_slist_next(l)) {
+               svc_info = (hal_gattc_service_t*)l->data;
+               if (svc_info == NULL)
+                       continue;
+
+               /* find characteristic object path */
+               for (k = svc_info->gatt_list_chars; k != NULL; k = g_slist_next(k)) {
+                       char_info = (hal_gattc_char_t *)k->data;
+                       if (char_info == NULL)
+                               continue;
+
+                       /* descriptor */
+                       for (m = char_info->gatt_list_descs; m != NULL; m = g_slist_next(m)) {
+                               desc_info = (hal_gattc_desc_t *)m->data;
+                               if (desc_info == NULL)
+                                       continue;
+                       }
+               }
+       }
 }
 
-/** Request RSSI for a given remote device */
-bt_status_t read_remote_rssi(int client_if, const bt_bdaddr_t *bd_addr)
+
+
+/**
+ * Enumerate all GATT services on a connected device.
+ * Optionally, the results can be filtered for a given UUID.
+ */
+static bt_status_t _gattc_client_search_service(int conn_id)
 {
        CHECK_BTGATT_INIT();
-       return BT_STATUS_UNSUPPORTED;
-}
 
-/** OTA firmware download */
+       GVariant *result = NULL;
+       GVariantIter *iter;
+       GVariantIter *svc_iter;
+       GVariantIter *interface_iter;
+       char *object_path = NULL;
+       char *interface_str = NULL;
+       const gchar *key = NULL;
+       GVariant *value = NULL;
+       GPtrArray *gp_array  = NULL;
+       char device_address[BT_HAL_ADDRESS_STRING_SIZE] = { 0 };
+       char temp_address[BT_HAL_ADDRESS_STRING_SIZE] = { 0 };
+       int ret = BT_STATUS_FAIL;
+       int idx = 0;
+       const gchar *uuid_str = NULL;
+       gsize len = 0;
+       hal_gattc_server_info_t *conn_info = NULL;
+       gboolean is_primary = FALSE;
+       int svc_count = 0;
+
+       char *char_handle = NULL;
+       GVariantIter *char_iter = NULL;
+       GPtrArray *gp_char_array  = NULL;
+
+       conn_info = __bt_find_gatt_conn_info_from_conn_id(conn_id);
+       if (NULL == conn_info) {
+               ERR("Failed to get the conn_info for conn_id [%d]", conn_id);
+               return BT_STATUS_FAIL;
+       }
+
+#if 0
+       // TODO: This logic is not able to handle in case service-added event is coming unexpectedly.
+       /* Check the service info is stored */
+       if (g_slist_length(conn_info->gatt_list_services) > 0) {
+               GSList *l = NULL;
+               hal_gattc_service_t *svc_info = NULL;
+               char svc_uuid_str[BT_HAL_UUID_STRING_LEN] = {0, };
+               DBG("Send event from service info list");
+               for (l = conn_info->gatt_list_services; l != NULL; l = g_slist_next(l)) {
+                       svc_info = l->data;
+                       if (svc_info == NULL)
+                               continue;
+                       _bt_hal_convert_uuid_type_to_string(svc_uuid_str, svc_info->svc_uuid.uu);
+                       _bt_hal_send_search_service_result_event(conn_id,
+                                       svc_info->is_primary, svc_uuid_str, conn_info->inst_id);
+               }
+               _bt_hal_send_search_service_complete_event(conn_id, BT_STATUS_SUCCESS);
+               return BT_STATUS_SUCCESS;
+       } else {
+               DBG("No stored service, request to bluez");
+       }
+#endif
+
+       _bt_hal_convert_addr_type_to_string(device_address,
+                       (unsigned char *)conn_info->bd_addr.address);
+
+       result = _bt_hal_get_managed_objects();
+       if (result == NULL)
+               return ret;
+
+       gp_array = g_ptr_array_new();
+       g_variant_get(result, "(a{oa{sa{sv}}})", &iter);
+
+       while (g_variant_iter_loop(iter, "{&oa{sa{sv}}}", &object_path,
+                               &interface_iter)) {
+               if (object_path == NULL)
+                       continue;
+
+               _bt_hal_convert_device_path_to_address(object_path, temp_address);
+
+               if (g_strcmp0(temp_address, device_address) != 0)
+                       continue;
+
+               while (g_variant_iter_loop(interface_iter, "{sa{sv}}",
+                                       &interface_str, &svc_iter)) {
+                       if (g_strcmp0(interface_str, GATT_SERV_INTERFACE) != 0)
+                               continue;
+
+                       DBG("[%d] Object Path : %s", idx++, object_path);
+                       /* for characteristic */
+                       gp_char_array = g_ptr_array_new();
+                       while (g_variant_iter_loop(svc_iter, "{sv}", &key, &value)) {
+                               if (g_strcmp0(key, "Primary") == 0) {
+                                       is_primary = g_variant_get_boolean(value);
+                                       if (is_primary) {
+                                               g_ptr_array_add(gp_array, (gpointer)object_path);
+                                               svc_count++;
+                                       }
+                               } else if (g_strcmp0(key, "UUID") == 0) {
+                                       uuid_str = g_variant_get_string(value, &len);
+                               } else if (g_strcmp0(key, "Characteristics") == 0) {
+                                       g_variant_get(value, "ao", &char_iter);
+                                       if (char_iter != NULL) {
+                                               while (g_variant_iter_loop(char_iter, "&o", &char_handle)) {
+                                                       g_ptr_array_add(gp_char_array, (gpointer)char_handle);
+                                               }
+                                       }
+                               }
+                       }
+
+                       if (uuid_str) {
+                               _bt_hal_send_search_service_result_event(conn_id, is_primary,
+                                               uuid_str, conn_info->inst_id);
+
+                               _gattc_create_new_service(conn_info, is_primary, uuid_str, object_path, gp_char_array);
+                       }
+               }
+       }
+
+       if (gp_array->len == 0 || svc_count == 0) {
+               ERR("gp_array is NULL");
+               ret = BT_STATUS_FAIL;
+       } else {
+               ret = BT_STATUS_SUCCESS;
+       }
+
+       browse_service_char(conn_id);
+       /* send search service complete event */
+       _bt_hal_send_search_service_complete_event(conn_id, ret);
+
+       g_ptr_array_free(gp_array, TRUE);
+       g_variant_iter_free(iter);
+       g_variant_unref(result);
+       DBG("-");
+       return ret;
+}
+
+bt_status_t btif_gattc_client_search_service(int conn_id, bt_uuid_t *filter_uuid)
+{
+       if (NULL == filter_uuid) {
+               DBG("Browse all the services");
+               return _gattc_client_search_service(conn_id);
+       } else {
+               DBG("TODO implement it");
+               return BT_STATUS_UNSUPPORTED;
+       }
+}
+/**
+ * Enumerate included services for a given service.
+ * Set start_incl_srvc_id to NULL to get the first included service.
+ */
+bt_status_t get_included_service(int conn_id, btgatt_srvc_id_t *srvc_id,
+               btgatt_srvc_id_t *start_incl_srvc_id)
+{
+       CHECK_BTGATT_INIT();
+       return BT_STATUS_UNSUPPORTED;
+}
+
+static void _bt_hal_send_client_char_search_result_event(int conn_id, int status,
+               btgatt_srvc_id_t *svc_id, bt_uuid_t *char_uuid, int char_prop)
+{
+       struct hal_ev_gatt_client_char_search_result  ev;
+
+        if (!event_cb) {
+               ERR("gatt client callback not registered");
+               return;
+       }
+
+       memset(&ev, 0, sizeof(ev));
+       ev.conn_id = conn_id;
+       ev.inst_id = svc_id->id.inst_id;
+       ev.is_primary = svc_id->is_primary;
+       ev.status = status;
+       memcpy(ev.svc_uuid, svc_id->id.uuid.uu, sizeof(ev.svc_uuid));
+
+       if (status == BT_STATUS_SUCCESS) {
+               /* building char uuid */
+               memcpy(ev.char_uuid, char_uuid->uu, sizeof(ev.char_uuid));
+               ev.char_prop = char_prop;
+       }
+
+       DBG("sending the char search event.  conn_id[%d] status[%d]", conn_id, status);
+       event_cb(HAL_EV_GATT_CLIENT_CHARAC_SEARCH_RESULT, (void *)&ev, sizeof(ev));
+}
+
+static int _hal_get_permission_flag(char *permission)
+{
+       int ret = 0;
+
+       if (NULL == permission) {
+               ERR("gatt permission is NULL");
+               return ret;
+       }
+
+       if (!g_strcmp0(permission, "broadcast"))
+               ret = HAL_GATT_CHARACTERISTIC_PROPERTY_BROADCAST;
+       else if (!g_strcmp0(permission, "read"))
+               ret = HAL_GATT_CHARACTERISTIC_PROPERTY_READ;
+       else if (!g_strcmp0(permission, "write-without-response"))
+               ret = HAL_GATT_CHARACTERISTIC_PROPERTY_WRITE_NO_RESPONSE;
+       else if (!g_strcmp0(permission, "write"))
+               ret = HAL_GATT_CHARACTERISTIC_PROPERTY_WRITE;
+       else if (!g_strcmp0(permission, "notify"))
+               ret = HAL_GATT_CHARACTERISTIC_PROPERTY_NOTIFY;
+       else if (!g_strcmp0(permission, "indicate"))
+               ret = HAL_GATT_CHARACTERISTIC_PROPERTY_INDICATE;
+       else if (!g_strcmp0(permission, "authenticated-signed-writes"))
+               ret = HAL_GATT_CHARACTERISTIC_PROPERTY_SIGNED_WRITE;
+       else if (!g_strcmp0(permission, "reliable-write"))
+               ret = HAL_GATT_CHARACTERISTIC_PROPERTY_RELIABLE_WRITE;
+       else if (!g_strcmp0(permission, "writable-auxiliaries"))
+               ret = HAL_GATT_CHARACTERISTIC_PROPERTY_WRITABLE_AUXILIARIES;
+       else if (!g_strcmp0(permission, "encrypt-read"))
+               ret = HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_READ;
+       else if (!g_strcmp0(permission, "encrypt-write"))
+               ret = HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_WRITE;
+       else if (!g_strcmp0(permission, "encrypt-authenticated-read"))
+               ret = HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_READ;
+       else if (!g_strcmp0(permission, "encrypt-authenticated-write"))
+               ret = HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_WRITE;
+
+       return ret;
+}
+
+static void __hal_convert_permission_flag_to_str(unsigned int permission)
+{
+       char perm[200] = { 0, };
+
+       if (permission & HAL_GATT_CHARACTERISTIC_PROPERTY_BROADCAST)
+               g_strlcat(perm, "broadcast ", sizeof(perm));
+       if (permission & HAL_GATT_CHARACTERISTIC_PROPERTY_READ)
+               g_strlcat(perm, "read ", sizeof(perm));
+       if (permission & HAL_GATT_CHARACTERISTIC_PROPERTY_WRITE_NO_RESPONSE)
+               g_strlcat(perm, "write-without-response ", sizeof(perm));
+       if (permission & HAL_GATT_CHARACTERISTIC_PROPERTY_WRITE)
+               g_strlcat(perm, "write ", sizeof(perm));
+       if (permission & HAL_GATT_CHARACTERISTIC_PROPERTY_NOTIFY)
+               g_strlcat(perm, "notify ", sizeof(perm));
+       if (permission & HAL_GATT_CHARACTERISTIC_PROPERTY_INDICATE)
+               g_strlcat(perm, "indicate ", sizeof(perm));
+       if (permission & HAL_GATT_CHARACTERISTIC_PROPERTY_SIGNED_WRITE)
+               g_strlcat(perm, "authenticated-signed-writes ", sizeof(perm));
+       if (permission & HAL_GATT_CHARACTERISTIC_PROPERTY_RELIABLE_WRITE)
+               g_strlcat(perm, "reliable-write ", sizeof(perm));
+       if (permission & HAL_GATT_CHARACTERISTIC_PROPERTY_WRITABLE_AUXILIARIES)
+               g_strlcat(perm, "writable-auxiliaries ", sizeof(perm));
+       if (permission & HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_READ)
+               g_strlcat(perm, "encrypt-read ", sizeof(perm));
+       if (permission & HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_WRITE)
+               g_strlcat(perm, "encrypt-write ", sizeof(perm));
+       if (permission & HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_READ)
+               g_strlcat(perm, "encrypt-authenticated-read ", sizeof(perm));
+       if (permission & HAL_GATT_CHARACTERISTIC_PROPERTY_ENCRYPT_AUTHENTICATED_WRITE)
+               g_strlcat(perm, "encrypt-authenticated-write ", sizeof(perm));
+
+       DBG("permission [0x%04x] : %s\n", permission, perm);
+       return;
+}
+
+static bt_status_t _hal_gattc_get_characteristic_info(hal_gattc_char_t *gattc_char)
+{
+       GDBusProxy *properties_proxy = NULL;
+       GError *error = NULL;
+       GVariant *value = NULL;
+       GVariant *result = NULL;
+       GDBusConnection *g_conn;
+       const gchar *key;
+       char *char_desc_handle = NULL;
+       gsize len;
+       GVariantIter *property_iter;
+       GVariantIter *char_desc_iter;
+       char* char_handle = NULL;
+       gchar *char_uuid_str = NULL;
+       GPtrArray *gp_desc_array  = NULL;
+       GVariantIter *char_perm_iter;
+       gchar* permission;
+       unsigned int char_permission = 0 ;
+
+       if (gattc_char->chr_path == NULL) {
+               DBG("char path is NULL");
+                return BT_STATUS_FAIL;
+       }
+       char_handle = gattc_char->chr_path;
+
+       g_conn = _bt_hal_get_system_gconn();
+       if (NULL == g_conn) {
+                ERR("_bt_gdbus_get_system_gconn returned NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       properties_proxy = g_dbus_proxy_new_sync(g_conn,
+                       G_DBUS_PROXY_FLAGS_NONE, NULL,
+                       BT_HAL_BLUEZ_NAME,
+                       char_handle,
+                       BT_HAL_PROPERTIES_INTERFACE,
+                       NULL, &error);
+
+       if (properties_proxy == NULL) {
+               ERR("properties_proxy returned NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       result = g_dbus_proxy_call_sync(properties_proxy,
+                       "GetAll",
+                       g_variant_new("(s)", BT_HAL_GATT_CHAR_INTERFACE),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       NULL,
+                       &error);
+       if (!result) {
+               if (error != NULL) {
+                       ERR("Fail to get properties (Error: %s)", error->message);
+                       g_clear_error(&error);
+               } else
+                       ERR("Fail to get properties");
+               g_object_unref(properties_proxy);
+               return BT_STATUS_FAIL;
+       }
+
+       gp_desc_array = g_ptr_array_new();
+
+       g_variant_get(result, "(a{sv})", &property_iter);
+
+       while (g_variant_iter_loop(property_iter, "{sv}", &key, &value)) {
+               if (!g_strcmp0(key, "UUID")) {
+                       char_uuid_str = g_variant_dup_string(value, &len);
+                       INFO("%s [%s]", char_handle + 37, char_uuid_str);
+               } else if (!g_strcmp0(key, "Flags")) {
+                       g_variant_get(value, "as", &char_perm_iter);
+                               char_permission = 0x00;
+
+                       while (g_variant_iter_loop(char_perm_iter, "s", &permission)) {
+                               char_permission |= _hal_get_permission_flag(permission);
+                       }
+                       __hal_convert_permission_flag_to_str(char_permission);
+               } else if (!g_strcmp0(key, "Descriptors")) {
+                       g_variant_get(value, "ao", &char_desc_iter);
+                       while (g_variant_iter_loop(char_desc_iter, "&o", &char_desc_handle)) {
+                               g_ptr_array_add(gp_desc_array, (gpointer)char_desc_handle);
+                       }
+               }
+       }
+
+       _hal_gattc_update_char_property(gattc_char, char_uuid_str, gp_desc_array, char_permission);
+
+       g_free(char_uuid_str);
+       g_variant_iter_free(property_iter);
+       g_variant_unref(result);
+       g_object_unref(properties_proxy);
+       g_ptr_array_free(gp_desc_array, TRUE);
+
+       return BT_STATUS_SUCCESS;
+}
+
+static bt_status_t _gattc_get_all_characteristic(int conn_id,
+               btgatt_srvc_id_t *srvc_id)
+{
+       hal_gattc_server_info_t * conn_info = NULL;
+       hal_gattc_service_t *gattc_service = NULL;
+       GSList *l;
+       hal_gattc_char_t *gattc_char = NULL;
+       char svc_uuid_str[BT_HAL_UUID_STRING_LEN];
+       int status = BT_STATUS_FAIL;
+
+       conn_info = __bt_find_gatt_conn_info_from_conn_id(conn_id);
+       if (NULL == conn_info) {
+               ERR("Failed to get the conn_info for conn_id [%d]", conn_id);
+               return BT_STATUS_FAIL;
+       }
+
+       /* find service */
+       gattc_service = _gattc_find_service_from_uuid(conn_info, &srvc_id->id.uuid);
+       if (NULL == gattc_service) {
+               ERR("Failed to get the gatt service");
+               return BT_STATUS_FAIL;
+       }
+
+       _bt_hal_convert_uuid_type_to_string(svc_uuid_str, gattc_service->svc_uuid.uu);
+       INFO("%s %s", gattc_service->svc_path + 37, svc_uuid_str);
+
+       /* find characteristic object path */
+       for (l = gattc_service->gatt_list_chars; l != NULL; l = g_slist_next(l)) {
+               gattc_char = (hal_gattc_char_t *)l->data;
+               status = _hal_gattc_get_characteristic_info(gattc_char);
+
+               /* send event */
+               if (BT_STATUS_SUCCESS == status) {
+                       _bt_hal_send_client_char_search_result_event(conn_id, status, srvc_id,
+                                       &gattc_char->chr_uuid, gattc_char->permission);
+               }
+       }
+
+       status = BT_STATUS_FAIL;
+       _bt_hal_send_client_char_search_result_event(conn_id, status, srvc_id, NULL, 0);
+
+       browse_service_char(conn_id);
+       /* retrive uuid for characteristic and object path for descriptor */
+
+       return BT_STATUS_SUCCESS;
+}
+
+/**
+ * Enumerate characteristics for a given service.
+ * Set start_char_id to NULL to get the first characteristic.
+ */
+bt_status_t btif_gattc_get_characteristic(int conn_id,
+               btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *start_char_id)
+{
+       CHECK_BTGATT_INIT();
+
+       if (start_char_id == NULL) {
+               DBG("Get all the characteristics");
+               return _gattc_get_all_characteristic(conn_id, srvc_id);
+
+       } else {
+               DBG("TBD Get specific characteristics");
+               return BT_STATUS_UNSUPPORTED;
+       }
+}
+
+static bt_status_t _hal_gattc_get_descriptor_info(hal_gattc_desc_t *gattc_desc)
+{
+       GDBusProxy *properties_proxy = NULL;
+       GError *error = NULL;
+       GVariant *value = NULL;
+       GVariant *result = NULL;
+       GDBusConnection *g_conn;
+       const gchar *key;
+       gsize len;
+       GVariantIter *property_iter;
+       char* desc_handle = NULL;
+       const gchar *desc_uuid_str = NULL;
+
+       if (gattc_desc->desc_path == NULL) {
+               DBG("desc path is NULL");
+               return BT_STATUS_FAIL;
+       }
+       desc_handle = gattc_desc->desc_path;
+
+       g_conn = _bt_hal_get_system_gconn();
+       if (NULL == g_conn) {
+               ERR("_bt_gdbus_get_system_gconn returned NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       properties_proxy = g_dbus_proxy_new_sync(g_conn,
+                       G_DBUS_PROXY_FLAGS_NONE, NULL,
+                       BT_HAL_BLUEZ_NAME,
+                       desc_handle,
+                       BT_HAL_PROPERTIES_INTERFACE,
+                       NULL, &error);
+
+       if (properties_proxy == NULL) {
+               ERR("properties_proxy returned NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       result = g_dbus_proxy_call_sync(properties_proxy,
+                       "GetAll",
+                       g_variant_new("(s)", BT_HAL_GATT_DESC_INTERFACE),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       NULL,
+                       &error);
+       if (!result) {
+               if (error != NULL) {
+                       ERR("Fail to get properties (Error: %s)", error->message);
+                       g_clear_error(&error);
+               } else
+                       ERR("Fail to get properties");
+               g_object_unref(properties_proxy);
+               return BT_STATUS_FAIL;
+       }
+
+       g_variant_get(result, "(a{sv})", &property_iter);
+
+       while (g_variant_iter_loop(property_iter, "{sv}", &key, &value)) {
+               if (!g_strcmp0(key, "UUID")) {
+                       desc_uuid_str = g_variant_get_string(value, &len);
+                       _hal_gattc_update_desc_property(gattc_desc, desc_uuid_str);
+                       break;
+               }
+       }
+
+       g_variant_iter_free(property_iter);
+       g_variant_unref(result);
+       g_object_unref(properties_proxy);
+
+       return BT_STATUS_SUCCESS;
+}
+
+static void _bt_hal_send_client_desc_search_result_event(int conn_id, int status,
+               btgatt_srvc_id_t *svc_id, btgatt_gatt_id_t *char_id, bt_uuid_t *desc_uuid)
+{
+       struct hal_ev_gatt_client_desc_search_result  ev;
+
+       if (!event_cb) {
+               ERR("gatt client callback not registered");
+               return;
+       }
+
+       memset(&ev, 0, sizeof(ev));
+       ev.conn_id = conn_id;
+       ev.inst_id = svc_id->id.inst_id;
+       ev.is_primary = svc_id->is_primary;
+       ev.status = status;
+
+       memcpy(ev.svc_uuid, svc_id->id.uuid.uu, sizeof(ev.svc_uuid));
+       memcpy(ev.char_uuid, char_id->uuid.uu, sizeof(ev.char_uuid));
+
+       if (status == BT_STATUS_SUCCESS) {
+               /* building desc uuid */
+               memcpy(ev.desc_uuid, desc_uuid->uu, sizeof(ev.desc_uuid));
+       }
+
+       DBG("sending the desc search event. conn_id[%d] status[%d]", conn_id, status);
+
+       event_cb(HAL_EV_GATT_CLIENT_DESC_SEARCH_RESULT, (void *)&ev, sizeof(ev));
+}
+
+static bt_status_t _hal_gattc_get_all_descriptor(int conn_id,
+               btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id)
+{
+       hal_gattc_server_info_t * conn_info = NULL;
+       hal_gattc_service_t *gattc_service = NULL;
+       GSList *l;
+       GSList *m;
+       hal_gattc_char_t *gattc_char = NULL;
+       hal_gattc_desc_t *gattc_desc = NULL;
+       char svc_uuid_str[BT_HAL_UUID_STRING_LEN];
+       char char_uuid_str[BT_HAL_UUID_STRING_LEN];
+       int status = BT_STATUS_FAIL;
+
+       conn_info = __bt_find_gatt_conn_info_from_conn_id(conn_id);
+       if (NULL == conn_info) {
+               ERR("Failed to get the conn_info for conn_id [%d]", conn_id);
+               return BT_STATUS_FAIL;
+       }
+
+       /* find service */
+       gattc_service = _gattc_find_service_from_uuid(conn_info, &srvc_id->id.uuid);
+       if (NULL == gattc_service) {
+               ERR("Failed to get the gatt service");
+               return BT_STATUS_FAIL;
+       }
+
+       _bt_hal_convert_uuid_type_to_string(svc_uuid_str, gattc_service->svc_uuid.uu);
+       INFO("%s %s", gattc_service->svc_path + 37, svc_uuid_str);
+
+       /* find characteristics */
+       /* a service can have two char with same uuid */
+       for (l = gattc_service->gatt_list_chars; l != NULL; l = g_slist_next(l)) {
+               gattc_char = (hal_gattc_char_t*)l->data;
+               if (gattc_char == NULL)
+                       continue;
+
+               if (!memcmp(&gattc_char->chr_uuid, &char_id->uuid, sizeof(bt_uuid_t))) {
+                       _bt_hal_convert_uuid_type_to_string(char_uuid_str, gattc_char->chr_uuid.uu);
+                       INFO("%s %s", gattc_char->chr_path + 37, char_uuid_str);
+
+                       /* get descriptor uuid */
+                       for (m = gattc_char->gatt_list_descs; m != NULL; m = g_slist_next(m)) {
+                               gattc_desc = (hal_gattc_desc_t *)m->data;
+                               if (gattc_desc == NULL)
+                                       continue;
+
+                               status = _hal_gattc_get_descriptor_info(gattc_desc);
+
+                               /* send event */
+                               if (BT_STATUS_SUCCESS == status) {
+                                       _bt_hal_send_client_desc_search_result_event(conn_id, status, srvc_id,
+                                                       char_id, &gattc_desc->desc_uuid);
+                               }
+                       }
+               }
+       }
+
+       status = BT_STATUS_FAIL;
+       _bt_hal_send_client_desc_search_result_event(conn_id, status, srvc_id, char_id, NULL);
+
+       browse_service_char(conn_id);
+       /* retrive uuid for characteristic and object path for descriptor */
+
+       return BT_STATUS_SUCCESS;
+}
+
+/**
+ * Enumerate descriptors for a given characteristic.
+ * Set start_descr_id to NULL to get the first descriptor.
+ */
+bt_status_t btif_gattc_get_descriptor(int conn_id,
+               btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+               btgatt_gatt_id_t *start_descr_id)
+{
+       CHECK_BTGATT_INIT();
+
+       if (start_descr_id == NULL) {
+               return _hal_gattc_get_all_descriptor(conn_id, srvc_id, char_id);
+       } else {
+               DBG("TBD Get specific descriptor");
+               return BT_STATUS_UNSUPPORTED;
+       }
+}
+
+static void __hal_send_char_read_event(hal_gatt_resp_data_t *resp_data, int result, uint8_t *value, int len)
+{
+       struct hal_ev_gatt_client_read_data  ev;
+
+       if (!event_cb) {
+               ERR("gatt client callback not registered");
+               return;
+       }
+
+       memset(&ev, 0, sizeof(ev));
+       ev.conn_id = resp_data->conn_id;
+       ev.inst_id = resp_data->srvc_id.id.inst_id;
+       ev.is_primary = resp_data->srvc_id.is_primary;
+       ev.status = result;
+
+       memcpy(ev.svc_uuid, resp_data->srvc_id.id.uuid.uu, sizeof(ev.svc_uuid));
+       memcpy(ev.char_uuid, resp_data->char_id.uuid.uu, sizeof(ev.char_uuid));
+
+       ev.len = len;
+       if (len > 0) {
+               /* building the char read value */
+               memcpy(ev.value, value, len);
+       }
+
+       DBG("sending gatt client charac read event. conn_id[%d] status[%d]", resp_data->conn_id, result);
+
+       event_cb(HAL_EV_GATT_CLIENT_READ_CHARAC, (void *)&ev, sizeof(ev));
+}
+
+static void __hal_internal_read_char_cb(GObject *source_object,
+               GAsyncResult *res, gpointer user_data)
+{
+       GError *error = NULL;
+       GDBusConnection *system_gconn = NULL;
+       GVariant *value;
+       GVariantIter *iter;
+       GByteArray *gp_byte_array = NULL;
+       guint8 g_byte;
+       hal_gatt_resp_data_t *resp_data = user_data;
+       int result = BT_STATUS_SUCCESS;
+
+       system_gconn = _bt_hal_get_system_gconn();
+       value = g_dbus_connection_call_finish(system_gconn, res, &error);
+
+       if (error) {
+               ERR("Read Characteristic dbus failed Error:[%s]", error->message);
+
+               //send failed event
+               result  = BT_STATUS_FAIL;
+               __hal_send_char_read_event(resp_data, result, NULL, 0);
+               g_clear_error(&error);
+               g_free(resp_data);
+               return;
+       }
+
+       gp_byte_array = g_byte_array_new();
+       g_variant_get(value, "(ay)", &iter);
+
+       while (g_variant_iter_loop(iter, "y", &g_byte))
+               g_byte_array_append(gp_byte_array, &g_byte, 1);
+
+
+       //send value  event
+       __hal_send_char_read_event(resp_data, result, gp_byte_array->data, gp_byte_array->len);
+
+       g_free(resp_data);
+
+       g_byte_array_free(gp_byte_array, TRUE);
+       g_variant_iter_free(iter);
+       g_variant_unref(value);
+
+}
+
+static bt_status_t _hal_read_characteristic_value(int conn_id, btgatt_srvc_id_t *srvc_id,
+               btgatt_gatt_id_t *char_id, int auth_req)
+{
+       GDBusConnection *g_conn;
+       hal_gatt_resp_data_t *resp_data;
+       hal_gattc_service_t *gattc_service = NULL;
+       GVariantBuilder *builder = NULL;
+       guint16 offset = 0;
+       hal_gattc_server_info_t * conn_info = NULL;
+       hal_gattc_char_t *gattc_char = NULL;
+       char svc_uuid_str[BT_HAL_UUID_STRING_LEN];
+       char char_uuid_str[BT_HAL_UUID_STRING_LEN];
+       char* char_handle = NULL;
+
+       /* get the connection info */
+       conn_info = __bt_find_gatt_conn_info_from_conn_id(conn_id);
+       if (NULL == conn_info) {
+               ERR("Failed to get the conn_info for conn_id [%d]", conn_id);
+               return BT_STATUS_FAIL;
+       }
+
+       /* find service */
+       gattc_service = _gattc_find_service_from_uuid(conn_info, &srvc_id->id.uuid);
+       if (NULL == gattc_service) {
+               ERR("Failed to get the gatt service");
+               return BT_STATUS_FAIL;
+       }
+
+       _bt_hal_convert_uuid_type_to_string(svc_uuid_str, gattc_service->svc_uuid.uu);
+
+       /* find characteristic */
+       gattc_char = _gattc_find_char_from_uuid(gattc_service, &char_id->uuid,
+                       HAL_GATT_CHARACTERISTIC_PROPERTY_READ);
+       if (NULL == gattc_char) {
+               ERR("Failed to get the gatt char");
+               return BT_STATUS_FAIL;
+       }
+
+       _bt_hal_convert_uuid_type_to_string(char_uuid_str, gattc_char->chr_uuid.uu);
+       INFO("%s %s", gattc_char->chr_path + 37, char_uuid_str);
+
+       g_conn = _bt_hal_get_system_gconn();
+       if (NULL == g_conn) {
+               ERR("_bt_gdbus_get_system_gconn returned NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       resp_data = g_malloc0(sizeof(hal_gatt_resp_data_t));
+       resp_data->conn_id = conn_id;
+       memcpy(&resp_data->srvc_id, srvc_id, sizeof(btgatt_srvc_id_t));
+       memcpy(&resp_data->char_id, char_id, sizeof(btgatt_gatt_id_t));
+
+       builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+
+       /*offset*/
+       g_variant_builder_add(builder, "{sv}", "offset",
+                       g_variant_new("q", offset));
+
+       char_handle = gattc_char->chr_path;
+
+       g_dbus_connection_call(g_conn, BT_HAL_BLUEZ_NAME, char_handle, BT_HAL_GATT_CHAR_INTERFACE,
+                       "ReadValue", g_variant_new("(a{sv})", builder),
+                       G_VARIANT_TYPE("(ay)"), G_DBUS_CALL_FLAGS_NONE, -1, NULL,
+                       (GAsyncReadyCallback)__hal_internal_read_char_cb,
+                       (gpointer)resp_data);
+       g_variant_builder_unref(builder);
+
+       return BT_STATUS_SUCCESS;
+}
+
+/** Read a characteristic on a remote device */
+bt_status_t btif_read_characteristic(int conn_id,
+               btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+               int auth_req)
+{
+       CHECK_BTGATT_INIT();
+
+       return _hal_read_characteristic_value(conn_id, srvc_id, char_id, auth_req);
+}
+
+static void __hal_send_char_write_event(hal_gatt_resp_data_t *resp_data, int result)
+{
+       struct hal_ev_gatt_client_write_result  ev;
+
+        if (!event_cb) {
+               ERR("gatt client callback not registered");
+               return;
+       }
+
+       memset(&ev, 0, sizeof(ev));
+       ev.conn_id = resp_data->conn_id;
+       ev.inst_id = resp_data->srvc_id.id.inst_id;
+       ev.is_primary = resp_data->srvc_id.is_primary;
+       ev.status = result;
+
+       memcpy(ev.svc_uuid, resp_data->srvc_id.id.uuid.uu, sizeof(ev.svc_uuid));
+       memcpy(ev.char_uuid, resp_data->char_id.uuid.uu, sizeof(ev.char_uuid));
+
+       DBG("sending gatt client charac write event. conn_id[%d] status[%d]", resp_data->conn_id, result);
+
+       event_cb(HAL_EV_GATT_CLIENT_WRITE_CHARAC, (void *)&ev, sizeof(ev));
+}
+
+static void __hal_bluetooth_internal_write_cb(GObject *source_object,
+               GAsyncResult *res, gpointer user_data)
+{
+       GError *error = NULL;
+       GDBusConnection *system_gconn = NULL;
+       GVariant *value;
+       hal_gatt_resp_data_t *resp_data = user_data;
+       int result = BT_STATUS_SUCCESS;
+
+       DBG("+");
+
+       system_gconn = _bt_hal_get_system_gconn();
+       value = g_dbus_connection_call_finish(system_gconn, res, &error);
+
+       if (error) {
+               ERR("write Characteristic dbus failed Error:[%s]", error->message);
+
+               result  = BT_STATUS_FAIL;
+               //send failed event
+               __hal_send_char_write_event(resp_data, result);
+               g_clear_error(&error);
+               g_free(resp_data);
+               return;
+       }
+
+       //send write value  event
+       __hal_send_char_write_event(resp_data, result);
+
+       g_free(resp_data);
+       g_variant_unref(value);
+
+       DBG("-");
+}
+
+static bt_status_t __hal_get_write_prop(hal_gatt_write_type_t type, bt_gatt_characteristic_property_t *prop)
+{
+       switch (type) {
+       case HAL_GATT_WRITE_TYPE_WRITE:
+               *prop = HAL_GATT_CHARACTERISTIC_PROPERTY_WRITE;
+               break;
+       case HAL_GATT_WRITE_TYPE_WRITE_NO_RESPONSE:
+               *prop = HAL_GATT_CHARACTERISTIC_PROPERTY_WRITE_NO_RESPONSE;
+               break;
+       default:
+               ERR("Unknow write type : %d", type);
+               return BT_STATUS_FAIL;
+       }
+
+       return BT_STATUS_SUCCESS;
+}
+
+
+static int __bluetooth_gatt_acquire_write_fd(const char *chr, int *fd, int *mtu)
+{
+       GDBusConnection *conn;
+       GVariantBuilder *builder = NULL;
+       guint16 offset = 0;
+       GError *err = NULL;
+       GVariant *value;
+       gint32 idx;
+       guint16 att_mtu;
+       GUnixFDList *fd_list = NULL;
+
+       conn = _bt_hal_get_system_gconn();
+       if (NULL == conn) {
+               ERR("_bt_gdbus_get_system_gconn returned NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+       //val = g_variant_new("ay", builder1);
+
+       g_variant_builder_add(builder, "{sv}", "offset",
+       g_variant_new("q", offset));
+
+       value = g_dbus_connection_call_with_unix_fd_list_sync(conn, BT_HAL_BLUEZ_NAME, chr, BT_HAL_GATT_CHAR_INTERFACE,
+                       "AcquireWrite", g_variant_new("(a{sv})", builder),
+                       G_VARIANT_TYPE("(hq)"), G_DBUS_CALL_FLAGS_NONE, -1,
+                       NULL, &fd_list, NULL, &err);
+       if (err != NULL) {
+               g_dbus_error_strip_remote_error(err);
+               ERR("Error: %s", err->message);
+               g_error_free(err);
+               g_variant_builder_unref(builder);
+               return BT_STATUS_FAIL;
+       }
+
+       g_variant_get(value, "(hq)", &idx, &att_mtu);
+       *fd = g_unix_fd_list_get(fd_list, idx, NULL);
+
+       INFO("Acquired Write fd %d,  index %d, mtu %d", *fd, idx, att_mtu);
+       *mtu = att_mtu;
+
+       g_object_unref(fd_list);
+       g_variant_unref(value);
+       g_variant_builder_unref(builder);
+
+       return BT_STATUS_SUCCESS;
+}
+
+static int __bluetooth_gatt_acquire_notify_fd(const char *chr, int *fd, int *mtu)
+{
+       GDBusConnection *conn;
+       GVariantBuilder *builder = NULL;
+       guint16 offset = 0;
+       GError *err = NULL;
+       GVariant *value;
+       gint32 idx, notify_fd;
+       guint16 att_mtu;
+       GUnixFDList *fd_list = NULL;
+
+       conn = _bt_hal_get_system_gconn();
+
+       if (NULL == conn) {
+               ERR("_bt_gdbus_get_system_gconn returned NULL");
+               return BT_STATUS_FAIL;
+       }
+
+
+       builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+
+
+       g_variant_builder_add(builder, "{sv}", "offset",
+               g_variant_new("q", offset));
+
+       value = g_dbus_connection_call_with_unix_fd_list_sync(conn, BT_HAL_BLUEZ_NAME, chr, BT_HAL_GATT_CHAR_INTERFACE,
+               "AcquireNotify", g_variant_new("(a{sv})", builder),
+               G_VARIANT_TYPE("(hq)"), G_DBUS_CALL_FLAGS_NONE, -1,
+               NULL, &fd_list, NULL, &err);
+       if (err != NULL) {
+               g_dbus_error_strip_remote_error(err);
+               ERR("Error: %s", err->message);
+               g_error_free(err);
+               g_variant_builder_unref(builder);
+               return BT_STATUS_FAIL;
+       }
+
+       g_variant_get(value, "(hq)", &idx, &att_mtu);
+       notify_fd = g_unix_fd_list_get(fd_list, idx, NULL);
+       *mtu = att_mtu;
+
+       INFO("Acquired Notify fd %d, mtu %d", notify_fd, *mtu);
+
+       *fd = notify_fd;
+
+       g_object_unref(fd_list);
+       g_variant_unref(value);
+       g_variant_builder_unref(builder);
+
+       return BT_STATUS_SUCCESS;
+}
+
+
+static bt_status_t _hal_write_characteristic_value(int conn_id, btgatt_srvc_id_t *srvc_id,
+               btgatt_gatt_id_t *char_id, int write_type, int length, int auth_req, char* value)
+{
+       GVariant *val, *options;
+       GVariantBuilder *builder1;
+       GVariantBuilder *builder2;
+       GDBusConnection *g_conn;
+       guint16 offset = 0;
+       int i = 0;
+       hal_gatt_resp_data_t  *resp_data;
+       hal_gattc_service_t *gattc_service = NULL;
+       hal_gattc_server_info_t * conn_info = NULL;
+       hal_gattc_char_t *gattc_char = NULL;
+       char svc_uuid_str[BT_HAL_UUID_STRING_LEN];
+       char char_uuid_str[BT_HAL_UUID_STRING_LEN];
+       char* char_handle = NULL;
+       bt_gatt_characteristic_property_t write_prop = HAL_GATT_CHARACTERISTIC_PROPERTY_WRITE;
+       int ret = BT_STATUS_SUCCESS;
+
+       ret = __hal_get_write_prop(write_type, &write_prop);
+       if (BT_STATUS_FAIL == ret) {
+               DBG("received invalid  write type:[%d] ", write_type);
+               return BT_STATUS_FAIL;
+       }
+
+       /* get the connection info */
+       conn_info = __bt_find_gatt_conn_info_from_conn_id(conn_id);
+       if (NULL == conn_info) {
+               ERR("Failed to get the conn_info for conn_id [%d]", conn_id);
+               return BT_STATUS_FAIL;
+       }
+
+       /* find service */
+       gattc_service = _gattc_find_service_from_uuid(conn_info, &srvc_id->id.uuid);
+       if (NULL == gattc_service) {
+               ERR("Failed to get the gatt service");
+               return BT_STATUS_FAIL;
+       }
+
+       _bt_hal_convert_uuid_type_to_string(svc_uuid_str, gattc_service->svc_uuid.uu);
+       DBG("%s %s", gattc_service->svc_path + 37, svc_uuid_str);
+
+       /* find characteristic */
+       gattc_char = _gattc_find_char_from_uuid(gattc_service, &char_id->uuid, write_prop);
+       if (NULL == gattc_char) {
+               ERR("Failed to get the gatt char");
+               return BT_STATUS_FAIL;
+       }
+
+       _bt_hal_convert_uuid_type_to_string(char_uuid_str, gattc_char->chr_uuid.uu);
+       DBG("%s %s", gattc_char->chr_path + 37, char_uuid_str);
+
+       g_conn = _bt_hal_get_system_gconn();
+       if (NULL == g_conn) {
+                ERR("_bt_gdbus_get_system_gconn returned NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       resp_data = g_malloc0(sizeof(hal_gatt_resp_data_t));
+       resp_data->conn_id = conn_id;
+       memcpy(&resp_data->srvc_id, srvc_id, sizeof(btgatt_srvc_id_t));
+       memcpy(&resp_data->char_id, char_id, sizeof(btgatt_gatt_id_t));
+
+       char_handle = gattc_char->chr_path;
+
+       builder1 = g_variant_builder_new(G_VARIANT_TYPE("ay"));
+
+       for (i = 0; i < length; i++)
+               g_variant_builder_add(builder1, "y", value[i]);
+
+       val = g_variant_new("ay", builder1);
+
+       builder2 = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+       /*offset*/
+       g_variant_builder_add(builder2, "{sv}", "offset",
+                       g_variant_new_uint16(offset));
+
+       options = g_variant_new("a{sv}", builder2);
+
+       g_dbus_connection_call(g_conn, BT_HAL_BLUEZ_NAME, char_handle, BT_HAL_GATT_CHAR_INTERFACE,
+                       "WriteValuebyType",
+                       g_variant_new("(y@ay@a{sv})", write_prop, val, options),
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE, -1, NULL,
+                       (GAsyncReadyCallback)__hal_bluetooth_internal_write_cb,
+                       (gpointer)resp_data);
+
+       g_variant_builder_unref(builder1);
+       g_variant_builder_unref(builder2);
+
+       return BT_STATUS_SUCCESS;
+}
+
+bt_status_t btif_get_acquire_write_fd(int conn_id,
+               btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+               int auth_req, int *fd, int*mtu)
+{
+       CHECK_BTGATT_INIT();
+
+       hal_gattc_service_t *gattc_service = NULL;
+       hal_gattc_server_info_t * conn_info = NULL;
+       hal_gattc_char_t *gattc_char = NULL;
+       char char_uuid_str[BT_HAL_UUID_STRING_LEN];
+
+       bt_gatt_characteristic_property_t write_prop = HAL_GATT_CHARACTERISTIC_PROPERTY_WRITE_NO_RESPONSE;
+       int ret = BT_STATUS_SUCCESS;
+
+       DBG("svc isntance id:[%d]", srvc_id->id.inst_id);
+
+       /* get the connection info */
+       conn_info = __bt_find_gatt_conn_info_from_conn_id(conn_id);
+       if (NULL == conn_info) {
+               ERR("Failed to get the conn_info for conn_id [%d]", conn_id);
+               return BT_STATUS_FAIL;
+       }
+
+       /* find service */
+       gattc_service = _gattc_find_service_from_uuid(conn_info, &srvc_id->id.uuid);
+       if (NULL == gattc_service) {
+               ERR("Failed to get the gatt service");
+               return BT_STATUS_FAIL;
+       }
+
+       gattc_char = _gattc_find_char_from_uuid(gattc_service, &char_id->uuid, write_prop);
+       if (NULL == gattc_char) {
+               ERR("Failed to get the gatt char");
+               return BT_STATUS_FAIL;
+       }
+
+       _bt_hal_convert_uuid_type_to_string(char_uuid_str, gattc_char->chr_uuid.uu);
+       INFO("%s %s", gattc_char->chr_path + 37, char_uuid_str);
+
+       ret = __bluetooth_gatt_acquire_write_fd(gattc_char->chr_path, fd, mtu);
+       if (ret != BT_STATUS_SUCCESS)
+               return ret;
+
+       return ret;
+}
+
+bt_status_t btif_get_acquire_notify_fd(int conn_id,
+               btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id, int *fd, int *mtu)
+{
+       CHECK_BTGATT_INIT();
+
+       hal_gattc_service_t *gattc_service = NULL;
+       hal_gattc_server_info_t * conn_info = NULL;
+       hal_gattc_char_t *gattc_char = NULL;
+       char char_uuid_str[BT_HAL_UUID_STRING_LEN];
+
+       bt_gatt_characteristic_property_t write_prop = HAL_GATT_CHARACTERISTIC_PROPERTY_NOTIFY;
+       int ret = BT_STATUS_SUCCESS;
+
+       DBG("svc isntance id [%d]", srvc_id->id.inst_id);
+
+       /* get the connection info */
+       conn_info = __bt_find_gatt_conn_info_from_conn_id(conn_id);
+       if (NULL == conn_info) {
+               ERR("Failed to get the conn_info for conn_id [%d]", conn_id);
+               return BT_STATUS_FAIL;
+       }
+
+       /* find service */
+       gattc_service = _gattc_find_service_from_uuid(conn_info, &srvc_id->id.uuid);
+       if (NULL == gattc_service) {
+               ERR("Failed to get the gatt service");
+               return BT_STATUS_FAIL;
+       }
+
+       gattc_char = _gattc_find_char_from_uuid(gattc_service, &char_id->uuid, write_prop);
+       if (NULL == gattc_char) {
+               ERR("Failed to get the gatt char");
+               return BT_STATUS_FAIL;
+       }
+
+       _bt_hal_convert_uuid_type_to_string(char_uuid_str, gattc_char->chr_uuid.uu);
+       INFO("%s %s", gattc_char->chr_path + 37, char_uuid_str);
+
+       ret = __bluetooth_gatt_acquire_notify_fd(gattc_char->chr_path, fd, mtu);
+       if (ret != BT_STATUS_SUCCESS)
+               return ret;
+
+       return ret;
+}
+
+
+/** Write a remote characteristic */
+bt_status_t btif_write_characteristic(int conn_id,
+               btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+               int write_type, int len, int auth_req,
+               char* p_value)
+{
+       CHECK_BTGATT_INIT();
+
+       DBG("svc isntance id:[%d]", srvc_id->id.inst_id);
+       return _hal_write_characteristic_value(conn_id, srvc_id, char_id, write_type,
+                               len, auth_req, p_value);
+}
+
+static void __hal_send_desc_read_event(hal_gatt_resp_data_t *resp_data, int result, uint8_t *value, int len)
+{
+       struct hal_ev_gatt_client_read_data  ev;
+
+        if (!event_cb) {
+               ERR("gatt client callback not registered");
+               return;
+       }
+
+       memset(&ev, 0, sizeof(ev));
+       ev.conn_id = resp_data->conn_id;
+       ev.inst_id = resp_data->srvc_id.id.inst_id;
+       ev.is_primary = resp_data->srvc_id.is_primary;
+       ev.status = result;
+
+       memcpy(ev.svc_uuid, resp_data->srvc_id.id.uuid.uu, sizeof(ev.svc_uuid));
+       memcpy(ev.char_uuid, resp_data->char_id.uuid.uu, sizeof(ev.char_uuid));
+       memcpy(ev.desc_uuid, resp_data->desc_id.uuid.uu, sizeof(ev.char_uuid));
+
+       ev.len = len;
+       if (len > 0) {
+               /* building the desc read value */
+               memcpy(ev.value, value, len);
+       }
+
+       DBG("sending gatt client desc read conn_id[%d] status[%d]", resp_data->conn_id, result);
+
+       event_cb(HAL_EV_GATT_CLIENT_READ_DESC, (void *)&ev, sizeof(ev));
+}
+
+static void __hal_internal_read_desc_cb(GObject *source_object,
+               GAsyncResult *res, gpointer user_data)
+{
+       GError *error = NULL;
+       GDBusConnection *system_gconn = NULL;
+       GVariant *value;
+       GVariantIter *iter;
+       GByteArray *gp_byte_array = NULL;
+       guint8 g_byte;
+       hal_gatt_resp_data_t *resp_data = user_data;
+       int result = BT_STATUS_SUCCESS;
+       int i;
+
+       DBG("+");
+
+       system_gconn = _bt_hal_get_system_gconn();
+       value = g_dbus_connection_call_finish(system_gconn, res, &error);
+
+       if (error) {
+               ERR("Read descriptor dbus failed Error:[%s]", error->message);
+
+               //send failed event
+               result  = BT_STATUS_FAIL;
+               __hal_send_desc_read_event(resp_data, result, NULL, 0);
+               g_clear_error(&error);
+               g_free(resp_data);
+               return;
+       }
+
+       gp_byte_array = g_byte_array_new();
+       g_variant_get(value, "(ay)", &iter);
+
+       while (g_variant_iter_loop(iter, "y", &g_byte))
+               g_byte_array_append(gp_byte_array, &g_byte, 1);
+
+       //print the value
+       DBG("value is");
+       for (i = 0; i < gp_byte_array->len; i++)
+               DBG("%02x", gp_byte_array->data[i]);
+
+       //send value  event
+       __hal_send_desc_read_event(resp_data, result, gp_byte_array->data, gp_byte_array->len);
+
+       g_free(resp_data);
+
+       g_byte_array_free(gp_byte_array, TRUE);
+       g_variant_iter_free(iter);
+       g_variant_unref(value);
+
+       DBG("-");
+}
+
+static bt_status_t _hal_read_descriptor_value(int conn_id, btgatt_srvc_id_t *srvc_id,
+               btgatt_gatt_id_t *char_id, btgatt_gatt_id_t *desc_id, int auth_req)
+{
+       GDBusConnection *g_conn;
+       hal_gatt_resp_data_t *resp_data;
+       hal_gattc_service_t *gattc_service = NULL;
+       GVariantBuilder *builder = NULL;
+       guint16 offset = 0;
+       hal_gattc_server_info_t * conn_info = NULL;
+       hal_gattc_char_t *gattc_char = NULL;
+       char svc_uuid_str[BT_HAL_UUID_STRING_LEN];
+       char char_uuid_str[BT_HAL_UUID_STRING_LEN];
+       char desc_uuid_str[BT_HAL_UUID_STRING_LEN];
+       char* desc_handle = NULL;
+       GSList *l;
+
+       hal_gattc_desc_t *gattc_desc = NULL;
+
+       /* get the connection info */
+       conn_info = __bt_find_gatt_conn_info_from_conn_id(conn_id);
+       if (NULL == conn_info) {
+               ERR("Failed to get the conn_info for conn_id [%d]", conn_id);
+               return BT_STATUS_FAIL;
+       }
+
+       /* find service */
+       gattc_service = _gattc_find_service_from_uuid(conn_info, &srvc_id->id.uuid);
+       if (NULL == gattc_service) {
+               ERR("Failed to get the gatt service");
+               return BT_STATUS_FAIL;
+       }
+
+       _bt_hal_convert_uuid_type_to_string(svc_uuid_str, gattc_service->svc_uuid.uu);
+       DBG("%s %s", gattc_service->svc_path + 37, svc_uuid_str);
+
+       /* find characteristic */
+       /* service can have two char with same uuid */
+       for (l = gattc_service->gatt_list_chars; l != NULL; l = g_slist_next(l)) {
+               gattc_char = (hal_gattc_char_t*)l->data;
+               if (gattc_char == NULL)
+                       continue;
+
+               if (!memcmp(&gattc_char->chr_uuid, &char_id->uuid, sizeof(bt_uuid_t))) {
+                       _bt_hal_convert_uuid_type_to_string(char_uuid_str, gattc_char->chr_uuid.uu);
+                       DBG("%s %s", gattc_char->chr_path + 37, char_uuid_str);
+
+                       /* find descriptor */
+                       gattc_desc = _gattc_find_desc_from_uuid(gattc_char, &desc_id->uuid);
+                       if (gattc_desc) {
+                               _bt_hal_convert_uuid_type_to_string(desc_uuid_str, gattc_desc->desc_uuid.uu);
+                               DBG("%s %s", gattc_desc->desc_path + 37, desc_uuid_str);
+                               break;
+                       }
+               }
+       }
+
+       if (NULL == gattc_desc) {
+               ERR("Failed to get the gatt desc");
+               return BT_STATUS_FAIL;
+       }
+
+       g_conn = _bt_hal_get_system_gconn();
+       if (NULL == g_conn) {
+                ERR("_bt_gdbus_get_system_gconn returned NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       resp_data = g_malloc0(sizeof(hal_gatt_resp_data_t));
+       resp_data->conn_id = conn_id;
+       memcpy(&resp_data->srvc_id, srvc_id, sizeof(btgatt_srvc_id_t));
+       memcpy(&resp_data->char_id, char_id, sizeof(btgatt_gatt_id_t));
+       memcpy(&resp_data->desc_id, desc_id, sizeof(btgatt_gatt_id_t));
+
+       builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+
+       /*offset*/
+       g_variant_builder_add(builder, "{sv}", "offset",
+                       g_variant_new("q", offset));
+
+       desc_handle = gattc_desc->desc_path;
+
+       DBG("calling desc read value");
+
+       g_dbus_connection_call(g_conn, BT_HAL_BLUEZ_NAME, desc_handle, BT_HAL_GATT_DESC_INTERFACE,
+                       "ReadValue", g_variant_new("(a{sv})", builder),
+                       G_VARIANT_TYPE("(ay)"), G_DBUS_CALL_FLAGS_NONE, -1, NULL,
+                       (GAsyncReadyCallback)__hal_internal_read_desc_cb,
+                       (gpointer)resp_data);
+       g_variant_builder_unref(builder);
+
+       return BT_STATUS_SUCCESS;
+}
+
+/** Read the descriptor for a given characteristic */
+bt_status_t btif_read_descriptor(int conn_id,
+               btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+               btgatt_gatt_id_t *descr_id, int auth_req)
+{
+       CHECK_BTGATT_INIT();
+
+       return _hal_read_descriptor_value(conn_id, srvc_id, char_id, descr_id, auth_req);
+}
+
+static void __hal_send_desc_write_event(hal_gatt_resp_data_t *resp_data, int result)
+{
+       struct hal_ev_gatt_client_write_result  ev;
+
+        if (!event_cb) {
+               ERR("gatt client callback not registered");
+               return;
+       }
+
+       memset(&ev, 0, sizeof(ev));
+       ev.conn_id = resp_data->conn_id;
+       ev.inst_id = resp_data->srvc_id.id.inst_id;
+       ev.is_primary = resp_data->srvc_id.is_primary;
+       ev.status = result;
+
+       memcpy(ev.svc_uuid, resp_data->srvc_id.id.uuid.uu, sizeof(ev.svc_uuid));
+       memcpy(ev.char_uuid, resp_data->char_id.uuid.uu, sizeof(ev.char_uuid));
+       memcpy(ev.desc_uuid, resp_data->desc_id.uuid.uu, sizeof(ev.desc_uuid));
+
+       DBG("sending gatt client charac write event. conn_id[%d] status[%d]", resp_data->conn_id, result);
+
+       event_cb(HAL_EV_GATT_CLIENT_WRITE_DESC, (void *)&ev, sizeof(ev));
+}
+
+static void __hal_bluetooth_internal_desc_write_cb(GObject *source_object,
+               GAsyncResult *res, gpointer user_data)
+{
+       GError *error = NULL;
+       GDBusConnection *system_gconn = NULL;
+       GVariant *value;
+       hal_gatt_resp_data_t *resp_data = user_data;
+       int result = BT_STATUS_SUCCESS;
+
+       DBG("+");
+
+       system_gconn = _bt_hal_get_system_gconn();
+       value = g_dbus_connection_call_finish(system_gconn, res, &error);
+
+       if (error) {
+               ERR("write descriptor dbus failed Error: [%s]", error->message);
+
+               //send failed event
+               result  = BT_STATUS_FAIL;
+               __hal_send_desc_write_event(resp_data, result);
+               g_clear_error(&error);
+               g_free(resp_data);
+               return;
+       }
+
+       //send write value  event
+       __hal_send_desc_write_event(resp_data, result);
+
+       g_free(resp_data);
+       g_variant_unref(value);
+
+       DBG("-");
+}
+
+static bt_status_t _hal_write_descriptor_value(int conn_id, btgatt_srvc_id_t *srvc_id,
+                               btgatt_gatt_id_t *char_id, btgatt_gatt_id_t *descr_id,
+                               int write_type, int length, int auth_req, char* value)
+{
+       GVariant *val, *options;
+       GVariantBuilder *builder1;
+       GVariantBuilder *builder2;
+       GDBusConnection *g_conn;
+       guint16 offset = 0;
+       int i = 0;
+       hal_gatt_resp_data_t  *resp_data;
+       hal_gattc_service_t *gattc_service = NULL;
+       hal_gattc_server_info_t * conn_info = NULL;
+       hal_gattc_char_t *gattc_char = NULL;
+       hal_gattc_desc_t *gattc_desc = NULL;
+       char svc_uuid_str[BT_HAL_UUID_STRING_LEN];
+       char char_uuid_str[BT_HAL_UUID_STRING_LEN];
+       char desc_uuid_str[BT_HAL_UUID_STRING_LEN];
+       char* desc_handle = NULL;
+       bt_gatt_characteristic_property_t write_prop = HAL_GATT_CHARACTERISTIC_PROPERTY_WRITE;
+       int ret = BT_STATUS_SUCCESS;
+       GSList *l;
+
+       DBG("+");
+
+       ret = __hal_get_write_prop(write_type, &write_prop);
+       if (BT_STATUS_FAIL == ret) {
+               ERR("received invalid  write type:[%d] ", write_type);
+               return BT_STATUS_FAIL;
+       }
+
+       /* get the connection info */
+       conn_info = __bt_find_gatt_conn_info_from_conn_id(conn_id);
+       if (NULL == conn_info) {
+               ERR("Failed to get the conn_info for conn_id [%d]", conn_id);
+               return BT_STATUS_FAIL;
+       }
+
+       /* find service */
+       gattc_service = _gattc_find_service_from_uuid(conn_info, &srvc_id->id.uuid);
+       if (NULL == gattc_service) {
+               ERR("Failed to get the gatt service");
+               return BT_STATUS_FAIL;
+       }
+
+       _bt_hal_convert_uuid_type_to_string(svc_uuid_str, gattc_service->svc_uuid.uu);
+       DBG("%s %s", gattc_service->svc_path + 37, svc_uuid_str);
+
+       /* find characteristic */
+       /* service can have two char with same uuid */
+       for (l = gattc_service->gatt_list_chars; l != NULL; l = g_slist_next(l)) {
+               gattc_char = (hal_gattc_char_t*)l->data;
+               if (gattc_char == NULL)
+                       continue;
+
+               if (!memcmp(&gattc_char->chr_uuid, &char_id->uuid, sizeof(bt_uuid_t))) {
+                       _bt_hal_convert_uuid_type_to_string(char_uuid_str, gattc_char->chr_uuid.uu);
+                       DBG("%s %s", gattc_char->chr_path + 37, char_uuid_str);
+
+                       /* find descriptor */
+                       gattc_desc = _gattc_find_desc_from_uuid(gattc_char, &descr_id->uuid);
+                       if (gattc_desc) {
+                               _bt_hal_convert_uuid_type_to_string(desc_uuid_str, gattc_desc->desc_uuid.uu);
+                               DBG("%s %s", gattc_desc->desc_path + 37, desc_uuid_str);
+                               break;
+                       }
+               }
+       }
+
+       if (NULL == gattc_desc) {
+               ERR("Failed to get the gatt desc");
+               return BT_STATUS_FAIL;
+       }
+
+       g_conn = _bt_hal_get_system_gconn();
+       if (NULL == g_conn) {
+                ERR("_bt_gdbus_get_system_gconn returned NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       resp_data = g_malloc0(sizeof(hal_gatt_resp_data_t));
+       resp_data->conn_id = conn_id;
+       memcpy(&resp_data->srvc_id, srvc_id, sizeof(btgatt_srvc_id_t));
+       memcpy(&resp_data->char_id, char_id, sizeof(btgatt_gatt_id_t));
+       memcpy(&resp_data->desc_id, descr_id, sizeof(btgatt_gatt_id_t));
+
+       desc_handle = gattc_desc->desc_path;
+
+       builder1 = g_variant_builder_new(G_VARIANT_TYPE("ay"));
+
+       for (i = 0; i < length; i++)
+               g_variant_builder_add(builder1, "y", value[i]);
+
+       val = g_variant_new("ay", builder1);
+
+       builder2 = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+       /*offset*/
+       g_variant_builder_add(builder2, "{sv}", "offset",
+                       g_variant_new_uint16(offset));
+
+       options = g_variant_new("a{sv}", builder2);
+
+       g_dbus_connection_call(g_conn, BT_HAL_BLUEZ_NAME, desc_handle, BT_HAL_GATT_DESC_INTERFACE,
+                       "WriteValue",
+                       g_variant_new("(@ay@a{sv})", val, options),
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE, -1, NULL,
+                       (GAsyncReadyCallback)__hal_bluetooth_internal_desc_write_cb,
+                       (gpointer)resp_data);
+
+       g_variant_builder_unref(builder1);
+       g_variant_builder_unref(builder2);
+
+       return BT_STATUS_SUCCESS;
+}
+
+/** Write a remote descriptor for a given characteristic */
+bt_status_t btif_write_descriptor(int conn_id,
+               btgatt_srvc_id_t *srvc_id, btgatt_gatt_id_t *char_id,
+               btgatt_gatt_id_t *descr_id, int write_type, int len,
+               int auth_req, char* p_value)
+{
+       CHECK_BTGATT_INIT();
+
+       return _hal_write_descriptor_value(conn_id, srvc_id, char_id, descr_id, write_type,
+                       len, auth_req, p_value);
+}
+
+/** Execute a prepared write operation */
+bt_status_t execute_write(int conn_id, int execute)
+{
+       CHECK_BTGATT_INIT();
+       return BT_STATUS_UNSUPPORTED;
+}
+
+static gboolean _hal_watch_register_notifi_cb(gpointer user_data)
+{
+       struct hal_ev_gatt_client_watch_notification ev;
+       hal_gatt_resp_data_t *resp_data = user_data;
+
+       DBG("sending the watch register notification event");
+       /* send the event */
+       memset(&ev, 0, sizeof(ev));
+       ev.client_if = resp_data->conn_id; /* conn_id is saved with client_if */
+       ev.registered = 1;
+       ev.status = resp_data->result;
+
+       ev.is_primary = resp_data->srvc_id.is_primary;
+       ev.inst_id = resp_data->srvc_id.id.inst_id;
+
+       memcpy(ev.svc_uuid, resp_data->srvc_id.id.uuid.uu, sizeof(ev.svc_uuid));
+       memcpy(ev.char_uuid, resp_data->char_id.uuid.uu, sizeof(ev.char_uuid));
+
+       if (!event_cb)
+               ERR("GATT Callback not registered");
+       else
+               event_cb(HAL_EV_GATT_CLIENT_WATCH_NOTIFICATION, (void *)&ev, sizeof(ev));
+
+       g_free(user_data);
+
+       return FALSE;
+}
+
+static bt_status_t _hal_register_for_notification(int client_if,
+               bt_bdaddr_t *bd_addr, btgatt_srvc_id_t *srvc_id,
+               btgatt_gatt_id_t *char_id)
+{
+       int result = BT_STATUS_SUCCESS;
+       GError *error = NULL;
+       GDBusConnection *g_conn;
+       hal_gattc_client_info_t *gattc_client = NULL;
+       hal_gattc_server_info_t * conn_info = NULL;
+       hal_gattc_service_t *gattc_service = NULL;
+       hal_gattc_char_t *gattc_char = NULL;
+       char* char_handle = NULL;
+       char svc_uuid_str[BT_HAL_UUID_STRING_LEN];
+       char char_uuid_str[BT_HAL_UUID_STRING_LEN];
+       hal_gatt_resp_data_t *resp_data;
+
+       DBG("+");
+
+       gattc_client = __bt_find_gatt_client_info(bd_addr);
+       if (gattc_client == NULL) {
+               ERR("failed to get the gatt client info");
+               return BT_STATUS_FAIL;
+       }
+
+       if (gattc_client->client_if != client_if) {
+               ERR("could not find the gatt client for client id[%d]", client_if);
+               return BT_STATUS_FAIL;
+       }
+
+        /* get the connection info */
+       conn_info = __bt_find_gatt_conn_info(bd_addr);
+       if (NULL == conn_info) {
+               ERR("Failed to get the conn_info");
+               return BT_STATUS_FAIL;
+       }
+
+       if (conn_info->inst_id != gattc_client->inst_id) {
+               ERR("could not fild the conn_info");
+               return BT_STATUS_FAIL;
+       }
+
+       /* find service */
+       gattc_service = _gattc_find_service_from_uuid(conn_info, &srvc_id->id.uuid);
+       if (NULL == gattc_service) {
+               ERR("Failed to get the gatt service");
+               return BT_STATUS_FAIL;
+       }
+
+       _bt_hal_convert_uuid_type_to_string(svc_uuid_str, gattc_service->svc_uuid.uu);
+       DBG("%s %s", gattc_service->svc_path + 15, svc_uuid_str);
+
+
+       /* find characteristic */
+       gattc_char = _gattc_find_char_from_uuid_for_notify(gattc_service, &char_id->uuid);
+       if (NULL == gattc_char) {
+               ERR("Failed to get the gatt char");
+               return BT_STATUS_FAIL;
+       }
+
+       _bt_hal_convert_uuid_type_to_string(char_uuid_str, gattc_char->chr_uuid.uu);
+       DBG("%s %s", gattc_char->chr_path + 15, char_uuid_str);
+
+       char_handle = gattc_char->chr_path;
+
+       g_conn = _bt_hal_get_system_gconn();
+       if (g_conn == NULL) {
+               ERR("conn NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       resp_data = g_malloc0(sizeof(hal_gatt_resp_data_t));
+
+       INFO_C("### Request StartNotify : %s [%s]", gattc_char->chr_path + 15, char_uuid_str);
+
+       g_dbus_connection_call_sync(g_conn,
+                       BT_HAL_BLUEZ_NAME,
+                       char_handle,
+                       BT_HAL_GATT_CHAR_INTERFACE,
+                       "StartNotify",
+                       NULL,
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE,
+                       BT_HAL_MAX_DBUS_TIMEOUT, NULL, &error);
+
+       if (error) {
+               g_dbus_error_strip_remote_error(error);
+               ERR("### StartNotify Failed: %s", error->message);
+               if (g_strrstr(error->message, "Already notifying"))
+                       result = BT_STATUS_SUCCESS;
+               else if (g_strrstr(error->message, "In Progress"))
+                       result = BT_STATUS_BUSY;
+               else if (g_strrstr(error->message, "Operation is not supported"))
+                       result = BT_STATUS_UNSUPPORTED;
+               /*failed because of either Insufficient Authorization or Write Not Permitted */
+               else if (g_strrstr(error->message, "Write not permitted") ||
+                               g_strrstr(error->message, "Operation Not Authorized"))
+                       result = BT_STATUS_AUTH_FAILURE;
+               /* failed because of either Insufficient Authentication,
+                  Insufficient Encryption Key Size, or Insufficient Encryption. */
+               else if (g_strrstr(error->message, "Not paired"))
+                       result = BT_STATUS_NOT_READY;
+               else
+                       result = BT_STATUS_FAIL;
+
+               g_clear_error(&error);
+       }
+
+       resp_data->conn_id = gattc_client->client_if; /* saving client_if instead of conn_id */
+       resp_data->result = result;
+       memcpy(&resp_data->srvc_id, srvc_id, sizeof(btgatt_srvc_id_t));
+       memcpy(&resp_data->char_id, char_id, sizeof(btgatt_gatt_id_t));
+
+       g_idle_add(_hal_watch_register_notifi_cb, (gpointer)resp_data);
+
+       DBG("-");
+
+       return BT_STATUS_SUCCESS;
+}
+
+/**
+ * Register to receive notifications or indications for a given
+ * characteristic
+ */
+bt_status_t btif_register_for_notification(int client_if,
+               const bt_bdaddr_t *bd_addr, btgatt_srvc_id_t *srvc_id,
+               btgatt_gatt_id_t *char_id)
+{
+       CHECK_BTGATT_INIT();
+
+       return _hal_register_for_notification(client_if, (bt_bdaddr_t *)bd_addr, srvc_id, char_id);
+}
+
+static gboolean _hal_watch_deregister_notifi_cb(gpointer user_data)
+{
+       struct hal_ev_gatt_client_watch_notification ev;
+       hal_gatt_resp_data_t *resp_data = user_data;
+
+       DBG("sending the watch deregister notification event");
+       /* send the event */
+       memset(&ev, 0, sizeof(ev));
+       ev.client_if = resp_data->conn_id; /* conn_id is saved with client_if */
+       ev.registered = 0;
+       ev.status = resp_data->result;
+
+       ev.is_primary = resp_data->srvc_id.is_primary;
+       ev.inst_id = resp_data->srvc_id.id.inst_id;
+
+       memcpy(ev.svc_uuid, resp_data->srvc_id.id.uuid.uu, sizeof(ev.svc_uuid));
+       memcpy(ev.char_uuid, resp_data->char_id.uuid.uu, sizeof(ev.char_uuid));
+
+       if (!event_cb)
+               ERR("GATT Callback not registered");
+       else
+               event_cb(HAL_EV_GATT_CLIENT_WATCH_NOTIFICATION, (void *)&ev, sizeof(ev));
+
+       g_free(user_data);
+
+       return FALSE;
+}
+
+static bt_status_t _hal_deregister_for_notification(int client_if,
+               bt_bdaddr_t *bd_addr, btgatt_srvc_id_t *srvc_id,
+               btgatt_gatt_id_t *char_id)
+{
+       int result = BT_STATUS_SUCCESS;
+       GError *error = NULL;
+       GDBusConnection *g_conn;
+       hal_gattc_client_info_t *gattc_client = NULL;
+       hal_gattc_server_info_t * conn_info = NULL;
+       hal_gattc_service_t *gattc_service = NULL;
+       hal_gattc_char_t *gattc_char = NULL;
+       char* char_handle = NULL;
+       char svc_uuid_str[BT_HAL_UUID_STRING_LEN];
+       char char_uuid_str[BT_HAL_UUID_STRING_LEN];
+       hal_gatt_resp_data_t *resp_data;
+
+       DBG("+");
+
+       gattc_client = __bt_find_gatt_client_info(bd_addr);
+       if (gattc_client == NULL) {
+               ERR("failed to get the gatt client info");
+               return BT_STATUS_FAIL;
+       }
+
+       if (gattc_client->client_if != client_if) {
+               ERR("could not find the gatt client for client id[%d]", client_if);
+               return BT_STATUS_FAIL;
+       }
+
+        /* get the connection info */
+       conn_info = __bt_find_gatt_conn_info(bd_addr);
+       if (NULL == conn_info) {
+               ERR("Failed to get the conn_info");
+               return BT_STATUS_FAIL;
+       }
+
+       if (conn_info->inst_id != gattc_client->inst_id) {
+               ERR("could not fild the conn_info");
+               return BT_STATUS_FAIL;
+       }
+
+       /* find service */
+       gattc_service = _gattc_find_service_from_uuid(conn_info, &srvc_id->id.uuid);
+       if (NULL == gattc_service) {
+               ERR("Failed to get the gatt service");
+               return BT_STATUS_FAIL;
+       }
+
+       _bt_hal_convert_uuid_type_to_string(svc_uuid_str, gattc_service->svc_uuid.uu);
+       DBG("%s %s", gattc_service->svc_path + 15, svc_uuid_str);
+
+
+       /* find characteristic */
+       gattc_char = _gattc_find_char_from_uuid_for_notify(gattc_service, &char_id->uuid);
+       if (NULL == gattc_char) {
+               ERR("Failed to get the gatt char");
+               return BT_STATUS_FAIL;
+       }
+
+       _bt_hal_convert_uuid_type_to_string(char_uuid_str, gattc_char->chr_uuid.uu);
+       DBG("%s %s", gattc_char->chr_path + 15, char_uuid_str);
+
+       char_handle = gattc_char->chr_path;
+
+       g_conn = _bt_hal_get_system_gconn();
+       if (g_conn == NULL) {
+               ERR("conn NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       resp_data = g_malloc0(sizeof(hal_gatt_resp_data_t));
+
+       INFO("### Request StopNotify : %s [%s]", gattc_char->chr_path + 15, char_uuid_str);
+       g_dbus_connection_call_sync(g_conn,
+                       BT_HAL_BLUEZ_NAME,
+                       char_handle,
+                       BT_HAL_GATT_CHAR_INTERFACE,
+                       "StopNotify",
+                       NULL,
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE,
+                       BT_HAL_MAX_DBUS_TIMEOUT, NULL, &error);
+
+       if (error) {
+               ERR("### StopNotify Failed: %s", error->message);
+               g_clear_error(&error);
+               result = BT_STATUS_FAIL;
+       }
+
+       resp_data->conn_id = gattc_client->client_if; /* saving client_if instead of conn_id */
+       resp_data->result = result;
+       memcpy(&resp_data->srvc_id, srvc_id, sizeof(btgatt_srvc_id_t));
+       memcpy(&resp_data->char_id, char_id, sizeof(btgatt_gatt_id_t));
+
+       g_idle_add(_hal_watch_deregister_notifi_cb, (gpointer)resp_data);
+
+       DBG("-");
+
+       return BT_STATUS_SUCCESS;
+}
+/** Deregister a previous request for notifications/indications */
+bt_status_t btif_deregister_for_notification(int client_if,
+               const bt_bdaddr_t *bd_addr, btgatt_srvc_id_t *srvc_id,
+               btgatt_gatt_id_t *char_id)
+{
+       CHECK_BTGATT_INIT();
+       return _hal_deregister_for_notification(client_if, (bt_bdaddr_t *)bd_addr, srvc_id, char_id);
+}
+
+/** Request RSSI for a given remote device */
+bt_status_t read_remote_rssi(int client_if, const bt_bdaddr_t *bd_addr)
+{
+       CHECK_BTGATT_INIT();
+       return BT_STATUS_UNSUPPORTED;
+}
+
+/** OTA firmware download */
 bt_status_t ota_fw_update(int client_if, int conn_id, const bt_bdaddr_t *bd_addr, char* path)
 {
        CHECK_BTGATT_INIT();
@@ -296,11 +2614,77 @@ int get_device_type(const bt_bdaddr_t *bd_addr)
        return BT_STATUS_UNSUPPORTED;
 }
 
+static bt_status_t __hal_update_conn_parameter(bt_bdaddr_t *bd_addr,
+                       int min_int, int max_int, int latency, int timeout)
+{
+       gchar *device_path = NULL;
+       GError *error = NULL;
+       GDBusProxy *device_proxy = NULL;
+       GDBusConnection *conn;
+       GVariant *reply;
+       int ret = BT_STATUS_SUCCESS;
+       char device_address[BT_HAL_ADDRESS_STRING_SIZE] = { 0 };
+
+       INFO("Min interval: %d, Max interval: %d, Latency: %d, Supervision timeout: %d",
+                       min_int, max_int, latency, timeout);
+
+       conn = _bt_hal_get_system_gconn();
+       if (conn == NULL) {
+               ERR("conn NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       _bt_hal_convert_addr_type_to_string(device_address,
+                               (unsigned char *)bd_addr->address);
+       device_path = _bt_hal_get_device_object_path(device_address);
+
+       if (device_path == NULL) {
+               ERR("device_path NULL : [%s]", device_address);
+               return BT_STATUS_FAIL;
+       }
+
+       device_proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
+                       NULL, BT_HAL_BLUEZ_NAME,
+                       device_path, BT_HAL_DEVICE_INTERFACE,  NULL, NULL);
+
+       g_free(device_path);
+       if (NULL == device_proxy) {
+               ERR("device_proxy returned NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       INFO("Request LeConnUpdate");
+       reply = g_dbus_proxy_call_sync(device_proxy, "LeConnUpdate",
+                       g_variant_new("(uuuu)", min_int, max_int, latency, timeout),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1,
+                       NULL,
+                       &error);
+
+       g_object_unref(device_proxy);
+       if (reply == NULL) {
+               if (error) {
+                       ERR("Error %s[%s]", error->message, device_address);
+                       if (g_strrstr(error->message, "In Progress"))
+                               ret = BT_STATUS_SUCCESS;
+                       else
+                               ret = BT_STATUS_FAIL;
+                       g_error_free(error);
+                       return ret;
+               }
+       }
+       g_variant_unref(reply);
+
+       DBG("LE Connection parameter Updated");
+       return ret;
+}
+
 /** Request a connection parameter update */
-bt_status_t conn_parameter_update(bt_bdaddr_t *bd, int min_int, int max_int, int latency, int timeout)
+bt_status_t btif_gattc_conn_parameter_update(bt_bdaddr_t *bd, int min_int, int max_int, int latency, int timeout)
 {
        CHECK_BTGATT_INIT();
-       return BT_STATUS_UNSUPPORTED;
+
+       return __hal_update_conn_parameter(bd, min_int, max_int, latency, timeout);
 }
 
 /** Test mode interface */
@@ -310,48 +2694,518 @@ bt_status_t test_command(int command, btgatt_test_params_t* params)
        return BT_STATUS_UNSUPPORTED;
 }
 
-/** MTU Exchange request from client */
-bt_status_t configure_mtu(int conn_id, int mtu)
-{
-       CHECK_BTGATT_INIT();
-       return BT_STATUS_UNSUPPORTED;
-}
+static void __bt_request_att_mtu_device_cb(GDBusProxy *proxy, GAsyncResult *res,
+                                                       gpointer user_data)
+{
+       GError *g_error = NULL;
+       GVariant *reply = NULL;
+       int result = BT_STATUS_SUCCESS;
+       struct hal_ev_gatt_client_mtu_exchange_completed  ev;
+       struct conn_mtu_s *conn_mtu = (struct conn_mtu_s *)user_data;
+
+       reply = g_dbus_proxy_call_finish(proxy, res, &g_error);
+       g_object_unref(proxy);
+       if (reply == NULL) {
+               ERR("Connect LE Dbus Call Error");
+               if (g_error) {
+                       ERR("Error occured in RequestAttMtu [%s]", g_error->message);
+                       g_clear_error(&g_error);
+               }
+               result = BT_STATUS_FAIL;
+       }
+       g_variant_unref(reply);
+
+       memset(&ev, 0, sizeof(ev));
+       ev.status = result;
+       ev.mtu = conn_mtu->mtu;
+       ev.conn_id = conn_mtu->conn_id;
+
+       if (!event_cb) {
+               ERR("gatt client callback not registered");
+       } else {
+               DBG("sending gatt client MTU exchange completed event");
+               event_cb(HAL_EV_GATT_CLIENT_MTU_EXCHANGE_COMPLETED  , (void *)&ev, sizeof(ev));
+       }
+
+       g_free(conn_mtu);
+}
+
+
+static bt_status_t __hal_configure_mtu(int conn_id, int mtu)
+{
+       gchar *device_path = NULL;
+       GDBusProxy *device_proxy = NULL;
+       GDBusConnection *conn;
+       hal_gattc_client_info_t *gattc_client = NULL;
+       char device_address[BT_HAL_ADDRESS_STRING_SIZE] = { 0 };
+       struct conn_mtu_s *conn_mtu = g_malloc0(sizeof(struct conn_mtu_s));
+
+       conn = _bt_hal_get_system_gconn();
+       if (conn == NULL) {
+               ERR("conn NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       gattc_client = __bt_find_gatt_client_info_from_conn_id(conn_id);
+       if (gattc_client == NULL) {
+               INFO("GATT client conn info not found");
+               return BT_STATUS_FAIL;
+       }
+
+       _bt_hal_convert_addr_type_to_string(device_address,
+                               (unsigned char *)gattc_client->bd_addr.address);
+
+       device_path = _bt_hal_get_device_object_path(device_address);
+       if (device_path == NULL) {
+               ERR("device_path NULL : [%s]", device_address);
+               return BT_STATUS_FAIL;
+       }
+
+       device_proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
+                       NULL, BT_HAL_BLUEZ_NAME,
+                       device_path, BT_HAL_DEVICE_INTERFACE,  NULL, NULL);
+
+       g_free(device_path);
+       if (NULL == device_proxy) {
+               ERR("device_proxy returned NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       conn_mtu->conn_id = conn_id;
+       conn_mtu->mtu = mtu;
+
+       g_dbus_proxy_call(device_proxy, "RequestAttMtu",
+                       g_variant_new("(q)", mtu),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       BT_HAL_MAX_DBUS_TIMEOUT,
+                       NULL,
+                       (GAsyncReadyCallback)__bt_request_att_mtu_device_cb,
+                       conn_mtu);
+
+       return BT_STATUS_SUCCESS;
+}
+
+/** MTU Exchange request from client */
+static bt_status_t configure_mtu(int conn_id, int mtu)
+{
+       CHECK_BTGATT_INIT();
+
+       return __hal_configure_mtu(conn_id, mtu);
+}
+
+/** Setup scan filter params */
+bt_status_t scan_filter_param_setup(int client_if, int action, int filt_index, int feat_seln,
+               int list_logic_type, int filt_logic_type, int rssi_high_thres,
+               int rssi_low_thres, int dely_mode, int found_timeout,
+               int lost_timeout, int found_timeout_cnt)
+{
+       GDBusProxy *proxy;
+       GError *error = NULL;
+       GVariant *ret, *param;
+       CHECK_BTGATT_INIT();
+
+       proxy = _bt_hal_get_adapter_proxy();
+
+       if (proxy == NULL)
+               return BT_STATUS_FAIL;
+
+       param = g_variant_new("(iiiiiiiiiiii)",
+                               client_if,
+                               action,
+                               filt_index,
+                               feat_seln,
+                               list_logic_type,
+                               filt_logic_type,
+                               rssi_high_thres,
+                               rssi_low_thres,
+                               dely_mode,
+                               found_timeout,
+                               lost_timeout,
+                               found_timeout_cnt);
+       ret = g_dbus_proxy_call_sync(proxy, "scan_filter_param_setup",
+                       param, G_DBUS_CALL_FLAGS_NONE,
+                       -1, NULL, &error);
+
+       if (error) {
+               ERR("scan_filter_param_setup Fail: %s", error->message);
+               g_clear_error(&error);
+               return BT_STATUS_FAIL;
+       }
+
+       if (ret)
+               g_variant_unref(ret);
+
+       return BT_STATUS_SUCCESS;
+}
+
+/** Configure a scan filter condition */
+bt_status_t scan_filter_add_remove(int client_if, int action, int filt_type,
+               int filt_index, int company_id,
+               int company_id_mask, const bt_uuid_t *p_uuid,
+               const bt_uuid_t *p_uuid_mask, const bt_bdaddr_t *bd_addr,
+               char addr_type, int data_len, char* p_data, int mask_len,
+               char* p_mask)
+{
+       GDBusProxy *proxy;
+       GError *error = NULL;
+       GVariant *ret, *param;
+       GVariant *arr_uuid_param = NULL, *arr_uuid_mask_param = NULL;
+       GVariant *arr_data_param = NULL, *arr_data_mask_param = NULL;
+       GArray *arr_uuid = NULL;
+       GArray *arr_uuid_mask = NULL;
+       GArray *arr_data = NULL;
+       GArray *arr_data_mask = NULL;
+       CHECK_BTGATT_INIT();
+
+       proxy = _bt_hal_get_adapter_proxy();
+
+       if (proxy == NULL)
+               return BT_STATUS_FAIL;
+
+       if (filt_type == BT_SCAN_FILTER_FEATURE_DEVICE_ADDRESS) {
+
+               char address[BT_HAL_ADDRESS_STRING_SIZE] = { 0 };
+
+               _bt_hal_convert_addr_type_to_string(address, bd_addr->address);
+
+               INFO("BT_SCAN_FILTER_FEATURE_DEVICE_ADDRESS being added\nRemote Device Address is [%s]", address);
+
+               arr_uuid_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               NULL, 0, TRUE, NULL, NULL);
+               arr_uuid_mask_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               NULL, 0, TRUE, NULL, NULL);
+               arr_data_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               NULL, 0, TRUE, NULL, NULL);
+               arr_data_mask_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               NULL, 0, TRUE, NULL, NULL);
+
+               param = g_variant_new("(iiiiii@ay@aysu@ay@ay)",
+                                       client_if,      // client_if
+                                       action,      // action (Add - 0x00, Delete - 0x01, Clear - 0x02)
+                                       BT_SCAN_FILTER_FEATURE_DEVICE_ADDRESS,        // filter_type
+                                       filt_index,       // filter_index
+                                       company_id,      // company_id
+                                       company_id_mask,      // company_id_mask
+                                       arr_uuid_param, // p_uuid
+                                       arr_uuid_mask_param,    // p_uuid_mask
+                                       address,        // string
+                                       addr_type,      // address_type
+                                       arr_data_param, // p_data
+                                       arr_data_mask_param);   // p_mask
+
+               ret = g_dbus_proxy_call_sync(proxy, "scan_filter_add_remove",
+                               param, G_DBUS_CALL_FLAGS_NONE,
+                               -1, NULL, &error);
+
+               if (error) {
+                       ERR("scan_filter_add_remove Fail: %s", error->message);
+                       g_clear_error(&error);
+                       return BT_STATUS_FAIL;
+               }
+
+               if (ret)
+                       g_variant_unref(ret);
+
+               return BT_STATUS_SUCCESS;
+       }
+
+       if (filt_type == BT_SCAN_FILTER_FEATURE_DEVICE_NAME) {
+
+               INFO("BT_SCAN_FILTER_FEATURE_DEVICE_NAME being added\nRemote Device Name is %s", p_data);
+               arr_uuid_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               NULL, 0, TRUE, NULL, NULL);
+               arr_uuid_mask_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               NULL, 0, TRUE, NULL, NULL);
+               arr_data_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               NULL, 0, TRUE, NULL, NULL);
+               arr_data_mask_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               NULL, 0, TRUE, NULL, NULL);
+
+               param = g_variant_new("(iiiiii@ay@aysu@ay@ay)",
+                                       client_if,      // client_if
+                                       action,      // action (Add - 0x00, Delete - 0x01, Clear - 0x02)
+                                       BT_SCAN_FILTER_FEATURE_DEVICE_NAME,   // filter_type
+                                       filt_index,       // filter_index
+                                       company_id,      // company_id
+                                       company_id_mask,      // company_id_mask
+                                       arr_uuid_param, // p_uuid
+                                       arr_uuid_mask_param,    // p_uuid_mask
+                                       p_data,    // string
+                                       addr_type,      // address_type
+                                       arr_data_param, // p_data
+                                       arr_data_mask_param);
+
+               ret = g_dbus_proxy_call_sync(proxy, "scan_filter_add_remove",
+                               param, G_DBUS_CALL_FLAGS_NONE,
+                               -1, NULL, &error);
+
+               if (error) {
+                       ERR("scan_filter_add_remove Fail: %s", error->message);
+                       g_clear_error(&error);
+                       return BT_STATUS_FAIL;
+               }
+
+               if (ret)
+                       g_variant_unref(ret);
+
+               return BT_STATUS_SUCCESS;
+       }
+
+       if (filt_type == BT_SCAN_FILTER_FEATURE_SERVICE_UUID) {
+
+               arr_uuid = g_array_new(TRUE, TRUE, sizeof(guint8));
+               arr_uuid_mask = g_array_new(TRUE, TRUE, sizeof(guint8));
+
+               g_array_append_vals(arr_uuid, p_uuid->uu, data_len * sizeof(guint8));
+               g_array_append_vals(arr_uuid_mask, p_uuid_mask->uu, mask_len * sizeof(guint8));
+
+               arr_uuid_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               arr_uuid->data, arr_uuid->len, TRUE, NULL, NULL);
+               arr_uuid_mask_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               arr_uuid_mask->data, arr_uuid_mask->len, TRUE, NULL, NULL);
+               arr_data_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               NULL, 0, TRUE, NULL, NULL);
+               arr_data_mask_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               NULL, 0, TRUE, NULL, NULL);
+
+               param = g_variant_new("(iiiiii@ay@aysu@ay@ay)",
+                                       client_if,      // client_if
+                                       action,      // action (Add - 0x00, Delete - 0x01, Clear - 0x02)
+                                       BT_SCAN_FILTER_FEATURE_SERVICE_UUID,  // filter_type
+                                       filt_index,       // filter_index
+                                       company_id,      // company_id
+                                       company_id_mask,      // company_id_mask
+                                       arr_uuid_param, // p_uuid
+                                       arr_uuid_mask_param,    // p_uuid_mask
+                                       "",   // string
+                                       addr_type,      // address_type
+                                       arr_data_param, // p_data
+                                       arr_data_mask_param);
+
+               ret = g_dbus_proxy_call_sync(proxy, "scan_filter_add_remove",
+                               param, G_DBUS_CALL_FLAGS_NONE,
+                               -1, NULL, &error);
+
+               if (error) {
+                       ERR("scan_filter_add_remove Fail: %s", error->message);
+                       g_clear_error(&error);
+                       return BT_STATUS_FAIL;
+               }
+
+               if (ret)
+                       g_variant_unref(ret);
+
+               g_array_free(arr_uuid, TRUE);
+               g_array_free(arr_uuid_mask, TRUE);
+
+               return BT_STATUS_SUCCESS;
+       }
+
+       if (filt_type == BT_SCAN_FILTER_FEATURE_SERVICE_SOLICITATION_UUID) {
+
+               arr_uuid = g_array_new(TRUE, TRUE, sizeof(guint8));
+               arr_uuid_mask = g_array_new(TRUE, TRUE, sizeof(guint8));
+
+               g_array_append_vals(arr_uuid, p_uuid->uu, data_len * sizeof(guint8));
+               g_array_append_vals(arr_uuid_mask, p_uuid_mask->uu, mask_len * sizeof(guint8));
+
+               arr_uuid_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               arr_uuid->data, arr_uuid->len, TRUE, NULL, NULL);
+               arr_uuid_mask_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               arr_uuid_mask->data, arr_uuid_mask->len, TRUE, NULL, NULL);
+               arr_data_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               NULL, 0, TRUE, NULL, NULL);
+               arr_data_mask_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               NULL, 0, TRUE, NULL, NULL);
+
+               param = g_variant_new("(iiiiii@ay@aysu@ay@ay)",
+                                       client_if,      // client_if
+                                       action,      // action (Add - 0x00, Delete - 0x01, Clear - 0x02)
+                                       BT_SCAN_FILTER_FEATURE_SERVICE_SOLICITATION_UUID,     // filter_type
+                                       filt_index,       // filter_index
+                                       company_id,      // company_id
+                                       company_id_mask,      // company_id_mask
+                                       arr_uuid_param, // p_uuid
+                                       arr_uuid_mask_param,    // p_uuid_mask
+                                       "",   // string
+                                       addr_type,      // address_type
+                                       arr_data_param, // p_data
+                                       arr_data_mask_param);
+
+               ret = g_dbus_proxy_call_sync(proxy, "scan_filter_add_remove", param,
+                               G_DBUS_CALL_FLAGS_NONE,
+                               -1, NULL, &error);
+
+               if (error) {
+                       ERR("scan_filter_add_remove Fail: %s", error->message);
+                       g_clear_error(&error);
+                       return BT_STATUS_FAIL;
+               }
+
+               if (ret)
+                       g_variant_unref(ret);
+
+               g_array_free(arr_uuid, TRUE);
+               g_array_free(arr_uuid_mask, TRUE);
+
+               return BT_STATUS_SUCCESS;
+       }
+
+       if (filt_type == BT_SCAN_FILTER_FEATURE_SERVICE_DATA) {
+
+               arr_data = g_array_new(TRUE, TRUE, sizeof(guint8));
+               arr_data_mask = g_array_new(TRUE, TRUE, sizeof(guint8));
+
+               g_array_append_vals(arr_data, p_data, data_len * sizeof(guint8));
+               g_array_append_vals(arr_data_mask, p_mask, mask_len * sizeof(guint8));
+
+               arr_uuid_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               NULL, 0, TRUE, NULL, NULL);
+               arr_uuid_mask_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               NULL, 0, TRUE, NULL, NULL);
+               arr_data_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               arr_data->data, arr_data->len, TRUE, NULL, NULL);
+                               arr_data_mask_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               arr_data_mask->data, arr_data_mask->len, TRUE, NULL, NULL);
+
+               param = g_variant_new("(iiiiii@ay@aysu@ay@ay)",
+                                       client_if,      // client_if
+                                       action,      // action (Add - 0x00, Delete - 0x01, Clear - 0x02)
+                                       BT_SCAN_FILTER_FEATURE_SERVICE_DATA,  // filter_type
+                                       filt_index,       // filter_index
+                                       company_id,      // company_id
+                                       company_id_mask,      // company_id_mask
+                                       arr_uuid_param, // p_uuid
+                                       arr_uuid_mask_param,    // p_uuid_mask
+                                       "",   // string
+                                       addr_type,      // address_type
+                                       arr_data_param, // p_data
+                                       arr_data_mask_param);
+
+               ret = g_dbus_proxy_call_sync(proxy, "scan_filter_add_remove", param,
+                               G_DBUS_CALL_FLAGS_NONE,
+                               -1, NULL, &error);
+
+               if (error) {
+                       ERR("scan_filter_add_remove Fail: %s", error->message);
+                       g_clear_error(&error);
+                       return BT_STATUS_FAIL;
+               }
+
+               if (ret)
+                       g_variant_unref(ret);
+
+               g_array_free(arr_data, TRUE);
+               g_array_free(arr_data_mask, TRUE);
+
+               return BT_STATUS_SUCCESS;
+       }
+
+       if (filt_type == BT_SCAN_FILTER_FEATURE_MANUFACTURER_DATA) {
+
+               arr_data = g_array_new(TRUE, TRUE, sizeof(guint8));
+               arr_data_mask = g_array_new(TRUE, TRUE, sizeof(guint8));
+
+               g_array_append_vals(arr_data, p_data, data_len * sizeof(guint8));
+               g_array_append_vals(arr_data_mask, p_mask, mask_len * sizeof(guint8));
+
+               arr_uuid_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               NULL, 0, TRUE, NULL, NULL);
+               arr_uuid_mask_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               NULL, 0, TRUE, NULL, NULL);
+               arr_data_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               arr_data->data, arr_data->len, TRUE, NULL, NULL);
+               arr_data_mask_param = g_variant_new_from_data((const GVariantType *)"ay",
+                               arr_data_mask->data, arr_data_mask->len, TRUE, NULL, NULL);
+
+               param = g_variant_new("(iiiiii@ay@aysu@ay@ay)",
+                                       client_if,      // client_if
+                                       action,      // action (Add - 0x00, Delete - 0x01, Clear - 0x02)
+                                       BT_SCAN_FILTER_FEATURE_MANUFACTURER_DATA,     // filter_type
+                                       filt_index,       // filter_index
+                                       company_id,        // company_id
+                                       company_id_mask, // company_id_mask
+                                       arr_uuid_param, // p_uuid
+                                       arr_uuid_mask_param,    // p_uuid_mask
+                                       "",   // string
+                                       addr_type,      // address_type
+                                       arr_data_param, // p_data
+                                       arr_data_mask_param);
 
-/** Setup scan filter params */
-bt_status_t scan_filter_param_setup(int client_if, int action, int filt_index, int feat_seln,
-               int list_logic_type, int filt_logic_type, int rssi_high_thres,
-               int rssi_low_thres, int dely_mode, int found_timeout,
-               int lost_timeout, int found_timeout_cnt)
-{
-       CHECK_BTGATT_INIT();
-       return BT_STATUS_UNSUPPORTED;
-}
+               ret = g_dbus_proxy_call_sync(proxy, "scan_filter_add_remove", param,
+                               G_DBUS_CALL_FLAGS_NONE,
+                               -1, NULL, &error);
 
+               if (error) {
+                       ERR("scan_filter_add_remove Fail: %s", error->message);
+                       g_clear_error(&error);
+                       return BT_STATUS_FAIL;
+               }
+
+               if (ret)
+                       g_variant_unref(ret);
+
+               g_array_free(arr_data, TRUE);
+               g_array_free(arr_data_mask, TRUE);
+
+               return BT_STATUS_SUCCESS;
+       }
 
-/** Configure a scan filter condition */
-bt_status_t scan_filter_add_remove(int client_if, int action, int filt_type,
-               int filt_index, int company_id,
-               int company_id_mask, const bt_uuid_t *p_uuid,
-               const bt_uuid_t *p_uuid_mask, const bt_bdaddr_t *bd_addr,
-               char addr_type, int data_len, char* p_data, int mask_len,
-               char* p_mask)
-{
-       CHECK_BTGATT_INIT();
        return BT_STATUS_UNSUPPORTED;
 }
 
 /** Clear all scan filter conditions for specific filter index*/
 bt_status_t scan_filter_clear(int client_if, int filt_index)
 {
+       GDBusProxy *proxy;
+       GError *error = NULL;
+       GVariant *ret;
        CHECK_BTGATT_INIT();
-       return BT_STATUS_UNSUPPORTED;
+
+       proxy = _bt_hal_get_adapter_proxy();
+       if (proxy == NULL)
+               return BT_STATUS_FAIL;
+
+       ret = g_dbus_proxy_call_sync(proxy, "scan_filter_clear",
+                               g_variant_new("(ii)", client_if, filt_index),
+                               G_DBUS_CALL_FLAGS_NONE,
+                               -1, NULL, &error);
+
+       if (error) {
+               ERR("scan_filter_clear Fail: %s", error->message);
+               g_clear_error(&error);
+               return BT_STATUS_FAIL;
+       }
+       if (ret)
+               g_variant_unref(ret);
+       return BT_STATUS_SUCCESS;
 }
 
 /** Enable / disable scan filter feature*/
 bt_status_t scan_filter_enable(int client_if, bool enable)
 {
+       GDBusProxy *proxy;
+       GError *error = NULL;
+       GVariant *ret;
        CHECK_BTGATT_INIT();
-       return BT_STATUS_UNSUPPORTED;
+
+       proxy = _bt_hal_get_adapter_proxy();
+       if (proxy == NULL)
+               return BT_STATUS_FAIL;
+
+       ret = g_dbus_proxy_call_sync(proxy, "scan_filter_enable",
+                               g_variant_new("(ib)", client_if, enable),
+                               G_DBUS_CALL_FLAGS_NONE,
+                               -1, NULL, &error);
+
+       if (error) {
+               ERR("scan_filter_enable Fail: %s", error->message);
+               g_clear_error(&error);
+               return BT_STATUS_FAIL;
+       }
+       g_variant_unref(ret);
+
+       return BT_STATUS_SUCCESS;
 }
 
 /** Sets the LE scan interval and window in units of N*0.625 msec */
@@ -406,36 +3260,761 @@ bt_status_t batchscan_read_reports(int client_if, int scan_mode)
 }
 
 const btgatt_client_interface_t btgatt_client_interface = {
-       register_client,
-       unregister_client,
-       scan,
-       connect,
-       disconnect,
-       refresh,
-       search_service,
-       get_included_service,
-       get_characteristic,
-       get_descriptor,
-       read_characteristic,
-       write_characteristic,
-       read_descriptor,
-       write_descriptor,
-       execute_write,
-       register_for_notification,
-       deregister_for_notification,
-       read_remote_rssi,
-       ota_fw_update,
-       get_device_type,
-       conn_parameter_update,
-       test_command,
-       configure_mtu,
-       scan_filter_param_setup,
-       scan_filter_add_remove,
-       scan_filter_clear,
-       scan_filter_enable,
-       set_scan_parameters,
-       batchscan_cfg_storage,
-       batchscan_enb_batch_scan,
-       batchscan_dis_batch_scan,
-       batchscan_read_reports
+       .register_client = btif_gattc_register_client,
+       .unregister_client = btif_gattc_unregister_client,
+       .scan = scan,
+       .connect = btif_gattc_client_connect,
+       .disconnect = btif_gattc_client_disconnect,
+       .refresh = refresh,
+       .search_service = btif_gattc_client_search_service,
+       .get_included_service = get_included_service,
+       .get_characteristic = btif_gattc_get_characteristic,
+       .get_descriptor = btif_gattc_get_descriptor,
+       .read_characteristic = btif_read_characteristic,
+       .write_characteristic = btif_write_characteristic,
+       .acquire_write = btif_get_acquire_write_fd,
+       .acquire_notify = btif_get_acquire_notify_fd,
+       .read_descriptor = btif_read_descriptor,
+       .write_descriptor = btif_write_descriptor,
+       .execute_write = execute_write,
+       .register_for_notification = btif_register_for_notification,
+       .deregister_for_notification = btif_deregister_for_notification,
+       .read_remote_rssi = read_remote_rssi,
+       .ota_fw_update = ota_fw_update,
+       .get_device_type = get_device_type,
+       .conn_parameter_update = btif_gattc_conn_parameter_update,
+       .test_command = test_command,
+       .configure_mtu = configure_mtu,
+       .scan_filter_param_setup = scan_filter_param_setup,
+       .scan_filter_add_remove = scan_filter_add_remove,
+       .scan_filter_clear = scan_filter_clear,
+       .scan_filter_enable = scan_filter_enable,
+       .set_scan_parameters = set_scan_parameters,
+       .batchscan_cfg_storage = batchscan_cfg_storage,
+       .batchscan_enb_batch_scan = batchscan_enb_batch_scan,
+       .batchscan_dis_batch_scan = batchscan_dis_batch_scan,
+       .batchscan_read_reports = batchscan_read_reports,
+       .add_connection_info = btif_gattc_add_connection_info,
 };
+
+static hal_gattc_server_info_t *__bt_find_gatt_conn_info(const bt_bdaddr_t *serv_addr)
+{
+       GSList *l;
+       hal_gattc_server_info_t *info = NULL;
+
+       for (l = hal_gattc_server_info_list; l != NULL; l = g_slist_next(l)) {
+               info = (hal_gattc_server_info_t*)l->data;
+               if (info == NULL)
+                       continue;
+
+               if (!memcmp(&info->bd_addr, serv_addr, sizeof(bt_bdaddr_t)))
+                       return info;
+               }
+
+       return NULL;
+}
+
+static hal_gattc_client_info_t *__bt_find_gatt_client_info(bt_bdaddr_t *serv_addr)
+{
+       GSList *l;
+       hal_gattc_client_info_t *info = NULL;
+
+       for (l = hal_gattc_client_info_list; l != NULL; l = g_slist_next(l)) {
+               info = (hal_gattc_client_info_t*)l->data;
+               if (info == NULL)
+                       continue;
+
+               if (!memcmp(&info->bd_addr, serv_addr, sizeof(bt_bdaddr_t)))
+                       return info;
+               }
+
+       return NULL;
+}
+
+static hal_gattc_client_info_t *__bt_find_gatt_client_info_from_conn_id(int conn_id)
+{
+       GSList *l;
+       hal_gattc_client_info_t *info = NULL;
+
+       for (l = hal_gattc_client_info_list; l != NULL; l = g_slist_next(l)) {
+               info = (hal_gattc_client_info_t*)l->data;
+               if (info == NULL)
+                       continue;
+
+               if (info->conn_id == conn_id)
+                       return info;
+               }
+
+       return NULL;
+}
+
+static hal_gattc_server_info_t *__bt_find_gatt_conn_info_from_conn_id(int  conn_id)
+{
+       GSList *l;
+       hal_gattc_server_info_t *info = NULL;
+       hal_gattc_client_info_t *gattc_client = NULL;
+
+       gattc_client = __bt_find_gatt_client_info_from_conn_id(conn_id);
+       if (gattc_client == NULL) {
+               ERR("GATT client conn info not found");
+               return NULL;
+       }
+
+       for (l = hal_gattc_server_info_list; l != NULL; l = g_slist_next(l)) {
+               info = (hal_gattc_server_info_t*)l->data;
+               if (info == NULL)
+                       continue;
+
+               if ((info->inst_id == gattc_client->inst_id) &&
+                       !memcmp(&info->bd_addr, &gattc_client->bd_addr, sizeof(bt_bdaddr_t))) {
+                       return info;
+               }
+       }
+       return NULL;
+}
+
+static bt_status_t __bt_connect_le_device_internal(int client_if, const bt_bdaddr_t *bd_addr,
+               gboolean auto_connect)
+{
+       char device_address[BT_HAL_ADDRESS_STRING_SIZE] = { 0 };
+       gchar *device_path = NULL;
+       GDBusProxy *device_proxy = NULL;
+       GDBusConnection *conn;
+       int ret = BT_STATUS_SUCCESS;
+       hal_gattc_client_info_t *gattc_data;
+
+       DBG("+");
+
+       if (NULL == bd_addr) {
+               ERR("bd_addr is NULL");
+               return BT_STATUS_PARM_INVALID;
+       }
+
+       conn = _bt_hal_get_system_gconn();
+       if (NULL == conn) {
+               ERR("_bt_gdbus_get_system_gconn returned NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       _bt_hal_convert_addr_type_to_string(device_address,
+                       (unsigned char *)bd_addr->address);
+       device_path = _bt_hal_get_device_object_path(device_address);
+       if (device_path == NULL) {
+               ERR("device_path NULL : [%s]", device_address);
+               ret = BT_STATUS_FAIL;
+               return ret;
+       }
+       ERR("device_path:%s", device_path);
+
+       device_proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE,
+                       NULL, BT_HAL_BLUEZ_NAME,
+                       device_path, BT_HAL_DEVICE_INTERFACE,  NULL, NULL);
+       g_free(device_path);
+       if (NULL == device_proxy) {
+               ERR("device_proxy returned NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       gattc_data = g_malloc0(sizeof(hal_gattc_client_info_t));
+       memcpy(gattc_data->bd_addr.address, bd_addr->address,
+                                       BT_HAL_ADDRESS_LENGTH_MAX);
+
+       DBG("Connect LE [%s]", device_address);
+
+       gattc_data->client_if = client_if;
+
+       g_dbus_proxy_call(device_proxy, "ConnectLE",
+                       g_variant_new("(b)", auto_connect),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       BT_HAL_MAX_DBUS_TIMEOUT,
+                       NULL,
+                       (GAsyncReadyCallback)__le_connection_req_cb, gattc_data);
+
+       return ret;
+}
+
+static bt_status_t _bt_hold_current_advertising()
+{
+       int ret = BT_STATUS_FAIL;
+       gboolean is_advertising = FALSE;
+       DBG("+");
+
+       is_advertising = _bt_hal_is_advertising_in_slot(0);
+       if (is_advertising) {
+               DBG("+ Stop current advertising");
+
+               ret = _bt_hal_enable_advertising(0, 0, FALSE, FALSE);
+               g_timeout_add(2000, __bt_hold_current_advertising_timeout_cb, NULL);
+       }
+
+       return ret;
+}
+
+static gboolean __bt_hold_current_advertising_timeout_cb(gpointer user_data)
+{
+       DBG("+ start current advertising");
+
+       _bt_hal_enable_advertising(0, 0, TRUE, FALSE);
+
+       return FALSE;
+}
+
+static gboolean __bt_connect_le_timer_cb(gpointer user_data)
+{
+       DBG("Try to initiate pending LE connection");
+
+       pending_le_conn_timer_id = 0;
+
+       __bt_connect_le_device_internal(pending_le_conn_info->client_if,
+                       &pending_le_conn_info->bd_addr,
+                       pending_le_conn_info->auto_connect);
+
+       g_free(pending_le_conn_info);
+       pending_le_conn_info = NULL;
+
+       return FALSE;
+}
+
+static int __hal_generate_conn_id()
+{
+        return ++bt_conn_id;
+}
+
+static int __hal_generate_server_instance_id()
+{
+       return ++bt_inst_id;
+}
+
+static void __le_connection_req_cb(GDBusProxy *proxy, GAsyncResult *res,
+               gpointer user_data)
+{
+       GError *g_error = NULL;
+       GVariant *reply = NULL;
+       hal_gattc_client_info_t *gattc_data  = user_data;
+       int result = BT_STATUS_SUCCESS;
+       struct hal_ev_gatt_client_connected ev;
+       hal_gattc_server_info_t *gatt_conn_info = NULL;
+
+       DBG("+");
+
+       reply = g_dbus_proxy_call_finish(proxy, res, &g_error);
+       g_object_unref(proxy);
+       if (reply == NULL) {
+               ERR("Connect LE Dbus Call Error");
+               if (g_error) {
+                       ERR("Error: %s\n", g_error->message);
+                       g_clear_error(&g_error);
+               }
+               result = BT_STATUS_FAIL;
+       }
+       g_variant_unref(reply);
+
+       if (NULL == gattc_data) {
+               ERR("server_data is NULL");
+               return;
+       }
+
+       /*send fail event*/
+       if (result == BT_STATUS_FAIL) {
+               memset(&ev, 0, sizeof(ev));
+               ev.conn_id = -1;
+               ev.status = result;
+               ev.client_if = gattc_data->client_if;
+               memcpy(ev.bdaddr, gattc_data->bd_addr.address,
+                                               BT_HAL_ADDRESS_LENGTH_MAX);
+
+               if (!event_cb) {
+                       ERR("gatt client callback not registered");
+               } else {
+                       DBG("sending gatt client connected event");
+                       event_cb(HAL_EV_GATT_CLIENT_CONNECTED, (void *)&ev, sizeof(ev));
+               }
+
+               goto fail;
+       }
+
+       DBG("adding the server conn info in list");
+       gattc_data->conn_id = __hal_generate_conn_id() ;
+       gattc_data->inst_id = __hal_generate_server_instance_id();
+
+       hal_gattc_client_info_list = g_slist_append(hal_gattc_client_info_list, gattc_data);
+
+       /*add gatt server connection info*/
+       gatt_conn_info = g_malloc0(sizeof(hal_gattc_server_info_t));
+       memcpy(gatt_conn_info->bd_addr.address, gattc_data->bd_addr.address, BT_HAL_ADDRESS_LENGTH_MAX);
+       gatt_conn_info->conn_id = gattc_data->conn_id;
+       gatt_conn_info->inst_id = gattc_data->inst_id;
+       hal_gattc_server_info_list = g_slist_append(hal_gattc_server_info_list, gatt_conn_info);
+
+       DBG("-");
+       return;
+
+fail:
+       /*remove conn_info*/
+       if (gattc_data)
+               g_free(gattc_data);
+}
+
+static void __hal_gattc_free_desc_info(hal_gattc_desc_t *desc_info)
+{
+       g_free(desc_info->desc_path);
+       g_free(desc_info);
+}
+
+static void __hal_gattc_free_char_info(hal_gattc_char_t *char_info)
+{
+       GSList *l = NULL;
+       hal_gattc_desc_t *desc_info = NULL;
+       for (l = char_info->gatt_list_descs; l != NULL; ) {
+               desc_info = l->data;
+               l = g_slist_next(l);
+               if (desc_info == NULL)
+                       continue;
+               /* Remove descriptor element */
+               char_info->gatt_list_descs = g_slist_remove(char_info->gatt_list_descs, desc_info);
+               __hal_gattc_free_desc_info(desc_info);
+       }
+       g_slist_free(char_info->gatt_list_descs);
+       g_free(char_info->chr_path);
+       g_free(char_info);
+}
+
+static void __hal_gattc_free_svc_info(hal_gattc_service_t *svc_info)
+{
+       GSList *l = NULL;
+       hal_gattc_char_t *char_info = NULL;
+       for (l = svc_info->gatt_list_chars; l != NULL; ) {
+               char_info = l->data;
+               l = g_slist_next(l);
+               if (char_info == NULL)
+                       continue;
+               /* Remove characteristic element */
+               svc_info->gatt_list_chars = g_slist_remove(svc_info->gatt_list_chars, char_info);
+               __hal_gattc_free_char_info(char_info);
+       }
+       g_slist_free(svc_info->gatt_list_chars);
+       g_free(svc_info->svc_path);
+       g_free(svc_info);
+}
+
+static void __hal_clean_gattc_server_info(hal_gattc_server_info_t *conn_info)
+{
+       GSList *l = NULL;
+       hal_gattc_service_t *svc_info = NULL;
+
+       DBG("+");
+
+       for (l = conn_info->gatt_list_services; l != NULL; ) {
+               svc_info = (hal_gattc_service_t *)l->data;
+               l = g_slist_next(l);
+               if (svc_info == NULL)
+                       continue;
+               /* Remove service element */
+               conn_info->gatt_list_services = g_slist_remove(conn_info->gatt_list_services, svc_info);
+               __hal_gattc_free_svc_info(svc_info);
+       }
+       g_slist_free(conn_info->gatt_list_services);
+       g_free(conn_info);
+}
+
+gboolean _bt_hal_check_gattc_is_existing(const char *address)
+{
+       bt_bdaddr_t bd_addr;
+       _bt_hal_convert_addr_string_to_type(bd_addr.address, address);
+       if (__bt_find_gatt_client_info(&bd_addr) != NULL)
+               return TRUE;
+       else
+               return FALSE;
+}
+
+void _bt_hal_handle_gattc_connected_event(char* address, gboolean gatt_connected)
+{
+       int result = BT_STATUS_SUCCESS;
+       struct hal_ev_gatt_client_connected ev;
+       hal_gattc_server_info_t *conn_info = NULL;
+       bt_bdaddr_t bd_addr;
+       int event;
+       hal_gattc_client_info_t *gattc_client = NULL;
+       int inst_id = -1;
+
+
+       DBG("+ connected device address [%s]", address);
+
+       event = gatt_connected ? HAL_EV_GATT_CLIENT_CONNECTED :
+                               HAL_EV_GATT_CLIENT_DISCONNECTED;
+
+       _bt_hal_convert_addr_string_to_type(bd_addr.address, address);
+       /* find the gatt client info */
+       gattc_client = __bt_find_gatt_client_info(&bd_addr);
+       if (NULL == gattc_client) {
+               ERR("Fail to get gatt client info");
+               return;
+       }
+
+       //send event
+       memset(&ev, 0, sizeof(ev));
+       ev.conn_id = gattc_client->conn_id;
+       ev.status = result;
+       ev.client_if = gattc_client->client_if;
+       memcpy(ev.bdaddr, gattc_client->bd_addr.address,
+                               BT_HAL_ADDRESS_LENGTH_MAX);
+
+       if (!event_cb) {
+               ERR("gatt client callback not registered");
+       } else {
+               DBG("sending gatt client connected status  event");
+               event_cb(event, (void *)&ev, sizeof(ev));
+       }
+
+       if (!gatt_connected) {
+               inst_id = gattc_client->inst_id;
+
+               /* remove the gatt client info from the client list also*/
+               hal_gattc_client_info_list = g_slist_remove(hal_gattc_client_info_list, gattc_client);
+               g_free(gattc_client);
+
+               //find the connected server info
+               conn_info = __bt_find_gatt_conn_info(&bd_addr);
+               if (NULL == conn_info) {
+                       ERR("Fail to get gatt server info");
+                       return;
+               }
+
+               if (inst_id != conn_info->inst_id) {
+                       ERR("server instance is different");
+                       return;
+               }
+
+               //remove gatt conn info from the server list
+               DBG("remove the server conn_info from list after gatt disconnection");
+               hal_gattc_server_info_list = g_slist_remove(hal_gattc_server_info_list, conn_info);
+               __hal_clean_gattc_server_info(conn_info);
+       }
+
+       DBG("-");
+}
+
+static void _bt_hal_send_search_service_result_event(int conn_id, int is_primary,
+                                               const char* uuid_str, int inst_id)
+{
+       struct hal_ev_gatt_client_search_result ev;
+
+        if (!event_cb) {
+               ERR("gatt client callback not registered");
+               return;
+       }
+
+       DBG("Send service searching result. [%s] conn_id[%d]", uuid_str, conn_id);
+
+       memset(&ev, 0, sizeof(ev));
+       ev.conn_id = conn_id;
+       ev.inst_id = inst_id;
+       ev.is_primary = is_primary;
+       _bt_hal_convert_uuid_string_to_type(ev.uuid, uuid_str);
+
+       event_cb(HAL_EV_GATT_CLIENT_SEARCH_RESULT, (void *)&ev, sizeof(ev));
+}
+
+static void _bt_hal_send_search_service_complete_event(int conn_id, int status)
+{
+       struct hal_ev_gatt_client_search_complete ev;
+
+        if (!event_cb) {
+               ERR("gatt client callback not registered");
+               return;
+       }
+
+       DBG("sending gatt client search service complete event conn_id[%d]", conn_id);
+
+
+       memset(&ev, 0, sizeof(ev));
+       ev.conn_id = conn_id;
+       ev.status = status;
+
+       event_cb(HAL_EV_GATT_CLIENT_SEARCH_COMPLETE, (void *)&ev, sizeof(ev));
+}
+
+static void _bt_hal_send_value_changed_event(hal_gattc_server_info_t *conn_info,
+               hal_gattc_service_t *svc_info, hal_gattc_char_t *char_info,
+               char *char_value, int len)
+{
+       struct hal_ev_gatt_client_notify_changed_value ev;
+       hal_gattc_client_info_t *gattc_client = NULL;
+
+       if (!event_cb) {
+               ERR("gatt client callback not registered");
+               return;
+       }
+
+       gattc_client = __bt_find_gatt_client_info(&conn_info->bd_addr);
+       if (NULL == gattc_client) {
+               ERR("failed to get the gatt client info");
+               return ;
+       }
+
+       //send event
+       DBG("sending gatt client connected status  event");
+       memset(&ev, 0, sizeof(ev));
+
+       ev.conn_id = gattc_client->conn_id;
+       ev.inst_id = conn_info->inst_id;
+       ev.is_primary = svc_info->is_primary;
+       memcpy(ev.svc_uuid, svc_info->svc_uuid.uu, sizeof(ev.svc_uuid));
+       memcpy(ev.char_uuid, char_info->chr_uuid.uu, sizeof(ev.char_uuid));
+
+       memcpy(ev.bdaddr, conn_info->bd_addr.address, BT_HAL_ADDRESS_LENGTH_MAX);
+
+       if (len > 0 && (char_value != NULL)) {
+               memcpy(ev.value, char_value, len);
+               ev.len = len;
+       }
+
+       event_cb(HAL_EV_GATT_CLIENT_NOTIFY_CHANGED_VALUE, (void *)&ev, sizeof(ev));
+}
+
+void _bt_hal_handle_gattc_value_changed_event(int result, const char *char_handle,
+                                               char *char_value, int len)
+{
+       char device_address[BT_HAL_ADDRESS_STRING_SIZE] = { 0 };
+       hal_gattc_server_info_t *conn_info = NULL;
+       bt_bdaddr_t bd_addr;
+       GSList *l;
+       GSList *k;
+       hal_gattc_service_t *svc_info = NULL;
+       hal_gattc_char_t *char_info = NULL;
+
+       DBG("+");
+
+       _bt_hal_convert_device_path_to_address(char_handle, device_address);
+       device_address[BT_HAL_ADDRESS_STRING_SIZE - 1] = '\0';
+       DBG("device address:[%s]", device_address);
+       DBG("char handle:[%s]", char_handle);
+
+       _bt_hal_convert_addr_string_to_type(bd_addr.address, device_address);
+       conn_info =  __bt_find_gatt_conn_info(&bd_addr);
+
+       if (conn_info != NULL) {
+               //find service for notified char path
+               for (l = conn_info->gatt_list_services; l != NULL; l = g_slist_next(l)) {
+                       svc_info = (hal_gattc_service_t*)l->data;
+                       if (svc_info == NULL)
+                               continue;
+
+                       /* find characteristic object path */
+                       for (k = svc_info->gatt_list_chars; k != NULL; k = g_slist_next(k)) {
+                               char_info = (hal_gattc_char_t *)k->data;
+                               if (char_info == NULL)
+                                       continue;
+
+                               if (g_strcmp0(char_info->chr_path, char_handle) == 0) {
+                                       DBG("Found char handle[%s]", char_info->chr_path);
+
+                                       //send event
+                                       _bt_hal_send_value_changed_event(conn_info, svc_info,
+                                                       char_info, char_value, len);
+                                       return;
+                               }
+                       }
+               }
+       }
+}
+
+static bt_status_t __hal_gattc_get_service_info(hal_gattc_server_info_t *server_info, const char *service_path)
+{
+       GDBusConnection *g_conn = NULL;
+       GDBusProxy *properties_proxy = NULL;
+       GVariant *result = NULL;
+       GError *error = NULL;
+       GVariantIter *property_iter = NULL;
+       const gchar *key = NULL;
+       GVariant *value = NULL;
+       const char *uuid_str = NULL;
+       gsize len = 0;
+       gboolean is_primary = FALSE;
+       GVariantIter *char_iter = NULL;
+       const char *char_handle = NULL;
+       GPtrArray *gp_char_array = NULL;
+
+       if (service_path == NULL) {
+               ERR("service_path is NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       DBG("service_path: %s", service_path);
+
+       g_conn = _bt_hal_get_system_gconn();
+       if (g_conn == NULL) {
+               ERR("g_conn is NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       properties_proxy = g_dbus_proxy_new_sync(g_conn,
+                       G_DBUS_PROXY_FLAGS_NONE, NULL,
+                       BT_HAL_BLUEZ_NAME,
+                       service_path,
+                       BT_HAL_PROPERTIES_INTERFACE,
+                       NULL, &error);
+       if (properties_proxy == NULL) {
+               ERR("properties_proxy is NULL");
+               return BT_STATUS_FAIL;
+       }
+
+       result = g_dbus_proxy_call_sync(properties_proxy,
+                       "GetAll",
+                       g_variant_new("(s)", BT_HAL_GATT_SERVICE_INTERFACE),
+                       G_DBUS_CALL_FLAGS_NONE,
+                       -1, NULL, &error);
+       if (result == NULL) {
+               if (error != NULL) {
+                       ERR("Fail to get properties (Error: %s)", error->message);
+                       g_clear_error(&error);
+               } else {
+                       ERR("Fail to get properties");
+               }
+               g_object_unref(properties_proxy);
+               return BT_STATUS_FAIL;
+       }
+
+       g_variant_get(result, "(a{sv})", &property_iter);
+
+       while (g_variant_iter_loop(property_iter, "{sv}", &key, &value)) {
+               if (g_strcmp0(key, "UUID") == 0) {
+                       uuid_str = g_variant_get_string(value, &len);
+                       DBG("UUID: %s", uuid_str);
+               } else if (g_strcmp0(key, "Primary") == 0) {
+                       is_primary = g_variant_get_boolean(value);
+                       DBG("is_primary: %s", is_primary ? "TRUE" : "FALSE");
+               } else if (g_strcmp0(key, "Characteristics") == 0) {
+                       g_variant_get(value, "ao", &char_iter);
+                       if (char_iter != NULL) {
+                               gp_char_array = g_ptr_array_new();
+                               while (g_variant_iter_loop(char_iter, "&o", &char_handle)) {
+                                       DBG("char_handle: %s", char_handle);
+                                       g_ptr_array_add(gp_char_array, (gpointer)char_handle);
+                               }
+                       }
+               }
+       }
+
+       if (uuid_str == NULL || gp_char_array == NULL) {
+               ERR("uuid_str and gp_char_array should be set");
+               goto done;
+       }
+
+       /* Create new service */
+       _gattc_create_new_service(server_info, is_primary, uuid_str, service_path, gp_char_array);
+
+done:
+       g_variant_iter_free(property_iter);
+       g_variant_unref(result);
+       g_object_unref(properties_proxy);
+       DBG("-");
+       return BT_STATUS_SUCCESS;
+}
+
+static void __bt_hal_gattc_get_uuid_from_path(const char *path, char **service_uuid)
+{
+       GDBusConnection *conn = NULL;
+       GDBusProxy *proxy = NULL;
+       GError *err = NULL;
+       GVariant *ret = NULL;
+       GVariant *value = NULL;
+
+       conn = _bt_hal_get_system_gconn();
+       if (conn == NULL) {
+               ERR("_bt_gdbus_get_system_gconn returned NULL");
+               return;
+       }
+
+       proxy = g_dbus_proxy_new_sync(conn,
+                       G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL,
+                       BT_HAL_BLUEZ_NAME, path, BT_HAL_PROPERTIES_INTERFACE, NULL, &err);
+       if (proxy == NULL) {
+               ERR("device_proxy returned NULL");
+               return;
+       }
+
+       ret = g_dbus_proxy_call_sync(proxy, "Get",
+                       g_variant_new("(ss)", BT_HAL_GATT_SERVICE_INTERFACE, "UUID"),
+                       G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
+       if (err) {
+               ERR("DBus Error : %s", err->message);
+               g_clear_error(&err);
+       } else {
+               g_variant_get(ret, "(v)", &value);
+               *service_uuid = g_variant_dup_string(value, NULL);
+               g_variant_unref(value);
+               g_variant_unref(ret);
+       }
+
+       if (proxy)
+               g_object_unref(proxy);
+
+       return;
+}
+
+void _bt_hal_handle_gattc_service_changed_event(gboolean is_added, const char *path)
+{
+       struct hal_ev_gatt_client_service_changed ev = {0, };
+       char address[BT_HAL_ADDRESS_STRING_SIZE];
+       hal_gattc_server_info_t *server_info = NULL;
+       hal_gattc_service_t *service = NULL;
+       GSList *list = NULL;
+       char *uuid_str = NULL;
+
+       _bt_hal_convert_device_path_to_address(path, address);
+       _bt_hal_convert_addr_string_to_type(ev.bdaddr, address);
+       server_info = __bt_find_gatt_conn_info((bt_bdaddr_t *)ev.bdaddr);
+       if (server_info == NULL) {
+               ERR("service_info is NULL");
+               return;
+       }
+
+       if (is_added) {
+               /* Get service UUID from path */
+               __bt_hal_gattc_get_uuid_from_path(path, &uuid_str);
+               if (uuid_str) {
+                       DBG("conn_id(%d) GATT Service(%s) Added", server_info->conn_id, uuid_str);
+                       _bt_hal_convert_uuid_string_to_type(ev.uuid, uuid_str);
+                       g_free(uuid_str);
+               } else {
+                       ERR("uuid_str is NULL");
+                       return;
+               }
+
+               /* Create new service and append into the list */
+               __hal_gattc_get_service_info(server_info, path);
+       } else {
+               /* Find service UUID from path */
+               for (list = server_info->gatt_list_services; list; list = g_slist_next(list)) {
+                       service = (hal_gattc_service_t *)list->data;
+                       if (service == NULL)
+                               continue;
+
+                       if (g_strcmp0(service->svc_path, path) == 0) {
+                               memcpy(ev.uuid, service->svc_uuid.uu, sizeof(bt_uuid_t));
+                               uuid_str = g_malloc0(BT_HAL_UUID_STRING_LEN);
+                               _bt_hal_convert_uuid_type_to_string(uuid_str, ev.uuid);
+                               DBG("conn_id(%d) GATT Service(%s) Removed", server_info->conn_id, uuid_str);
+
+                               /* Remove service info in list */
+                               server_info->gatt_list_services = g_slist_remove(server_info->gatt_list_services, service);
+                               __hal_gattc_free_svc_info(service);
+                               break;
+                       }
+               }
+
+               if (uuid_str) {
+                       g_free(uuid_str);
+               } else {
+                       ERR("uuid_str is NULL");
+                       return;
+               }
+       }
+
+       /* Send GATT Client service changed event */
+       ev.change_type = is_added;
+       ev.conn_id = server_info->conn_id;
+       ev.inst_id = server_info->inst_id;
+       event_cb(HAL_EV_GATT_CLIENT_SERVICE_CHANGED, (void *)&ev, sizeof(ev));
+}