Browse Source

qcacld-3.0: Add flow control to limit deauth per peer

Invalid peer keeps sending rx ind which triggers sending of
deauth mgmt frame continiously.

Fix is to add flow control in wma_rx_invalid_peer_ind()
to limit per peer deauth mgmt frame to one.

Change-Id: Icfbcb9452ee9890a26945b3cdd0c0ab07649367a
CRs-Fixed: 2538222
Amruta Kulkarni 5 years ago
parent
commit
f3773e9435
3 changed files with 105 additions and 8 deletions
  1. 25 2
      core/wma/inc/wma.h
  2. 76 6
      core/wma/src/wma_data.c
  3. 4 0
      core/wma/src/wma_dev_if.c

+ 25 - 2
core/wma/inc/wma.h

@@ -90,6 +90,7 @@
 #define wma_warn(params...) QDF_TRACE_WARN(QDF_MODULE_ID_WMA, params)
 #define wma_info(params...) QDF_TRACE_INFO(QDF_MODULE_ID_WMA, params)
 #define wma_debug(params...) QDF_TRACE_DEBUG(QDF_MODULE_ID_WMA, params)
+#define wma_debug_rl(params...) QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_WMA, params)
 #define wma_err_rl(params...) QDF_TRACE_ERROR_RL(QDF_MODULE_ID_WMA, params)
 
 #define wma_nofl_alert(params...) \
@@ -672,6 +673,16 @@ struct roam_synch_frame_ind {
 	uint8_t *reassoc_rsp;
 };
 
+/* Max number of invalid peer entries */
+#define INVALID_PEER_MAX_NUM 5
+
+/**
+ * struct wma_invalid_peer_params - stores invalid peer entries
+ * @rx_macaddr: store mac addr of invalid peer
+ */
+struct wma_invalid_peer_params {
+	uint8_t rx_macaddr[QDF_MAC_ADDR_SIZE];
+};
 
 /**
  * struct wma_txrx_node - txrx node
@@ -725,7 +736,8 @@ struct roam_synch_frame_ind {
  * @vdev_set_key_runtime_wakelock: runtime pm wakelock for set key
  * @ch_freq: channel frequency
  * @roam_scan_stats_req: cached roam scan stats request
- *
+ * @wma_invalid_peer_params: structure storing invalid peer params
+ * @invalid_peer_idx: invalid peer index
  * It stores parameters per vdev in wma.
  */
 struct wma_txrx_node {
@@ -785,6 +797,8 @@ struct wma_txrx_node {
 	bool is_waiting_for_key;
 	uint32_t ch_freq;
 	struct sir_roam_scan_stats *roam_scan_stats_req;
+	struct wma_invalid_peer_params invalid_peers[INVALID_PEER_MAX_NUM];
+	uint8_t invalid_peer_idx;
 };
 
 /**
@@ -2434,7 +2448,16 @@ void wma_check_and_set_wake_timer(uint32_t time);
 #endif
 
 /**
- * wma_rx_invalid_peer_ind(): the callback for DP to notify WMA layer
+ * wma_delete_invalid_peer_entries() - Delete invalid peer entries stored
+ * @vdev_id: virtual interface id
+ * @peer_mac_addr: Peer MAC address
+ *
+ * Removes the invalid peer mac entry from wma node
+ */
+void wma_delete_invalid_peer_entries(uint8_t vdev_id, uint8_t *peer_mac_addr);
+
+/**
+ * wma_rx_invalid_peer_ind() - the callback for DP to notify WMA layer
  * invalid peer data is received, this function will send message to
  * lim module.
  * @vdev_id: virtual device ID

+ 76 - 6
core/wma/src/wma_data.c

@@ -3091,27 +3091,97 @@ QDF_STATUS wma_lro_config_cmd(void *handle,
 						&wmi_lro_cmd);
 }
 
+void wma_delete_invalid_peer_entries(uint8_t vdev_id, uint8_t *peer_mac_addr)
+{
+	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
+	uint8_t i;
+	struct wma_txrx_node *iface;
+
+	if (!wma) {
+		wma_err("wma handle is NULL");
+		return;
+	}
+
+	iface = &wma->interfaces[vdev_id];
+
+	if (peer_mac_addr) {
+		for (i = 0; i < INVALID_PEER_MAX_NUM; i++) {
+			if (qdf_mem_cmp
+				      (iface->invalid_peers[i].rx_macaddr,
+				      peer_mac_addr,
+				      QDF_MAC_ADDR_SIZE) == 0) {
+				qdf_mem_zero(iface->invalid_peers[i].rx_macaddr,
+					     sizeof(QDF_MAC_ADDR_SIZE));
+				break;
+			}
+		}
+		if (i == INVALID_PEER_MAX_NUM)
+			wma_debug("peer_mac_addr %pM is not found", peer_mac_addr);
+	} else {
+		qdf_mem_zero(iface->invalid_peers,
+			     sizeof(iface->invalid_peers));
+	}
+}
+
 uint8_t wma_rx_invalid_peer_ind(uint8_t vdev_id, void *wh)
 {
 	struct ol_rx_inv_peer_params *rx_inv_msg;
 	struct ieee80211_frame *wh_l = (struct ieee80211_frame *)wh;
 	tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA);
+	uint8_t i, index;
+	bool invalid_peer_found = false;
+	struct wma_txrx_node *iface;
+
+	if (!wma) {
+		wma_err("wma handle is NULL");
+		return -EINVAL;
+	}
 
+	iface = &wma->interfaces[vdev_id];
 	rx_inv_msg = qdf_mem_malloc(sizeof(struct ol_rx_inv_peer_params));
 	if (!rx_inv_msg)
 		return -ENOMEM;
 
+	index = iface->invalid_peer_idx;
 	rx_inv_msg->vdev_id = vdev_id;
 	qdf_mem_copy(rx_inv_msg->ra, wh_l->i_addr1, QDF_MAC_ADDR_SIZE);
 	qdf_mem_copy(rx_inv_msg->ta, wh_l->i_addr2, QDF_MAC_ADDR_SIZE);
 
-	WMA_LOGD("%s: vdev_id %d", __func__, vdev_id);
-	wma_debug("RA:"QDF_MAC_ADDR_STR,
-		  QDF_MAC_ADDR_ARRAY(rx_inv_msg->ra));
-	wma_debug("TA:"QDF_MAC_ADDR_STR,
-		  QDF_MAC_ADDR_ARRAY(rx_inv_msg->ta));
 
-	wma_send_msg(wma, SIR_LIM_RX_INVALID_PEER, (void *)rx_inv_msg, 0);
+	for (i = 0; i < INVALID_PEER_MAX_NUM; i++) {
+		if (qdf_mem_cmp
+			      (iface->invalid_peers[i].rx_macaddr,
+			      rx_inv_msg->ra,
+			      QDF_MAC_ADDR_SIZE) == 0) {
+			invalid_peer_found = true;
+			break;
+		}
+	}
+
+	if (!invalid_peer_found) {
+		qdf_mem_copy(iface->invalid_peers[index].rx_macaddr,
+			     rx_inv_msg->ra,
+			    QDF_MAC_ADDR_SIZE);
+
+		/* reset count if reached max */
+		iface->invalid_peer_idx =
+			(index + 1) % INVALID_PEER_MAX_NUM;
+
+		/* send deauth */
+		WMA_LOGD("%s: vdev_id %d", __func__, vdev_id);
+		wma_debug(" RA: " QDF_MAC_ADDR_STR,
+			  QDF_MAC_ADDR_ARRAY(rx_inv_msg->ra));
+		wma_debug(" TA: " QDF_MAC_ADDR_STR,
+			  QDF_MAC_ADDR_ARRAY(rx_inv_msg->ta));
+
+		wma_send_msg(wma,
+			     SIR_LIM_RX_INVALID_PEER,
+			     (void *)rx_inv_msg, 0);
+	} else {
+		wma_debug_rl("Ignore invalid peer indication as received more than once "
+			QDF_MAC_ADDR_STR,
+			QDF_MAC_ADDR_ARRAY(rx_inv_msg->ra));
+	}
 
 	return 0;
 }

+ 4 - 0
core/wma/src/wma_dev_if.c

@@ -3966,6 +3966,8 @@ static void wma_add_sta_req_ap_mode(tp_wma_handle wma, tpAddStaParams add_sta)
 		goto send_rsp;
 	}
 
+	wma_delete_invalid_peer_entries(add_sta->smesessionId, add_sta->staMac);
+
 	status = wma_create_peer(wma, pdev, vdev, add_sta->staMac,
 				 WMI_PEER_TYPE_DEFAULT, add_sta->smesessionId,
 				 false);
@@ -5113,6 +5115,8 @@ void wma_delete_bss(tp_wma_handle wma, uint8_t vdev_id)
 		goto out;
 	}
 
+	wma_delete_invalid_peer_entries(vdev_id, NULL);
+
 	if (iface->psnr_req) {
 		qdf_mem_free(iface->psnr_req);
 		iface->psnr_req = NULL;