Bladeren bron

qcacld-3.0: 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: 2942099
Yeshwanth Sriram Guntuka 4 jaren geleden
bovenliggende
commit
e4322f1e96
1 gewijzigde bestanden met toevoegingen van 97 en 0 verwijderingen
  1. 97 0
      core/dp/txrx/ol_rx_defrag.c

+ 97 - 0
core/dp/txrx/ol_rx_defrag.c

@@ -95,6 +95,13 @@ const struct ol_rx_defrag_cipher f_wep = {
 	0,
 };
 
+const struct ol_rx_defrag_cipher f_gcmp = {
+	"AES-GCMP",
+	WLAN_IEEE80211_GCMP_HEADERLEN,
+	WLAN_IEEE80211_GCMP_MICLEN,
+	WLAN_IEEE80211_GCMP_MICLEN,
+};
+
 #if defined(CONFIG_HL_SUPPORT)
 
 /**
@@ -663,6 +670,79 @@ void ol_rx_defrag_waitlist_flush(struct ol_txrx_pdev_t *pdev)
 	}
 }
 
+/**
+ * ol_rx_frag_gcmp_decap() - Remove GCMP header from fragment
+ * @pdev - data path pdev handle
+ * @nbuf - network buffer
+ * @hdrlen - MAC header len
+ *
+ * Return: OL_RX_DEFRAG_OK on success else failure code
+ */
+static int
+ol_rx_frag_gcmp_decap(ol_txrx_pdev_handle pdev,
+		      qdf_nbuf_t nbuf, uint16_t hdrlen)
+{
+	uint8_t *ivp, *orig_hdr;
+	void *rx_desc_old_position = NULL;
+	void *ind_old_position = NULL;
+	int rx_desc_len = 0;
+
+	ol_rx_frag_desc_adjust(pdev,
+			       nbuf,
+			       &rx_desc_old_position,
+			       &ind_old_position, &rx_desc_len);
+
+	orig_hdr = (uint8_t *)(qdf_nbuf_data(nbuf) + rx_desc_len);
+	ivp = orig_hdr + hdrlen;
+	if (!(ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV))
+		return OL_RX_DEFRAG_ERR;
+
+	qdf_mem_move(orig_hdr + f_gcmp.ic_header, orig_hdr, hdrlen);
+	ol_rx_frag_restructure(
+			pdev,
+			nbuf,
+			rx_desc_old_position,
+			ind_old_position,
+			&f_gcmp,
+			rx_desc_len);
+	qdf_nbuf_pull_head(nbuf, f_gcmp.ic_header);
+
+	return OL_RX_DEFRAG_OK;
+}
+
+/**
+ * ol_rx_frag_gcmp_demic() - Remove MIC info from GCMP fragment
+ * @pdev - data path pdev handle
+ * @nbuf - network buffer
+ * @hdrlen - MAC header len
+ *
+ * Return: OL_RX_DEFRAG_OK on success else failure code
+ */
+static int
+ol_rx_frag_gcmp_demic(ol_txrx_pdev_handle pdev,
+		      qdf_nbuf_t wbuf, uint16_t hdrlen)
+{
+	uint8_t *ivp, *orig_hdr;
+	void *rx_desc_old_position = NULL;
+	void *ind_old_position = NULL;
+	int rx_desc_len = 0;
+
+	ol_rx_frag_desc_adjust(pdev,
+			       wbuf,
+			       &rx_desc_old_position,
+			       &ind_old_position, &rx_desc_len);
+
+	orig_hdr = (uint8_t *)(qdf_nbuf_data(wbuf) + rx_desc_len);
+
+	ivp = orig_hdr + hdrlen;
+	if (!(ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV))
+		return OL_RX_DEFRAG_ERR;
+
+	qdf_nbuf_trim_tail(wbuf, f_gcmp.ic_trailer);
+
+	return OL_RX_DEFRAG_OK;
+}
+
 /*
  * Handling security checking and processing fragments
  */
@@ -780,7 +860,24 @@ ol_rx_defrag(ol_txrx_pdev_handle pdev,
 			cur = tmp_next;
 		}
 		break;
+	case htt_sec_type_aes_gcmp:
+	case htt_sec_type_aes_gcmp_256:
+		while (cur) {
+			tmp_next = qdf_nbuf_next(cur);
+			if (!ol_rx_frag_gcmp_demic(pdev, cur, hdr_space)) {
+				ol_rx_frames_free(htt_pdev, frag_list);
+				ol_txrx_err("GCMP demic failed");
+				return;
+			}
+			if (!ol_rx_frag_gcmp_decap(pdev, cur, hdr_space)) {
+				ol_rx_frames_free(htt_pdev, frag_list);
+				ol_txrx_err("GCMP decap failed");
+				return;
+			}
+			cur = tmp_next;
+		}
 
+		break;
 	default:
 		break;
 	}