wlan: Check if cancel ROC is started before canceling existing ROC

If ROC is in progress and an new ROC session is requested, as part
of new ROC request the existing ROC need to be canceled. But
while canceling existing ROC the driver doesnot check if cancel ROC
has already started, which may lead to resume link called twice and
in this case gLimResumeLink callback is not set to NULL.

Thus next time when ROC is called the finish scan request is not
sent to firmware assuming finish scan is already sent as
gLimResumeLink callback is not NULL. This leads to back to back
init scan request to firmware which cause crash.

Check if cancel ROC is started before canceling existing ROC.

CRs-Fixed: 887489
Change-Id: I5ee609713d27bcf383d35893a10c20b5d27635a4
diff --git a/CORE/HDD/src/wlan_hdd_p2p.c b/CORE/HDD/src/wlan_hdd_p2p.c
index 7a2f93b..23547e9 100644
--- a/CORE/HDD/src/wlan_hdd_p2p.c
+++ b/CORE/HDD/src/wlan_hdd_p2p.c
@@ -304,44 +304,67 @@
                 return VOS_STATUS_E_FAILURE;
             }
 
-            INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var);
             mutex_lock(&pHddCtx->roc_lock);
-            pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = TRUE;
-            mutex_unlock(&pHddCtx->roc_lock);
+            /* Check again if cancel remain on channel is started.
+             * If its started wait for its completiona and return.
+             */
+            if (TRUE == pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress)
+            {
+                mutex_unlock(&pHddCtx->roc_lock);
+                hddLog( LOG1,
+                      "ROC timer cancellation in progress,"
+                      " wait for completion");
+                status = wait_for_completion_interruptible_timeout(
+                                     &pAdapter->cancel_rem_on_chan_var,
+                                     msecs_to_jiffies(WAIT_CANCEL_REM_CHAN));
+                if (0 >= status)
+                {
+                    hddLog( LOGE,
+                          "%s:wait on cancel_rem_on_chan_var failed %d",
+                           __func__, status);
+                    return VOS_STATUS_E_FAILURE;
+                }
+                return VOS_STATUS_SUCCESS;
+            }
+            else
+                pRemainChanCtx->hdd_remain_on_chan_cancel_in_progress = TRUE;
 
-             /* Issue abort remain on chan request to sme.
-              * The remain on channel callback will make sure the remain_on_chan
-              * expired event is sent.
-              */
-              if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
+            mutex_unlock(&pHddCtx->roc_lock);
+            INIT_COMPLETION(pAdapter->cancel_rem_on_chan_var);
+
+            /* Issue abort remain on chan request to sme.
+             * The remain on channel callback will make sure the remain_on_chan
+             * expired event is sent.
+             */
+            if ( ( WLAN_HDD_INFRA_STATION == pAdapter->device_mode ) ||
                    ( WLAN_HDD_P2P_CLIENT == pAdapter->device_mode ) ||
                    ( WLAN_HDD_P2P_DEVICE == pAdapter->device_mode ))
-              {
-                  if (eHAL_STATUS_SUCCESS !=
-                          sme_CancelRemainOnChannel( WLAN_HDD_GET_HAL_CTX( pAdapter ),
+            {
+                if (eHAL_STATUS_SUCCESS !=
+                    sme_CancelRemainOnChannel( WLAN_HDD_GET_HAL_CTX( pAdapter ),
                                                      pAdapter->sessionId ))
-                  {
-                      VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
-                              FL("Failed to Cancel Remain on Channel"));
-                  }
-              }
-              else if (WLAN_HDD_P2P_GO == pAdapter->device_mode)
-              {
-                  WLANSAP_CancelRemainOnChannel(
-                          (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
-              }
+                {
+                    VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,
+                            FL("Failed to Cancel Remain on Channel"));
+                }
+            }
+            else if (WLAN_HDD_P2P_GO == pAdapter->device_mode)
+            {
+                 WLANSAP_CancelRemainOnChannel(
+                         (WLAN_HDD_GET_CTX(pAdapter))->pvosContext);
+            }
 
-              status = wait_for_completion_interruptible_timeout(
-                                       &pAdapter->cancel_rem_on_chan_var,
-                                       msecs_to_jiffies(WAIT_CANCEL_REM_CHAN));
-              if (0 >= status)
-              {
-                  hddLog( LOGE,
-                          "%s: timeout waiting for cancel remain on channel"
-                          " ready indication %d",
-                           __func__, status);
-              }
-              hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC);
+            status = wait_for_completion_interruptible_timeout(
+                                    &pAdapter->cancel_rem_on_chan_var,
+                                    msecs_to_jiffies(WAIT_CANCEL_REM_CHAN));
+            if (0 >= status)
+            {
+                hddLog( LOGE,
+                       "%s: timeout waiting for cancel remain on channel"
+                         " ready indication %d",
+                          __func__, status);
+            }
+            hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_ROC);
          }
          else
          {