Browse Source

qcacmn: [CRYPTO] Support word-aligned 802.11 headers

Some chipsets using Direct-attach architecture need the 802.11 header
padded to a 32-bit boundary for 4-address and QoS frames.

Change-Id: Id29c114b2246cbb1230c9b22f4d04c070069d569
CRs-Fixed: 2233228
Padma Raghunathan 7 years ago
parent
commit
6ac6143190

+ 24 - 2
umac/cmn_services/crypto/src/wlan_crypto_def_i.h

@@ -482,10 +482,10 @@ static inline bool wlan_crypto_is_data_protected(const void *data)
  *
  * Return: header size of the frame
  */
-static inline int ieee80211_hdrsize(const void *data)
+static inline uint8_t ieee80211_hdrsize(const void *data)
 {
 	const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *)data;
-	int16_t size = sizeof(struct ieee80211_hdr);
+	uint8_t size = sizeof(struct ieee80211_hdr);
 
 	if ((hdr->frame_control[1] & WLAN_FC1_DIR_MASK)
 				== (WLAN_FC1_DSTODS)) {
@@ -502,6 +502,28 @@ static inline int ieee80211_hdrsize(const void *data)
 	return size;
 }
 
+/**
+ * ieee80211_hdrspace - calculate frame header size with padding
+ * @pdev: pdev
+ * @data: frame header
+ *
+ * This function returns the space occupied by the 802.11 header
+ * and any padding required by the driver. This works for a management
+ * or data frame.
+ *
+ * Return: header size of the frame with padding
+ */
+static inline uint8_t
+ieee80211_hdrspace(struct wlan_objmgr_pdev *pdev, const void *data)
+{
+	uint8_t size = ieee80211_hdrsize(data);
+
+	if (wlan_pdev_nif_feat_cap_get(pdev, WLAN_PDEV_F_DATAPAD))
+		size = roundup(size, sizeof(u_int32_t));
+
+	return size;
+}
+
 /**
  * wlan_get_tid - get tid of the frame
  * @data: frame

+ 41 - 7
umac/cmn_services/crypto/src/wlan_crypto_global_api.c

@@ -1051,7 +1051,10 @@ QDF_STATUS wlan_crypto_encap(struct wlan_objmgr_vdev *vdev,
 	struct wlan_objmgr_peer *peer;
 	uint8_t bssid_mac[WLAN_ALEN];
 	uint8_t pdev_id;
+	uint8_t hdrlen;
+	enum QDF_OPMODE opmode;
 
+	opmode = wlan_vdev_mlme_get_opmode(vdev);
 	wlan_vdev_obj_lock(vdev);
 	qdf_mem_copy(bssid_mac, wlan_vdev_mlme_get_macaddr(vdev), WLAN_ALEN);
 	psoc = wlan_vdev_get_psoc(vdev);
@@ -1117,10 +1120,16 @@ QDF_STATUS wlan_crypto_encap(struct wlan_objmgr_vdev *vdev,
 		if (!key)
 			return QDF_STATUS_E_INVAL;
 	}
+	if (opmode == QDF_MONITOR_MODE)
+		hdrlen = ieee80211_hdrsize((uint8_t *)qdf_nbuf_data(wbuf));
+	else
+		hdrlen = ieee80211_hdrspace(wlan_vdev_get_pdev(vdev),
+					    (uint8_t *)qdf_nbuf_data(wbuf));
+
 	/* if tkip, is counter measures enabled, then drop the frame */
 	cipher_table = (struct wlan_crypto_cipher *)key->cipher_table;
 	status = cipher_table->encap(key, wbuf, encapdone,
-			ieee80211_hdrsize((uint8_t *)qdf_nbuf_data(wbuf)));
+				     hdrlen);
 
 	return status;
 }
@@ -1151,7 +1160,10 @@ QDF_STATUS wlan_crypto_decap(struct wlan_objmgr_vdev *vdev,
 	uint8_t bssid_mac[WLAN_ALEN];
 	uint8_t keyid;
 	uint8_t pdev_id;
+	uint8_t hdrlen;
+	enum QDF_OPMODE opmode;
 
+	opmode = wlan_vdev_mlme_get_opmode(vdev);
 	wlan_vdev_obj_lock(vdev);
 	qdf_mem_copy(bssid_mac, wlan_vdev_mlme_get_macaddr(vdev), WLAN_ALEN);
 	psoc = wlan_vdev_get_psoc(vdev);
@@ -1162,6 +1174,12 @@ QDF_STATUS wlan_crypto_decap(struct wlan_objmgr_vdev *vdev,
 	}
 	wlan_vdev_obj_unlock(vdev);
 
+	if (opmode == QDF_MONITOR_MODE)
+		hdrlen = ieee80211_hdrsize((uint8_t *)qdf_nbuf_data(wbuf));
+	else
+		hdrlen = ieee80211_hdrspace(wlan_vdev_get_pdev(vdev),
+					    (uint8_t *)qdf_nbuf_data(wbuf));
+
 	keyid = wlan_crypto_get_keyid((uint8_t *)qdf_nbuf_data(wbuf));
 
 	if (keyid >= WLAN_CRYPTO_MAXKEYIDX)
@@ -1223,8 +1241,7 @@ QDF_STATUS wlan_crypto_decap(struct wlan_objmgr_vdev *vdev,
 	}
 	/* if tkip, is counter measures enabled, then drop the frame */
 	cipher_table = (struct wlan_crypto_cipher *)key->cipher_table;
-	status = cipher_table->decap(key, wbuf, tid,
-			ieee80211_hdrsize((uint8_t *)qdf_nbuf_data(wbuf)));
+	status = cipher_table->decap(key, wbuf, tid, hdrlen);
 
 	return status;
 }
@@ -1251,6 +1268,10 @@ QDF_STATUS wlan_crypto_enmic(struct wlan_objmgr_vdev *vdev,
 	struct wlan_crypto_cipher *cipher_table;
 	struct wlan_objmgr_psoc *psoc;
 	uint8_t bssid_mac[WLAN_ALEN];
+	uint8_t hdrlen;
+	enum QDF_OPMODE opmode;
+
+	opmode = wlan_vdev_mlme_get_opmode(vdev);
 
 
 	wlan_vdev_obj_lock(vdev);
@@ -1305,10 +1326,15 @@ QDF_STATUS wlan_crypto_enmic(struct wlan_objmgr_vdev *vdev,
 		if (!key)
 			return QDF_STATUS_E_INVAL;
 	}
+	if (opmode == QDF_MONITOR_MODE)
+		hdrlen = ieee80211_hdrsize((uint8_t *)qdf_nbuf_data(wbuf));
+	else
+		hdrlen = ieee80211_hdrspace(wlan_vdev_get_pdev(vdev),
+					    (uint8_t *)qdf_nbuf_data(wbuf));
+
 	/* if tkip, is counter measures enabled, then drop the frame */
 	cipher_table = (struct wlan_crypto_cipher *)key->cipher_table;
-	status = cipher_table->enmic(key, wbuf, encapdone,
-			ieee80211_hdrsize((uint8_t *)qdf_nbuf_data(wbuf)));
+	status = cipher_table->enmic(key, wbuf, encapdone, hdrlen);
 
 	return status;
 }
@@ -1336,7 +1362,16 @@ QDF_STATUS wlan_crypto_demic(struct wlan_objmgr_vdev *vdev,
 	struct wlan_crypto_cipher *cipher_table;
 	struct wlan_objmgr_psoc *psoc;
 	uint8_t bssid_mac[WLAN_ALEN];
+	uint8_t hdrlen;
+	enum QDF_OPMODE opmode;
+
+	opmode = wlan_vdev_mlme_get_opmode(vdev);
 
+	if (opmode == QDF_MONITOR_MODE)
+		hdrlen = ieee80211_hdrsize((uint8_t *)qdf_nbuf_data(wbuf));
+	else
+		hdrlen = ieee80211_hdrspace(wlan_vdev_get_pdev(vdev),
+					    (uint8_t *)qdf_nbuf_data(wbuf));
 
 	wlan_vdev_obj_lock(vdev);
 	qdf_mem_copy(bssid_mac, wlan_vdev_mlme_get_macaddr(vdev), WLAN_ALEN);
@@ -1391,8 +1426,7 @@ QDF_STATUS wlan_crypto_demic(struct wlan_objmgr_vdev *vdev,
 	}
 	/* if tkip, is counter measures enabled, then drop the frame */
 	cipher_table = (struct wlan_crypto_cipher *)key->cipher_table;
-	status = cipher_table->demic(key, wbuf, tid,
-			ieee80211_hdrsize((uint8_t *)qdf_nbuf_data(wbuf)));
+	status = cipher_table->demic(key, wbuf, tid, hdrlen);
 
 	return status;
 }