Browse Source

qcacmn: [CRYPTO] Fix encap/decap issues in TKIP/WEP

1. Fetch keyid from pkt during TKIP demic
2. Support to restore keys in h/w keycache, when h/w reset takes place

Change-Id: Icc4039a6cf6b89bd3ec3a874b698445382aff024
CRs-Fixed: 2233228
Padma Raghunathan 7 years ago
parent
commit
43ebaa7182

+ 15 - 3
umac/cmn_services/crypto/inc/wlan_crypto_global_api.h

@@ -200,15 +200,17 @@ QDF_STATUS wlan_crypto_enmic(struct wlan_objmgr_vdev *vdev,
  * @wbuf: wbuf
  * @macaddr: macaddr
  * @tid: tid of the frame
+ * @keyid: keyid in the received frame
  *
  * This function gets called from mgmt txrx to decap frame.
  *
  * Return: QDF_STATUS_SUCCESS - in case of success
  */
 QDF_STATUS wlan_crypto_demic(struct wlan_objmgr_vdev *vdev,
-					qdf_nbuf_t wbuf,
-					uint8_t *macaddr,
-					uint8_t tid);
+			     qdf_nbuf_t wbuf,
+			     uint8_t *macaddr,
+			     uint8_t tid,
+			     uint8_t keyid);
 
 /**
  * wlan_crypto_vdev_is_pmf_enabled - called to check is pmf enabled in vdev
@@ -576,4 +578,14 @@ uint8_t wlan_crypto_get_key_miclen(struct wlan_crypto_key *key);
  * Return: keyid
  */
 uint16_t wlan_crypto_get_keyid(uint8_t *data, int hdrlen);
+
+/**
+ * wlan_crypto_restore_keys - restore crypto keys in hw keycache
+ * @vdev: vdev
+ *
+ * This function restores keys in hw keycache
+ *
+ * Return: void
+ */
+void wlan_crypto_restore_keys(struct wlan_objmgr_vdev *vdev);
 #endif /* end of _WLAN_CRYPTO_GLOBAL_API_H_ */

+ 1 - 1
umac/cmn_services/crypto/inc/wlan_crypto_global_def.h

@@ -324,7 +324,7 @@ struct wlan_lmac_if_crypto_rx_ops {
 					uint8_t encapdone);
 	QDF_STATUS(*crypto_demic)(struct wlan_objmgr_vdev *vdev,
 					qdf_nbuf_t wbuf, uint8_t *macaddr,
-					uint8_t tid);
+					uint8_t tid, uint8_t keyid);
 	QDF_STATUS(*set_peer_wep_keys)(struct wlan_objmgr_vdev *vdev,
 					struct wlan_objmgr_peer *peer);
 };

+ 141 - 6
umac/cmn_services/crypto/src/wlan_crypto_global_api.c

@@ -649,6 +649,16 @@ QDF_STATUS wlan_crypto_setkey(struct wlan_objmgr_vdev *vdev,
 	}
 	status = cipher->setkey(key);
 
+	if ((req_key->flags & WLAN_CRYPTO_KEY_DEFAULT) &&
+	    (req_key->keyix != WLAN_CRYPTO_KEYIX_NONE) &&
+	    (!IS_MGMT_CIPHER(req_key->type))) {
+		/* default xmit key */
+		wlan_crypto_default_key(vdev,
+					req_key->macaddr,
+					req_key->keyix,
+					!isbcast);
+		}
+
 	return status;
 }
 
@@ -1346,15 +1356,16 @@ QDF_STATUS wlan_crypto_enmic(struct wlan_objmgr_vdev *vdev,
  * @wbuf: wbuf
  * @macaddr: macaddr
  * @tid: tid of the frame
- *
+ * @keyid: keyid in the received frame
  * This function gets called from mgmt txrx to decap frame.
  *
  * Return: QDF_STATUS_SUCCESS - in case of success
  */
 QDF_STATUS wlan_crypto_demic(struct wlan_objmgr_vdev *vdev,
-				qdf_nbuf_t wbuf,
-				uint8_t *mac_addr,
-				uint8_t tid){
+			     qdf_nbuf_t wbuf,
+			     uint8_t *mac_addr,
+			     uint8_t tid,
+			     uint8_t keyid){
 	struct wlan_crypto_comp_priv *crypto_priv;
 	struct wlan_crypto_params *crypto_params;
 	struct wlan_crypto_key *key;
@@ -1392,7 +1403,7 @@ QDF_STATUS wlan_crypto_demic(struct wlan_objmgr_vdev *vdev,
 			return QDF_STATUS_E_INVAL;
 		}
 
-		key = crypto_priv->key[crypto_priv->def_tx_keyid];
+		key = crypto_priv->key[keyid];
 		if (!key)
 			return QDF_STATUS_E_INVAL;
 
@@ -1420,7 +1431,7 @@ QDF_STATUS wlan_crypto_demic(struct wlan_objmgr_vdev *vdev,
 			return QDF_STATUS_E_INVAL;
 		}
 
-		key = crypto_priv->key[crypto_priv->def_tx_keyid];
+		key = crypto_priv->key[keyid];
 		if (!key)
 			return QDF_STATUS_E_INVAL;
 	}
@@ -3201,3 +3212,127 @@ uint16_t wlan_crypto_get_keyid(uint8_t *data, int hdrlen)
 }
 
 qdf_export_symbol(wlan_crypto_get_keyid);
+
+/**
+ * crypto_plumb_peer_keys - called during radio reset
+ * @vdev: vdev
+ * @object: peer
+ * @arg: psoc
+ *
+ * Restore unicast and persta hardware keys
+ *
+ * Return: void
+ */
+static void crypto_plumb_peer_keys(struct wlan_objmgr_vdev *vdev,
+				   void *object, void *arg) {
+	struct wlan_objmgr_peer *peer = (struct wlan_objmgr_peer *)object;
+	struct wlan_objmgr_psoc *psoc = (struct wlan_objmgr_psoc *)arg;
+	struct wlan_crypto_comp_priv *crypto_priv;
+	struct wlan_crypto_params *crypto_params;
+	struct wlan_crypto_key *key = NULL;
+	int i;
+
+	if ((NULL == peer) || (NULL == vdev) || (NULL == psoc)) {
+		QDF_TRACE(QDF_MODULE_ID_CRYPTO, QDF_TRACE_LEVEL_ERROR,
+			  "%s[%d] Peer or vdev or psoc objects are null!\n",
+			  __func__, __LINE__);
+		return;
+	}
+
+	crypto_params = wlan_crypto_peer_get_comp_params(peer,
+							 &crypto_priv);
+
+	if (!crypto_priv) {
+		QDF_TRACE(QDF_MODULE_ID_CRYPTO, QDF_TRACE_LEVEL_ERROR,
+			  "%s[%d] crypto_priv NULL\n",
+			  __func__, __LINE__);
+		return;
+	}
+
+	for (i = 0; i < WLAN_CRYPTO_MAXKEYIDX; i++) {
+		key = crypto_priv->key[i];
+		if (key && key->valid) {
+			if (WLAN_CRYPTO_TX_OPS_SETKEY(psoc)) {
+				WLAN_CRYPTO_TX_OPS_SETKEY(psoc)
+					(
+					 vdev,
+					 key,
+					 wlan_peer_get_macaddr(peer),
+					 wlan_crypto_get_key_type(key)
+					);
+			}
+		}
+	}
+}
+
+/**
+ * wlan_crypto_restore_keys - called during radio reset
+ * @vdev: vdev
+ *
+ * Clear and restore keycache, needed for some DA chipsets which put
+ * random values in keycache when phy reset is triggered
+ *
+ * Return: void
+ */
+void wlan_crypto_restore_keys(struct wlan_objmgr_vdev *vdev)
+{
+	int i;
+	struct wlan_crypto_comp_priv *crypto_priv;
+	struct wlan_crypto_params *crypto_params;
+	struct wlan_crypto_key *key;
+	uint8_t macaddr[WLAN_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+	struct wlan_objmgr_pdev *pdev = NULL;
+	struct wlan_objmgr_psoc *psoc = NULL;
+
+	pdev = wlan_vdev_get_pdev(vdev);
+	psoc = wlan_vdev_get_psoc(vdev);
+	if (NULL == pdev) {
+		QDF_TRACE(QDF_MODULE_ID_CRYPTO, QDF_TRACE_LEVEL_ERROR,
+			  "%s[%d] pdev is NULL\n",
+			  __func__, __LINE__);
+		return;
+	}
+	if (NULL == psoc) {
+		QDF_TRACE(QDF_MODULE_ID_CRYPTO, QDF_TRACE_LEVEL_ERROR,
+			  "%s[%d] psoc is NULL\n",
+			  __func__, __LINE__);
+		return;
+	}
+
+	/* TBD: QWRAP key restore*/
+	/* crypto is on */
+	if (wlan_vdev_mlme_feat_cap_get(vdev, WLAN_VDEV_F_PRIVACY)) {
+		/* restore static shared keys */
+		for (i = 0; i < WLAN_CRYPTO_MAXKEYIDX; i++) {
+			crypto_params = wlan_crypto_vdev_get_comp_params
+				(
+				 vdev,
+				 &crypto_priv
+				);
+			if (!crypto_priv) {
+				QDF_TRACE(QDF_MODULE_ID_CRYPTO,
+					  QDF_TRACE_LEVEL_ERROR,
+					  "%s[%d] crypto_priv is NULL\n",
+					  __func__, __LINE__);
+				return;
+			}
+			key = crypto_priv->key[i];
+			if (key && key->valid) {
+				if (WLAN_CRYPTO_TX_OPS_SETKEY(psoc)) {
+					WLAN_CRYPTO_TX_OPS_SETKEY(psoc)
+						(
+						 vdev,
+						 key,
+						 macaddr,
+						 wlan_crypto_get_key_type(key)
+						 );
+				}
+			}
+		}
+
+		wlan_objmgr_iterate_peerobj_list(vdev,
+						 crypto_plumb_peer_keys,
+						 psoc,
+						 WLAN_CRYPTO_ID);
+	}
+}

+ 14 - 3
umac/cmn_services/crypto/src/wlan_crypto_tkip.c

@@ -60,10 +60,17 @@ static QDF_STATUS tkip_encap(struct wlan_crypto_key *key,
 	if (encapdone) {
 		ivp = (uint8_t *)qdf_nbuf_data(wbuf);
 	} else {
-		ivp = qdf_nbuf_push_head(wbuf, cipher_table->header);
-		qdf_mem_move(ivp, (ivp + cipher_table->header), hdrlen);
+		uint8_t ivmictrailer_len = cipher_table->header +
+			cipher_table->miclen +
+			cipher_table->trailer;
+		ivp = qdf_nbuf_push_head(wbuf, ivmictrailer_len);
+		qdf_mem_move(ivp, (ivp + ivmictrailer_len), hdrlen);
+		qdf_mem_move((ivp + hdrlen + cipher_table->header),
+			     (ivp + ivmictrailer_len + hdrlen),
+			     (qdf_nbuf_len(wbuf) - hdrlen - ivmictrailer_len));
 	}
 
+	ivp += hdrlen;
 	key->keytsc++;         /* XXX wrap at 48 bits */
 
 	ivp[0] = key->keytsc >> 8;            /* TSC1 */
@@ -151,13 +158,17 @@ static QDF_STATUS tkip_demic(struct wlan_crypto_key *key,
 				qdf_nbuf_t wbuf,
 				uint8_t tid,
 				uint8_t hdrlen){
+	struct wlan_crypto_cipher *cipher_table;
+
+	cipher_table = key->cipher_table;
+	qdf_nbuf_trim_tail(wbuf, cipher_table->miclen);
 	return QDF_STATUS_SUCCESS;
 }
 
 const struct wlan_crypto_cipher tkip_cipher_table = {
 	"TKIP",
 	WLAN_CRYPTO_CIPHER_TKIP,
-	WLAN_CRYPTO_IV_LEN + WLAN_CRYPTO_KEYID_LEN,
+	WLAN_CRYPTO_IV_LEN + WLAN_CRYPTO_KEYID_LEN + WLAN_CRYPTO_EXT_IV_LEN,
 	WLAN_CRYPTO_CRC_LEN,
 	WLAN_CRYPTO_MIC_LEN,
 	256,

+ 1 - 1
umac/cmn_services/crypto/src/wlan_crypto_wep.c

@@ -65,7 +65,7 @@ static QDF_STATUS wep_encap(struct wlan_crypto_key *key,
 			ivp + hdrlen
 			+ cipher_table->header + cipher_table->trailer,
 			(qdf_nbuf_len(wbuf) - hdrlen
-			- cipher_table->header + cipher_table->trailer));
+			- cipher_table->header - cipher_table->trailer));
 		ivp = (uint8_t *)qdf_nbuf_data(wbuf);
 	}