From 43ebaa7182e559292d0b4302d1989cb8eb3d76cd Mon Sep 17 00:00:00 2001 From: Padma Raghunathan Date: Mon, 30 Apr 2018 09:46:38 +0530 Subject: [PATCH] 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 --- .../crypto/inc/wlan_crypto_global_api.h | 18 ++- .../crypto/inc/wlan_crypto_global_def.h | 2 +- .../crypto/src/wlan_crypto_global_api.c | 147 +++++++++++++++++- .../crypto/src/wlan_crypto_tkip.c | 17 +- .../cmn_services/crypto/src/wlan_crypto_wep.c | 2 +- 5 files changed, 172 insertions(+), 14 deletions(-) diff --git a/umac/cmn_services/crypto/inc/wlan_crypto_global_api.h b/umac/cmn_services/crypto/inc/wlan_crypto_global_api.h index 8b570cecf787..c154e534e88c 100644 --- a/umac/cmn_services/crypto/inc/wlan_crypto_global_api.h +++ b/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_ */ diff --git a/umac/cmn_services/crypto/inc/wlan_crypto_global_def.h b/umac/cmn_services/crypto/inc/wlan_crypto_global_def.h index 200d03372ece..b688796c23a4 100644 --- a/umac/cmn_services/crypto/inc/wlan_crypto_global_def.h +++ b/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); }; diff --git a/umac/cmn_services/crypto/src/wlan_crypto_global_api.c b/umac/cmn_services/crypto/src/wlan_crypto_global_api.c index 12aff6865e35..8ccfa6f18f61 100644 --- a/umac/cmn_services/crypto/src/wlan_crypto_global_api.c +++ b/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); + } +} diff --git a/umac/cmn_services/crypto/src/wlan_crypto_tkip.c b/umac/cmn_services/crypto/src/wlan_crypto_tkip.c index 1d424cd9f7ab..947e39828c7d 100644 --- a/umac/cmn_services/crypto/src/wlan_crypto_tkip.c +++ b/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, diff --git a/umac/cmn_services/crypto/src/wlan_crypto_wep.c b/umac/cmn_services/crypto/src/wlan_crypto_wep.c index 21421b58c0fe..b3a5ba756ffc 100644 --- a/umac/cmn_services/crypto/src/wlan_crypto_wep.c +++ b/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); }