Merge tizen_5.0 codes into tizen_4.0
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / bt_le_adapter / tizen / caleclient.c
index c30ad82..6884a8e 100644 (file)
 #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"
 uint64_t const TIMEOUT = 30 * MICROSECS_PER_SEC;
 
 /**
+ * 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 +112,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 +123,34 @@ 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;
 
 /**
  * Flag to check status of write characteristic.
@@ -158,127 +178,230 @@ 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 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;
+    oc_mutex_unlock(g_isConnectionInProgressMutex);
+
+    // Pause the scanning
+    CALEGattStopDeviceScanning();
+
+    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;
+    }
 
-    // Start the scanning.
-    CAResult_t ret = CALEGattStartDeviceScanning();
-    if (CA_STATUS_OK != ret)
+    char *addr = OICStrdup(remoteAddress);
+    if (NULL == addr)
     {
-        OIC_LOG(ERROR, TAG, "CALEGattStartDeviceDiscovery Failed");
+        oc_mutex_unlock(g_LEClientThreadPoolMutex);
+        OIC_LOG(ERROR, TAG, "OICStrdup failed");
+        return CA_STATUS_FAILED;
     }
-    // Signal the start timer.
-    ca_cond_signal(g_scanningTimeCond);
+
+    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_V(ERROR, TAG,
+                  "ca_thread_pool_add_task failed with ret [%d]", res);
+        OICFree(addr);
+        return CA_STATUS_FAILED;
+    }
+    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);
+        oc_mutex_lock(g_LEServerListMutex);
+        CARemoveLEServerInfoFromList(&g_LEServerList, remoteAddress);
+        oc_mutex_unlock(g_LEServerListMutex);
     }
     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);
+
+        // Resume the scanning
+        oc_mutex_lock(g_scanMutex);
+        if (g_isMulticastInProgress || g_isUnicastScanInProgress)
+        {
+            CAResult_t ret = CALEGattStartDeviceScanning();
+            if (CA_STATUS_OK != ret)
+            {
+                OIC_LOG(ERROR, TAG, "CALEGattStartDeviceScanning Failed");
+            }
+        }
+        oc_mutex_unlock(g_scanMutex);
 
-        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);
+    }
+    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 +414,153 @@ 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)
-    {
-        g_deviceDiscoveredList = u_arraylist_create();
-    }
-    char *deviceAddr = OICStrdup(scanInfo->remote_address);
-    u_arraylist_add(g_deviceDiscoveredList, (void *) deviceAddr);
-    ca_mutex_unlock(g_deviceDiscoveredListMutex);
+    oc_mutex_lock(g_scanMutex);
+    bool isMulticastInProgress = g_isMulticastInProgress;
+    oc_mutex_unlock(g_scanMutex);
 
-    size_t len = strlen(scanInfo->remote_address);
+    LEServerInfo *serverInfo = NULL;
+    oc_mutex_lock(g_LEServerListMutex);
+    CAResult_t ret = CAGetLEServerInfo(g_LEServerList, scanInfo->remote_address, &serverInfo);
 
-    char *addr = (char *)OICMalloc(sizeof(char) * (len + 1));
-    VERIFY_NON_NULL_VOID(addr, TAG, "Malloc failed");
+    if (CA_STATUS_OK == ret && serverInfo->status == LE_STATUS_UNICAST_PENDING)
+    {
+        // Stop the scan if no other device is in unicast pending
+        // state and if multicast is not in progress
+        LEServerInfoList *curNode = g_LEServerList;
+        for (; curNode; curNode = curNode->next)
+        {
+            if (curNode->serverInfo == serverInfo)
+            {
+                continue;
+            }
+            if (curNode->serverInfo->status == LE_STATUS_UNICAST_PENDING)
+            {
+                break;
+            }
+        }
 
-    strncpy(addr, scanInfo->remote_address, len + 1);
+        if (NULL == curNode)
+        {
+            oc_mutex_lock(g_scanMutex);
+            if (!g_isMulticastInProgress && g_isUnicastScanInProgress)
+            {
+                CALEGattStopDeviceScanning();
+                g_isUnicastScanInProgress = false;
+                oc_cond_signal(g_scanningTimeCond);
+            }
+            oc_mutex_unlock(g_scanMutex);
+        }
 
-    OIC_LOG_V(DEBUG, TAG,
-              "Trying to do Gatt connection to [%s]", addr);
+        if (!CALEIsHaveService(scanInfo, CA_GATT_SERVICE_UUID))
+        {
+            serverInfo->status = LE_STATUS_INVALID;
+            OIC_LOG_V(DEBUG, TAG, "Device [%s] does not support OIC service", serverInfo->remoteAddress);
+            oc_mutex_unlock(g_LEServerListMutex);
+            return;
+        }
 
-    ca_mutex_lock(g_LEClientThreadPoolMutex);
-    if (NULL == g_LEClientThreadPool)
-    {
-        OIC_LOG(ERROR, TAG, "g_LEClientThreadPool is NULL");
-        OICFree(addr);
-        ca_mutex_unlock(g_LEClientThreadPoolMutex);
+        serverInfo->status = LE_STATUS_CONNECTION_INITIATED;
+        if (CA_STATUS_OK != CALEGattInitiateConnection(serverInfo->remoteAddress))
+        {
+            serverInfo->status = LE_STATUS_DISCOVERED;
+            OIC_LOG_V(ERROR, TAG, "Could not initiate connection to [%s]", serverInfo->remoteAddress);
+            oc_mutex_unlock(g_LEServerListMutex);
+            return;
+        }
+        oc_mutex_unlock(g_LEServerListMutex);
+        OIC_LOG(DEBUG, TAG, "OUT");
         return;
     }
 
-    CAResult_t res = ca_thread_pool_add_task(g_LEClientThreadPool, CAGattConnectThread, addr);
-    if (CA_STATUS_OK != res)
+    if (isMulticastInProgress)
     {
-        OIC_LOG_V(ERROR, TAG,
-                  "ca_thread_pool_add_task failed with ret [%d]", res);
-        OICFree(addr);
+        if (CA_STATUS_OK != ret)
+        {
+            OIC_LOG_V(DEBUG, TAG,
+                      "Newly discovered device with address [%s], adding to list", scanInfo->remote_address);
+
+            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;
+
+            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;
+            }
+
+            if (!CALEIsHaveService(scanInfo, CA_GATT_SERVICE_UUID))
+            {
+                serverInfo->status = LE_STATUS_INVALID;
+                OIC_LOG_V(DEBUG, TAG, "Device [%s] does not support OIC service", serverInfo->remoteAddress);
+                oc_mutex_unlock(g_LEServerListMutex);
+                return;
+            }
+
+            oc_mutex_lock(g_multicastDataListMutex);
+            uint32_t lengthData = u_arraylist_length(g_multicastDataList);
+            for (uint32_t len = 0; len < lengthData; ++len)
+            {
+                LEData *multicastData = (LEData *)u_arraylist_get(g_multicastDataList, len);
+                if (NULL == multicastData)
+                {
+                    OIC_LOG(ERROR, TAG, "multicastData is NULL");
+                    continue;
+                }
+                if (CA_STATUS_OK != CAAddLEDataToList(&serverInfo->pendingDataList,
+                                                      multicastData->data, multicastData->dataLength))
+                {
+                    OIC_LOG(ERROR, TAG, "Failed to add to pending list");
+                    continue;
+                }
+            }
+            oc_mutex_unlock(g_multicastDataListMutex);
+        }
+
+        if (serverInfo->status == LE_STATUS_DISCOVERED)
+        {
+            // Initiate connection if not yet initiated
+            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;
+            }
+        }
+        else
+        {
+            OIC_LOG_V(DEBUG, TAG, "Device already discovered, status= [%d]", serverInfo->status);
+        }
     }
-    ca_mutex_unlock(g_LEClientThreadPoolMutex);
+
+    oc_mutex_unlock(g_LEServerListMutex);
     OIC_LOG(DEBUG, TAG, "OUT");
 }
 
@@ -345,9 +568,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 +579,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 +597,86 @@ 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);
-
-    g_main_context_push_thread_default(thread_context);
-
-    g_main_loop_run(g_eventLoop);
+    oc_mutex_unlock(g_LEClientThreadPoolMutex);
 
     OIC_LOG(DEBUG, TAG, "OUT");
+    return CA_STATUS_OK;
 }
 
 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 +686,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 +702,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);
-
-    ca_mutex_lock(g_threadWriteCharacteristicMutex);
-    ca_cond_signal(g_threadWriteCharacteristicCond);
-    ca_mutex_unlock(g_threadWriteCharacteristicMutex);
+    oc_mutex_unlock(g_LEServerListMutex);
 
-    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 +731,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 +742,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,110 +774,130 @@ 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_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;
         }
     }
@@ -712,37 +910,43 @@ 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_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;
 
@@ -763,14 +967,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 +987,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 +1014,24 @@ 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;
+    }
+    else
+    {
+        OIC_LOG(DEBUG, TAG, "Ignore, scanning not in progress");
     }
+    oc_mutex_unlock(g_isScanningInProgressMutex);
 
     OIC_LOG(DEBUG, TAG, "OUT");
 }
@@ -833,21 +1065,22 @@ CAResult_t CALEGattConnect(const char *remoteAddress)
     VERIFY_NON_NULL_RET(remoteAddress, TAG,
                         "remote address is NULL", CA_STATUS_FAILED);
 
-    ca_mutex_lock(g_LEClientConnectMutex);
-
-    int ret = bt_gatt_connect(remoteAddress, true);
+    oc_mutex_lock(g_LEClientConnectMutex);
+    CAResult_t result = CA_STATUS_OK;
 
+    int ret = bt_gatt_connect(remoteAddress, false);
     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);
+        oc_mutex_unlock(g_LEClientConnectMutex);
         return CA_STATUS_FAILED;
     }
-    ca_mutex_unlock(g_LEClientConnectMutex);
+
+    oc_mutex_unlock(g_LEClientConnectMutex);
 
     OIC_LOG(DEBUG, TAG, "OUT");
-    return CA_STATUS_OK;
+    return result;
 }
 
 CAResult_t CALEGattDisConnect(const char *remoteAddress)
@@ -861,7 +1094,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;
     }
@@ -870,7 +1103,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");
 
@@ -919,7 +1231,7 @@ CAResult_t CALEGattDiscoverServices(const char *remoteAddress)
     // 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,
@@ -933,7 +1245,7 @@ CAResult_t CALEGattDiscoverServices(const char *remoteAddress)
     // 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,
@@ -947,9 +1259,17 @@ CAResult_t CALEGattDiscoverServices(const char *remoteAddress)
 
     //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");
+        bt_gatt_client_destroy(clientHandle);
+        CALEGattDisConnect(remoteAddress);
+        return CA_STATUS_FAILED;
+    }
+
     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,
@@ -960,56 +1280,46 @@ CAResult_t CALEGattDiscoverServices(const char *remoteAddress)
         return CA_STATUS_FAILED;
     }
 
-    LEServerInfo *serverInfo = (LEServerInfo *)OICCalloc(1, sizeof(LEServerInfo));
-    if (NULL == serverInfo)
+    LEServerInfo *serverInfo = NULL;
+    oc_mutex_lock(g_LEServerListMutex);
+    if (CA_STATUS_OK != CAGetLEServerInfo(g_LEServerList, remoteAddress, &serverInfo))
     {
-        OIC_LOG(ERROR, TAG, "Malloc failed");
+        oc_mutex_unlock(g_LEServerListMutex);
+        OIC_LOG_V(ERROR, TAG, "Could not get server info for [%s]", remoteAddress);
+        bt_gatt_client_destroy(clientHandle);
         CALEGattDisConnect(remoteAddress);
-        return CA_MEMORY_ALLOC_FAILED;
+        return CA_STATUS_FAILED;
     }
+
     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)
-    {
-        OIC_LOG(ERROR, TAG, "CAAddBLEClientInfoToList failed");
-        bt_gatt_client_destroy(clientHandle);
-        CALEGattDisConnect(remoteAddress);
-        return CA_STATUS_FAILED;
-    }
-    ca_mutex_unlock(g_LEServerListMutex);
+    serverInfo->status = LE_STATUS_SERVICES_DISCOVERED;
 
-    // Send the data of pending multicast data list if any.
-    if (g_multicastDataList)
+    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;
 }
 
-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");
 
@@ -1021,71 +1331,123 @@ CAResult_t  CAUpdateCharacteristicsToGattServer(const char *remoteAddress,
         return CA_STATUS_INVALID_PARAM;
     }
 
-    LEServerInfo *leServerInfo = NULL;
-    CAResult_t ret =  CA_STATUS_FAILED;
-
-    ca_mutex_lock(g_LEServerListMutex);
+    LEServerInfo *serverInfo = NULL;
+    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;
+            }
 
-    VERIFY_NON_NULL(leServerInfo, TAG, "bleServiceInfo is NULL");
+            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;
+            }
 
-    OIC_LOG_V(DEBUG, TAG, "Updating the data of length [%d] to [%s] ", dataLen,
-              leServerInfo->remoteAddress);
+            serverInfo->remoteAddress = addr;
+            serverInfo->status = LE_STATUS_UNICAST_PENDING;
 
-    int result = bt_gatt_set_value(leServerInfo->writeChar, (char *)data, dataLen);
+            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", serverInfo->remoteAddress);
+                CAFreeLEServerInfo(serverInfo);
+                return CA_STATUS_FAILED;
+            }
 
-    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;
-    }
+            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;
+            }
 
-    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;
-    }
+            oc_mutex_unlock(g_LEServerListMutex);
 
-    // 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))
+            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 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);
+
+            OIC_LOG(DEBUG, TAG, "OUT");
+            return CA_STATUS_OK;
+        }
+
+        if (serverInfo->status == LE_STATUS_DISCOVERED)
         {
-            OIC_LOG(ERROR, TAG, "there is no response. write has failed");
-            g_isSignalSetFlag = false;
-            ca_mutex_unlock(g_threadWriteCharacteristicMutex);
-            return CA_SEND_FAILED;
+            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;
+            }
+
+            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;
+            }
         }
     }
-    // reset flag set by writeCharacteristic Callback
-    g_isSignalSetFlag = false;
-    ca_mutex_unlock(g_threadWriteCharacteristicMutex);
-
+    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;
 }
@@ -1102,26 +1464,32 @@ CAResult_t CAUpdateCharacteristicsToAllGattServers(const uint8_t *data, uint32_t
         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)
         {
-            OIC_LOG_V(ERROR, TAG,
-                      "CAUpdateCharacteristicsToGattServer Failed with return val [%d] ", ret);
-            g_clientErrorCallback(NULL, data, dataLen, ret);
+            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)
+        {
+            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");
@@ -1134,30 +1502,73 @@ 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;
 }
 
+bool CALEClientIsConnected(const char* address)
+{
+    (void)address;
+    //@Todo
+    return true;
+}
+
+uint16_t CALEClientGetMtuSize(const char* address)
+{
+    VERIFY_NON_NULL_RET(address, TAG, "address is null", CA_DEFAULT_BLE_MTU_SIZE);
+    //@Todo
+    //it should be implemented after update Tizen 3.0
+    return CA_DEFAULT_BLE_MTU_SIZE;
+}
+
+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;
+}
\ No newline at end of file