瀏覽代碼

qcacld-3.0: Fix smmu fault when inject deauth frame

1. The original mgmt send path changed by converged p2p component, now
wma_tx_packet() will not invoke when sending station mode action
frames, it invokes p2p_mgmt_tx() instead. But for tx buffers of PMF
frames sending to some target require to do bi-direction dma map to
pass smmu sanity check, which is missed in p2p_mgmt_tx() path.
2. The offchan flag passed to wlan_hdd_mgmt_tx() is not always accurate.
There have been cases where the flag is set even though the operation is
taking place on the home channel, and blindly following the flag leads
to an unnecessary ROC.

Fix it by adding QDF_NBUF_CB_TX_DMA_BI_MAP to new p2p mgmt tx path and
bring back home channel check to override the offchan flag if
necessary.

Change-Id: I9589157e57e95d0c61a432f87a07630c4b77f757
CRs-Fixed: 2423341
Will Huang 6 年之前
父節點
當前提交
79af29fd46

+ 7 - 0
components/p2p/core/src/wlan_p2p_off_chan_tx.c

@@ -1548,6 +1548,13 @@ static QDF_STATUS p2p_populate_rmf_field(struct tx_action_context *tx_ctx,
 		*ppbuf = frame;
 		*ppkt = pkt;
 		*size = frame_len;
+		/*
+		 * Some target which support sending mgmt frame based on htt
+		 * would DMA write this PMF tx frame buffer, it may cause smmu
+		 * check permission fault, set a flag to do bi-direction DMA
+		 * map, normal tx unmap is enough for this case.
+		 */
+		QDF_NBUF_CB_TX_DMA_BI_MAP(pkt) = 1;
 	}
 
 	return status;

+ 11 - 0
core/hdd/inc/wlan_hdd_main.h

@@ -2025,6 +2025,17 @@ struct hdd_adapter *hdd_get_adapter_by_vdev(struct hdd_context *hdd_ctx,
 struct hdd_adapter *hdd_get_adapter_by_macaddr(struct hdd_context *hdd_ctx,
 					       tSirMacAddr mac_addr);
 
+/**
+ * hdd_get_adapter_home_channel() - return home channel of adapter
+ * @adapter: hdd adapter of vdev
+ *
+ * This function returns operation channel of station/p2p-cli if
+ * connected, returns opration channel of sap/p2p-go if started.
+ *
+ * Return: home channel if connected/started or invalid channel 0
+ */
+uint8_t hdd_get_adapter_home_channel(struct hdd_adapter *adapter);
+
 /*
  * hdd_get_adapter_by_rand_macaddr() - find Random mac adapter
  * @hdd_ctx: hdd context

+ 19 - 0
core/hdd/src/wlan_hdd_main.c

@@ -699,6 +699,25 @@ int hdd_validate_channel_and_bandwidth(struct hdd_adapter *adapter,
 	return 0;
 }
 
+uint8_t hdd_get_adapter_home_channel(struct hdd_adapter *adapter)
+{
+	uint8_t home_channel = 0;
+
+	if ((adapter->device_mode == QDF_SAP_MODE ||
+	     adapter->device_mode == QDF_P2P_GO_MODE) &&
+	    test_bit(SOFTAP_BSS_STARTED, &adapter->event_flags)) {
+		home_channel = adapter->session.ap.operating_channel;
+	} else if ((adapter->device_mode == QDF_STA_MODE ||
+		    adapter->device_mode == QDF_P2P_CLIENT_MODE) &&
+		   adapter->session.station.conn_info.conn_state ==
+		   eConnectionState_Associated) {
+		home_channel =
+			adapter->session.station.conn_info.channel;
+	}
+
+	return home_channel;
+}
+
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0))
 static inline struct net_device *hdd_net_dev_from_notifier(void *context)
 {

+ 37 - 0
core/hdd/src/wlan_hdd_p2p.c

@@ -222,6 +222,35 @@ int wlan_hdd_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
 	return errno;
 }
 
+/**
+ * wlan_hdd_validate_and_override_offchan() - To validate and override offchan
+ * @adapter: hdd adapter of vdev
+ * @chan: channel info of mgmt to be sent
+ * @offchan: off channel flag to check and override
+ *
+ * This function is to validate the channel info against adapter current state
+ * and home channel, if off channel not needed, override offchan flag.
+ *
+ * Return: None
+ */
+static void
+wlan_hdd_validate_and_override_offchan(struct hdd_adapter *adapter,
+				       struct ieee80211_channel *chan,
+				       bool *offchan)
+{
+	uint8_t home_ch;
+
+	if (!offchan || !chan || !(*offchan))
+		return;
+
+	home_ch = hdd_get_adapter_home_channel(adapter);
+
+	if (ieee80211_frequency_to_channel(chan->center_freq) == home_ch) {
+		hdd_debug("override offchan to 0 at home channel %d", home_ch);
+		*offchan = false;
+	}
+}
+
 static int __wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
 			      struct ieee80211_channel *chan, bool offchan,
 			      unsigned int wait,
@@ -278,6 +307,14 @@ static int __wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
 			return -EINVAL;
 	}
 
+	hdd_debug("device_mode:%d type:%d sub_type:%d chan:%d",
+		  adapter->device_mode, type, sub_type,
+		  chan ? chan->center_freq : 0);
+	hdd_debug("wait:%d offchan:%d do_not_wait_ack:%d",
+		  wait, offchan, dont_wait_for_ack);
+
+	wlan_hdd_validate_and_override_offchan(adapter, chan, &offchan);
+
 	qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_OS_IF,
 		   TRACE_CODE_HDD_SEND_MGMT_TX,
 		   wlan_vdev_get_id(adapter->vdev), 0);