Pārlūkot izejas kodu

qcacld-3.0: Avoid sending frame before ready on channel event

If the ROC is requested from the supplicant, the driver sends
scan request to the firmware. The driver start the timeout after
receiving ready on channel event from the firmware. While packet
transmission, if the channel is same and timer is not running,
the driver assumes that it is in the listen channel and thus
transmits the frame. But this condition even meets while the
driver waits for ready on channel event, and thus, it sends
the frame in the wrong channel.

The fix is to wait for the ready on channel event if the timer
is not running. The change also address that ROC is dequeued only
after cancel ROC is completed.

Change-Id: If35c75e4bda4f11913a1326896754f29ac43946a
CRs-Fixed: 2005917
Nitesh Shah 8 gadi atpakaļ
vecāks
revīzija
a438c1898f
1 mainītis faili ar 31 papildinājumiem un 12 dzēšanām
  1. 31 12
      core/hdd/src/wlan_hdd_p2p.c

+ 31 - 12
core/hdd/src/wlan_hdd_p2p.c

@@ -225,15 +225,6 @@ QDF_STATUS wlan_hdd_remain_on_channel_callback(tHalHandle hHal, void *pCtx,
 	req_type = pRemainChanCtx->rem_on_chan_request;
 	mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
 
-	/* Schedule any pending RoC: Any new roc request during this time
-	 * would have got queued in 'wlan_hdd_request_remain_on_channel'
-	 * since the queue is not empty. So, the roc at the head of the
-	 * queue will only get the priority. Scheduling the work queue
-	 * after sending any cancel remain on channel event will also
-	 * ensure that the cancel roc is sent without any delays.
-	 */
-	schedule_delayed_work(&hdd_ctx->roc_req_work, 0);
-
 	if ((QDF_STA_MODE == pAdapter->device_mode) ||
 	    (QDF_P2P_CLIENT_MODE == pAdapter->device_mode) ||
 	    (QDF_P2P_DEVICE_MODE == pAdapter->device_mode)
@@ -270,6 +261,17 @@ QDF_STATUS wlan_hdd_remain_on_channel_callback(tHalHandle hHal, void *pCtx,
 	complete(&pAdapter->cancel_rem_on_chan_var);
 	if (QDF_STATUS_SUCCESS != status)
 		complete(&pAdapter->rem_on_chan_ready_event);
+
+	/* If we schedule work queue to start new RoC before completing
+	 * cancel_rem_on_chan_var then the work queue may immediately get
+	 * scheduled and update cfgState->remain_on_chan_ctx which is referred
+	 * in mgmt_tx. Due to this update the the mgmt_tx may extend the roc
+	 * which was already completed. This will lead to mgmt tx failure.
+	 * Always schedule below work queue only after completing the
+	 * cancel_rem_on_chan_var event.
+	 */
+	schedule_delayed_work(&hdd_ctx->roc_req_work, 0);
+
 	return QDF_STATUS_SUCCESS;
 }
 
@@ -1514,9 +1516,26 @@ static int __wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
 			mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
 
 		mutex_lock(&cfgState->remain_on_chan_ctx_lock);
-		if ((cfgState->remain_on_chan_ctx != NULL) &&
-		    (cfgState->current_freq == chan->center_freq)
-		    ) {
+		pRemainChanCtx = cfgState->remain_on_chan_ctx;
+
+		/* At this point if remain_on_chan_ctx exists but timer not
+		 * running means that roc workqueue requested a new RoC and it
+		 * is in progress. So wait for Ready on channel indication */
+		if ((pRemainChanCtx) &&
+			(QDF_TIMER_STATE_RUNNING !=
+			 qdf_mc_timer_get_current_state(
+				 &pRemainChanCtx->hdd_remain_on_chan_timer))) {
+			hdd_notice("remain_on_chan_ctx exists but RoC timer not running. wait for ready on channel");
+			rc = wait_for_completion_timeout(&pAdapter->
+					rem_on_chan_ready_event,
+					msecs_to_jiffies
+					(WAIT_REM_CHAN_READY));
+			if (!rc)
+				hdd_err("timeout waiting for remain on channel ready indication");
+		}
+
+		if ((pRemainChanCtx != NULL) &&
+			(cfgState->current_freq == chan->center_freq)) {
 			mutex_unlock(&cfgState->remain_on_chan_ctx_lock);
 			hdd_notice("action frame: extending the wait time");
 			extendedWait = (uint16_t) wait;