Browse Source

qcacmn: Add support for GCMP in rx de-fragmentation

GCMP header and MIC are not removed for received
fragments which will result in incorrect ethertype
and presence of LLC hdr in the data when the frames
are sent to network stack.

Fix is to add support for GCMP in rx de-fragmentation
path.

Change-Id: I83ed29a766e40e32f4b712342ebd40d08a2c65e0
CRs-Fixed: 2941879
Yeshwanth Sriram Guntuka 4 năm trước cách đây
mục cha
commit
548c146aa0
1 tập tin đã thay đổi với 57 bổ sung0 xóa
  1. 57 0
      dp/wifi3.0/dp_rx_defrag.c

+ 57 - 0
dp/wifi3.0/dp_rx_defrag.c

@@ -51,6 +51,17 @@ const struct dp_rx_defrag_cipher dp_f_wep = {
 	0,
 };
 
+/*
+ * The header and mic length are same for both
+ * GCMP-128 and GCMP-256.
+ */
+const struct dp_rx_defrag_cipher dp_f_gcmp = {
+	"AES-GCMP",
+	WLAN_IEEE80211_GCMP_HEADERLEN,
+	WLAN_IEEE80211_GCMP_MICLEN,
+	WLAN_IEEE80211_GCMP_MICLEN,
+};
+
 /*
  * dp_rx_defrag_frames_free(): Free fragment chain
  * @frames: Fragment chain
@@ -1414,6 +1425,36 @@ static QDF_STATUS dp_rx_defrag_reo_reinject(struct dp_peer *peer,
 }
 #endif
 
+/*
+ * dp_rx_defrag_gcmp_demic(): Remove MIC information from GCMP fragment
+ * @nbuf: Pointer to the fragment buffer
+ * @hdrlen: 802.11 header length
+ *
+ * Remove MIC information from GCMP fragment
+ *
+ * Returns: QDF_STATUS
+ */
+static QDF_STATUS dp_rx_defrag_gcmp_demic(qdf_nbuf_t nbuf, uint16_t hdrlen)
+{
+	uint8_t *ivp, *orig_hdr;
+	int rx_desc_len = SIZE_OF_DATA_RX_TLV;
+
+	/* start of the 802.11 header */
+	orig_hdr = (uint8_t *)(qdf_nbuf_data(nbuf) + rx_desc_len);
+
+	/*
+	 * GCMP header is located after 802.11 header and EXTIV
+	 * field should always be set to 1 for GCMP protocol.
+	 */
+	ivp = orig_hdr + hdrlen;
+	if (!(ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV))
+		return QDF_STATUS_E_DEFRAG_ERROR;
+
+	qdf_nbuf_trim_tail(nbuf, dp_f_gcmp.ic_trailer);
+
+	return QDF_STATUS_SUCCESS;
+}
+
 /*
  * dp_rx_defrag(): Defragment the fragment chain
  * @peer: Pointer to the peer
@@ -1523,6 +1564,22 @@ static QDF_STATUS dp_rx_defrag(struct dp_peer *peer, unsigned tid,
 		/* If success, increment header to be stripped later */
 		hdr_space += dp_f_wep.ic_header;
 		break;
+	case cdp_sec_type_aes_gcmp:
+	case cdp_sec_type_aes_gcmp_256:
+		while (cur) {
+			tmp_next = qdf_nbuf_next(cur);
+			if (dp_rx_defrag_gcmp_demic(cur, hdr_space)) {
+				QDF_TRACE(QDF_MODULE_ID_TXRX,
+					  QDF_TRACE_LEVEL_ERROR,
+					  "dp_rx_defrag: GCMP demic failed");
+
+				return QDF_STATUS_E_DEFRAG_ERROR;
+			}
+			cur = tmp_next;
+		}
+
+		hdr_space += dp_f_gcmp.ic_header;
+		break;
 	default:
 		break;
 	}