2008-03-19 23:49:52

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 0/7] iwlwifi and mac80211 updates (TKIP)

This series reverts the previous TKIP related patches to mac80211
and iwlwifi and addresses the issues discussed on the mailing list.

[PATCH 1/7] tkip: revert TKIP patches
[PATCH 2/7] iwlwifi-2.6: Cleans up set_key flow
[PATCH 3/7] iwlwifi-2.6: RX status translation to old scheme
[PATCH 4/7] mac80211: get a TKIP phase key from skb
[PATCH 5/7] mac80211: allows driver to request a Phase 1 RX key
[PATCH 6/7] iwlwifi-2.6: enables HW TKIP encryption
[PATCH 7/7] iwlwifi-2.6: enables RX TKIP decryption in HW


Thanks

Reinette


2008-03-19 23:49:48

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 6/7] iwlwifi-2.6: enables HW TKIP encryption

From: Emmanuel Grumbach <[email protected]>

This patch add support for TKIP encryption (TX) in HW.

Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-4965.h | 1 +
drivers/net/wireless/iwlwifi/iwl4965-base.c | 33 +++++++++++++++++++-------
2 files changed, 25 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h
index bf17289..0842176 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.h
@@ -478,6 +478,7 @@ struct iwl4965_tid_data {
struct iwl4965_hw_key {
enum ieee80211_key_alg alg;
int keylen;
+ struct ieee80211_key_conf *conf;
u8 key[32];
};

diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 9d4cd8e..2449e00 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -1385,7 +1385,27 @@ static int iwl4965_set_tkip_dynamic_key_info(struct iwl_priv *priv,
struct ieee80211_key_conf *keyconf,
u8 sta_id)
{
- return -EOPNOTSUPP;
+ unsigned long flags;
+ int ret = 0;
+
+ keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+ keyconf->hw_key_idx = keyconf->keyidx;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ priv->stations[sta_id].keyinfo.alg = keyconf->alg;
+ priv->stations[sta_id].keyinfo.conf = keyconf;
+ priv->stations[sta_id].keyinfo.keylen = 16;
+
+ /* This copy is acutally not needed: we get the key with each TX */
+ memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16);
+
+ memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, 16);
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ return ret;
}

static int iwl4965_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
@@ -2333,15 +2353,10 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
break;

case ALG_TKIP:
-#if 0
cmd->cmd.tx.sec_ctl = TX_CMD_SEC_TKIP;
-
- if (last_frag)
- memcpy(cmd->cmd.tx.tkip_mic.byte, skb_frag->tail - 8,
- 8);
- else
- memset(cmd->cmd.tx.tkip_mic.byte, 0, 8);
-#endif
+ ieee80211_get_tkip_key(keyinfo->conf, skb_frag,
+ IEEE80211_TKIP_P2_KEY, cmd->cmd.tx.key);
+ IWL_DEBUG_TX("tx_cmd with tkip hwcrypto\n");
break;

case ALG_WEP:
--
1.5.3.4


2008-03-19 23:49:53

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 5/7] mac80211: allows driver to request a Phase 1 RX key

From: Emmanuel Grumbach <[email protected]>

This patch makes mac80211 able to send a phase1 key for TKIP
decryption.
This is needed for drivers that don't do the rekeying by themselves
(i.e. iwlwifi). Upon IV16 wrap around, the packet is decrypted in SW,
if decryption is ok, mac80211 calls to update_tkip_key with a new
phase 1 RX key.

Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
---
include/net/mac80211.h | 27 ++++++++++++++++++++++++---
net/mac80211/tkip.c | 16 +++++++++++++++-
net/mac80211/tkip.h | 2 +-
net/mac80211/wpa.c | 2 +-
4 files changed, 41 insertions(+), 6 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 4b35f64..d3e2337 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -586,11 +586,15 @@ enum ieee80211_key_alg {
* @IEEE80211_KEY_FLAG_GENERATE_MMIC: This flag should be set by
* the driver for a TKIP key if it requires Michael MIC
* generation in software.
+ * @IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY: This flag should bet by
+ * the driver for a TKIP key if it requires phase 1 key generation
+ * in SW.
*/
enum ieee80211_key_flags {
- IEEE80211_KEY_FLAG_WMM_STA = 1<<0,
- IEEE80211_KEY_FLAG_GENERATE_IV = 1<<1,
- IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2,
+ IEEE80211_KEY_FLAG_WMM_STA = 1<<0,
+ IEEE80211_KEY_FLAG_GENERATE_IV = 1<<1,
+ IEEE80211_KEY_FLAG_GENERATE_MMIC = 1<<2,
+ IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY = 1<<3,
};

/**
@@ -827,6 +831,16 @@ static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr)
* parameter is guaranteed to be valid until another call to set_key()
* removes it, but it can only be used as a cookie to differentiate
* keys.
+ *
+ * In TKIP some HW need to be provided a phase 1 key, for RX decryption
+ * acceleration (i.e. iwlwifi). Those drivers should set
+ * IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY.
+ * The update_tkip_key() call updates the driver with the new phase 1 key.
+ * This happens everytime the iv16 wraps around (every 65536 packets). The
+ * set_key() call will happen only once during a rekeying session, it will not
+ * include a valid phase 1 key. The valid phase 1 key is provided by
+ * udpate_tkip_key only. The trigger that makes mac80211 call this handler is
+ * software decryption with wrap around of iv16.
*/

/**
@@ -1003,6 +1017,10 @@ enum ieee80211_ampdu_mlme_action {
* and remove_interface calls, i.e. while the interface with the
* given local_address is enabled.
*
+ * @update_tkip_key: See the section "Hardware crypto acceleration"
+ * This callback will be called in the context of Rx. Called for drivers
+ * which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY.
+ *
* @hw_scan: Ask the hardware to service the scan request, no need to start
* the scan state machine in stack. The scan must honour the channel
* configuration done by the regulatory agent in the wiphy's registered
@@ -1094,6 +1112,9 @@ struct ieee80211_ops {
int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd,
const u8 *local_address, const u8 *address,
struct ieee80211_key_conf *key);
+ void (*update_tkip_key)(struct ieee80211_hw *hw,
+ struct ieee80211_key_conf *conf, const u8 *address,
+ u32 iv32, u16 *phase1key);
int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len);
int (*get_stats)(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats);
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c
index 5c36b2d..94d4f1b 100644
--- a/net/mac80211/tkip.c
+++ b/net/mac80211/tkip.c
@@ -291,7 +291,7 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm,
int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
struct ieee80211_key *key,
u8 *payload, size_t payload_len, u8 *ta,
- int only_iv, int queue,
+ u8 *ra, int only_iv, int queue,
u32 *out_iv32, u16 *out_iv16)
{
u32 iv32;
@@ -368,6 +368,20 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
printk("\n");
}
#endif /* CONFIG_TKIP_DEBUG */
+ if (key->conf.flags & IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY) {
+ u8 bcast[ETH_ALEN] =
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ u8 *sta_addr = key->sta->addr;
+
+ BUG_ON(!key->local->ops->update_tkip_key);
+
+ if (is_multicast_ether_addr(ra))
+ sta_addr = bcast;
+
+ key->local->ops->update_tkip_key(
+ local_to_hw(key->local), &key->conf,
+ sta_addr, iv32, key->u.tkip.p1k_rx[queue]);
+ }
}

tkip_mixing_phase2(key->u.tkip.p1k_rx[queue],
diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h
index 73d8ef2..ffaee32 100644
--- a/net/mac80211/tkip.h
+++ b/net/mac80211/tkip.h
@@ -31,7 +31,7 @@ enum {
int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
struct ieee80211_key *key,
u8 *payload, size_t payload_len, u8 *ta,
- int only_iv, int queue,
+ u8 *ra, int only_iv, int queue,
u32 *out_iv32, u16 *out_iv16);

#endif /* TKIP_H */
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index df0b734..45709ad 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -312,7 +312,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm,
key, skb->data + hdrlen,
skb->len - hdrlen, rx->sta->addr,
- hwaccel, rx->queue,
+ hdr->addr1, hwaccel, rx->queue,
&rx->tkip_iv32,
&rx->tkip_iv16);
if (res != TKIP_DECRYPT_OK || wpa_test) {
--
1.5.3.4


2008-03-19 23:49:51

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 2/7] iwlwifi-2.6: Cleans up set_key flow

From: Emmanuel Grumbach <[email protected]>

This patch cleans up the set_key flow. Rxon with hw encryption bit set is
not sent upon each call to set_key. Separation is made between global key
(WEP) and dynamic key (TKIP + CCMP and WEP in some cases).

Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-4965-commands.h | 1 +
drivers/net/wireless/iwlwifi/iwl4965-base.c | 165 ++++++++++++++--------
2 files changed, 110 insertions(+), 56 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h
index 1025ffe..085d813 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h
@@ -741,6 +741,7 @@ struct iwl4965_qosparam_cmd {
/* wep key in STA: 5-bytes (0) or 13-bytes (1) */
#define STA_KEY_FLG_KEY_SIZE_MSK __constant_cpu_to_le16(0x1000)
#define STA_KEY_MULTICAST_MSK __constant_cpu_to_le16(0x4000)
+#define STA_KEY_MAX_NUM 8

/* Flags indicate whether to modify vs. don't change various station params */
#define STA_MODIFY_KEY_MASK 0x01
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 43f251c..3d1f43a 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -788,6 +788,17 @@ out:
return ret;
}

+static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
+{
+ struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon;
+
+ if (hw_decrypt)
+ rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
+ else
+ rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK;
+
+}
+
int iwl4965_send_cmd(struct iwl_priv *priv, struct iwl4965_host_cmd *cmd)
{
if (cmd->meta.flags & CMD_ASYNC)
@@ -1116,6 +1127,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
le16_to_cpu(priv->staging_rxon.channel),
print_mac(mac, priv->staging_rxon.bssid_addr));

+ iwl4965_set_rxon_hwcrypto(priv, priv->cfg->mod_params->hw_crypto);
/* Apply the new configuration */
rc = iwl4965_send_cmd_pdu(priv, REPLY_RXON,
sizeof(struct iwl4965_rxon_cmd), &priv->staging_rxon);
@@ -1328,33 +1340,36 @@ int iwl4965_send_add_station(struct iwl_priv *priv,
return rc;
}

-static int iwl4965_update_sta_key_info(struct iwl_priv *priv,
+static int iwl4965_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
struct ieee80211_key_conf *keyconf,
u8 sta_id)
{
unsigned long flags;
__le16 key_flags = 0;

- switch (keyconf->alg) {
- case ALG_CCMP:
- key_flags |= STA_KEY_FLG_CCMP;
- key_flags |= cpu_to_le16(
- keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
- key_flags &= ~STA_KEY_FLG_INVALID;
- break;
- case ALG_TKIP:
- case ALG_WEP:
- default:
- return -EINVAL;
- }
+ key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
+ key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+
+ if (sta_id == priv->hw_setting.bcast_sta_id)
+ key_flags |= STA_KEY_MULTICAST_MSK;
+
+ keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ keyconf->hw_key_idx = keyconf->keyidx;
+
+ key_flags &= ~STA_KEY_FLG_INVALID;
+
spin_lock_irqsave(&priv->sta_lock, flags);
priv->stations[sta_id].keyinfo.alg = keyconf->alg;
priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
+
memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
keyconf->keylen);

memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
keyconf->keylen);
+
+ priv->stations[sta_id].sta.key.key_offset
+ = (sta_id % STA_KEY_MAX_NUM);/*FIXME*/
priv->stations[sta_id].sta.key.key_flags = key_flags;
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
@@ -1362,8 +1377,15 @@ static int iwl4965_update_sta_key_info(struct iwl_priv *priv,
spin_unlock_irqrestore(&priv->sta_lock, flags);

IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
- iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0);
- return 0;
+ return iwl4965_send_add_station(priv,
+ &priv->stations[sta_id].sta, CMD_ASYNC);
+}
+
+static int iwl4965_set_tkip_dynamic_key_info(struct iwl_priv *priv,
+ struct ieee80211_key_conf *keyconf,
+ u8 sta_id)
+{
+ return -EOPNOTSUPP;
}

static int iwl4965_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
@@ -1383,6 +1405,46 @@ static int iwl4965_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
return 0;
}

+static int iwl4965_set_dynamic_key(struct iwl_priv *priv,
+ struct ieee80211_key_conf *key, u8 sta_id)
+{
+ int ret;
+
+ switch (key->alg) {
+ case ALG_CCMP:
+ ret = iwl4965_set_ccmp_dynamic_key_info(priv, key, sta_id);
+ break;
+ case ALG_TKIP:
+ ret = iwl4965_set_tkip_dynamic_key_info(priv, key, sta_id);
+ break;
+ case ALG_WEP:
+ ret = -EOPNOTSUPP;
+ break;
+ default:
+ IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, key->alg);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int iwl4965_remove_static_key(struct iwl_priv *priv)
+{
+ int ret = -EOPNOTSUPP;
+
+ return ret;
+}
+
+static int iwl4965_set_static_key(struct iwl_priv *priv,
+ struct ieee80211_key_conf *key)
+{
+ if (key->alg == ALG_WEP)
+ return -EOPNOTSUPP;
+
+ IWL_ERROR("Static key invalid: alg %d\n", key->alg);
+ return -EINVAL;
+}
+
static void iwl4965_clear_free_frames(struct iwl_priv *priv)
{
struct list_head *element;
@@ -2114,17 +2176,6 @@ static int iwl4965_scan_initiate(struct iwl_priv *priv)
return 0;
}

-static int iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
-{
- struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon;
-
- if (hw_decrypt)
- rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
- else
- rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK;
-
- return 0;
-}

static void iwl4965_set_flags_for_phymode(struct iwl_priv *priv,
enum ieee80211_band band)
@@ -2268,9 +2319,9 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
struct ieee80211_tx_control *ctl,
struct iwl4965_cmd *cmd,
struct sk_buff *skb_frag,
- int last_frag)
+ int sta_id)
{
- struct iwl4965_hw_key *keyinfo = &priv->stations[ctl->key_idx].keyinfo;
+ struct iwl4965_hw_key *keyinfo = &priv->stations[sta_id].keyinfo;

switch (keyinfo->alg) {
case ALG_CCMP:
@@ -2606,7 +2657,7 @@ static int iwl4965_tx_skb(struct iwl_priv *priv,
iwl4965_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len);

if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
- iwl4965_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, 0);
+ iwl4965_build_tx_cmd_hwcrypto(priv, ctl, out_cmd, skb, sta_id);

/* Set up TFD's 2nd entry to point directly to remainder of skb,
* if any (802.11 null frames have no payload). */
@@ -7113,8 +7164,9 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
{
struct iwl_priv *priv = hw->priv;
DECLARE_MAC_BUF(mac);
- int rc = 0;
- u8 sta_id;
+ int ret = 0;
+ u8 sta_id = IWL_INVALID_STATION;
+ u8 static_key;

IWL_DEBUG_MAC80211("enter\n");

@@ -7127,44 +7179,45 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
/* only support pairwise keys */
return -EOPNOTSUPP;

- sta_id = iwl4965_hw_find_station(priv, addr);
- if (sta_id == IWL_INVALID_STATION) {
- IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
- print_mac(mac, addr));
- return -EINVAL;
- }
+ /* FIXME: need to differenciate between static and dynamic key
+ * in the level of mac80211 */
+ static_key = !iwl4965_is_associated(priv);

- mutex_lock(&priv->mutex);
+ if (!static_key) {
+ sta_id = iwl4965_hw_find_station(priv, addr);
+ if (sta_id == IWL_INVALID_STATION) {
+ IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
+ print_mac(mac, addr));
+ return -EINVAL;
+ }
+ }

iwl4965_scan_cancel_timeout(priv, 100);

switch (cmd) {
- case SET_KEY:
- rc = iwl4965_update_sta_key_info(priv, key, sta_id);
- if (!rc) {
- iwl4965_set_rxon_hwcrypto(priv, 1);
- iwl4965_commit_rxon(priv);
- key->hw_key_idx = sta_id;
- IWL_DEBUG_MAC80211("set_key success, using hwcrypto\n");
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- }
+ case SET_KEY:
+ if (static_key)
+ ret = iwl4965_set_static_key(priv, key);
+ else
+ ret = iwl4965_set_dynamic_key(priv, key, sta_id);
+
+ IWL_DEBUG_MAC80211("enable hwcrypto key\n");
break;
case DISABLE_KEY:
- rc = iwl4965_clear_sta_key_info(priv, sta_id);
- if (!rc) {
- iwl4965_set_rxon_hwcrypto(priv, 0);
- iwl4965_commit_rxon(priv);
- IWL_DEBUG_MAC80211("disable hwcrypto key\n");
- }
+ if (static_key)
+ ret = iwl4965_remove_static_key(priv);
+ else
+ ret = iwl4965_clear_sta_key_info(priv, sta_id);
+
+ IWL_DEBUG_MAC80211("disable hwcrypto key\n");
break;
default:
- rc = -EINVAL;
+ ret = -EINVAL;
}

IWL_DEBUG_MAC80211("leave\n");
- mutex_unlock(&priv->mutex);

- return rc;
+ return ret;
}

static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, int queue,
--
1.5.3.4


2008-03-19 23:49:43

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 1/7] tkip: revert TKIP patches

From: Tomas Winkler <[email protected]>

This patch revert tkip patches in mac80211 and iwlwifi

Signed-off-by: Tomas Winkler <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-4965-commands.h | 10 -
drivers/net/wireless/iwlwifi/iwl-4965.c | 66 -------
drivers/net/wireless/iwlwifi/iwl4965-base.c | 226 ++++++----------------
include/net/mac80211.h | 15 --
net/mac80211/ieee80211_i.h | 2 -
net/mac80211/tkip.c | 17 +--
net/mac80211/tx.c | 12 --
net/mac80211/wpa.c | 27 +---
8 files changed, 64 insertions(+), 311 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h
index 5107100..1025ffe 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h
@@ -741,7 +741,6 @@ struct iwl4965_qosparam_cmd {
/* wep key in STA: 5-bytes (0) or 13-bytes (1) */
#define STA_KEY_FLG_KEY_SIZE_MSK __constant_cpu_to_le16(0x1000)
#define STA_KEY_MULTICAST_MSK __constant_cpu_to_le16(0x4000)
-#define STA_KEY_MAX_NUM 8

/* Flags indicate whether to modify vs. don't change various station params */
#define STA_MODIFY_KEY_MASK 0x01
@@ -890,10 +889,6 @@ struct iwl4965_rx_frame_hdr {
#define RX_RES_STATUS_SEC_TYPE_WEP (0x1 << 8)
#define RX_RES_STATUS_SEC_TYPE_CCMP (0x2 << 8)
#define RX_RES_STATUS_SEC_TYPE_TKIP (0x3 << 8)
-#define RX_RES_STATUS_SEC_TYPE_ERR (0x7 << 8)
-
-#define RX_RES_STATUS_STATION_FOUND (1<<6)
-#define RX_RES_STATUS_NO_STATION_INFO_MISMATCH (1<<7)

#define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11)
#define RX_RES_STATUS_NOT_DECRYPT (0x0 << 11)
@@ -901,11 +896,6 @@ struct iwl4965_rx_frame_hdr {
#define RX_RES_STATUS_BAD_ICV_MIC (0x1 << 11)
#define RX_RES_STATUS_BAD_KEY_TTAK (0x2 << 11)

-#define RX_MPDU_RES_STATUS_ICV_OK (0x20)
-#define RX_MPDU_RES_STATUS_MIC_OK (0x40)
-#define RX_MPDU_RES_STATUS_TTAK_OK (1 << 7)
-#define RX_MPDU_RES_STATUS_DEC_DONE_MSK (0x800)
-
struct iwl4965_rx_frame_end {
__le32 status;
__le64 timestamp;
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 376968f..5fe42ae 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -3401,65 +3401,6 @@ static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len)
priv->rx_stats[idx].bytes += len;
}

-static u32 iwl4965_translate_rx_status(u32 decrypt_in)
-{
- u32 decrypt_out = 0;
-
- if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) ==
- RX_RES_STATUS_STATION_FOUND)
- decrypt_out |= (RX_RES_STATUS_STATION_FOUND |
- RX_RES_STATUS_NO_STATION_INFO_MISMATCH);
-
- decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK);
-
- /* packet was not encrypted */
- if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
- RX_RES_STATUS_SEC_TYPE_NONE)
- return decrypt_out;
-
- /* packet was encrypted with unknown alg */
- if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
- RX_RES_STATUS_SEC_TYPE_ERR)
- return decrypt_out;
-
- /* decryption was not done in HW */
- if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) !=
- RX_MPDU_RES_STATUS_DEC_DONE_MSK)
- return decrypt_out;
-
- switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) {
-
- case RX_RES_STATUS_SEC_TYPE_CCMP:
- /* alg is CCM: check MIC only */
- if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK))
- /* Bad MIC */
- decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
- else
- decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
-
- break;
-
- case RX_RES_STATUS_SEC_TYPE_TKIP:
- if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) {
- /* Bad TTAK */
- decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK;
- break;
- }
- /* fall through if TTAK OK */
- default:
- if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK))
- decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
- else
- decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
- break;
- };
-
- IWL_DEBUG_RX("decrypt_in:0x%x decrypt_out = 0x%x\n",
- decrypt_in, decrypt_out);
-
- return decrypt_out;
-}
-
static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
int include_phy,
struct iwl4965_rx_mem_buffer *rxb,
@@ -3473,7 +3414,6 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
__le32 *rx_end;
unsigned int skblen;
u32 ampdu_status;
- u32 ampdu_status_legacy;

if (!include_phy && priv->last_phy_res[0])
rx_start = (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1];
@@ -3510,12 +3450,6 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
ampdu_status = le32_to_cpu(*rx_end);
skblen = ((u8 *) rx_end - (u8 *) & pkt->u.raw[0]) + sizeof(u32);

- if (!include_phy) {
- /* New status scheme, need to translate */
- ampdu_status_legacy = ampdu_status;
- ampdu_status = iwl4965_translate_rx_status(ampdu_status);
- }
-
/* start from MAC */
skb_reserve(rxb->skb, (void *)hdr - (void *)pkt);
skb_put(rxb->skb, len); /* end where data ends */
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 7ba4f1a..43f251c 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -788,17 +788,6 @@ out:
return ret;
}

-static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
-{
- struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon;
-
- if (hw_decrypt)
- rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
- else
- rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK;
-
-}
-
int iwl4965_send_cmd(struct iwl_priv *priv, struct iwl4965_host_cmd *cmd)
{
if (cmd->meta.flags & CMD_ASYNC)
@@ -1127,7 +1116,6 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv)
le16_to_cpu(priv->staging_rxon.channel),
print_mac(mac, priv->staging_rxon.bssid_addr));

- iwl4965_set_rxon_hwcrypto(priv, priv->cfg->mod_params->hw_crypto);
/* Apply the new configuration */
rc = iwl4965_send_cmd_pdu(priv, REPLY_RXON,
sizeof(struct iwl4965_rxon_cmd), &priv->staging_rxon);
@@ -1340,36 +1328,33 @@ int iwl4965_send_add_station(struct iwl_priv *priv,
return rc;
}

-static int iwl4965_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
+static int iwl4965_update_sta_key_info(struct iwl_priv *priv,
struct ieee80211_key_conf *keyconf,
u8 sta_id)
{
unsigned long flags;
__le16 key_flags = 0;

- key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
- key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
-
- if (sta_id == priv->hw_setting.bcast_sta_id)
- key_flags |= STA_KEY_MULTICAST_MSK;
-
- keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- keyconf->hw_key_idx = sta_id;
-
- key_flags &= ~STA_KEY_FLG_INVALID;
-
+ switch (keyconf->alg) {
+ case ALG_CCMP:
+ key_flags |= STA_KEY_FLG_CCMP;
+ key_flags |= cpu_to_le16(
+ keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+ key_flags &= ~STA_KEY_FLG_INVALID;
+ break;
+ case ALG_TKIP:
+ case ALG_WEP:
+ default:
+ return -EINVAL;
+ }
spin_lock_irqsave(&priv->sta_lock, flags);
priv->stations[sta_id].keyinfo.alg = keyconf->alg;
priv->stations[sta_id].keyinfo.keylen = keyconf->keylen;
-
memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key,
keyconf->keylen);

memcpy(priv->stations[sta_id].sta.key.key, keyconf->key,
keyconf->keylen);
-
- priv->stations[sta_id].sta.key.key_offset
- = (sta_id % STA_KEY_MAX_NUM);/*FIXME*/
priv->stations[sta_id].sta.key.key_flags = key_flags;
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
@@ -1377,66 +1362,8 @@ static int iwl4965_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
spin_unlock_irqrestore(&priv->sta_lock, flags);

IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
- return iwl4965_send_add_station(priv,
- &priv->stations[sta_id].sta, CMD_ASYNC);
-}
-
-static int iwl4965_set_tkip_dynamic_key_info(struct iwl_priv *priv,
- struct ieee80211_key_conf *keyconf,
- u8 sta_id)
-{
- unsigned long flags;
- __le16 key_flags = 0;
- int i, ret = 0;
-
- keyconf->flags |= IEEE80211_KEY_FLAG_TKIP_REQ_TX_P2_KEY;
- keyconf->flags |= IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY;
- keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
- keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
- keyconf->hw_key_idx = sta_id;
-
- key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK);
- key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
- key_flags &= ~STA_KEY_FLG_INVALID;
-
- if (sta_id == priv->hw_setting.bcast_sta_id)
- key_flags |= STA_KEY_MULTICAST_MSK;
-
- spin_lock_irqsave(&priv->sta_lock, flags);
-
- priv->stations[sta_id].keyinfo.alg = keyconf->alg;
- priv->stations[sta_id].keyinfo.keylen = 16;
-
- /* This copy is acutally not needed: we get the key with each TX */
- memcpy(priv->stations[sta_id].keyinfo.key, keyconf->key, 16);
-
- memcpy(priv->stations[sta_id].sta.key.key, keyconf->key, 16);
-
- priv->stations[sta_id].sta.key.key_offset = (sta_id%8);/*FIXME!!!*/
- priv->stations[sta_id].sta.key.key_flags = key_flags;
- if (keyconf->flags & IEEE80211_KEY_FLAG_TKIP_PHASE1_VALID) {
- priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 =
- (u8) keyconf->tkip_iv32;
- for (i = 0; i < 5; i++)
- priv->stations[sta_id].sta.key.tkip_rx_ttak[i] =
- cpu_to_le16(keyconf->tkip_p1k[i]);
- } else {
- priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = 0xff;
- }
-
- priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
- priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-
- /* Don't send an incomplete key: a key w/o valid TTAK */
- if (keyconf->flags & IEEE80211_KEY_FLAG_TKIP_PHASE1_VALID) {
- IWL_DEBUG_INFO("hwcrypto: modify ucode station key info\n");
- ret = iwl4965_send_add_station(priv,
- &priv->stations[sta_id].sta, CMD_ASYNC);
- }
-
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-
- return ret;
+ iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, 0);
+ return 0;
}

static int iwl4965_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
@@ -1456,46 +1383,6 @@ static int iwl4965_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
return 0;
}

-static int iwl4965_set_dynamic_key(struct iwl_priv *priv,
- struct ieee80211_key_conf *key, u8 sta_id)
-{
- int ret;
-
- switch (key->alg) {
- case ALG_CCMP:
- ret = iwl4965_set_ccmp_dynamic_key_info(priv, key, sta_id);
- break;
- case ALG_TKIP:
- ret = iwl4965_set_tkip_dynamic_key_info(priv, key, sta_id);
- break;
- case ALG_WEP:
- ret = -EOPNOTSUPP;
- break;
- default:
- IWL_ERROR("Unknown alg: %s alg = %d\n", __func__, key->alg);
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int iwl4965_remove_static_key(struct iwl_priv *priv)
-{
- int ret = -EOPNOTSUPP;
-
- return ret;
-}
-
-static int iwl4965_set_static_key(struct iwl_priv *priv,
- struct ieee80211_key_conf *key)
-{
- if (key->alg == ALG_WEP)
- return -EOPNOTSUPP;
-
- IWL_ERROR("Static key invalid: alg %d\n", key->alg);
- return -EINVAL;
-}
-
static void iwl4965_clear_free_frames(struct iwl_priv *priv)
{
struct list_head *element;
@@ -2227,6 +2114,17 @@ static int iwl4965_scan_initiate(struct iwl_priv *priv)
return 0;
}

+static int iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt)
+{
+ struct iwl4965_rxon_cmd *rxon = &priv->staging_rxon;
+
+ if (hw_decrypt)
+ rxon->filter_flags &= ~RXON_FILTER_DIS_DECRYPT_MSK;
+ else
+ rxon->filter_flags |= RXON_FILTER_DIS_DECRYPT_MSK;
+
+ return 0;
+}

static void iwl4965_set_flags_for_phymode(struct iwl_priv *priv,
enum ieee80211_band band)
@@ -2384,9 +2282,15 @@ static void iwl4965_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
break;

case ALG_TKIP:
+#if 0
cmd->cmd.tx.sec_ctl = TX_CMD_SEC_TKIP;
- memcpy(cmd->cmd.tx.key, ctl->tkip_key, keyinfo->keylen);
- IWL_DEBUG_TX("tx_cmd with tkip hwcrypto\n");
+
+ if (last_frag)
+ memcpy(cmd->cmd.tx.tkip_mic.byte, skb_frag->tail - 8,
+ 8);
+ else
+ memset(cmd->cmd.tx.tkip_mic.byte, 0, 8);
+#endif
break;

case ALG_WEP:
@@ -2893,12 +2797,6 @@ void iwl4965_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res);
switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) {
case RX_RES_STATUS_SEC_TYPE_TKIP:
- /* The uCode has got a bad phase 1 Key, pushes the packet.
- * Decryption will be done in SW. */
- if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
- RX_RES_STATUS_BAD_KEY_TTAK)
- break;
-
if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
RX_RES_STATUS_BAD_ICV_MIC)
stats->flag |= RX_FLAG_MMIC_ERROR;
@@ -7215,9 +7113,8 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
{
struct iwl_priv *priv = hw->priv;
DECLARE_MAC_BUF(mac);
- int ret = 0;
- u8 sta_id = IWL_INVALID_STATION;
- u8 static_key;
+ int rc = 0;
+ u8 sta_id;

IWL_DEBUG_MAC80211("enter\n");

@@ -7230,45 +7127,44 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
/* only support pairwise keys */
return -EOPNOTSUPP;

- /* FIXME: need to differenciate between static and dynamic key
- * in the level of mac80211 */
- static_key = !iwl4965_is_associated(priv);
-
- if (!static_key) {
- sta_id = iwl4965_hw_find_station(priv, addr);
- if (sta_id == IWL_INVALID_STATION) {
- IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
- print_mac(mac, addr));
- return -EINVAL;
- }
+ sta_id = iwl4965_hw_find_station(priv, addr);
+ if (sta_id == IWL_INVALID_STATION) {
+ IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
+ print_mac(mac, addr));
+ return -EINVAL;
}

+ mutex_lock(&priv->mutex);
+
iwl4965_scan_cancel_timeout(priv, 100);

switch (cmd) {
- case SET_KEY:
- if (static_key)
- ret = iwl4965_set_static_key(priv, key);
- else
- ret = iwl4965_set_dynamic_key(priv, key, sta_id);
-
- IWL_DEBUG_MAC80211("enable hwcrypto key\n");
+ case SET_KEY:
+ rc = iwl4965_update_sta_key_info(priv, key, sta_id);
+ if (!rc) {
+ iwl4965_set_rxon_hwcrypto(priv, 1);
+ iwl4965_commit_rxon(priv);
+ key->hw_key_idx = sta_id;
+ IWL_DEBUG_MAC80211("set_key success, using hwcrypto\n");
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+ }
break;
case DISABLE_KEY:
- if (static_key)
- ret = iwl4965_remove_static_key(priv);
- else
- ret = iwl4965_clear_sta_key_info(priv, sta_id);
-
- IWL_DEBUG_MAC80211("disable hwcrypto key\n");
+ rc = iwl4965_clear_sta_key_info(priv, sta_id);
+ if (!rc) {
+ iwl4965_set_rxon_hwcrypto(priv, 0);
+ iwl4965_commit_rxon(priv);
+ IWL_DEBUG_MAC80211("disable hwcrypto key\n");
+ }
break;
default:
- ret = -EINVAL;
+ rc = -EINVAL;
}

IWL_DEBUG_MAC80211("leave\n");
+ mutex_unlock(&priv->mutex);

- return ret;
+ return rc;
}

static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, int queue,
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 3b5d57c..5ab6a35 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -287,7 +287,6 @@ struct ieee80211_tx_control {
u8 iv_len; /* length of the IV field in octets */
u8 queue; /* hardware queue to use for this frame;
* 0 = highest, hw->queues-1 = lowest */
- u8 tkip_key[16]; /* generated phase2/phase1 key for hw TKIP */
int type; /* internal */
};

@@ -587,23 +586,11 @@ enum ieee80211_key_alg {
* @IEEE80211_KEY_FLAG_GENERATE_MMIC: This flag should be set by
* the driver for a TKIP key if it requires Michael MIC
* generation in software.
- * @IEEE80211_KEY_FLAG_TKIP_REQ_TX_P2_KEY: This flag should be set by
- * the driver for a TKIP key if it requires a phase2 TX key generation
- * in SW. The key will be attached to each packet.
- * @IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY: This flag should be set by the driver
- * for a TKIP key if it requires phase 1 key generation in software.
- * The phase 1 key will be sent in the same context as Rx.
- * @IEEE80211_KEY_FLAG_TKIP_PHASE1_VALID: Set by mac80211, valid only when
- * IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY was set. When set, the phase 1
- * fields (tkip_p1k and tkip_iv32) in ieee80211_key_conf are valid.
*/
enum ieee80211_key_flags {
IEEE80211_KEY_FLAG_WMM_STA = 1<<0,
IEEE80211_KEY_FLAG_GENERATE_IV = 1<<1,
IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2,
- IEEE80211_KEY_FLAG_TKIP_REQ_TX_P2_KEY = 1<<3,
- IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY = 1<<4,
- IEEE80211_KEY_FLAG_TKIP_PHASE1_VALID = 1<<5,
};

/**
@@ -627,8 +614,6 @@ struct ieee80211_key_conf {
u8 flags;
s8 keyidx;
u8 keylen;
- u16 tkip_p1k[5];
- u8 tkip_iv32;
u8 key[0];
};

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index d4c5f65..a6485f0 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -156,7 +156,6 @@ struct ieee80211_tx_data {
struct sta_info *sta;
u16 fc, ethertype;
struct ieee80211_key *key;
- u8 tkip_key[16];
unsigned int flags;

struct ieee80211_tx_control *control;
@@ -171,7 +170,6 @@ struct ieee80211_tx_data {
* in skb) */
int num_extra_frag;
struct sk_buff **extra_frag;
- u8 *frag_tkip_key; /* size 16 * num_extra_frag */
};


diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c
index 03b5ded..3abe194 100644
--- a/net/mac80211/tkip.c
+++ b/net/mac80211/tkip.c
@@ -286,8 +286,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
return TKIP_DECRYPT_REPLAY;
}

- if (only_iv &&
- !(key->conf.flags & IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY)) {
+ if (only_iv) {
res = TKIP_DECRYPT_OK;
key->u.tkip.rx_initialized[queue] = 1;
goto done;
@@ -299,14 +298,6 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
/* IV16 wrapped around - perform TKIP phase 1 */
tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
iv32, key->u.tkip.p1k_rx[queue]);
- if (key->conf.flags & IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY) {
- /* The driver needs a phase 1 key, provide it */
- memcpy(&key->conf.tkip_p1k,
- &key->u.tkip.p1k_rx[queue],
- sizeof(key->conf.tkip_p1k));
- key->conf.tkip_iv32 = iv32;
- key->conf.flags |= IEEE80211_KEY_FLAG_TKIP_PHASE1_VALID;
- }
#ifdef CONFIG_TKIP_DEBUG
{
int i;
@@ -326,12 +317,6 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm,
#endif /* CONFIG_TKIP_DEBUG */
}

- if (only_iv) {
- res = TKIP_DECRYPT_OK;
- key->u.tkip.rx_initialized[queue] = 1;
- goto done;
- }
-
tkip_mixing_phase2(key->u.tkip.p1k_rx[queue],
&key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
iv16, rc4key);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index ee09464..80f4343 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1078,11 +1078,6 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
if (skb) {
ieee80211_dump_frame(wiphy_name(local->hw.wiphy),
"TX to low-level driver", skb);
-
- if (tx->key && (tx->key->conf.flags &
- IEEE80211_KEY_FLAG_TKIP_REQ_TX_P2_KEY))
- memcpy(control->tkip_key, tx->tkip_key, 16);
-
ret = local->ops->tx(local_to_hw(local), skb, control);
if (ret)
return IEEE80211_TX_AGAIN;
@@ -1097,11 +1092,6 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
for (i = 0; i < tx->num_extra_frag; i++) {
if (!tx->extra_frag[i])
continue;
-
- if (tx->frag_tkip_key)
- memcpy(control->tkip_key,
- &tx->frag_tkip_key[i * 16], 16);
-
if (__ieee80211_queue_stopped(local, control->queue))
return IEEE80211_TX_FRAG_AGAIN;
if (i == tx->num_extra_frag) {
@@ -1129,8 +1119,6 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
}
kfree(tx->extra_frag);
tx->extra_frag = NULL;
- kfree(tx->frag_tkip_key);
- tx->frag_tkip_key = NULL;
}
return IEEE80211_TX_OK;
}
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index 60f2349..df0b734 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -229,7 +229,6 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx,
(u8) key->u.tkip.iv16);

tx->control->key_idx = tx->key->conf.hw_key_idx;
-
return 0;
}

@@ -247,7 +246,6 @@ ieee80211_tx_result
ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx)
{
struct sk_buff *skb = tx->skb;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
int wpa_test = 0, test = 0;

tx->control->icv_len = TKIP_ICV_LEN;
@@ -265,21 +263,12 @@ ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx)
if (tkip_encrypt_skb(tx, skb, test) < 0)
return TX_DROP;

- if (tx->key->conf.flags & IEEE80211_KEY_FLAG_TKIP_REQ_TX_P2_KEY)
- ieee80211_tkip_gen_rc4key(tx->key, hdr->addr2, tx->tkip_key);
-
-
if (tx->extra_frag) {
int i;
- if (tx->key->conf.flags & IEEE80211_KEY_FLAG_TKIP_REQ_TX_P2_KEY)
- tx->frag_tkip_key =
- kzalloc(tx->num_extra_frag * 16, GFP_ATOMIC);
for (i = 0; i < tx->num_extra_frag; i++) {
- if (tkip_encrypt_skb(tx, tx->extra_frag[i], test) < 0)
+ if (tkip_encrypt_skb(tx, tx->extra_frag[i], test)
+ < 0)
return TX_DROP;
- if (tx->key->conf.flags & IEEE80211_KEY_FLAG_TKIP_REQ_TX_P2_KEY)
- ieee80211_tkip_gen_rc4key(tx->key, hdr->addr2,
- &tx->frag_tkip_key[i * 16]);
}
}

@@ -336,18 +325,6 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx)
return RX_DROP_UNUSABLE;
}

- if (key->conf.flags & IEEE80211_KEY_FLAG_TKIP_PHASE1_VALID) {
- u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- u8 *sta_addr = rx->sta->addr;
-
- if (is_multicast_ether_addr(hdr->addr1))
- sta_addr = bcast;
-
- rx->local->ops->set_key(local_to_hw(rx->local),
- SET_KEY, rx->dev->dev_addr, sta_addr, &key->conf);
- key->conf.flags &= ~IEEE80211_KEY_FLAG_TKIP_PHASE1_VALID;
- }
-
/* Trim ICV */
skb_trim(skb, skb->len - TKIP_ICV_LEN);

--
1.5.3.4


2008-03-20 00:00:49

by Reinette Chatre

[permalink] [raw]
Subject: RE: [PATCH 0/7] iwlwifi and mac80211 updates (TKIP)

On Wednesday, March 19, 2008 4:42 PM, Chatre, Reinette wrote:

> This series reverts the previous TKIP related patches to mac80211
> and iwlwifi and addresses the issues discussed on the mailing list.
>
> [PATCH 1/7] tkip: revert TKIP patches
> [PATCH 2/7] iwlwifi-2.6: Cleans up set_key flow
> [PATCH 3/7] iwlwifi-2.6: RX status translation to old scheme
> [PATCH 4/7] mac80211: get a TKIP phase key from skb
> [PATCH 5/7] mac80211: allows driver to request a Phase 1 RX key
> [PATCH 6/7] iwlwifi-2.6: enables HW TKIP encryption
> [PATCH 7/7] iwlwifi-2.6: enables RX TKIP decryption in HW

This may be useful:

The patches reverted by the first patch in this series are titled:

mac80211: allows driver to request a Phase 2 key
mac80211: allows driver to request a Phase 1 RX key
iwlwifi-2.6: Cleans up set_key flow
iwlwifi-2.6: enables HW TKIP security
iwlwifi-2.6: RX status translation to old scheme
mac80211: TKIP enable HW encryption for fragmented packets

Reinette

2008-03-20 20:39:08

by John W. Linville

[permalink] [raw]
Subject: Re: [PATCH 0/7] iwlwifi and mac80211 updates (TKIP)

On Wed, Mar 19, 2008 at 04:56:20PM -0700, Chatre, Reinette wrote:
> On Wednesday, March 19, 2008 4:42 PM, Chatre, Reinette wrote:
>
> > This series reverts the previous TKIP related patches to mac80211
> > and iwlwifi and addresses the issues discussed on the mailing list.
> >
> > [PATCH 1/7] tkip: revert TKIP patches
> > [PATCH 2/7] iwlwifi-2.6: Cleans up set_key flow
> > [PATCH 3/7] iwlwifi-2.6: RX status translation to old scheme
> > [PATCH 4/7] mac80211: get a TKIP phase key from skb
> > [PATCH 5/7] mac80211: allows driver to request a Phase 1 RX key
> > [PATCH 6/7] iwlwifi-2.6: enables HW TKIP encryption
> > [PATCH 7/7] iwlwifi-2.6: enables RX TKIP decryption in HW
>
> This may be useful:
>
> The patches reverted by the first patch in this series are titled:
>
> mac80211: allows driver to request a Phase 2 key
> mac80211: allows driver to request a Phase 1 RX key
> iwlwifi-2.6: Cleans up set_key flow
> iwlwifi-2.6: enables HW TKIP security
> iwlwifi-2.6: RX status translation to old scheme
> mac80211: TKIP enable HW encryption for fragmented packets

FWIW, I'll revert those patches individually. Thanks for the hint
on which ones! :-)

John
--
John W. Linville
[email protected]

2008-03-19 23:49:51

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 3/7] iwlwifi-2.6: RX status translation to old scheme

From: Emmanuel Grumbach <[email protected]>

This patch adds translation for the RX status of an incoming packet.
The incoming status has to be translated to the old scheme in order to know
if the decryption has been done, MIC failure has occured, TTAK is valid etc...
This translation is mandatory for all RX packets when using 5300 and for
all HT packets using 4965.

Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl-4965-commands.h | 9 +++
drivers/net/wireless/iwlwifi/iwl-4965.c | 66 ++++++++++++++++++++++
drivers/net/wireless/iwlwifi/iwl4965-base.c | 6 ++
3 files changed, 81 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h
index 085d813..1d82f10 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-commands.h
@@ -890,6 +890,10 @@ struct iwl4965_rx_frame_hdr {
#define RX_RES_STATUS_SEC_TYPE_WEP (0x1 << 8)
#define RX_RES_STATUS_SEC_TYPE_CCMP (0x2 << 8)
#define RX_RES_STATUS_SEC_TYPE_TKIP (0x3 << 8)
+#define RX_RES_STATUS_SEC_TYPE_ERR (0x7 << 8)
+
+#define RX_RES_STATUS_STATION_FOUND (1<<6)
+#define RX_RES_STATUS_NO_STATION_INFO_MISMATCH (1<<7)

#define RX_RES_STATUS_DECRYPT_TYPE_MSK (0x3 << 11)
#define RX_RES_STATUS_NOT_DECRYPT (0x0 << 11)
@@ -897,6 +901,11 @@ struct iwl4965_rx_frame_hdr {
#define RX_RES_STATUS_BAD_ICV_MIC (0x1 << 11)
#define RX_RES_STATUS_BAD_KEY_TTAK (0x2 << 11)

+#define RX_MPDU_RES_STATUS_ICV_OK (0x20)
+#define RX_MPDU_RES_STATUS_MIC_OK (0x40)
+#define RX_MPDU_RES_STATUS_TTAK_OK (1 << 7)
+#define RX_MPDU_RES_STATUS_DEC_DONE_MSK (0x800)
+
struct iwl4965_rx_frame_end {
__le32 status;
__le64 timestamp;
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 5fe42ae..376968f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -3401,6 +3401,65 @@ static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len)
priv->rx_stats[idx].bytes += len;
}

+static u32 iwl4965_translate_rx_status(u32 decrypt_in)
+{
+ u32 decrypt_out = 0;
+
+ if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) ==
+ RX_RES_STATUS_STATION_FOUND)
+ decrypt_out |= (RX_RES_STATUS_STATION_FOUND |
+ RX_RES_STATUS_NO_STATION_INFO_MISMATCH);
+
+ decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK);
+
+ /* packet was not encrypted */
+ if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
+ RX_RES_STATUS_SEC_TYPE_NONE)
+ return decrypt_out;
+
+ /* packet was encrypted with unknown alg */
+ if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) ==
+ RX_RES_STATUS_SEC_TYPE_ERR)
+ return decrypt_out;
+
+ /* decryption was not done in HW */
+ if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) !=
+ RX_MPDU_RES_STATUS_DEC_DONE_MSK)
+ return decrypt_out;
+
+ switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) {
+
+ case RX_RES_STATUS_SEC_TYPE_CCMP:
+ /* alg is CCM: check MIC only */
+ if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK))
+ /* Bad MIC */
+ decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
+ else
+ decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
+
+ break;
+
+ case RX_RES_STATUS_SEC_TYPE_TKIP:
+ if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) {
+ /* Bad TTAK */
+ decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK;
+ break;
+ }
+ /* fall through if TTAK OK */
+ default:
+ if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK))
+ decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC;
+ else
+ decrypt_out |= RX_RES_STATUS_DECRYPT_OK;
+ break;
+ };
+
+ IWL_DEBUG_RX("decrypt_in:0x%x decrypt_out = 0x%x\n",
+ decrypt_in, decrypt_out);
+
+ return decrypt_out;
+}
+
static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
int include_phy,
struct iwl4965_rx_mem_buffer *rxb,
@@ -3414,6 +3473,7 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
__le32 *rx_end;
unsigned int skblen;
u32 ampdu_status;
+ u32 ampdu_status_legacy;

if (!include_phy && priv->last_phy_res[0])
rx_start = (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1];
@@ -3450,6 +3510,12 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
ampdu_status = le32_to_cpu(*rx_end);
skblen = ((u8 *) rx_end - (u8 *) & pkt->u.raw[0]) + sizeof(u32);

+ if (!include_phy) {
+ /* New status scheme, need to translate */
+ ampdu_status_legacy = ampdu_status;
+ ampdu_status = iwl4965_translate_rx_status(ampdu_status);
+ }
+
/* start from MAC */
skb_reserve(rxb->skb, (void *)hdr - (void *)pkt);
skb_put(rxb->skb, len); /* end where data ends */
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 3d1f43a..9d4cd8e 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -2848,6 +2848,12 @@ void iwl4965_set_decrypted_flag(struct iwl_priv *priv, struct sk_buff *skb,
IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res);
switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) {
case RX_RES_STATUS_SEC_TYPE_TKIP:
+ /* The uCode has got a bad phase 1 Key, pushes the packet.
+ * Decryption will be done in SW. */
+ if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
+ RX_RES_STATUS_BAD_KEY_TTAK)
+ break;
+
if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) ==
RX_RES_STATUS_BAD_ICV_MIC)
stats->flag |= RX_FLAG_MMIC_ERROR;
--
1.5.3.4


2008-03-19 23:49:51

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 7/7] iwlwifi-2.6: enables RX TKIP decryption in HW

From: Emmanuel Grumbach <[email protected]>

This patch enables RX TKIP decryption in HW.

Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
---
drivers/net/wireless/iwlwifi/iwl4965-base.c | 51 +++++++++++++++++++++++++++
1 files changed, 51 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 2449e00..4af365f 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -1390,6 +1390,7 @@ static int iwl4965_set_tkip_dynamic_key_info(struct iwl_priv *priv,

keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
+ keyconf->flags |= IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY;
keyconf->hw_key_idx = keyconf->keyidx;

spin_lock_irqsave(&priv->sta_lock, flags);
@@ -7179,6 +7180,55 @@ out_unlock:
return rc;
}

+static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw,
+ struct ieee80211_key_conf *keyconf, const u8 *addr,
+ u32 iv32, u16 *phase1key)
+{
+ struct iwl_priv *priv = hw->priv;
+ u8 sta_id = IWL_INVALID_STATION;
+ unsigned long flags;
+ __le16 key_flags = 0;
+ int i;
+ DECLARE_MAC_BUF(mac);
+
+ IWL_DEBUG_MAC80211("enter\n");
+
+ sta_id = iwl4965_hw_find_station(priv, addr);
+ if (sta_id == IWL_INVALID_STATION) {
+ IWL_DEBUG_MAC80211("leave - %s not in station map.\n",
+ print_mac(mac, addr));
+ return;
+ }
+
+ iwl4965_scan_cancel_timeout(priv, 100);
+
+ key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK);
+ key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+ key_flags &= ~STA_KEY_FLG_INVALID;
+
+ if (sta_id == priv->hw_setting.bcast_sta_id)
+ key_flags |= STA_KEY_MULTICAST_MSK;
+
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
+ priv->stations[sta_id].sta.key.key_offset = (sta_id % 8);/* FIXME */
+ priv->stations[sta_id].sta.key.key_flags = key_flags;
+ priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32;
+
+ for (i = 0; i < 5; i++)
+ priv->stations[sta_id].sta.key.tkip_rx_ttak[i] =
+ cpu_to_le16(phase1key[i]);
+
+ priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
+ priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+
+ iwl4965_send_add_station(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
+
+ IWL_DEBUG_MAC80211("leave\n");
+}
+
static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
const u8 *local_addr, const u8 *addr,
struct ieee80211_key_conf *key)
@@ -8120,6 +8170,7 @@ static struct ieee80211_ops iwl4965_hw_ops = {
.config_interface = iwl4965_mac_config_interface,
.configure_filter = iwl4965_configure_filter,
.set_key = iwl4965_mac_set_key,
+ .update_tkip_key = iwl4965_mac_update_tkip_key,
.get_stats = iwl4965_mac_get_stats,
.get_tx_stats = iwl4965_mac_get_tx_stats,
.conf_tx = iwl4965_mac_conf_tx,
--
1.5.3.4


2008-03-19 23:49:47

by Reinette Chatre

[permalink] [raw]
Subject: [PATCH 4/7] mac80211: get a TKIP phase key from skb

From: Emmanuel Grumbach <[email protected]>

This patch makes mac80211 able to compute a TKIP key from an skb.
The requested key can be a phase 1 or a phase 2 key.
This is useful for drivers who need to provide tkip key to their
HW to enable HW encryption.

Signed-off-by: Emmanuel Grumbach <[email protected]>
Signed-off-by: Tomas Winkler <[email protected]>
---
include/net/mac80211.h | 30 +++++++++++++++++++++++++++
net/mac80211/tkip.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 83 insertions(+), 0 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 5ab6a35..4b35f64 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -644,6 +644,21 @@ enum sta_notify_cmd {
};

/**
+ * enum ieee80211_tkip_key_type - get tkip key
+ *
+ * Used by drivers which need to get a tkip key for skb. Some drivers need a
+ * phase 1 key, others need a phase 2 key. A single function allows the driver
+ * to get the key, this enum indicates what type of key is required.
+ *
+ * @IEEE80211_TKIP_P1_KEY: the driver needs a phase 1 key
+ * @IEEE80211_TKIP_P2_KEY: the driver needs a phase 2 key
+ */
+enum ieee80211_tkip_key_type {
+ IEEE80211_TKIP_P1_KEY = 1<<0,
+ IEEE80211_TKIP_P2_KEY = 1<<1,
+};
+
+/**
* enum ieee80211_hw_flags - hardware flags
*
* These flags are used to indicate hardware capabilities to
@@ -1472,6 +1487,21 @@ int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb);
int ieee80211_get_hdrlen(u16 fc);

/**
+ * ieee80211_get_tkip_rc4_key - get a phase 2 key for skb
+ *
+ * This function computes a phase 2 key for an skb. It computes
+ * a phase 1 key if needed (iv16 wraps around). This function is to
+ * be used by drivers which can do HW encryption but need to compute
+ * to phase 2 key in SW.
+ *
+ * @keyconf: the parameter passed with the set key
+ * @skb: the skb for which the key is needed
+ * @rc4key: a buffer to which the key will be written
+ */
+void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
+ struct sk_buff *skb,
+ enum ieee80211_tkip_key_type type, u8 *key);
+/**
* ieee80211_wake_queue - wake specific queue
* @hw: pointer as obtained from ieee80211_alloc_hw().
* @queue: queue number (counted from zero).
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c
index 3abe194..5c36b2d 100644
--- a/net/mac80211/tkip.c
+++ b/net/mac80211/tkip.c
@@ -214,6 +214,59 @@ void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta,
key->u.tkip.iv16, rc4key);
}

+void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf,
+ struct sk_buff *skb, enum ieee80211_tkip_key_type type,
+ u8 *outkey)
+{
+ struct ieee80211_key *key = (struct ieee80211_key *)
+ container_of(keyconf, struct ieee80211_key, conf);
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ u8 *data = (u8 *) hdr;
+ u16 fc = le16_to_cpu(hdr->frame_control);
+ int hdr_len = ieee80211_get_hdrlen(fc);
+ u8 *ta = hdr->addr2;
+ u16 iv16;
+ u32 iv32;
+
+ iv16 = data[hdr_len] << 8;
+ iv16 += data[hdr_len + 2];
+ iv32 = data[hdr_len + 4] +
+ (data[hdr_len + 5] >> 8) +
+ (data[hdr_len + 6] >> 16) +
+ (data[hdr_len + 7] >> 24);
+
+#ifdef CONFIG_TKIP_DEBUG
+ printk(KERN_DEBUG "TKIP encrypt: iv16 = 0x%04x, iv32 = 0x%08x\n",
+ iv16, iv32);
+
+ if (iv32 != key->u.tkip.iv32) {
+ printk(KERN_DEBUG "skb: iv32 = 0x%08x key: iv32 = 0x%08x\n",
+ iv32, key->u.tkip.iv32);
+ printk(KERN_DEBUG "Wrap around of iv16 in the middle of a "
+ "fragmented packet\n");
+ }
+#endif /* CONFIG_TKIP_DEBUG */
+
+ /* Update the p1k only when the iv16 in the packet wraps around, this
+ * might occur after the wrap around of iv16 in the key in case of
+ * fragmented packets. */
+ if (iv16 == 0 || !key->u.tkip.tx_initialized) {
+ /* IV16 wrapped around - perform TKIP phase 1 */
+ tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY],
+ iv32, key->u.tkip.p1k);
+ key->u.tkip.tx_initialized = 1;
+ }
+
+ if (type == IEEE80211_TKIP_P1_KEY) {
+ memcpy(outkey, key->u.tkip.p1k, sizeof(u16) * 5);
+ return;
+ }
+
+ tkip_mixing_phase2(key->u.tkip.p1k,
+ &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], iv16, outkey);
+}
+EXPORT_SYMBOL(ieee80211_get_tkip_key);
+
/* Encrypt packet payload with TKIP using @key. @pos is a pointer to the
* beginning of the buffer containing payload. This payload must include
* headroom of eight octets for IV and Ext. IV and taildroom of four octets
--
1.5.3.4


2008-03-20 00:00:49

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 4/7] mac80211: get a TKIP phase key from skb

Hi,

Thanks for your efforts!

> +enum ieee80211_tkip_key_type {
> + IEEE80211_TKIP_P1_KEY = 1<<0,

Please don't make them look like flags, not giving any explicit value at
all would be fine.

> /**
> + * ieee80211_get_tkip_rc4_key - get a phase 2 key for skb
> + *
> + * This function computes a phase 2 key for an skb. It computes
> + * a phase 1 key if needed (iv16 wraps around). This function is to
> + * be used by drivers which can do HW encryption but need to compute
> + * to phase 2 key in SW.

That documentation seems wrong given you can ask for key types.

Looks good otherwise.

johannes


Attachments:
signature.asc (828.00 B)
This is a digitally signed message part

2008-03-20 00:04:50

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 5/7] mac80211: allows driver to request a Phase 1 RX key


> --- a/include/net/mac80211.h
> +++ b/include/net/mac80211.h
> @@ -586,11 +586,15 @@ enum ieee80211_key_alg {
> * @IEEE80211_KEY_FLAG_GENERATE_MMIC: This flag should be set by
> * the driver for a TKIP key if it requires Michael MIC
> * generation in software.
> + * @IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY: This flag should bet by
> + * the driver for a TKIP key if it requires phase 1 key generation
> + * in SW.

Please get rid of the flag and just use a condition like

if (ops->update_tkip_callback &&
key->conf.flags & UPLOADED_TO_HARDWARE)

I cannot imagine hardware that wants this callback for some keys but not
for others.

> + *
> + * In TKIP some HW need to be provided a phase 1 key, for RX decryption
> + * acceleration (i.e. iwlwifi). Those drivers should set
> + * IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY.
> + * The update_tkip_key() call updates the driver with the new phase 1 key.
> + * This happens everytime the iv16 wraps around (every 65536 packets). The
> + * set_key() call will happen only once during a rekeying session, it will not

I would say "The set_key() call will still happen only once for each
key, ..."

> + * include a valid phase 1 key. The valid phase 1 key is provided by
> + * udpate_tkip_key only. The trigger that makes mac80211 call this handler is

typo: update_tkip_key

johannes


Attachments:
signature.asc (828.00 B)
This is a digitally signed message part