浏览代码

qcacmn: Add Non Association WDS(NAWDS) Support for Lithium

Add API to handle NAWDS packets on tx side.
Add API to handle invalid peers and pass them to umac.

Change-Id: Ie8c2508e4f51c7d6969c9eb6439919c57dd427d4
CRs-Fixed: 2008205
Ishank Jain 8 年之前
父节点
当前提交
9f174c6e2f
共有 9 个文件被更改,包括 231 次插入6 次删除
  1. 11 1
      dp/inc/cdp_txrx_cmn_struct.h
  2. 18 0
      dp/inc/cdp_txrx_ctrl.h
  3. 5 0
      dp/inc/cdp_txrx_ops.h
  4. 34 0
      dp/wifi3.0/dp_main.c
  5. 73 0
      dp/wifi3.0/dp_rx.c
  6. 1 0
      dp/wifi3.0/dp_rx.h
  7. 2 1
      dp/wifi3.0/dp_rx_err.c
  8. 69 4
      dp/wifi3.0/dp_tx.c
  9. 18 0
      dp/wifi3.0/dp_types.h

+ 11 - 1
dp/inc/cdp_txrx_cmn_struct.h

@@ -401,7 +401,17 @@ struct cdp_soc_t {
 	struct ol_if_ops *ol_ops;
 };
 
-
+/*
+ * cdp_vdev_param_type: different types of parameters
+ *			to set values in vdev
+ * @CDP_ENABLE_NAWDS: set nawds enable/disable
+ * @CDP_ENABLE_MCAST_EN: enable/disable multicast enhancement
+ *
+ */
+enum cdp_vdev_param_type {
+	CDP_ENABLE_NAWDS,
+	CDP_ENABLE_MCAST_EN,
+};
 
 #define TXRX_FW_STATS_TXSTATS                     1
 #define TXRX_FW_STATS_RXSTATS                     2

+ 18 - 0
dp/inc/cdp_txrx_ctrl.h

@@ -288,4 +288,22 @@ static inline void cdp_tx_flush_buffers
 	return;
 }
 
+static inline void cdp_txrx_set_vdev_param(ol_txrx_soc_handle soc,
+		struct cdp_vdev *vdev, enum cdp_vdev_param_type type,
+		uint32_t val)
+{
+	if (soc->ops->ctrl_ops->txrx_set_vdev_param)
+		return soc->ops->ctrl_ops->txrx_set_vdev_param(vdev, type, val);
+	return;
+}
+
+static inline void
+cdp_peer_set_nawds(ol_txrx_soc_handle soc,
+		struct ol_txrx_peer_t *peer, uint8_t value)
+{
+	if (soc->ops->ctrl_ops->txrx_peer_set_nawds)
+		return soc->ops->ctrl_ops->txrx_peer_set_nawds
+			(peer, value);
+	return;
+}
 #endif

+ 5 - 0
dp/inc/cdp_txrx_ops.h

@@ -359,6 +359,10 @@ struct cdp_ctrl_ops {
 
 	int (*txrx_is_target_ar900b)(struct cdp_vdev *vdev);
 
+	void (*txrx_set_vdev_param)(struct cdp_vdev *vdev,
+			enum cdp_vdev_param_type param, uint32_t val);
+
+	void (*txrx_peer_set_nawds)(void *peer, uint8_t value);
 };
 
 struct cdp_me_ops {
@@ -557,6 +561,7 @@ struct ol_if_ops {
 			struct cdp_lro_hash_config *lro_hash);
 	void (*update_dp_stats)(void *soc, void *stats, uint16_t id,
 			uint8_t type);
+	uint8_t (*rx_invalid_peer)(void *osif_pdev, void *msg);
 
 	/* TODO: Add any other control path calls required to OL_IF/WMA layer */
 };

+ 34 - 0
dp/wifi3.0/dp_main.c

@@ -2960,6 +2960,38 @@ dp_get_peer_stats(struct cdp_pdev *pdev_handle, char *mac_addr)
 		dp_print_peer_stats(peer);
 		return;
 }
+/*
+ * dp_set_vdev_param: function to set parameters in vdev
+ * @param: parameter type to be set
+ * @val: value of parameter to be set
+ *
+ * return: void
+ */
+static void dp_set_vdev_param(struct cdp_vdev *vdev_handle,
+		enum cdp_vdev_param_type param, uint32_t val)
+{
+	struct dp_vdev *vdev = (struct dp_vdev *)vdev_handle;
+
+	switch (param) {
+	case CDP_ENABLE_NAWDS:
+		vdev->nawds_enabled = val;
+	default:
+		break;
+	}
+}
+
+/**
+ * dp_peer_set_nawds: set nawds bit in peer
+ * @peer_handle: pointer to peer
+ * @value: enable/disable nawds
+ *
+ * return: void
+ */
+static void dp_peer_set_nawds(void *peer_handle, uint8_t value)
+{
+	struct dp_peer *peer = (struct dp_peer *)peer_handle;
+	peer->nawds_enabled = value;
+}
 
 /*
  * dp_set_vdev_dscp_tid_map_wifi3(): Update Map ID selected for particular vdev
@@ -3065,6 +3097,8 @@ static struct cdp_ctrl_ops dp_ops_ctrl = {
 	.txrx_set_mesh_mode  = dp_peer_set_mesh_mode,
 	.txrx_set_mesh_rx_filter = dp_peer_set_mesh_rx_filter,
 #endif
+	.txrx_set_vdev_param = dp_set_vdev_param,
+	.txrx_peer_set_nawds = dp_peer_set_nawds,
 	/* TODO: Add other functions */
 };
 

+ 73 - 0
dp/wifi3.0/dp_rx.c

@@ -495,6 +495,78 @@ QDF_STATUS dp_rx_filter_mesh_packets(struct dp_vdev *vdev, qdf_nbuf_t nbuf)
 
 #endif
 
+#ifdef CONFIG_WIN
+/**
+ * dp_rx_process_invalid_peer(): Function to pass invalid peer list to umac
+ * @soc: DP SOC handle
+ * @nbuf: nbuf for which peer is invalid
+ *
+ * return: integer type
+ */
+uint8_t dp_rx_process_invalid_peer(struct dp_soc *soc, qdf_nbuf_t nbuf)
+{
+	struct dp_invalid_peer_msg msg;
+	struct dp_vdev *vdev = NULL;
+	struct dp_pdev *pdev = NULL;
+	struct ieee80211_frame *wh;
+	uint8_t i;
+	uint8_t *rx_pkt_hdr;
+
+	rx_pkt_hdr = qdf_nbuf_data(nbuf);
+	wh = (struct ieee80211_frame *)rx_pkt_hdr;
+
+	if (!DP_FRAME_IS_DATA(wh)) {
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
+				"NAWDS valid only for data frames");
+		return 1;
+	}
+
+	if (qdf_nbuf_len(nbuf) < sizeof(struct ieee80211_frame)) {
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+				"Invalid nbuf length");
+		return 1;
+	}
+
+
+	for (i = 0; i < MAX_PDEV_CNT; i++) {
+		pdev = soc->pdev_list[i];
+		if (!pdev) {
+			QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+					"PDEV not found");
+			continue;
+		}
+
+		TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) {
+			if (qdf_mem_cmp(wh->i_addr1, vdev->mac_addr.raw,
+						DP_MAC_ADDR_LEN) == 0) {
+				goto out;
+			}
+		}
+	}
+
+	if (!vdev) {
+		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
+				"VDEV not found");
+		return 1;
+	}
+
+out:
+	msg.wh = wh;
+	msg.nbuf = nbuf;
+	msg.vdev_id = vdev->vdev_id;
+	if (pdev->soc->cdp_soc.ol_ops->rx_invalid_peer)
+		return pdev->soc->cdp_soc.ol_ops->rx_invalid_peer(
+				pdev->osif_pdev, &msg);
+
+	return 0;
+}
+#else
+uint8_t dp_rx_process_invalid_peer(struct dp_soc *soc, qdf_nbuf_t nbuf)
+{
+	return 0;
+}
+#endif
+
 /**
  * dp_rx_process() - Brain of the Rx processing functionality
  *		     Called from the bottom half (tasklet/NET_RX_SOFTIRQ)
@@ -717,6 +789,7 @@ done:
 			/* Peer lookup failed */
 			if (!peer && !vdev) {
 
+				dp_rx_process_invalid_peer(soc, nbuf);
 				/* Drop & free packet */
 				qdf_nbuf_free(nbuf);
 

+ 1 - 0
dp/wifi3.0/dp_rx.h

@@ -256,6 +256,7 @@ dp_rx_wds_srcport_learn(struct dp_soc *soc,
 }
 #endif
 
+uint8_t dp_rx_process_invalid_peer(struct dp_soc *soc, qdf_nbuf_t nbuf);
 #define DP_RX_LIST_APPEND(head, tail, elem) \
 do {                                                \
 	if (!(head)) {                              \

+ 2 - 1
dp/wifi3.0/dp_rx_err.c

@@ -274,7 +274,8 @@ dp_rx_null_q_desc_handle(struct dp_soc *soc, struct dp_rx_desc *rx_desc,
 	if (!peer) {
 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
 		FL("peer is NULL"));
-		qdf_nbuf_free(nbuf);
+		qdf_nbuf_pull_head(nbuf, RX_PKT_TLVS_LEN);
+		dp_rx_process_invalid_peer(soc, nbuf);
 		goto fail;
 	}
 

+ 69 - 4
dp/wifi3.0/dp_tx.c

@@ -830,20 +830,23 @@ static void dp_tx_classify_tid(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
  * @nbuf: skb
  * @tid: TID from HLOS for overriding default DSCP-TID mapping
  * @tx_q: Tx queue to be used for this Tx frame
+ * @peer_id: peer_id of the peer in case of NAWDS frames
  *
  * Return: NULL on success,
  *         nbuf when it fails to send
  */
 static qdf_nbuf_t dp_tx_send_msdu_single(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
 		uint8_t tid, struct dp_tx_queue *tx_q,
-		uint32_t *meta_data)
+		uint32_t *meta_data, uint16_t peer_id)
 {
 	struct dp_pdev *pdev = vdev->pdev;
 	struct dp_soc *soc = pdev->soc;
 	struct dp_tx_desc_s *tx_desc;
 	QDF_STATUS status;
 	void *hal_srng = soc->tcl_data_ring[tx_q->ring_id].hal_srng;
+	uint16_t htt_tcl_metadata = 0;
 
+	HTT_TX_TCL_METADATA_VALID_HTT_SET(htt_tcl_metadata, 0);
 	/* Setup Tx descriptor for an MSDU, and MSDU extension descriptor */
 	tx_desc = dp_tx_prepare_desc_single(vdev, nbuf, tx_q->desc_pool_id, meta_data);
 	if (!tx_desc) {
@@ -862,9 +865,17 @@ static qdf_nbuf_t dp_tx_send_msdu_single(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
 		goto fail_return;
 	}
 
+	if (qdf_unlikely(peer_id != HTT_INVALID_PEER)) {
+		HTT_TX_TCL_METADATA_TYPE_SET(htt_tcl_metadata,
+				HTT_TCL_METADATA_TYPE_PEER_BASED);
+		HTT_TX_TCL_METADATA_PEER_ID_SET(htt_tcl_metadata,
+				peer_id);
+	} else
+		htt_tcl_metadata = vdev->htt_tcl_metadata;
+
 	/* Enqueue the Tx MSDU descriptor to HW for transmit */
 	status = dp_tx_hw_enqueue(soc, vdev, tx_desc, tid,
-		vdev->htt_tcl_metadata,	tx_q->ring_id);
+			htt_tcl_metadata, tx_q->ring_id);
 
 	if (status != QDF_STATUS_SUCCESS) {
 		QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
@@ -1160,6 +1171,49 @@ void dp_tx_extract_mesh_meta_data(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
 
 #endif
 
+/**
+ * dp_tx_prepare_nawds(): Tramit NAWDS frames
+ * @vdev: dp_vdev handle
+ * @nbuf: skb
+ * @tid: TID from HLOS for overriding default DSCP-TID mapping
+ * @tx_q: Tx queue to be used for this Tx frame
+ * @meta_data: Meta date for mesh
+ * @peer_id: peer_id of the peer in case of NAWDS frames
+ *
+ * return: NULL on success nbuf on failure
+ */
+static qdf_nbuf_t dp_tx_prepare_nawds(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
+		uint8_t tid, struct dp_tx_queue *tx_q, uint32_t *meta_data,
+		uint32_t peer_id)
+{
+	struct dp_peer *peer = NULL;
+	qdf_nbuf_t nbuf_copy;
+	TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) {
+		if ((peer->peer_ids[0] != HTT_INVALID_PEER) &&
+				(peer->nawds_enabled || peer->bss_peer)) {
+			nbuf_copy = qdf_nbuf_copy(nbuf);
+			if (!nbuf_copy) {
+				QDF_TRACE(QDF_MODULE_ID_DP,
+						QDF_TRACE_LEVEL_ERROR,
+						"nbuf copy failed");
+			}
+
+			peer_id = peer->peer_ids[0];
+			nbuf_copy = dp_tx_send_msdu_single(vdev, nbuf_copy, tid,
+					tx_q, meta_data, peer_id);
+			if (nbuf_copy != NULL) {
+				qdf_nbuf_free(nbuf);
+				return nbuf_copy;
+			}
+		}
+	}
+	if (peer_id == HTT_INVALID_PEER)
+		return nbuf;
+
+	qdf_nbuf_free(nbuf);
+	return NULL;
+}
+
 /**
  * dp_tx_send() - Transmit a frame on a given VAP
  * @vap_dev: DP vdev handle
@@ -1174,10 +1228,11 @@ void dp_tx_extract_mesh_meta_data(struct dp_vdev *vdev, qdf_nbuf_t nbuf,
  */
 qdf_nbuf_t dp_tx_send(void *vap_dev, qdf_nbuf_t nbuf)
 {
-	struct ether_header *eh;
+	struct ether_header *eh = NULL;
 	struct dp_tx_msdu_info_s msdu_info;
 	struct dp_tx_seg_info_s seg_info;
 	struct dp_vdev *vdev = (struct dp_vdev *) vap_dev;
+	uint16_t peer_id = HTT_INVALID_PEER;
 
 	qdf_mem_set(&msdu_info, sizeof(msdu_info), 0x0);
 	qdf_mem_set(&seg_info, sizeof(seg_info), 0x0);
@@ -1294,6 +1349,16 @@ qdf_nbuf_t dp_tx_send(void *vap_dev, qdf_nbuf_t nbuf)
 
 	}
 
+	if (vdev->nawds_enabled) {
+		eh = (struct ether_header *)qdf_nbuf_data(nbuf);
+		if (DP_FRAME_IS_MULTICAST((eh)->ether_dhost)) {
+			nbuf = dp_tx_prepare_nawds(vdev, nbuf, msdu_info.tid,
+					&msdu_info.tx_queue,
+					msdu_info.meta_data, peer_id);
+			return nbuf;
+		}
+	}
+
 	/*  Single linear frame */
 	/*
 	 * If nbuf is a simple linear frame, use send_single function to
@@ -1301,7 +1366,7 @@ qdf_nbuf_t dp_tx_send(void *vap_dev, qdf_nbuf_t nbuf)
 	 * SRNG. There is no need to setup a MSDU extension descriptor.
 	 */
 	nbuf = dp_tx_send_msdu_single(vdev, nbuf, msdu_info.tid,
-			&msdu_info.tx_queue, msdu_info.meta_data);
+			&msdu_info.tx_queue, msdu_info.meta_data, peer_id);
 
 	return nbuf;
 

+ 18 - 0
dp/wifi3.0/dp_types.h

@@ -104,6 +104,10 @@ union dp_rx_desc_list_elem_t;
      (_a)[4] == 0xff &&                         \
      (_a)[5] == 0xff)
 #define IS_LLC_PRESENT(typeorlen) ((typeorlen) >= 0x600)
+#define DP_FRAME_FC0_TYPE_MASK 0x0c
+#define DP_FRAME_FC0_TYPE_DATA 0x08
+#define DP_FRAME_IS_DATA(_frame) \
+	(((_frame)->i_fc[0] & DP_FRAME_FC0_TYPE_MASK) == DP_FRAME_FC0_TYPE_DATA)
 
 /**
  * macros to convert hw mac id to sw mac id:
@@ -968,4 +972,18 @@ struct dp_peer {
 	TAILQ_HEAD(, dp_ast_entry) ast_entry_list;
 	/* TBD */
 };
+
+#ifdef CONFIG_WIN
+/*
+ * dp_invalid_peer_msg
+ * @nbuf: data buffer
+ * @wh: 802.11 header
+ * @vdev_id: id of vdev
+ */
+struct dp_invalid_peer_msg {
+	qdf_nbuf_t nbuf;
+	struct ieee80211_frame *wh;
+	uint8_t vdev_id;
+};
+#endif
 #endif /* _DP_TYPES_H_ */