Merge tizen_5.0 codes into tizen_4.0
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / bt_le_adapter / tizen / caleclient.c
index a829960..6884a8e 100644 (file)
 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 oc_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 oc_mutex g_deviceDiscoveredListMutex = NULL;
+static oc_mutex g_multicastDataListMutex = NULL;
 
 /**
  * Condition to start the timer for scanning.
@@ -157,77 +178,6 @@ static GMainLoop *g_eventLoop = NULL;
  */
 static ca_thread_pool_t g_LEClientThreadPool = NULL;
 
-bool CALEIsHaveService(bt_adapter_le_device_scan_result_info_s* scanInfo, char* service_uuid)
-{
-    bool ret = false;
-    char **uuids = NULL;
-    int count = 0;
-    int result = 0;
-
-    // For arduino servers, scan response will give the UUIDs advertised.
-    result = bt_adapter_le_get_scan_result_service_uuids(scanInfo,
-                                                         BT_ADAPTER_LE_PACKET_SCAN_RESPONSE,
-                                                         &uuids, &count);
-    if (result == BT_ERROR_NONE && NULL != uuids)
-    {
-        int i;
-        for (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);
-    }
-
-    // For android/tizen servers, advertising packet will give the UUIDs.
-    result = bt_adapter_le_get_scan_result_service_uuids(scanInfo,
-                                                         BT_ADAPTER_LE_PACKET_ADVERTISING,
-                                                         &uuids, &count);
-    if (result == BT_ERROR_NONE && NULL != uuids)
-    {
-        int i;
-        for (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;
-}
-
-bool CALEIsDeviceDiscovered(const char * address)
-{
-    if (g_deviceDiscoveredList)
-    {
-        oc_mutex_lock(g_deviceDiscoveredListMutex);
-        uint32_t arrayLength = u_arraylist_length(g_deviceDiscoveredList);
-        for (uint32_t i = 0; i < arrayLength; i++)
-        {
-            char *deviceAddr = u_arraylist_get(g_deviceDiscoveredList, i);
-            if (0 == strcasecmp(deviceAddr, address))
-            {
-                oc_mutex_unlock(g_deviceDiscoveredListMutex);
-                return true;
-            }
-
-        }
-        oc_mutex_unlock(g_deviceDiscoveredListMutex);
-    }
-    return false;
-}
-
 void CALEGattCharacteristicChangedCb(bt_gatt_h characteristic,
                                      char *value,
                                      int valueLen, void *userData)
@@ -285,20 +235,60 @@ void CALEGattCharacteristicWriteCb(int result, bt_gatt_h reqHandle, void *userDa
     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);
 
-    // Start the scanning.
-    CAResult_t ret = CALEGattStartDeviceScanning();
-    if (CA_STATUS_OK != ret)
+    oc_mutex_lock(g_LEClientThreadPoolMutex);
+    if (NULL == g_LEClientThreadPool)
     {
-        OIC_LOG(ERROR, TAG, "CALEGattStartDeviceDiscovery Failed");
+        oc_mutex_unlock(g_LEClientThreadPoolMutex);
+        OIC_LOG(ERROR, TAG, "g_LEClientThreadPool is NULL");
+        return CA_STATUS_FAILED;
     }
-    // Signal the start timer.
-    oc_cond_signal(g_scanningTimeCond);
+
+    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_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)
     {
@@ -311,34 +301,102 @@ void CALEGattConnectionStateChanged(bool connected, const char *remoteAddress)
     {
         OIC_LOG_V(DEBUG, TAG, "Connected to [%s] ", remoteAddress);
 
-        char *addr = OICStrdup(remoteAddress);
-        if (NULL == addr)
+        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)
         {
-            OIC_LOG(ERROR, TAG, "addr is NULL");
+            CAResult_t ret = CALEGattStartDeviceScanning();
+            if (CA_STATUS_OK != ret)
+            {
+                OIC_LOG(ERROR, TAG, "CALEGattStartDeviceScanning Failed");
+            }
+        }
+        oc_mutex_unlock(g_scanMutex);
+
+        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);
+            return;
+        }
+
+        char *addr = OICStrdup(remoteAddress);
+        if (NULL == addr)
+        {
             oc_mutex_unlock(g_LEClientThreadPoolMutex);
+            OIC_LOG(ERROR, TAG, "addr is NULL");
             return;
         }
 
-        ret = ca_thread_pool_add_task(g_LEClientThreadPool, CADiscoverLEServicesThread,
-                                      addr, NULL);
+        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);
         }
-        oc_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)
 {
@@ -356,65 +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);
+
+    oc_mutex_lock(g_scanMutex);
+    bool isMulticastInProgress = g_isMulticastInProgress;
+    oc_mutex_unlock(g_scanMutex);
+
+    LEServerInfo *serverInfo = NULL;
+    oc_mutex_lock(g_LEServerListMutex);
+    CAResult_t ret = CAGetLEServerInfo(g_LEServerList, scanInfo->remote_address, &serverInfo);
 
-    if (!CALEIsHaveService(scanInfo, CA_GATT_SERVICE_UUID))
+    if (CA_STATUS_OK == ret && serverInfo->status == LE_STATUS_UNICAST_PENDING)
     {
-        oc_mutex_lock(g_deviceDiscoveredListMutex);
-        // Add the the device Discovered list.
-        if (NULL == g_deviceDiscoveredList)
+        // 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;
+            }
+        }
+
+        if (NULL == curNode)
         {
-            g_deviceDiscoveredList = u_arraylist_create();
+            oc_mutex_lock(g_scanMutex);
+            if (!g_isMulticastInProgress && g_isUnicastScanInProgress)
+            {
+                CALEGattStopDeviceScanning();
+                g_isUnicastScanInProgress = false;
+                oc_cond_signal(g_scanningTimeCond);
+            }
+            oc_mutex_unlock(g_scanMutex);
         }
-        char *deviceAddr = OICStrdup(scanInfo->remote_address);
-        if (NULL == deviceAddr)
+
+        if (!CALEIsHaveService(scanInfo, CA_GATT_SERVICE_UUID))
         {
-            OIC_LOG_V(ERROR, TAG, "Device address is NULL");
-            oc_mutex_unlock(g_deviceDiscoveredListMutex);
+            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;
         }
 
-        u_arraylist_add(g_deviceDiscoveredList, (void *) deviceAddr);
-        oc_mutex_unlock(g_deviceDiscoveredListMutex);
-        OIC_LOG_V(INFO, TAG, "Device[%s] is don't have service", scanInfo->remote_address);
+        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;
     }
 
-    // Stop the scan before invoking bt_gatt_connect().
-    CALEGattStopDeviceScanning();
+    if (isMulticastInProgress)
+    {
+        if (CA_STATUS_OK != ret)
+        {
+            OIC_LOG_V(DEBUG, TAG,
+                      "Newly discovered device with address [%s], adding to list", scanInfo->remote_address);
 
-    size_t len = strlen(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;
 
-    char *addr = (char *)OICMalloc(sizeof(char) * (len + 1));
-    VERIFY_NON_NULL_VOID(addr, TAG, "Malloc failed");
+            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;
+            }
 
-    strncpy(addr, scanInfo->remote_address, len + 1);
+            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;
+            }
 
-    OIC_LOG_V(DEBUG, TAG,
-              "Trying to do Gatt connection to [%s]", addr);
+            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);
+        }
 
-    oc_mutex_lock(g_LEClientThreadPoolMutex);
-    if (NULL == g_LEClientThreadPool)
-    {
-        OIC_LOG(ERROR, TAG, "g_LEClientThreadPool is NULL");
-        OICFree(addr);
-        oc_mutex_unlock(g_LEClientThreadPoolMutex);
-        return;
+        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);
+        }
     }
 
-    CAResult_t res = ca_thread_pool_add_task(g_LEClientThreadPool, CAGattConnectThread, addr, NULL);
-    if (CA_STATUS_OK != res)
-    {
-        OIC_LOG_V(ERROR, TAG,
-                  "ca_thread_pool_add_task failed with ret [%d]", res);
-        OICFree(addr);
-    }
-    oc_mutex_unlock(g_LEClientThreadPoolMutex);
+    oc_mutex_unlock(g_LEServerListMutex);
     OIC_LOG(DEBUG, TAG, "OUT");
 }
 
@@ -502,22 +648,16 @@ void CAStartTimerThread(void *data)
     OIC_LOG(DEBUG, TAG, "IN");
     while (g_isLEGattClientStarted)
     {
-        oc_mutex_lock(g_multicastDataListMutex);
-        if (!g_isMulticastInProgress)
+        oc_mutex_lock(g_scanMutex);
+        if (!g_isMulticastInProgress && !g_isUnicastScanInProgress)
         {
             OIC_LOG(DEBUG, TAG, "waiting....");
-            oc_cond_wait(g_startTimerCond, g_multicastDataListMutex);
+            oc_cond_wait(g_startTimerCond, g_scanMutex);
             OIC_LOG(DEBUG, TAG, "Wake up");
-            g_isMulticastInProgress = true;
-
-            if (!g_isLEGattClientStarted)
-            {
-               break;
-            }
         }
 
         // Timed conditional wait for stopping the scan.
-        OCWaitResult_t ret = oc_cond_wait_for(g_scanningTimeCond, g_multicastDataListMutex,
+        OCWaitResult_t ret = oc_cond_wait_for(g_scanningTimeCond, g_scanMutex,
                                               TIMEOUT);
         if (OC_WAIT_TIMEDOUT == ret)
         {
@@ -525,18 +665,18 @@ void CAStartTimerThread(void *data)
             // Call stop scan.
             CALEGattStopDeviceScanning();
 
-            // Clear the data list and device list.
-            u_arraylist_destroy(g_multicastDataList);
-            g_multicastDataList = NULL;
-
-            oc_mutex_lock(g_deviceDiscoveredListMutex);
-            u_arraylist_destroy(g_deviceDiscoveredList);
-            g_deviceDiscoveredList = NULL;
-            oc_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;
         }
-        oc_mutex_unlock(g_multicastDataListMutex);
+        oc_mutex_unlock(g_scanMutex);
     }
 
     OIC_LOG(DEBUG, TAG, "OUT");
@@ -559,8 +699,6 @@ void CAStopLEGattClient()
 
     CALEGattStopDeviceScanning();
 
-    // this flag should be set before signal g_startTimerCond.
-    // since scan thread can be stopped through this flag.
     g_isLEGattClientStarted = false;
 
     // Signal the conditions waiting in Start timer.
@@ -576,14 +714,6 @@ void CAStopLEGattClient()
         oc_mutex_unlock(g_multicastDataListMutex);
     }
 
-    if (NULL != g_deviceDiscoveredList)
-    {
-        oc_mutex_lock(g_deviceDiscoveredListMutex);
-        u_arraylist_destroy(g_deviceDiscoveredList);
-        g_deviceDiscoveredList = NULL;
-        oc_mutex_unlock(g_deviceDiscoveredListMutex);
-    }
-
     oc_mutex_lock(g_LEServerListMutex);
     CAFreeLEServerList(g_LEServerList);
     g_LEServerList = NULL;
@@ -593,8 +723,6 @@ void CAStopLEGattClient()
     oc_cond_signal(g_threadWriteCharacteristicCond);
     oc_mutex_unlock(g_threadWriteCharacteristicMutex);
 
-    CAResetRegisteredServiceCount();
-
     GMainContext  *context_event_loop = NULL;
     // Required for waking up the thread which is running in gmain loop
     if (NULL != g_eventLoop)
@@ -694,6 +822,26 @@ CAResult_t CAInitGattClientMutexVariables()
         }
     }
 
+    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 = oc_mutex_new();
@@ -704,10 +852,10 @@ CAResult_t CAInitGattClientMutexVariables()
         }
     }
 
-    if (NULL == g_deviceDiscoveredListMutex)
+    if (NULL == g_scanMutex)
     {
-        g_deviceDiscoveredListMutex = oc_mutex_new();
-        if (NULL == g_deviceDiscoveredListMutex)
+        g_scanMutex = oc_mutex_new();
+        if (NULL == g_scanMutex)
         {
             OIC_LOG(ERROR, TAG, "oc_mutex_new failed");
             return CA_STATUS_FAILED;
@@ -777,11 +925,17 @@ void CATerminateGattClientMutexVariables()
     oc_mutex_free(g_LEClientThreadPoolMutex);
     g_LEClientThreadPoolMutex = NULL;
 
+    oc_mutex_free(g_isScanningInProgressMutex);
+    g_isScanningInProgressMutex = NULL;
+
+    oc_mutex_free(g_isConnectionInProgressMutex);
+    g_isConnectionInProgressMutex = NULL;
+
     oc_mutex_free(g_multicastDataListMutex);
     g_multicastDataListMutex = NULL;
 
-    oc_mutex_free(g_deviceDiscoveredListMutex);
-    g_deviceDiscoveredListMutex = NULL;
+    oc_mutex_free(g_scanMutex);
+    g_scanMutex = NULL;
 
     oc_mutex_free(g_threadWriteCharacteristicMutex);
     g_threadWriteCharacteristicMutex = NULL;
@@ -813,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");
 }
 
@@ -828,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;
@@ -844,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");
 }
@@ -884,60 +1066,17 @@ CAResult_t CALEGattConnect(const char *remoteAddress)
                         "remote address is NULL", CA_STATUS_FAILED);
 
     oc_mutex_lock(g_LEClientConnectMutex);
-    bool isConnected = false;
-    int ret = bt_device_is_profile_connected(remoteAddress, BT_PROFILE_GATT, &isConnected);
+    CAResult_t result = CA_STATUS_OK;
+
+    int ret = bt_gatt_connect(remoteAddress, false);
     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));
         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));
-            oc_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");
-            oc_mutex_unlock(g_LEClientConnectMutex);
-            return CA_STATUS_FAILED;
-        }
-
-        oc_mutex_lock(g_LEClientThreadPoolMutex);
-        if (NULL == g_LEClientThreadPool)
-        {
-            OIC_LOG(ERROR, TAG, "g_LEClientThreadPool is NULL");
-            OICFree(addr);
-            oc_mutex_unlock(g_LEClientThreadPoolMutex);
-            oc_mutex_unlock(g_LEClientConnectMutex);
-            return CA_STATUS_FAILED;
-        }
-
-        result = ca_thread_pool_add_task(g_LEClientThreadPool, CADiscoverLEServicesThread,
-                                         addr, NULL);
-        if (CA_STATUS_OK != result)
-        {
-            OIC_LOG_V(ERROR, TAG, "ca_thread_pool_add_task failed with ret [%d]", result);
-            OICFree(addr);
-        }
-        oc_mutex_unlock(g_LEClientThreadPoolMutex);
-    }
     oc_mutex_unlock(g_LEClientConnectMutex);
 
     OIC_LOG(DEBUG, TAG, "OUT");
@@ -964,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");
 
@@ -989,50 +1207,13 @@ CAResult_t CALEGattDiscoverServices(const char *remoteAddress)
     VERIFY_NON_NULL_RET(remoteAddress, TAG,
                         "remote address is NULL", CA_STATUS_FAILED);
 
-    LEServerInfo *leServerInfo = NULL;
-    CAResult_t result =  CA_STATUS_FAILED;
-
-    oc_mutex_lock(g_LEServerListMutex);
-    result = CAGetLEServerInfo(g_LEServerList, remoteAddress, &leServerInfo);
-    oc_mutex_unlock(g_LEServerListMutex);
-
-    if (CA_STATUS_OK == result)
-    {
-        OIC_LOG_V(INFO, TAG, "Device[%s] is already discovered", leServerInfo->remoteAddress);
-
-        // Send the data of pending multicast data list if any.
-        if (g_multicastDataList)
-        {
-            oc_mutex_lock(g_multicastDataListMutex);
-            uint32_t arrayLength = u_arraylist_length(g_multicastDataList);
-            for (uint32_t i = 0; i < arrayLength; i++)
-            {
-                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);
-            }
-            oc_mutex_unlock(g_multicastDataListMutex);
-        }
-
-        OIC_LOG(DEBUG, TAG, "OUT");
-        return CA_STATUS_OK;
-    }
-    else
-    {
-        OIC_LOG_V(INFO, TAG, "CAGetLEServerInfo [%s] is failed, %d", remoteAddress, result);
-    }
-
     bt_gatt_client_h clientHandle = NULL;
     int32_t ret = bt_gatt_client_create(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(remoteAddress);
         return CA_STATUS_FAILED;
     }
 
@@ -1043,13 +1224,14 @@ CAResult_t CALEGattDiscoverServices(const char *remoteAddress)
         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;
     }
 
     // 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,
@@ -1063,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,
@@ -1086,8 +1268,8 @@ CAResult_t CALEGattDiscoverServices(const char *remoteAddress)
     }
 
     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,
@@ -1098,72 +1280,46 @@ CAResult_t CALEGattDiscoverServices(const char *remoteAddress)
         return CA_STATUS_FAILED;
     }
 
-    LEServerInfo *serverInfo = (LEServerInfo *)OICCalloc(1, sizeof(LEServerInfo));
-    if (NULL == serverInfo)
-    {
-        OIC_LOG(ERROR, TAG, "Malloc failed");
-        CALEGattDisConnect(remoteAddress);
-        return CA_MEMORY_ALLOC_FAILED;
-    }
-    serverInfo->clientHandle = clientHandle;
-    serverInfo->serviceHandle = serviceHandle;
-    serverInfo->readChar = readChrHandle;
-    serverInfo->writeChar = writeChrHandle;
-    serverInfo->remoteAddress = OICStrdup(remoteAddress);
-
+    LEServerInfo *serverInfo = NULL;
     oc_mutex_lock(g_LEServerListMutex);
-    result = CAAddLEServerInfoToList(&g_LEServerList, serverInfo);
-    if (CA_STATUS_OK != result)
+    if (CA_STATUS_OK != CAGetLEServerInfo(g_LEServerList, remoteAddress, &serverInfo))
     {
-        OIC_LOG(ERROR, TAG, "CAAddLEServerInfoToList 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_STATUS_FAILED;
     }
-    oc_mutex_unlock(g_LEServerListMutex);
 
-    oc_mutex_lock(g_deviceDiscoveredListMutex);
-    // Add the the device Discovered list.
-    if (NULL == g_deviceDiscoveredList)
-    {
-        g_deviceDiscoveredList = u_arraylist_create();
-    }
-    char *deviceAddr = OICStrdup(remoteAddress);
-    if (NULL == deviceAddr)
-    {
-        OIC_LOG_V(ERROR, TAG, "Device address is NULL");
-        oc_mutex_unlock(g_deviceDiscoveredListMutex);
-        return CA_STATUS_FAILED;
-    }
-    u_arraylist_add(g_deviceDiscoveredList, (void *) deviceAddr);
-    oc_mutex_unlock(g_deviceDiscoveredListMutex);
+    serverInfo->clientHandle = clientHandle;
+    serverInfo->serviceHandle = serviceHandle;
+    serverInfo->readChar = readChrHandle;
+    serverInfo->writeChar = writeChrHandle;
+    serverInfo->status = LE_STATUS_SERVICES_DISCOVERED;
 
-    // Send the data of pending multicast data list if any.
-    if (g_multicastDataList)
+    while (serverInfo->pendingDataList)
     {
-        oc_mutex_lock(g_multicastDataListMutex);
-        uint32_t arrayLength = u_arraylist_length(g_multicastDataList);
-        for (uint32_t 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;
         }
-        oc_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");
 
@@ -1175,71 +1331,123 @@ CAResult_t  CAUpdateCharacteristicsToGattServer(const char *remoteAddress,
         return CA_STATUS_INVALID_PARAM;
     }
 
-    LEServerInfo *leServerInfo = NULL;
-    CAResult_t ret =  CA_STATUS_FAILED;
-
+    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);
-    }
-    oc_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);
-    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))
+            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;
-            oc_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;
-    oc_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;
 }
@@ -1256,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");
@@ -1288,7 +1502,7 @@ CAResult_t CAUpdateCharacteristicsToAllGattServers(const uint8_t *data, uint32_t
         goto exit;
     }
     memcpy(multicastData->data, data, dataLen);
-    multicastData->dataLen = dataLen;
+    multicastData->dataLength = dataLen;
 
     oc_mutex_lock(g_multicastDataListMutex);
     if (NULL == g_multicastDataList)
@@ -1298,16 +1512,28 @@ CAResult_t CAUpdateCharacteristicsToAllGattServers(const uint8_t *data, uint32_t
     u_arraylist_add(g_multicastDataList, (void *)multicastData);
     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.
-    oc_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 ");
@@ -1345,4 +1571,4 @@ CAResult_t CALEClientSendNegotiationMessage(const char* address)
     //@Todo
     //it will be implemented when tizen public 3.0 is released.
     return CA_NOT_SUPPORTED;
-}
+}
\ No newline at end of file