Fix -Wreturn-type build warning
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / bt_le_adapter / tizen / caleclient.c
old mode 100644 (file)
new mode 100755 (executable)
index 3732bc9..7c5f6c8
 #include <pthread.h>
 #include <gio/gio.h>
 
-#include "camutex.h"
+#include "octhread.h"
 #include "uarraylist.h"
 #include "caqueueingthread.h"
 #include "caadapterutils.h"
-#include "cafragmentation.h"
 #include "cagattservice.h"
 #include "oic_string.h"
 #include "oic_malloc.h"
  */
 #define TAG "OIC_CA_LE_CLIENT"
 
+#define RETRY_COUNT 1
 #define MICROSECS_PER_SEC 1000000
 #define WAIT_TIME_WRITE_CHARACTERISTIC 10 * MICROSECS_PER_SEC
 
+//For custom uuid ble server
+#define CA_GATT_CUSTOM_UUID "4209"
+#define CA_GATT_CUSTOM_UUID2 "4204"
+#define CUSTOM_UUID_LEN 4
+#define MICROSECS_PER_SEC 1000000
+
+static const int samsung_code = 117;
+static int g_retrycount = 0;
+static int retry_flag = 0;
 uint64_t const TIMEOUT = 30 * MICROSECS_PER_SEC;
 
 /**
+ * Mutex to call connect only after disconnect during retry
+ */
+static oc_mutex g_isDisconnectedMutex = NULL;
+
+/**
+ * Condition for calling connect during connection retry
+ */
+static oc_cond g_LEDisconnectedCond = NULL;
+
+/**
+ * Flag to check if scanning is in progress
+ */
+static bool g_isScanningInProgress = false;
+
+/**
+ * Mutex to synchronize access to g_isScanningInProgress
+ */
+static oc_mutex g_isScanningInProgressMutex = NULL;
+
+/**
+ * Flag to check if connection is in progress
+ */
+static bool g_isConnectionInProgress = false;
+
+/**
+ * Mutex to synchronize access to g_isConnectionInProgress
+ */
+static oc_mutex g_isConnectionInProgressMutex = NULL;
+
+/**
  * Flag to check if multicast is already in progress.
  */
 static bool g_isMulticastInProgress = false;
 
 /**
- * Pending multicast data list to be sent.
+ * Flag to check if unicast scan is in progress
  */
-static u_arraylist_t *g_multicastDataList = NULL;
+static bool g_isUnicastScanInProgress = false;
 
 /**
- * Mutex to synchronize the access to Pending multicast data list.
+ * Mutex to synchronize access to g_isMulticastInProgress
+ * and g_isUnicastScanInProgress
  */
-static ca_mutex g_multicastDataListMutex = NULL;
+static oc_mutex g_scanMutex = NULL;
 
 /**
- * List of devices discovered.
+ * Pending multicast data list to be sent.
  */
-static u_arraylist_t *g_deviceDiscoveredList = NULL;
+static u_arraylist_t *g_multicastDataList = NULL;
 
 /**
- * Mutex to synchronize the access to discovered devices list.
+ * Mutex to synchronize the access to Pending multicast data list.
  */
-static ca_mutex g_deviceDiscoveredListMutex = NULL;
+static oc_mutex g_multicastDataListMutex = NULL;
 
 /**
  * Condition to start the timer for scanning.
  */
-static ca_cond g_startTimerCond = NULL;
+static oc_cond g_startTimerCond = NULL;
 
 /**
  * Condition for scanning Time interval.
  */
-static ca_cond g_scanningTimeCond = NULL;
+static oc_cond g_scanningTimeCond = NULL;
 
 /**
  * This contains the list of OIC services a client connect tot.
@@ -92,7 +132,7 @@ static LEServerInfoList *g_LEServerList = NULL;
 /**
  * Mutex to synchronize access to BleServiceList.
  */
-static ca_mutex g_LEServerListMutex = NULL;
+static oc_mutex g_LEServerListMutex = NULL;
 
 /**
  * Boolean variable to keep the state of the GATT Client.
@@ -103,34 +143,44 @@ static bool g_isLEGattClientStarted = false;
  * Mutex to synchronize access to the requestResponse callback to be called
  * when the data needs to be sent from GATTClient.
  */
-static ca_mutex g_LEReqRespClientCbMutex = NULL;
+static oc_mutex g_LEReqRespClientCbMutex = NULL;
 
 /**
  * Mutex to synchronize access to the requestResponse callback to be called
  * when the data needs to be sent from GATTClient.
  */
-static ca_mutex g_LEClientConnectMutex = NULL;
+static oc_mutex g_LEClientConnectMutex = NULL;
 
 /**
  * Mutex to synchronize the calls to be done to the platform from GATTClient
  * interfaces from different threads.
  */
-static ca_mutex g_LEClientStateMutex = NULL;
+static oc_mutex g_LEClientStateMutex = NULL;
 
 /**
  * Mutex to synchronize the task to be pushed to thread pool.
  */
-static ca_mutex g_LEClientThreadPoolMutex = NULL;
+static oc_mutex g_LEClientThreadPoolMutex = NULL;
 
 /**
  * Mutex to synchronize the task to write characteristic one packet after another.
  */
-static ca_mutex g_threadWriteCharacteristicMutex = NULL;
+static oc_mutex g_threadWriteCharacteristicMutex = NULL;
 
 /**
  * Condition for Writing characteristic.
  */
-static ca_cond g_threadWriteCharacteristicCond = NULL;
+static oc_cond g_threadWriteCharacteristicCond = NULL;
+
+/**
+ * Mutex to synchronize the task for MTU Changed.
+ */
+static oc_mutex g_threadMTUChangedMutex = NULL;
+
+/**
+ * Condition for MTU Changed.
+ */
+static oc_cond g_threadMTUChangedCond = NULL;
 
 /**
  * Flag to check status of write characteristic.
@@ -158,127 +208,272 @@ static GMainLoop *g_eventLoop = NULL;
  */
 static ca_thread_pool_t g_LEClientThreadPool = NULL;
 
-bt_scan_filter_h g_scanFilter = NULL;
-
-bool CALEIsDeviceDiscovered(const char * address)
-{
-    OIC_LOG(DEBUG, TAG, "IN");
-    if (g_deviceDiscoveredList)
-    {
-        ca_mutex_lock(g_deviceDiscoveredListMutex);
-        uint32_t arrayLength = u_arraylist_length(g_deviceDiscoveredList);
-        for (int i = 0; i < arrayLength; i++)
-        {
-            char *deviceAddr = u_arraylist_get(g_deviceDiscoveredList, i);
-            if (0 == strcasecmp(deviceAddr, address))
-            {
-                OIC_LOG(DEBUG, TAG, "Device Found");
-                ca_mutex_unlock(g_deviceDiscoveredListMutex);
-                return true;
-            }
-
-        }
-        ca_mutex_unlock(g_deviceDiscoveredListMutex);
-    }
-    OIC_LOG(DEBUG, TAG, "OUT");
-    return false;
-}
-
 void CALEGattCharacteristicChangedCb(bt_gatt_h characteristic,
                                      char *value,
                                      int valueLen, void *userData)
 {
+    (void)characteristic;
+
     OIC_LOG(DEBUG, TAG, "IN");
     OIC_LOG_V(DEBUG, TAG, "Changed characteristic value length [%d]", valueLen);
 
-    ca_mutex_lock(g_LEReqRespClientCbMutex);
+    oc_mutex_lock(g_LEReqRespClientCbMutex);
     if (NULL == g_LEClientDataReceivedCallback)
     {
         OIC_LOG(ERROR, TAG, "Request response callback is not set");
-        ca_mutex_unlock(g_LEReqRespClientCbMutex);
+        oc_mutex_unlock(g_LEReqRespClientCbMutex);
         return;
     }
 
     uint32_t sentLength = 0;
     g_LEClientDataReceivedCallback(userData, (uint8_t *)value, valueLen, &sentLength);
 
-    OIC_LOG_V(DEBUG, TAG, "Sent data Length is %d", sentLength);
+    OIC_LOG_V(DEBUG, TAG, "Recv data Length is %d", sentLength);
 
-    ca_mutex_unlock(g_LEReqRespClientCbMutex);
+    oc_mutex_unlock(g_LEReqRespClientCbMutex);
+
+    OIC_LOG(DEBUG, TAG, "OUT");
+}
 
+void CALEGattClientMTUChangedCb(bt_gatt_client_h client_handle, const bt_gatt_client_att_mtu_info_s *mtu_info, void *user_data)
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+    oc_mutex_lock(g_threadMTUChangedMutex);
+    OIC_LOG(DEBUG, TAG, "MTU changed signal");
+    oc_cond_signal(g_threadMTUChangedCond);
+    oc_mutex_unlock(g_threadMTUChangedMutex);
     OIC_LOG(DEBUG, TAG, "OUT");
 }
 
+
 void CALEGattCharacteristicWriteCb(int result, bt_gatt_h reqHandle, void *userData)
 {
+    (void)reqHandle;
+    (void)userData;
+
     OIC_LOG(DEBUG, TAG, "IN ");
 
     if (BT_ERROR_NONE != result)
     {
+        CALogSendStateInfo(CA_ADAPTER_GATT_BTLE, "", 0, -1,
+                           false, "writeChar failure");
+
         OIC_LOG(ERROR, TAG, "Write failed Need Retry ");
         //Need to Implement retry mechanism
     }
     else
     {
-        ca_mutex_lock(g_threadWriteCharacteristicMutex);
+        oc_mutex_lock(g_threadWriteCharacteristicMutex);
         OIC_LOG(DEBUG, TAG, "g_isSignalSetFlag is set true and signal");
         g_isSignalSetFlag = true;
-        ca_cond_signal(g_threadWriteCharacteristicCond);
-        ca_mutex_unlock(g_threadWriteCharacteristicMutex);
+        oc_cond_signal(g_threadWriteCharacteristicCond);
+        oc_mutex_unlock(g_threadWriteCharacteristicMutex);
+
+        CALogSendStateInfo(CA_ADAPTER_GATT_BTLE, "", 0, -1,
+                           true, "writeChar success");
     }
 
     OIC_LOG(DEBUG, TAG, "OUT ");
 }
 
-void CALEGattConnectionStateChanged(bool connected, const char *remoteAddress)
+CAResult_t CALEGattInitiateConnection(const char *remoteAddress)
 {
-    OIC_LOG(DEBUG, TAG, "IN ");
+    OIC_LOG(DEBUG, TAG, "IN");
 
-    VERIFY_NON_NULL_VOID(remoteAddress, TAG, "remote address is NULL");
+    oc_mutex_lock(g_isConnectionInProgressMutex);
+    if (g_isConnectionInProgress)
+    {
+        oc_mutex_unlock(g_isConnectionInProgressMutex);
+        OIC_LOG(DEBUG, TAG, "Connection already in progress, cannot initiate new connection");
+        return CA_STATUS_FAILED;
+    }
+    g_isConnectionInProgress = true;
+    // Set gatt connect retry count
+    g_retrycount = RETRY_COUNT;
+    oc_mutex_unlock(g_isConnectionInProgressMutex);
+
+    // Pause the scanning
+    CALEGattStopDeviceScanning();
 
-    // Start the scanning.
-    CAResult_t ret = CALEGattStartDeviceScanning();
-    if (CA_STATUS_OK != ret)
+    OIC_LOG_V(DEBUG, TAG,
+              "Trying to do Gatt connection to [%s]", remoteAddress);
+
+    oc_mutex_lock(g_LEClientThreadPoolMutex);
+    if (NULL == g_LEClientThreadPool)
+    {
+        oc_mutex_unlock(g_LEClientThreadPoolMutex);
+        OIC_LOG(ERROR, TAG, "g_LEClientThreadPool is NULL");
+        return CA_STATUS_FAILED;
+    }
+
+    char *addr = OICStrdup(remoteAddress);
+    if (NULL == addr)
+    {
+        oc_mutex_unlock(g_LEClientThreadPoolMutex);
+        OIC_LOG(ERROR, TAG, "OICStrdup failed");
+        return CA_STATUS_FAILED;
+    }
+
+    CAResult_t res = ca_thread_pool_add_task(g_LEClientThreadPool, CAGattConnectThread, addr, NULL);
+    oc_mutex_unlock(g_LEClientThreadPoolMutex);
+    if (CA_STATUS_OK != res)
     {
-        OIC_LOG(ERROR, TAG, "CALEGattStartDeviceDiscovery Failed");
+        OIC_LOG_V(ERROR, TAG,
+                  "ca_thread_pool_add_task failed with ret [%d]", res);
+        OICFree(addr);
+        return CA_STATUS_FAILED;
     }
-    // Signal the start timer.
-    ca_cond_signal(g_scanningTimeCond);
+    OIC_LOG(DEBUG, TAG, "OUT");
+    return CA_STATUS_OK;
+}
+
+void CALEGattConnectionStateChanged(bool connected, const char *remoteAddress)
+{
+    OIC_LOG(DEBUG, TAG, "IN ");
+
+    VERIFY_NON_NULL_VOID(remoteAddress, TAG, "remote address is NULL");
 
     if (!connected)
     {
         OIC_LOG_V(DEBUG, TAG, "DisConnected from [%s] ", remoteAddress);
+        if(!retry_flag)
+        {
+            oc_mutex_lock(g_LEServerListMutex);
+            CARemoveLEServerInfoFromList(&g_LEServerList, remoteAddress);
+            oc_mutex_unlock(g_LEServerListMutex);
+        }
+        else
+        {
+            oc_mutex_lock(g_isDisconnectedMutex);
+            oc_cond_signal(g_LEDisconnectedCond);
+            oc_mutex_unlock(g_isDisconnectedMutex);
+        }
+        retry_flag = 0;
     }
     else
     {
         OIC_LOG_V(DEBUG, TAG, "Connected to [%s] ", remoteAddress);
 
-        char *addr = OICStrdup(remoteAddress);
+        oc_mutex_lock(g_isConnectionInProgressMutex);
+        g_isConnectionInProgress = false;
+        oc_mutex_unlock(g_isConnectionInProgressMutex);
 
-        ca_mutex_lock(g_LEClientThreadPoolMutex);
+        LEServerInfo *serverInfo = NULL;
+        oc_mutex_lock(g_LEServerListMutex);
+        if (CA_STATUS_OK != CAGetLEServerInfo(g_LEServerList, remoteAddress, &serverInfo))
+        {
+            oc_mutex_unlock(g_LEServerListMutex);
+            OIC_LOG_V(ERROR, TAG, "Could not get server info for [%s]", remoteAddress);
+            return;
+        }
+
+        serverInfo->status = LE_STATUS_CONNECTED;
+        oc_mutex_unlock(g_LEServerListMutex);
+        oc_mutex_lock(g_LEClientThreadPoolMutex);
         if (NULL == g_LEClientThreadPool)
         {
+            oc_mutex_unlock(g_LEClientThreadPoolMutex);
             OIC_LOG(ERROR, TAG, "g_LEClientThreadPool is NULL");
-            OICFree(addr);
-            ca_mutex_unlock(g_LEClientThreadPoolMutex);
             return;
         }
 
-        ret = ca_thread_pool_add_task(g_LEClientThreadPool, CADiscoverLEServicesThread,
-                                      addr);
+        char *addr = OICStrdup(remoteAddress);
+        if (NULL == addr)
+        {
+            oc_mutex_unlock(g_LEClientThreadPoolMutex);
+            OIC_LOG(ERROR, TAG, "addr is NULL");
+            return;
+        }
+
+        CAResult_t ret = ca_thread_pool_add_task(g_LEClientThreadPool, CADiscoverLEServicesThread,
+                                                 addr, NULL);
+        oc_mutex_unlock(g_LEClientThreadPoolMutex);
         if (CA_STATUS_OK != ret)
         {
             OIC_LOG_V(ERROR, TAG, "ca_thread_pool_add_task failed with ret [%d]", ret);
             OICFree(addr);
         }
-        ca_mutex_unlock(g_LEClientThreadPoolMutex);
     }
     OIC_LOG(DEBUG, TAG, "OUT");
 }
 
+static bool CALEIsHaveServiceImpl(bt_adapter_le_device_scan_result_info_s *scanInfo,
+                                  const char *service_uuid,
+                                  bt_adapter_le_packet_type_e pkt_type)
+{
+    bool ret = false;
+    char **uuids = NULL;
+    int count = 0;
+    int result = 0;
+
+    result = bt_adapter_le_get_scan_result_service_uuids(scanInfo,
+             pkt_type, &uuids, &count);
+    if (result == BT_ERROR_NONE && NULL != uuids)
+    {
+        for (int i = 0; i < count; i++)
+        {
+            if (0 == strcasecmp(uuids[i], service_uuid))
+            {
+                OIC_LOG_V(DEBUG, TAG, "Service[%s] Found in %s",
+                          uuids[i], scanInfo->remote_address);
+                ret = true;
+            }
+            OICFree(uuids[i]);
+        }
+        OICFree(uuids);
+    }
+
+    if(ret == false){
+        char *man_data = NULL;
+        int man_data_len;
+        int man_id;
+        result = bt_adapter_le_get_scan_result_manufacturer_data(scanInfo,
+                              pkt_type, &man_id, &man_data, &man_data_len);
+
+        if (result == BT_ERROR_NONE && NULL != man_data)
+        {
+            int pos =0;
+            char *compare_man_data = OICCalloc(1, (man_data_len*2)+1);
+            if (!compare_man_data)
+            {
+                OIC_LOG(ERROR, TAG, "Memory allocation failed for compare_man_data");
+                OICFree(man_data);
+                return false;
+            }
+
+            for(int i=0;i<man_data_len;i++){
+                pos += snprintf(compare_man_data+pos, 2, "%.2x", man_data[i]);
+            }
+
+            if (man_id == samsung_code && 0 == strncasecmp(compare_man_data, service_uuid, CUSTOM_UUID_LEN))
+            {
+                OIC_LOG_V(DEBUG, TAG, "Manufacture Data[%s] Found in %s",
+                                       compare_man_data, scanInfo->remote_address);
+                ret = true;
+            }
+            OICFree(compare_man_data);
+            OICFree(man_data);
+        }
+    }
+    return ret;
+}
+
+static bool CALEIsHaveService(bt_adapter_le_device_scan_result_info_s *scanInfo,
+                              const char *service_uuid)
+{
+    return
+        // For arduino servers, scan response will give the UUIDs advertised.
+        CALEIsHaveServiceImpl(scanInfo, service_uuid,
+                              BT_ADAPTER_LE_PACKET_SCAN_RESPONSE) ||
+        // For android/tizen servers, advertising packet will give the UUIDs.
+        CALEIsHaveServiceImpl(scanInfo, service_uuid,
+                              BT_ADAPTER_LE_PACKET_ADVERTISING);
+}
+
 void CALEAdapterScanResultCb(int result, bt_adapter_le_device_scan_result_info_s *scanInfo,
                              void *userData)
 {
+    (void)userData;
     OIC_LOG(DEBUG, TAG, "IN");
 
     VERIFY_NON_NULL_VOID(scanInfo, TAG, "scanInfo");
@@ -291,53 +486,87 @@ void CALEAdapterScanResultCb(int result, bt_adapter_le_device_scan_result_info_s
               scanInfo->adv_data_len, scanInfo->scan_data_len, scanInfo->rssi,
               scanInfo->address_type);
 
-    // Check if device is already discovered.
-    if (CALEIsDeviceDiscovered(scanInfo->remote_address))
+    // Check if scanning was stopped (since this callback is
+    // being triggered even after stopping the scan)
+    oc_mutex_lock(g_isScanningInProgressMutex);
+    if (!g_isScanningInProgress)
     {
-        OIC_LOG_V(INFO, TAG, "Device[%s] is already discovered", scanInfo->remote_address);
+        oc_mutex_unlock(g_isScanningInProgressMutex);
+        OIC_LOG(DEBUG, TAG, "Scanning not in progress, so ignoring callback");
         return;
     }
+    oc_mutex_unlock(g_isScanningInProgressMutex);
 
-    // Stop the scan before invoking bt_gatt_connect().
-    CALEGattStopDeviceScanning();
-
-    ca_mutex_lock(g_deviceDiscoveredListMutex);
-    // Add the the device Discovered list.
-    if (NULL == g_deviceDiscoveredList)
+    if (CALEIsHaveService(scanInfo, CA_GATT_SERVICE_UUID) ||
+        CALEIsHaveService(scanInfo, CA_GATT_CUSTOM_UUID)||
+        CALEIsHaveService(scanInfo, CA_GATT_CUSTOM_UUID2))
     {
-        g_deviceDiscoveredList = u_arraylist_create();
-    }
-    char *deviceAddr = OICStrdup(scanInfo->remote_address);
-    u_arraylist_add(g_deviceDiscoveredList, (void *) deviceAddr);
-    ca_mutex_unlock(g_deviceDiscoveredListMutex);
+        OIC_LOG_V(DEBUG, TAG, "Device [%s] supports OIC or custom service", scanInfo->remote_address);
 
-    size_t len = strlen(scanInfo->remote_address);
-
-    char *addr = (char *)OICMalloc(sizeof(char) * (len + 1));
-    VERIFY_NON_NULL_VOID(addr, TAG, "Malloc failed");
-
-    strncpy(addr, scanInfo->remote_address, len + 1);
+        LEServerInfo *serverInfo = NULL;
+        oc_mutex_lock(g_LEServerListMutex);
+        CAResult_t ret = CAGetLEServerInfo(g_LEServerList, scanInfo->remote_address, &serverInfo);
+        if (CA_STATUS_OK != ret)
+        {
+            OIC_LOG_V(DEBUG, TAG,
+                      "Newly discovered device with address [%s] ", scanInfo->remote_address);
 
-    OIC_LOG_V(DEBUG, TAG,
-              "Trying to do Gatt connection to [%s]", addr);
+            char *addr = OICStrdup(scanInfo->remote_address);
+            if (NULL == addr)
+            {
+                oc_mutex_unlock(g_LEServerListMutex);
+                OIC_LOG(ERROR, TAG, "Device address is NULL");
+                return;
+            }
+            serverInfo = (LEServerInfo *)OICCalloc(1, sizeof(LEServerInfo));
+            if (NULL == serverInfo)
+            {
+                oc_mutex_unlock(g_LEServerListMutex);
+                OIC_LOG(ERROR, TAG, "Calloc failed");
+                OICFree(addr);
+                return;
+            }
+            serverInfo->remoteAddress = addr;
+            serverInfo->status = LE_STATUS_DISCOVERED;
 
-    ca_mutex_lock(g_LEClientThreadPoolMutex);
-    if (NULL == g_LEClientThreadPool)
-    {
-        OIC_LOG(ERROR, TAG, "g_LEClientThreadPool is NULL");
-        OICFree(addr);
-        ca_mutex_unlock(g_LEClientThreadPoolMutex);
-        return;
+            if (CA_STATUS_OK != CAAddLEServerInfoToList(&g_LEServerList, serverInfo))
+            {
+                oc_mutex_unlock(g_LEServerListMutex);
+                OIC_LOG_V(ERROR, TAG, "Could not add [%s] to server list", scanInfo->remote_address);
+                CAFreeLEServerInfo(serverInfo);
+                return;
+            }
+        }else {
+            OIC_LOG_V(DEBUG, TAG,
+                      "Device Present with address [%s] ", scanInfo->remote_address);
+
+            if(serverInfo->status == LE_STATUS_UNICAST_PENDING){
+                bt_gatt_client_h clientHandle = NULL;
+                int32_t ret = bt_gatt_client_create(serverInfo->remoteAddress, &clientHandle);
+                if (BT_ERROR_NONE != ret || NULL == clientHandle)
+                {
+                    OIC_LOG_V(ERROR, TAG,
+                              "bt_gatt_client_create Failed with ret value [%s] ", CALEGetErrorMsg(ret));
+                    CALEGattDisConnect(serverInfo->remoteAddress);
+                    oc_mutex_unlock(g_LEServerListMutex);
+                    return ;
+                }
+                serverInfo->clientHandle = clientHandle;
+
+                serverInfo->status = LE_STATUS_CONNECTION_INITIATED;
+                if (CA_STATUS_OK != CALEGattInitiateConnection(serverInfo->remoteAddress))
+                {
+                    OIC_LOG_V(ERROR, TAG, "Could not initiate connection to [%s]", serverInfo->remoteAddress);
+                    serverInfo->status = LE_STATUS_DISCOVERED;
+                    CADestroyLEDataList(&serverInfo->pendingDataList);
+                    oc_mutex_unlock(g_LEServerListMutex);
+                    return ;
+                }
+            }
+        }
+        oc_mutex_unlock(g_LEServerListMutex);
     }
 
-    CAResult_t res = ca_thread_pool_add_task(g_LEClientThreadPool, CAGattConnectThread, addr);
-    if (CA_STATUS_OK != res)
-    {
-        OIC_LOG_V(ERROR, TAG,
-                  "ca_thread_pool_add_task failed with ret [%d]", res);
-        OICFree(addr);
-    }
-    ca_mutex_unlock(g_LEClientThreadPoolMutex);
     OIC_LOG(DEBUG, TAG, "OUT");
 }
 
@@ -345,9 +574,9 @@ void CASetLEClientThreadPoolHandle(ca_thread_pool_t handle)
 {
     OIC_LOG(DEBUG, TAG, "IN");
 
-    ca_mutex_lock(g_LEClientThreadPoolMutex);
+    oc_mutex_lock(g_LEClientThreadPoolMutex);
     g_LEClientThreadPool = handle;
-    ca_mutex_unlock(g_LEClientThreadPoolMutex);
+    oc_mutex_unlock(g_LEClientThreadPoolMutex);
 
     OIC_LOG(DEBUG, TAG, "OUT");
 }
@@ -356,11 +585,11 @@ void CASetLEReqRespClientCallback(CABLEDataReceivedCallback callback)
 {
     OIC_LOG(DEBUG, TAG, "IN");
 
-    ca_mutex_lock(g_LEReqRespClientCbMutex);
+    oc_mutex_lock(g_LEReqRespClientCbMutex);
 
     g_LEClientDataReceivedCallback = callback;
 
-    ca_mutex_unlock(g_LEReqRespClientCbMutex);
+    oc_mutex_unlock(g_LEReqRespClientCbMutex);
 
     OIC_LOG(DEBUG, TAG, "OUT");
 }
@@ -374,121 +603,128 @@ CAResult_t CAStartLEGattClient()
 {
     OIC_LOG(DEBUG, TAG, "IN");
 
-    ca_mutex_lock(g_LEClientThreadPoolMutex);
-    if (NULL == g_LEClientThreadPool)
-    {
-        OIC_LOG(ERROR, TAG, "gBleServerThreadPool is NULL");
-        CATerminateGattClientMutexVariables();
-        ca_mutex_unlock(g_LEClientThreadPoolMutex);
-        return CA_STATUS_FAILED;
-    }
-
-    CAResult_t result = ca_thread_pool_add_task(g_LEClientThreadPool, CAStartLEGattClientThread,
-                                     NULL);
-    if (CA_STATUS_OK != result)
-    {
-        OIC_LOG(ERROR, TAG, "ca_thread_pool_add_task failed");
-        CATerminateGattClientMutexVariables();
-        ca_mutex_unlock(g_LEClientThreadPoolMutex);
-        return CA_STATUS_FAILED;
-    }
-    ca_mutex_unlock(g_LEClientThreadPoolMutex);
-
-    OIC_LOG(DEBUG, TAG, "OUT");
-    return CA_STATUS_OK;
-}
-
-void CAStartLEGattClientThread(void *data)
-{
-    OIC_LOG(DEBUG, TAG, "IN");
-
-    ca_mutex_lock(g_LEClientStateMutex);
+    oc_mutex_lock(g_LEClientStateMutex);
     if (true  == g_isLEGattClientStarted)
     {
         OIC_LOG(ERROR, TAG, "Gatt Client is already running!!");
-        ca_mutex_unlock(g_LEClientStateMutex);
-        return;
+        oc_mutex_unlock(g_LEClientStateMutex);
+        return CA_STATUS_FAILED;
     }
 
     CAResult_t  result = CALEGattSetCallbacks();
     if (CA_STATUS_OK != result)
     {
         OIC_LOG(ERROR, TAG, "CABleGattSetCallbacks Failed");
-        ca_mutex_unlock(g_LEClientStateMutex);
+        oc_mutex_unlock(g_LEClientStateMutex);
         CATerminateLEGattClient();
-        return;
+        return CA_STATUS_FAILED;
     }
 
     g_isLEGattClientStarted = true;
-    ca_mutex_unlock(g_LEClientStateMutex);
+    oc_mutex_unlock(g_LEClientStateMutex);
 
-    ca_mutex_lock(g_LEClientThreadPoolMutex);
+    oc_mutex_lock(g_LEClientThreadPoolMutex);
     if (NULL == g_LEClientThreadPool)
     {
         OIC_LOG(ERROR, TAG, "gBleServerThreadPool is NULL");
         CATerminateGattClientMutexVariables();
-        ca_mutex_unlock(g_LEClientThreadPoolMutex);
-        return;
+        oc_mutex_unlock(g_LEClientThreadPoolMutex);
+        return CA_STATUS_FAILED;
     }
 
     result = ca_thread_pool_add_task(g_LEClientThreadPool, CAStartTimerThread,
-                                     NULL);
+                                     NULL, NULL);
     if (CA_STATUS_OK != result)
     {
         OIC_LOG(ERROR, TAG, "ca_thread_pool_add_task failed");
-        ca_mutex_unlock(g_LEClientThreadPoolMutex);
-        return;
+        CATerminateGattClientMutexVariables();
+        oc_mutex_unlock(g_LEClientThreadPoolMutex);
+        return CA_STATUS_FAILED;
     }
-    ca_mutex_unlock(g_LEClientThreadPoolMutex);
-
-    OIC_LOG(DEBUG, TAG, "Giving the control to threadPool");
-
-    GMainContext *thread_context = g_main_context_new();
 
-    g_eventLoop = g_main_loop_new(thread_context, FALSE);
+#ifdef TIZEN_VD
+    result= ca_thread_pool_add_task(g_LEClientThreadPool, CALEClientScanThread,
+                                    NULL, NULL);
+    if (CA_STATUS_OK != result)
+    {
+        OIC_LOG(ERROR, TAG, "ca_thread_pool_add_task failed");
+        CATerminateGattClientMutexVariables();
+        oc_mutex_unlock(g_LEClientThreadPoolMutex);
+        return CA_STATUS_FAILED;
+    }
+#endif
+    oc_mutex_unlock(g_LEClientThreadPoolMutex);
 
-    g_main_context_push_thread_default(thread_context);
+    OIC_LOG(DEBUG, TAG, "OUT");
+    return CA_STATUS_OK;
+}
 
-    g_main_loop_run(g_eventLoop);
+#ifdef TIZEN_VD
+void CALEClientScanThread()
+{
+    oc_mutex_lock(g_scanMutex);
+    if (!g_isMulticastInProgress && !g_isUnicastScanInProgress)
+    {
+        CAResult_t result = CALEGattStartDeviceScanning();
+        if (CA_STATUS_OK != result)
+        {
+            oc_mutex_unlock(g_scanMutex);
+            OIC_LOG(ERROR, TAG, "CALEGattStartDeviceScanning failed");
+            return ;
+        }
+        g_isUnicastScanInProgress = true;
+        // Start Timer
+        oc_cond_signal(g_startTimerCond);
+    }
+    else
+    {
+        g_isUnicastScanInProgress = true;
+        // Reset Timer
+        oc_cond_signal(g_scanningTimeCond);
+    }
+    oc_mutex_unlock(g_scanMutex);
 
     OIC_LOG(DEBUG, TAG, "OUT");
+    return ;
 }
+#endif
 
 void CAStartTimerThread(void *data)
 {
+    (void)data;
+
     OIC_LOG(DEBUG, TAG, "IN");
     while (g_isLEGattClientStarted)
     {
-        ca_mutex_lock(g_multicastDataListMutex);
-        if (!g_isMulticastInProgress)
+        oc_mutex_lock(g_scanMutex);
+        if (!g_isMulticastInProgress && !g_isUnicastScanInProgress)
         {
             OIC_LOG(DEBUG, TAG, "waiting....");
-            ca_cond_wait(g_startTimerCond, g_multicastDataListMutex);
+            oc_cond_wait(g_startTimerCond, g_scanMutex);
             OIC_LOG(DEBUG, TAG, "Wake up");
-            g_isMulticastInProgress = true;
         }
 
         // Timed conditional wait for stopping the scan.
-        CAWaitResult_t ret = ca_cond_wait_for(g_scanningTimeCond, g_multicastDataListMutex,
+        OCWaitResult_t ret = oc_cond_wait_for(g_scanningTimeCond, g_scanMutex,
                                               TIMEOUT);
-        if (CA_WAIT_TIMEDOUT == ret)
+        if (OC_WAIT_TIMEDOUT == ret)
         {
             OIC_LOG(DEBUG, TAG, "Scan is timed Out");
             // Call stop scan.
             CALEGattStopDeviceScanning();
 
-            // Clear the data list and device list.
-            u_arraylist_destroy(g_multicastDataList);
-            g_multicastDataList = NULL;
-
-            ca_mutex_lock(g_deviceDiscoveredListMutex);
-            u_arraylist_destroy(g_deviceDiscoveredList);
-            g_deviceDiscoveredList = NULL;
-            ca_mutex_unlock(g_deviceDiscoveredListMutex);
-
-            g_isMulticastInProgress = false;
+            if (g_isMulticastInProgress)
+            {
+                oc_mutex_lock(g_multicastDataListMutex);
+                // Clear the data list and device list.
+                u_arraylist_destroy(g_multicastDataList);
+                g_multicastDataList = NULL;
+                oc_mutex_unlock(g_multicastDataListMutex);
+                g_isMulticastInProgress = false;
+            }
+            g_isUnicastScanInProgress = false;
         }
-        ca_mutex_unlock(g_multicastDataListMutex);
+        oc_mutex_unlock(g_scanMutex);
     }
 
     OIC_LOG(DEBUG, TAG, "OUT");
@@ -498,12 +734,12 @@ void CAStopLEGattClient()
 {
     OIC_LOG(DEBUG,  TAG, "IN");
 
-    ca_mutex_lock(g_LEClientStateMutex);
+    oc_mutex_lock(g_LEClientStateMutex);
 
     if (false == g_isLEGattClientStarted)
     {
         OIC_LOG(ERROR, TAG, "Gatt Client is not running to stop");
-        ca_mutex_unlock(g_LEClientStateMutex);
+        oc_mutex_unlock(g_LEClientStateMutex);
         return;
     }
 
@@ -514,36 +750,26 @@ void CAStopLEGattClient()
     g_isLEGattClientStarted = false;
 
     // Signal the conditions waiting in Start timer.
-    ca_cond_signal(g_startTimerCond);
-    ca_cond_signal(g_scanningTimeCond);
+    oc_cond_signal(g_startTimerCond);
+    oc_cond_signal(g_scanningTimeCond);
 
     // Destroy the multicast data list and device list if not empty.
     if (NULL != g_multicastDataList)
     {
-        ca_mutex_lock(g_multicastDataListMutex);
+        oc_mutex_lock(g_multicastDataListMutex);
         u_arraylist_destroy(g_multicastDataList);
         g_multicastDataList = NULL;
-        ca_mutex_unlock(g_multicastDataListMutex);
-    }
-
-    if (NULL != g_deviceDiscoveredList)
-    {
-        ca_mutex_lock(g_deviceDiscoveredListMutex);
-        u_arraylist_destroy(g_deviceDiscoveredList);
-        g_deviceDiscoveredList = NULL;
-        ca_mutex_unlock(g_deviceDiscoveredListMutex);
+        oc_mutex_unlock(g_multicastDataListMutex);
     }
 
-    ca_mutex_lock(g_LEServerListMutex);
+    oc_mutex_lock(g_LEServerListMutex);
     CAFreeLEServerList(g_LEServerList);
     g_LEServerList = NULL;
-    ca_mutex_unlock(g_LEServerListMutex);
+    oc_mutex_unlock(g_LEServerListMutex);
 
-    ca_mutex_lock(g_threadWriteCharacteristicMutex);
-    ca_cond_signal(g_threadWriteCharacteristicCond);
-    ca_mutex_unlock(g_threadWriteCharacteristicMutex);
-
-    CAResetRegisteredServiceCount();
+    oc_mutex_lock(g_threadWriteCharacteristicMutex);
+    oc_cond_signal(g_threadWriteCharacteristicCond);
+    oc_mutex_unlock(g_threadWriteCharacteristicMutex);
 
     GMainContext  *context_event_loop = NULL;
     // Required for waking up the thread which is running in gmain loop
@@ -553,7 +779,7 @@ void CAStopLEGattClient()
     }
     if (context_event_loop)
     {
-        OIC_LOG_V(DEBUG,  TAG, "g_eventLoop context %x", context_event_loop);
+        OIC_LOG_V(DEBUG,  TAG, "g_eventLoop context %p", (void *)context_event_loop);
         g_main_context_wakeup(context_event_loop);
 
         // Kill g main loops and kill threads.
@@ -564,7 +790,7 @@ void CAStopLEGattClient()
         OIC_LOG(ERROR, TAG, "g_eventLoop context is NULL");
     }
 
-    ca_mutex_unlock(g_LEClientStateMutex);
+    oc_mutex_unlock(g_LEClientStateMutex);
 
     OIC_LOG(DEBUG,  TAG, "OUT");
 }
@@ -596,114 +822,175 @@ CAResult_t CAInitGattClientMutexVariables()
     OIC_LOG(DEBUG,  TAG, "IN");
     if (NULL == g_LEClientStateMutex)
     {
-        g_LEClientStateMutex = ca_mutex_new();
+        g_LEClientStateMutex = oc_mutex_new();
         if (NULL == g_LEClientStateMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_LEServerListMutex)
     {
-        g_LEServerListMutex = ca_mutex_new();
+        g_LEServerListMutex = oc_mutex_new();
         if (NULL == g_LEServerListMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_LEReqRespClientCbMutex)
     {
-        g_LEReqRespClientCbMutex = ca_mutex_new();
+        g_LEReqRespClientCbMutex = oc_mutex_new();
         if (NULL == g_LEReqRespClientCbMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_LEClientThreadPoolMutex)
     {
-        g_LEClientThreadPoolMutex = ca_mutex_new();
+        g_LEClientThreadPoolMutex = oc_mutex_new();
         if (NULL == g_LEClientThreadPoolMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_LEClientConnectMutex)
     {
-        g_LEClientConnectMutex = ca_mutex_new();
+        g_LEClientConnectMutex = oc_mutex_new();
         if (NULL == g_LEClientConnectMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new failed");
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    if (NULL == g_isScanningInProgressMutex)
+    {
+        g_isScanningInProgressMutex = oc_mutex_new();
+        if (NULL == g_isScanningInProgressMutex)
+        {
+            OIC_LOG(ERROR, TAG, "oc_mutex_new failed");
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    if (NULL == g_isConnectionInProgressMutex)
+    {
+        g_isConnectionInProgressMutex = oc_mutex_new();
+        if (NULL == g_isConnectionInProgressMutex)
+        {
+            OIC_LOG(ERROR, TAG, "oc_mutex_new failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_multicastDataListMutex)
     {
-        g_multicastDataListMutex = ca_mutex_new();
+        g_multicastDataListMutex = oc_mutex_new();
         if (NULL == g_multicastDataListMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new failed");
             return CA_STATUS_FAILED;
         }
     }
 
-    if (NULL == g_deviceDiscoveredListMutex)
+    if (NULL == g_scanMutex)
     {
-        g_deviceDiscoveredListMutex = ca_mutex_new();
-        if (NULL == g_deviceDiscoveredListMutex)
+        g_scanMutex = oc_mutex_new();
+        if (NULL == g_scanMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_threadWriteCharacteristicMutex)
     {
-        g_threadWriteCharacteristicMutex = ca_mutex_new();
+        g_threadWriteCharacteristicMutex = oc_mutex_new();
         if (NULL == g_threadWriteCharacteristicMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    if (NULL == g_threadMTUChangedMutex)
+    {
+        g_threadMTUChangedMutex = oc_mutex_new();
+        if (NULL == g_threadMTUChangedMutex)
+        {
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    if (NULL == g_isDisconnectedMutex)
+    {
+        g_isDisconnectedMutex = oc_mutex_new();
+        if (NULL == g_isDisconnectedMutex)
+        {
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    if (NULL == g_LEDisconnectedCond)
+    {
+        g_LEDisconnectedCond = oc_cond_new();
+        if (NULL == g_LEDisconnectedCond)
+        {
+            OIC_LOG(ERROR, TAG, "oc_cond_new failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_startTimerCond)
     {
-        g_startTimerCond = ca_cond_new();
+        g_startTimerCond = oc_cond_new();
         if (NULL == g_startTimerCond)
         {
-            OIC_LOG(ERROR, TAG, "ca_cond_new failed");
+            OIC_LOG(ERROR, TAG, "oc_cond_new failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_scanningTimeCond)
     {
-        g_scanningTimeCond = ca_cond_new();
+        g_scanningTimeCond = oc_cond_new();
         if (NULL == g_scanningTimeCond)
         {
-            OIC_LOG(ERROR, TAG, "ca_cond_new failed");
+            OIC_LOG(ERROR, TAG, "oc_cond_new failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_threadWriteCharacteristicCond)
     {
-        g_threadWriteCharacteristicCond = ca_cond_new();
+        g_threadWriteCharacteristicCond = oc_cond_new();
         if (NULL == g_threadWriteCharacteristicCond)
         {
-            OIC_LOG(ERROR, TAG, "ca_cond_new failed");
+            OIC_LOG(ERROR, TAG, "oc_cond_new failed");
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    if (NULL == g_threadMTUChangedCond)
+    {
+        g_threadMTUChangedCond = oc_cond_new();
+        if (NULL == g_threadMTUChangedCond)
+        {
+            OIC_LOG(ERROR, TAG, "oc_cond_new failed");
             return CA_STATUS_FAILED;
         }
     }
 
+
     OIC_LOG(DEBUG,  TAG, "OUT");
     return CA_STATUS_OK;
 }
@@ -712,40 +999,58 @@ void CATerminateGattClientMutexVariables()
 {
     OIC_LOG(DEBUG,  TAG, "IN");
 
-    ca_mutex_free(g_LEClientStateMutex);
+    oc_mutex_free(g_LEClientStateMutex);
     g_LEClientStateMutex = NULL;
 
-    ca_mutex_free(g_LEServerListMutex);
+    oc_mutex_free(g_LEServerListMutex);
     g_LEServerListMutex = NULL;
 
-    ca_mutex_free(g_LEReqRespClientCbMutex);
+    oc_mutex_free(g_LEReqRespClientCbMutex);
     g_LEReqRespClientCbMutex = NULL;
 
-    ca_mutex_free(g_LEClientConnectMutex);
+    oc_mutex_free(g_LEClientConnectMutex);
     g_LEClientConnectMutex = NULL;
 
-    ca_mutex_free(g_LEClientThreadPoolMutex);
+    oc_mutex_free(g_LEClientThreadPoolMutex);
     g_LEClientThreadPoolMutex = NULL;
 
-    ca_mutex_free(g_multicastDataListMutex);
+    oc_mutex_free(g_isScanningInProgressMutex);
+    g_isScanningInProgressMutex = NULL;
+
+    oc_mutex_free(g_isConnectionInProgressMutex);
+    g_isConnectionInProgressMutex = NULL;
+
+    oc_mutex_free(g_multicastDataListMutex);
     g_multicastDataListMutex = NULL;
 
-    ca_mutex_free(g_deviceDiscoveredListMutex);
-    g_deviceDiscoveredListMutex = NULL;
+    oc_mutex_free(g_scanMutex);
+    g_scanMutex = NULL;
 
-    ca_mutex_free(g_threadWriteCharacteristicMutex);
+    oc_mutex_free(g_threadWriteCharacteristicMutex);
     g_threadWriteCharacteristicMutex = NULL;
 
-    ca_cond_free(g_startTimerCond);
+    oc_mutex_free(g_threadMTUChangedMutex);
+    g_threadMTUChangedMutex = NULL;
+
+    oc_mutex_free(g_isDisconnectedMutex);
+    g_isDisconnectedMutex = NULL;
+
+    oc_cond_free(g_LEDisconnectedCond);
+    g_LEDisconnectedCond = NULL;
+
+    oc_cond_free(g_startTimerCond);
     g_startTimerCond = NULL;
 
-    ca_cond_free(g_scanningTimeCond);
+    oc_cond_free(g_scanningTimeCond);
     g_scanningTimeCond = NULL;
 
-    ca_cond_free(g_threadWriteCharacteristicCond);
+    oc_cond_free(g_threadWriteCharacteristicCond);
     g_threadWriteCharacteristicCond = NULL;
     g_isSignalSetFlag = false;
 
+    oc_cond_free(g_threadMTUChangedCond);
+    g_threadMTUChangedCond = NULL;
+
     OIC_LOG(DEBUG,  TAG, "OUT");
 }
 
@@ -763,14 +1068,19 @@ void CALEGattUnSetCallbacks()
 
     bt_gatt_unset_connection_state_changed_cb();
 
-    int numOfServersConnected = CAGetRegisteredServiceCount();
-    LEServerInfo *leServerInfo = NULL;
-
-    for (int32_t index = 0; index < numOfServersConnected; index++)
+    oc_mutex_lock(g_LEServerListMutex);
+    LEServerInfoList *curNode = g_LEServerList;
+    while (curNode)
     {
-        CAGetLEServerInfoByPosition(g_LEServerList, index, &leServerInfo);
-        bt_gatt_client_unset_characteristic_value_changed_cb(leServerInfo->readChar);
+        LEServerInfo *serverInfo = curNode->serverInfo;
+        if (serverInfo->status >= LE_STATUS_SERVICES_DISCOVERED)
+        {
+            bt_gatt_client_unset_characteristic_value_changed_cb(serverInfo->readChar);
+        }
+        curNode = curNode->next;
     }
+    oc_mutex_unlock(g_LEServerListMutex);
+
     OIC_LOG(DEBUG, TAG, "OUT");
 }
 
@@ -778,13 +1088,24 @@ CAResult_t CALEGattStartDeviceScanning()
 {
     OIC_LOG(DEBUG, TAG, "IN");
 
-    int ret = bt_adapter_le_start_scan(CALEAdapterScanResultCb, NULL);
-    if(BT_ERROR_NONE != ret)
+    oc_mutex_lock(g_isScanningInProgressMutex);
+    if (!g_isScanningInProgress)
     {
-        OIC_LOG_V(ERROR, TAG, "bt_adapter_le_start_scan failed[%s]",
-                  CALEGetErrorMsg(ret));
-        return CA_STATUS_FAILED;
+        int ret = bt_adapter_le_start_scan(CALEAdapterScanResultCb, NULL);
+        if (BT_ERROR_NONE != ret)
+        {
+            oc_mutex_unlock(g_isScanningInProgressMutex);
+            OIC_LOG_V(ERROR, TAG, "bt_adapter_le_start_scan failed[%s]",
+                      CALEGetErrorMsg(ret));
+            return CA_STATUS_FAILED;
+        }
+        g_isScanningInProgress = true;
+    }
+    else
+    {
+        OIC_LOG(DEBUG, TAG, "Ignore, scanning already in progress");
     }
+    oc_mutex_unlock(g_isScanningInProgressMutex);
 
     OIC_LOG(DEBUG, TAG, "OUT");
     return CA_STATUS_OK;
@@ -794,12 +1115,25 @@ void CALEGattStopDeviceScanning()
 {
     OIC_LOG(DEBUG, TAG, "IN");
 
-    int ret = bt_adapter_le_stop_scan();
-    if (BT_ERROR_NONE != ret)
+    oc_mutex_lock(g_isScanningInProgressMutex);
+    if (g_isScanningInProgress)
     {
-        OIC_LOG_V(ERROR, TAG, "bt_adapter_le_stop_scan failed[%s]",
-                  CALEGetErrorMsg(ret));
+        int ret = bt_adapter_le_stop_scan();
+        if (BT_ERROR_NONE != ret)
+        {
+            oc_mutex_unlock(g_isScanningInProgressMutex);
+            OIC_LOG_V(ERROR, TAG, "bt_adapter_le_stop_scan failed[%s]",
+                      CALEGetErrorMsg(ret));
+            return;
+        }
+        g_isScanningInProgress = false;
+        g_isUnicastScanInProgress= false;
     }
+    else
+    {
+        OIC_LOG(DEBUG, TAG, "Ignore, scanning not in progress");
+    }
+    oc_mutex_unlock(g_isScanningInProgressMutex);
 
     OIC_LOG(DEBUG, TAG, "OUT");
 }
@@ -833,62 +1167,23 @@ CAResult_t CALEGattConnect(const char *remoteAddress)
     VERIFY_NON_NULL_RET(remoteAddress, TAG,
                         "remote address is NULL", CA_STATUS_FAILED);
 
-    ca_mutex_lock(g_LEClientConnectMutex);
-    bool isConnected = false;
-    int ret = bt_device_is_profile_connected(remoteAddress, BT_PROFILE_GATT, &isConnected);
+    oc_mutex_lock(g_LEClientConnectMutex);
+    CAResult_t result = CA_STATUS_OK;
+
+#ifdef TIZEN_VD
+    int ret = bt_gatt_connect(remoteAddress, true);
+#else
+    int ret = bt_gatt_connect(remoteAddress, false);
+#endif
     if (BT_ERROR_NONE != ret)
     {
-        OIC_LOG_V(ERROR, TAG, "bt_device_is_profile_connected Failed with ret value [%s] ",
+        OIC_LOG_V(ERROR, TAG, "bt_gatt_connect Failed with ret value [%s] ",
                   CALEGetErrorMsg(ret));
-        ca_mutex_unlock(g_LEClientConnectMutex);
+        oc_mutex_unlock(g_LEClientConnectMutex);
         return CA_STATUS_FAILED;
     }
 
-    CAResult_t result = CA_STATUS_OK;
-    if (!isConnected)
-    {
-        ret = bt_gatt_connect(remoteAddress, true);
-
-        if (BT_ERROR_NONE != ret)
-        {
-            OIC_LOG_V(ERROR, TAG, "bt_gatt_connect Failed with ret value [%s] ",
-                      CALEGetErrorMsg(ret));
-            ca_mutex_unlock(g_LEClientConnectMutex);
-            return CA_STATUS_FAILED;
-        }
-    }
-    else
-    {
-        OIC_LOG_V(INFO, TAG, "Remote address[%s] is already connected",
-                  remoteAddress);
-        char *addr = OICStrdup(remoteAddress);
-        if (NULL == addr)
-        {
-            OIC_LOG(ERROR, TAG, "addr is NULL");
-            ca_mutex_unlock(g_LEClientConnectMutex);
-            return CA_STATUS_FAILED;
-        }
-
-        ca_mutex_lock(g_LEClientThreadPoolMutex);
-        if (NULL == g_LEClientThreadPool)
-        {
-            OIC_LOG(ERROR, TAG, "g_LEClientThreadPool is NULL");
-            OICFree(addr);
-            ca_mutex_unlock(g_LEClientThreadPoolMutex);
-            ca_mutex_unlock(g_LEClientConnectMutex);
-            return CA_STATUS_FAILED;
-        }
-
-        result = ca_thread_pool_add_task(g_LEClientThreadPool, CADiscoverLEServicesThread,
-                                      addr);
-        if (CA_STATUS_OK != result)
-        {
-            OIC_LOG_V(ERROR, TAG, "ca_thread_pool_add_task failed with ret [%d]", result);
-            OICFree(addr);
-        }
-        ca_mutex_unlock(g_LEClientThreadPoolMutex);
-    }
-    ca_mutex_unlock(g_LEClientConnectMutex);
+    oc_mutex_unlock(g_LEClientConnectMutex);
 
     OIC_LOG(DEBUG, TAG, "OUT");
     return result;
@@ -905,7 +1200,7 @@ CAResult_t CALEGattDisConnect(const char *remoteAddress)
 
     if (BT_ERROR_NONE != ret)
     {
-        OIC_LOG_V(ERROR, TAG, "bt_gatt_disconnect Failed with ret value [%d] ",
+        OIC_LOG_V(ERROR, TAG, "bt_gatt_disconnect Failed with ret value [%s] ",
                   CALEGetErrorMsg(ret));
         return CA_STATUS_FAILED;
     }
@@ -914,7 +1209,86 @@ CAResult_t CALEGattDisConnect(const char *remoteAddress)
     return CA_STATUS_OK;
 }
 
-void CADiscoverLEServicesThread (void *remoteAddress)
+CAResult_t CAUpdateCharacteristicsToGattServerImpl(LEServerInfo *serverInfo,
+        const uint8_t *data, const uint32_t dataLen)
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+
+    VERIFY_NON_NULL(serverInfo, TAG, "Server Info is NULL");
+
+    CALEGattStopDeviceScanning();
+
+    OIC_LOG_V(DEBUG, TAG, "Updating the data of length [%d] to [%s] ", dataLen,
+              serverInfo->remoteAddress);
+
+    int result = bt_gatt_set_value(serverInfo->writeChar, (char *)data, dataLen);
+
+    if (BT_ERROR_NONE != result)
+    {
+        OIC_LOG_V(ERROR, TAG,
+                  "bt_gatt_set_value Failed with return val [%s]",
+                  CALEGetErrorMsg(result));
+        goto exit;
+    }
+
+    result = bt_gatt_client_write_value(serverInfo->writeChar, CALEGattCharacteristicWriteCb,
+                                        NULL);
+    if (BT_ERROR_NONE != result)
+    {
+        OIC_LOG_V(ERROR, TAG,
+                  "bt_gatt_client_write_value Failed with return val [%s]",
+                  CALEGetErrorMsg(result));
+        goto exit;
+    }
+
+    // wait for callback for write Characteristic with success to sent data
+    OIC_LOG_V(DEBUG, TAG, "callback flag is %d", g_isSignalSetFlag);
+    oc_mutex_lock(g_threadWriteCharacteristicMutex);
+    if (!g_isSignalSetFlag)
+    {
+        OIC_LOG(DEBUG, TAG, "wait for callback to notify writeCharacteristic is success");
+        if (OC_WAIT_SUCCESS != oc_cond_wait_for(g_threadWriteCharacteristicCond,
+                                                g_threadWriteCharacteristicMutex,
+                                                WAIT_TIME_WRITE_CHARACTERISTIC))
+        {
+            g_isSignalSetFlag = false;
+            oc_mutex_unlock(g_threadWriteCharacteristicMutex);
+            OIC_LOG(ERROR, TAG, "there is no response. write has failed");
+            goto exit;
+        }
+    }
+    // reset flag set by writeCharacteristic Callback
+    g_isSignalSetFlag = false;
+    oc_mutex_unlock(g_threadWriteCharacteristicMutex);
+
+    oc_mutex_lock(g_scanMutex);
+    if (g_isMulticastInProgress || g_isUnicastScanInProgress)
+    {
+        if (CA_STATUS_OK != CALEGattStartDeviceScanning())
+        {
+            OIC_LOG(ERROR, TAG, "Could not start device scanning");
+        }
+    }
+    oc_mutex_unlock(g_scanMutex);
+    OIC_LOG(DEBUG, TAG, "OUT");
+    return CA_STATUS_OK;
+
+exit:
+    oc_mutex_lock(g_scanMutex);
+    if (g_isMulticastInProgress || g_isUnicastScanInProgress)
+    {
+        if (CA_STATUS_OK != CALEGattStartDeviceScanning())
+        {
+            OIC_LOG(ERROR, TAG, "Could not start device scanning");
+        }
+    }
+    oc_mutex_unlock(g_scanMutex);
+
+    OIC_LOG(DEBUG, TAG, "OUT");
+    return CA_STATUS_FAILED;
+}
+
+void CADiscoverLEServicesThread(void *remoteAddress)
 {
     OIC_LOG(DEBUG, TAG, "IN");
 
@@ -932,6 +1306,30 @@ void CADiscoverLEServicesThread (void *remoteAddress)
     OIC_LOG(DEBUG, TAG, "OUT");
 }
 
+static int CALEWaittillDisconnect(oc_mutex mutex, oc_cond cv, int wait_seconds)
+{
+    OIC_LOG(DEBUG, TAG, "Waiting for server to be disconnected...");
+    oc_mutex_lock(mutex);
+    uint64_t wait_time = wait_seconds * MICROSECS_PER_SEC;
+    int ret = oc_cond_wait_for(cv, mutex, wait_time);
+    oc_mutex_unlock(mutex);
+    return ret;
+}
+
+static CAResult_t CALEGattConnectionRetry(const char *remoteAddress)
+{
+    OIC_LOG(DEBUG, TAG, "IN");
+
+    VERIFY_NON_NULL_RET(remoteAddress, TAG,
+                        "remote address is NULL", CA_STATUS_FAILED);
+
+    CALEGattDisConnect(remoteAddress);
+    CALEWaittillDisconnect(g_isDisconnectedMutex, g_LEDisconnectedCond, 10);
+    CAResult_t result = CALEGattConnect(remoteAddress);
+    OIC_LOG(DEBUG, TAG, "OUT");
+    return result;
+}
+
 CAResult_t CALEGattDiscoverServices(const char *remoteAddress)
 {
     OIC_LOG(DEBUG, TAG, "IN");
@@ -939,197 +1337,345 @@ CAResult_t CALEGattDiscoverServices(const char *remoteAddress)
     VERIFY_NON_NULL_RET(remoteAddress, TAG,
                         "remote address is NULL", CA_STATUS_FAILED);
 
-    bt_gatt_client_h clientHandle = NULL;
-    int32_t ret = bt_gatt_client_create(remoteAddress, &clientHandle);
-    if (BT_ERROR_NONE != ret || NULL == clientHandle)
+    LEServerInfo *serverInfo = NULL;
+    unsigned int mtu_size;
+    oc_mutex_lock(g_LEServerListMutex);
+    if (CA_STATUS_OK != CAGetLEServerInfo(g_LEServerList, remoteAddress, &serverInfo))
     {
-        OIC_LOG_V(ERROR, TAG,
-                  "bt_gatt_client_create Failed with ret value [%s] ", CALEGetErrorMsg(ret));
+        oc_mutex_unlock(g_LEServerListMutex);
+        OIC_LOG_V(ERROR, TAG, "Could not get server info for [%s]", remoteAddress);
         CALEGattDisConnect(remoteAddress);
         return CA_STATUS_FAILED;
     }
 
     bt_gatt_h serviceHandle = NULL;
-    ret = bt_gatt_client_get_service(clientHandle, CA_GATT_SERVICE_UUID, &serviceHandle);
+    int32_t ret = bt_gatt_client_get_service(serverInfo->clientHandle, CA_GATT_SERVICE_UUID, &serviceHandle);
     if (BT_ERROR_NONE != ret || NULL == serviceHandle)
     {
         OIC_LOG_V(ERROR, TAG,
                   "bt_gatt_client_get_service Failed with ret value [%s] ", CALEGetErrorMsg(ret));
-        bt_gatt_client_destroy(clientHandle);
-        CALEGattDisConnect(remoteAddress);
-        return CA_STATUS_FAILED;
+
+        if(g_retrycount)
+        {
+            OIC_LOG(DEBUG, TAG, "Retry will be attempted to connect Gatt Server");
+            g_retrycount--;
+            retry_flag = 1;
+            OIC_LOG_V(DEBUG, TAG, "Retry count left %d time(s)", g_retrycount);
+            CAResult_t result = CALEGattConnectionRetry(remoteAddress);
+            if(result == CA_STATUS_FAILED)
+            {
+                goto error_exit;
+            }
+            else
+            {
+                oc_mutex_unlock(g_LEServerListMutex);
+                OIC_LOG(ERROR, TAG, "Previous connection attempt failed, attempting to retry again");
+                OIC_LOG_V(DEBUG, TAG, "Retry count left %d time(s)", g_retrycount);
+                return CA_STATUS_FAILED;
+            }
+        }
     }
 
+    retry_flag = 0;
     // Server will read data on this characteristic.
     bt_gatt_h writeChrHandle = NULL;
     ret = bt_gatt_service_get_characteristic(serviceHandle, CA_GATT_REQUEST_CHRC_UUID,
-                                             &writeChrHandle);
+            &writeChrHandle);
     if (BT_ERROR_NONE != ret || NULL == writeChrHandle)
     {
         OIC_LOG_V(ERROR, TAG,
                   "bt_gatt_service_get_characteristic Failed with ret value [%s] ",
                   CALEGetErrorMsg(ret));
-        bt_gatt_client_destroy(clientHandle);
-        CALEGattDisConnect(remoteAddress);
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     // Server will notify data on this characteristic.
     bt_gatt_h readChrHandle = NULL;
     ret = bt_gatt_service_get_characteristic(serviceHandle, CA_GATT_RESPONSE_CHRC_UUID,
-                                             &readChrHandle);
+            &readChrHandle);
     if (BT_ERROR_NONE != ret || NULL == readChrHandle)
     {
         OIC_LOG_V(ERROR, TAG,
                   "bt_gatt_service_get_characteristic Failed with ret value [%s] ",
                   CALEGetErrorMsg(ret));
-        bt_gatt_client_destroy(clientHandle);
-        CALEGattDisConnect(remoteAddress);
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
 
     //TODO: This data has to be freed while unsetting the callback.
     char *addr = OICStrdup(remoteAddress);
+    if (NULL == addr)
+    {
+        OIC_LOG(ERROR, TAG, "addr is NULL");
+        goto error_exit;
+    }
+
     ret = bt_gatt_client_set_characteristic_value_changed_cb(readChrHandle,
-                                                             CALEGattCharacteristicChangedCb,
-                                                             (void *)addr);
+            CALEGattCharacteristicChangedCb,
+            (void *)addr);
     if (BT_ERROR_NONE != ret)
     {
         OIC_LOG_V(ERROR, TAG,
                   "bt_gatt_client_set_characteristic_value_changed_cb Failed with ret value [%s]",
                   CALEGetErrorMsg(ret));
-        bt_gatt_client_destroy(clientHandle);
-        CALEGattDisConnect(remoteAddress);
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
-    LEServerInfo *serverInfo = (LEServerInfo *)OICCalloc(1, sizeof(LEServerInfo));
-    if (NULL == serverInfo)
+    ret = bt_gatt_client_set_att_mtu_changed_cb(serverInfo->clientHandle,
+            CALEGattClientMTUChangedCb,
+            (void *)serverInfo->remoteAddress);
+    if (BT_ERROR_NONE != ret)
     {
-        OIC_LOG(ERROR, TAG, "Malloc failed");
-        CALEGattDisConnect(remoteAddress);
-        return CA_MEMORY_ALLOC_FAILED;
+        OIC_LOG_V(ERROR, TAG,
+                  "bt_gatt_client_set_att_mtu_changed_cb Failed with ret value [%s]",
+                  CALEGetErrorMsg(ret));
+        goto error_exit;
     }
-    serverInfo->clientHandle = clientHandle;
-    serverInfo->serviceHandle = serviceHandle;
-    serverInfo->readChar = readChrHandle;
-    serverInfo->writeChar = writeChrHandle;
-    serverInfo->remoteAddress = OICStrdup(remoteAddress);
 
-    ca_mutex_lock(g_LEServerListMutex);
-    CAResult_t result = CAAddLEServerInfoToList(&g_LEServerList, serverInfo);
-    if (CA_STATUS_OK != result)
+    oc_mutex_lock(g_threadMTUChangedMutex);
+    ret = bt_gatt_client_request_att_mtu_change(serverInfo->clientHandle, CA_SUPPORTED_BLE_MTU_SIZE - CA_BLE_MTU_HEADER_SIZE);
+    if (BT_ERROR_NONE != ret)
     {
-        OIC_LOG(ERROR, TAG, "CAAddBLEClientInfoToList failed");
-        bt_gatt_client_destroy(clientHandle);
-        CALEGattDisConnect(remoteAddress);
-        return CA_STATUS_FAILED;
+        OIC_LOG_V(ERROR, TAG,
+                  "bt_gatt_client_request_att_mtu_change Failed with ret value [%s]",
+                  CALEGetErrorMsg(ret));
+        oc_mutex_unlock(g_threadMTUChangedMutex);
+        goto error_exit;
     }
-    ca_mutex_unlock(g_LEServerListMutex);
 
-    // Send the data of pending multicast data list if any.
-    if (g_multicastDataList)
+    OIC_LOG(DEBUG, TAG, "wait for callback to notify MTU Changed Callback");
+    oc_cond_wait(g_threadMTUChangedCond, g_threadMTUChangedMutex);
+    oc_mutex_unlock(g_threadMTUChangedMutex);
+
+    OIC_LOG(DEBUG, TAG, "Done MTU");
+    ret = bt_gatt_client_get_att_mtu(serverInfo->clientHandle, &mtu_size);
+    if (BT_ERROR_NONE != ret)
+    {
+        OIC_LOG_V(ERROR, TAG,
+                  "bt_gatt_client_get_att_mtu Failed with ret value [%s]",
+                  CALEGetErrorMsg(ret));
+        goto error_exit;
+    }
+    OIC_LOG_V(DEBUG, TAG,"Negotiated MTU Size %d",mtu_size);
+
+    serverInfo->serviceHandle = serviceHandle;
+    serverInfo->readChar = readChrHandle;
+    serverInfo->writeChar = writeChrHandle;
+    serverInfo->status = LE_STATUS_SERVICES_DISCOVERED;
+    serverInfo->mtu_size = mtu_size;
+
+    while (serverInfo->pendingDataList)
     {
-        ca_mutex_lock(g_multicastDataListMutex);
-        uint32_t arrayLength = u_arraylist_length(g_multicastDataList);
-        for (int i = 0; i < arrayLength; i++)
+        LEData *leData = serverInfo->pendingDataList->data;
+        if (CA_STATUS_OK != CAUpdateCharacteristicsToGattServerImpl(
+                serverInfo, leData->data, leData->dataLength))
         {
-            CALEData_t *multicastData = u_arraylist_get(g_multicastDataList, i);
-            if (NULL == multicastData)
-            {
-                OIC_LOG(DEBUG, TAG, "multicastData is NULL");
-                continue;
-            }
-            CAUpdateCharacteristicsToGattServer(remoteAddress, multicastData->data,
-                                                multicastData->dataLen, LE_UNICAST, 0);
+            OIC_LOG_V(ERROR, TAG, "Failed to send pending data to [%s]",
+                      serverInfo->remoteAddress);
+
+            CADestroyLEDataList(&serverInfo->pendingDataList);
+            break;
         }
-        ca_mutex_unlock(g_multicastDataListMutex);
+        CARemoveLEDataFromList(&serverInfo->pendingDataList);
     }
+    oc_mutex_unlock(g_LEServerListMutex);
 
     OIC_LOG(DEBUG, TAG, "OUT");
     return CA_STATUS_OK;
+
+error_exit:
+    bt_gatt_client_destroy(serverInfo->clientHandle);
+    serverInfo->clientHandle = NULL;
+    oc_mutex_unlock(g_LEServerListMutex);
+    CALEGattDisConnect(remoteAddress);
+    return CA_STATUS_FAILED;
 }
 
-CAResult_t  CAUpdateCharacteristicsToGattServer(const char *remoteAddress,
-                                                const uint8_t *data, const uint32_t dataLen,
-                                                CALETransferType_t type, const int32_t position)
+CAResult_t CAUpdateCharacteristicsToGattServer(const char *remoteAddress,
+        const uint8_t *data, const uint32_t dataLen,
+        CALETransferType_t type, const int32_t position)
 {
     OIC_LOG(DEBUG, TAG, "IN");
 
     VERIFY_NON_NULL(data, TAG, "data is NULL");
 
-    if (0 >= dataLen)
+    if (0 == dataLen)
     {
         OIC_LOG(ERROR, TAG, "dataLen is less than or equal zero. Invalid input!");
         return CA_STATUS_INVALID_PARAM;
     }
 
-    LEServerInfo *leServerInfo = NULL;
-    CAResult_t ret =  CA_STATUS_FAILED;
-
-    ca_mutex_lock(g_LEServerListMutex);
+    LEServerInfo *serverInfo = NULL;
+    bool isConnected = false;
+    oc_mutex_lock(g_LEServerListMutex);
     if (LE_UNICAST == type)
     {
-        ret = CAGetLEServerInfo(g_LEServerList, remoteAddress, &leServerInfo);
-    }
-    else if (LE_MULTICAST == type)
-    {
-        ret = CAGetLEServerInfoByPosition(g_LEServerList, position, &leServerInfo);
-    }
-    ca_mutex_unlock(g_LEServerListMutex);
+        if (CA_STATUS_OK != CAGetLEServerInfo(g_LEServerList, remoteAddress, &serverInfo))
+        {
+            OIC_LOG_V(DEBUG, TAG,
+                      "Device with address [%s] not yet found, initiating scan",
+                      remoteAddress);
 
-    if (CA_STATUS_OK != ret)
-    {
-        OIC_LOG(ERROR, TAG, "CAGetBLEServiceInfoByPosition is failed");
-        return CA_STATUS_FAILED;
-    }
+            char *addr = OICStrdup(remoteAddress);
+            if (NULL == addr)
+            {
+                oc_mutex_unlock(g_LEServerListMutex);
+                OIC_LOG(ERROR, TAG, "Device address is NULL");
+                return CA_STATUS_FAILED;
+            }
+            serverInfo = (LEServerInfo *)OICCalloc(1, sizeof(LEServerInfo));
+            if (NULL == serverInfo)
+            {
+                oc_mutex_unlock(g_LEServerListMutex);
+                OIC_LOG(ERROR, TAG, "Calloc failed");
+                OICFree(addr);
+                return CA_STATUS_FAILED;
+            }
+            serverInfo->remoteAddress = addr;
+            serverInfo->status = LE_STATUS_UNICAST_PENDING;
 
-    VERIFY_NON_NULL(leServerInfo, TAG, "bleServiceInfo is NULL");
+            if (CA_STATUS_OK != CAAddLEServerInfoToList(&g_LEServerList, serverInfo))
+            {
+                oc_mutex_unlock(g_LEServerListMutex);
+                OIC_LOG_V(ERROR, TAG, "Could not add [%s] to server list", remoteAddress);
+                CAFreeLEServerInfo(serverInfo);
+                return CA_STATUS_FAILED;
+            }
 
-    OIC_LOG_V(DEBUG, TAG, "Updating the data of length [%d] to [%s] ", dataLen,
-              leServerInfo->remoteAddress);
+            if (CA_STATUS_OK != CAAddLEDataToList(&serverInfo->pendingDataList, data, dataLen))
+            {
+                oc_mutex_unlock(g_LEServerListMutex);
+                OIC_LOG(ERROR, TAG, "Could not add data to pending list");
+                return CA_STATUS_FAILED;
+            }
+        }
 
-    int result = bt_gatt_set_value(leServerInfo->writeChar, (char *)data, dataLen);
+        if(serverInfo->status == LE_STATUS_UNICAST_PENDING)
+        {
 
-    if (BT_ERROR_NONE != result)
-    {
-        OIC_LOG_V(ERROR, TAG,
-                  "bt_gatt_set_value Failed with return val [%s]",
-                  CALEGetErrorMsg(result));
-        return CA_STATUS_FAILED;
-    }
+            int ret = bt_device_is_profile_connected(remoteAddress, BT_PROFILE_GATT, &isConnected);
+            if (BT_ERROR_NONE != ret)
+            {
+                OIC_LOG_V(ERROR, TAG, "bt_device_is_profile_connected Failed with ret value [%s] ",
+                          CALEGetErrorMsg(ret));
+                oc_mutex_unlock(g_LEServerListMutex);
+                return CA_STATUS_FAILED;
+            }
 
-    result = bt_gatt_client_write_value(leServerInfo->writeChar, CALEGattCharacteristicWriteCb,
-                                        NULL);
-    if (BT_ERROR_NONE != result)
-    {
-        OIC_LOG_V(ERROR, TAG,
-                  "bt_gatt_client_write_value Failed with return val [%s]",
-                  CALEGetErrorMsg(result));
-        return CA_STATUS_FAILED;
-    }
+            if (isConnected){
+                OIC_LOG_V(DEBUG, TAG, "Already connected to address [%s]", remoteAddress);
+                serverInfo->status = LE_STATUS_CONNECTED;
+            } else {
+                oc_mutex_lock(g_scanMutex);
+                if (!g_isMulticastInProgress && !g_isUnicastScanInProgress)
+                {
+                    CAResult_t result = CALEGattStartDeviceScanning();
+                    if (CA_STATUS_OK != result)
+                    {
+                        oc_mutex_unlock(g_scanMutex);
+                        OIC_LOG(ERROR, TAG, "CALEGattStartDeviceScanning failed");
+                        oc_mutex_unlock(g_LEServerListMutex);
+                        return CA_STATUS_FAILED;
+                    }
+                    g_isUnicastScanInProgress = true;
+                    // Start Timer
+                    oc_cond_signal(g_startTimerCond);
+                }
+                else
+                {
+                    g_isUnicastScanInProgress = true;
+                    // Reset Timer
+                    oc_cond_signal(g_scanningTimeCond);
+                }
+                oc_mutex_unlock(g_scanMutex);
+              }
 
-    // wait for callback for write Characteristic with success to sent data
-    OIC_LOG_V(DEBUG, TAG, "callback flag is %d", g_isSignalSetFlag);
-    ca_mutex_lock(g_threadWriteCharacteristicMutex);
-    if (!g_isSignalSetFlag)
-    {
-        OIC_LOG(DEBUG, TAG, "wait for callback to notify writeCharacteristic is success");
-        if (CA_WAIT_SUCCESS != ca_cond_wait_for(g_threadWriteCharacteristicCond,
-                                  g_threadWriteCharacteristicMutex,
-                                  WAIT_TIME_WRITE_CHARACTERISTIC))
+        }
+
+        if (serverInfo->status == LE_STATUS_CONNECTED)
         {
-            OIC_LOG(ERROR, TAG, "there is no response. write has failed");
-            g_isSignalSetFlag = false;
-            ca_mutex_unlock(g_threadWriteCharacteristicMutex);
-            return CA_SEND_FAILED;
+            oc_mutex_lock(g_LEClientThreadPoolMutex);
+            if (NULL == g_LEClientThreadPool)
+            {
+                oc_mutex_unlock(g_LEClientThreadPoolMutex);
+                OIC_LOG(ERROR, TAG, "g_LEClientThreadPool is NULL");
+                oc_mutex_unlock(g_LEServerListMutex);
+                return CA_STATUS_FAILED;
+            }
+            char *addr = OICStrdup(remoteAddress);
+            if (NULL == addr)
+            {
+                oc_mutex_unlock(g_LEClientThreadPoolMutex);
+                OIC_LOG(ERROR, TAG, "addr is NULL");
+                oc_mutex_unlock(g_LEServerListMutex);
+                return CA_STATUS_FAILED;
+            }
+            CAResult_t ret = ca_thread_pool_add_task(g_LEClientThreadPool, CADiscoverLEServicesThread,
+                                                     addr, NULL);
+            oc_mutex_unlock(g_LEClientThreadPoolMutex);
+            if (CA_STATUS_OK != ret)
+            {
+                OIC_LOG_V(ERROR, TAG, "ca_thread_pool_add_task failed with ret [%d]", ret);
+                OICFree(addr);
+            }
         }
-    }
-    // reset flag set by writeCharacteristic Callback
-    g_isSignalSetFlag = false;
-    ca_mutex_unlock(g_threadWriteCharacteristicMutex);
 
+        if (serverInfo->status == LE_STATUS_DISCOVERED)
+        {
+            if (CA_STATUS_OK != CAAddLEDataToList(&serverInfo->pendingDataList, data, dataLen))
+            {
+                oc_mutex_unlock(g_LEServerListMutex);
+                OIC_LOG(ERROR, TAG, "Could not add data to pending list");
+                return CA_STATUS_FAILED;
+            }
+
+            bt_gatt_client_h clientHandle = NULL;
+            int32_t ret = bt_gatt_client_create(serverInfo->remoteAddress, &clientHandle);
+            if (BT_ERROR_NONE != ret || NULL == clientHandle)
+            {
+                OIC_LOG_V(ERROR, TAG,
+                          "bt_gatt_client_create Failed with ret value [%s] ", CALEGetErrorMsg(ret));
+                CALEGattDisConnect(serverInfo->remoteAddress);
+                oc_mutex_unlock(g_LEServerListMutex);
+                return CA_STATUS_FAILED;
+            }
+            serverInfo->clientHandle = clientHandle;
+
+            serverInfo->status = LE_STATUS_CONNECTION_INITIATED;
+            if (CA_STATUS_OK != CALEGattInitiateConnection(serverInfo->remoteAddress))
+            {
+                OIC_LOG_V(ERROR, TAG, "Could not initiate connection to [%s]", serverInfo->remoteAddress);
+                serverInfo->status = LE_STATUS_DISCOVERED;
+                CADestroyLEDataList(&serverInfo->pendingDataList);
+                oc_mutex_unlock(g_LEServerListMutex);
+                return CA_STATUS_FAILED;
+            }
+        }
+        else if (serverInfo->status < LE_STATUS_SERVICES_DISCOVERED)
+        {
+            if (CA_STATUS_OK != CAAddLEDataToList(&serverInfo->pendingDataList, data, dataLen))
+            {
+                oc_mutex_unlock(g_LEServerListMutex);
+                OIC_LOG(ERROR, TAG, "Could not add data to pending list");
+                return CA_STATUS_FAILED;
+            }
+        }
+        else
+        {
+            if (CA_STATUS_OK != CAUpdateCharacteristicsToGattServerImpl(serverInfo, data, dataLen))
+            {
+                OIC_LOG_V(ERROR, TAG, "Could not update characteristic to gatt server [%s]",
+                          serverInfo->remoteAddress);
+                oc_mutex_unlock(g_LEServerListMutex);
+                return CA_STATUS_FAILED;
+            }
+        }
+    }
+    else if (LE_MULTICAST == type)
+    {
+        OIC_LOG(ERROR, TAG, "LE_MULTICAST type Not used");
+    }
+    oc_mutex_unlock(g_LEServerListMutex);
     OIC_LOG(DEBUG, TAG, "OUT");
     return CA_STATUS_OK;
 }
@@ -1140,32 +1686,38 @@ CAResult_t CAUpdateCharacteristicsToAllGattServers(const uint8_t *data, uint32_t
 
     VERIFY_NON_NULL(data, TAG, "data is NULL");
 
-    if (0 >= dataLen)
+    if (0 == dataLen)
     {
         OIC_LOG(ERROR, TAG, "dataLen is less than or equal zero. Invalid input !");
         return CA_STATUS_INVALID_PARAM;
     }
 
-    int numOfServersConnected = CAGetRegisteredServiceCount();
-
-    // Send data to already connected devices.
-    for (int32_t pos = 0; pos < numOfServersConnected; pos++)
+    oc_mutex_lock(g_LEServerListMutex);
+    LEServerInfoList *curNode = g_LEServerList;
+    while (curNode)
     {
-        /*remoteAddress will be NULL.
-          Since we have to send to all destinations. pos will be used for getting remote address.
-         */
-        int32_t ret = CAUpdateCharacteristicsToGattServer(NULL, data, dataLen, LE_MULTICAST, pos);
-
-        if (CA_STATUS_OK != ret)
+        LEServerInfo *serverInfo = curNode->serverInfo;
+        if (serverInfo->status == LE_STATUS_SERVICES_DISCOVERED)
+        {
+            if (CA_STATUS_OK != CAUpdateCharacteristicsToGattServerImpl(serverInfo, data, dataLen))
+            {
+                OIC_LOG_V(ERROR, TAG, "Failed to update characteristics to gatt server [%s]",
+                          serverInfo->remoteAddress);
+            }
+        }
+        else if (serverInfo->status != LE_STATUS_INVALID)
         {
-            OIC_LOG_V(ERROR, TAG,
-                      "CAUpdateCharacteristicsToGattServer Failed with return val [%d] ", ret);
-            g_clientErrorCallback(NULL, data, dataLen, ret);
+            if (CA_STATUS_OK != CAAddLEDataToList(&serverInfo->pendingDataList, data, dataLen))
+            {
+                OIC_LOG(ERROR, TAG, "Failed to add to pending list");
+            }
         }
+        curNode = curNode->next;
     }
+    oc_mutex_unlock(g_LEServerListMutex);
 
     // Add the data to pending list.
-    CALEData_t *multicastData = (CALEData_t *)OICCalloc(1, sizeof(CALEData_t));
+    LEData *multicastData = (LEData *)OICCalloc(1, sizeof(LEData));
     if (NULL == multicastData)
     {
         OIC_LOG(ERROR, TAG, "Calloc failed");
@@ -1178,30 +1730,83 @@ CAResult_t CAUpdateCharacteristicsToAllGattServers(const uint8_t *data, uint32_t
         goto exit;
     }
     memcpy(multicastData->data, data, dataLen);
-    multicastData->dataLen = dataLen;
+    multicastData->dataLength = dataLen;
 
-    ca_mutex_lock(g_multicastDataListMutex);
+    oc_mutex_lock(g_multicastDataListMutex);
     if (NULL == g_multicastDataList)
     {
         g_multicastDataList = u_arraylist_create();
     }
     u_arraylist_add(g_multicastDataList, (void *)multicastData);
-    ca_mutex_unlock(g_multicastDataListMutex);
+    oc_mutex_unlock(g_multicastDataListMutex);
 
-    // Start the scanning.
-    CAResult_t result = CALEGattStartDeviceScanning();
-    if (CA_STATUS_OK != result)
+    // Start the scanning, if not started, else reset timer
+    oc_mutex_lock(g_scanMutex);
+    if (!g_isMulticastInProgress && !g_isUnicastScanInProgress)
     {
-        OIC_LOG(ERROR, TAG, "CALEGattStartDeviceDiscovery Failed");
-        goto exit;
+        CAResult_t result = CALEGattStartDeviceScanning();
+        if (CA_STATUS_OK != result)
+        {
+            oc_mutex_unlock(g_scanMutex);
+            OIC_LOG(ERROR, TAG, "CALEGattStartDeviceScanning Failed");
+            goto exit;
+        }
+        g_isMulticastInProgress = true;
+        // Start the timer by signalling it
+        oc_cond_signal(g_startTimerCond);
     }
-
-    // Start the timer by signalling it.
-    ca_cond_signal(g_startTimerCond);
+    else
+    {
+        g_isMulticastInProgress = true;
+        // Reset timer
+        oc_cond_signal(g_scanningTimeCond);
+    }
+    oc_mutex_unlock(g_scanMutex);
 
 exit:
     OIC_LOG(DEBUG, TAG, "OUT ");
     return CA_STATUS_OK;
 }
 
+uint16_t CALEClientGetMtuSize(const char* remote_address)
+{
+    LEServerInfo *serverInfo = NULL;
+    oc_mutex_lock(g_LEServerListMutex);
+    if (CA_STATUS_OK == CAGetLEServerInfo(g_LEServerList, remote_address, &serverInfo))
+    {
+        if (serverInfo->status == LE_STATUS_SERVICES_DISCOVERED){
+            OIC_LOG_V(DEBUG, TAG, "Mtu Size [%d]", serverInfo->mtu_size);
+            oc_mutex_unlock(g_LEServerListMutex);
+            OIC_LOG_V(INFO, TAG, "Returning Mtu Size [%d]", serverInfo->mtu_size - CA_BLE_MTU_HEADER_SIZE);
+            return serverInfo->mtu_size - CA_BLE_MTU_HEADER_SIZE;
+        }
+    }
+    oc_mutex_unlock(g_LEServerListMutex);
+    return CA_DEFAULT_BLE_MTU_SIZE;
+
+}
+
+bool CALEClientIsConnected(const char* address)
+{
+    (void)address;
+    //@Todo
+    return true;
+}
+
+CAResult_t CALEClientSetMtuSize(const char* address, uint16_t mtuSize)
+{
+    (void)mtuSize;
 
+    VERIFY_NON_NULL(address, TAG, "address is null");
+    //@Todo
+    //it should be implemented after update Tizen 3.0
+    return CA_NOT_SUPPORTED;
+}
+
+CAResult_t CALEClientSendNegotiationMessage(const char* address)
+{
+    OIC_LOG_V(DEBUG, TAG, "CALEClientSendNegotiationMessage(%s)", address);
+    //@Todo
+    //it will be implemented when tizen public 3.0 is released.
+    return CA_NOT_SUPPORTED;
+}