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
This commit is contained in:
Padma Raghunathan 2018-04-30 09:46:38 +05:30 • committed by nshrivas
commit 43ebaa7182
5 changed files with 172 additions and 14 deletions

View file

@ -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_ */

View file

@ -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);
};

View file

@ -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);
}
}

View file

@ -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,

View file

@ -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);
}