Commit 4af198fb authored by David Kilroy's avatar David Kilroy Committed by John W. Linville

orinoco: consolidate storage of WEP and TKIP keys

When TKIP support was added, we stored the keys separately to avoid
issues when both TKIP and WEP keys are sent to the driver.

We need to consolidate the storage to convert to cfg80211, so do this
first and try iron out the issues.
Signed-off-by: default avatarDavid Kilroy <kilroyd@googlemail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 2b260351
...@@ -768,12 +768,29 @@ int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv) ...@@ -768,12 +768,29 @@ int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
{ {
hermes_t *hw = &priv->hw; hermes_t *hw = &priv->hw;
int err = 0; int err = 0;
int i;
switch (priv->firmware_type) { switch (priv->firmware_type) {
case FIRMWARE_TYPE_AGERE: case FIRMWARE_TYPE_AGERE:
{
struct orinoco_key keys[ORINOCO_MAX_KEYS];
memset(&keys, 0, sizeof(keys));
for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
int len = min(priv->keys[i].key_len,
ORINOCO_MAX_KEY_SIZE);
memcpy(&keys[i].data, priv->keys[i].key, len);
if (len > SMALL_KEY_SIZE)
keys[i].len = cpu_to_le16(LARGE_KEY_SIZE);
else if (len > 0)
keys[i].len = cpu_to_le16(SMALL_KEY_SIZE);
else
keys[i].len = cpu_to_le16(0);
}
err = HERMES_WRITE_RECORD(hw, USER_BAP, err = HERMES_WRITE_RECORD(hw, USER_BAP,
HERMES_RID_CNFWEPKEYS_AGERE, HERMES_RID_CNFWEPKEYS_AGERE,
&priv->keys); &keys);
if (err) if (err)
return err; return err;
err = hermes_write_wordrec(hw, USER_BAP, err = hermes_write_wordrec(hw, USER_BAP,
...@@ -782,28 +799,38 @@ int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv) ...@@ -782,28 +799,38 @@ int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
if (err) if (err)
return err; return err;
break; break;
}
case FIRMWARE_TYPE_INTERSIL: case FIRMWARE_TYPE_INTERSIL:
case FIRMWARE_TYPE_SYMBOL: case FIRMWARE_TYPE_SYMBOL:
{ {
int keylen; int keylen;
int i;
/* Force uniform key length to work around /* Force uniform key length to work around
* firmware bugs */ * firmware bugs */
keylen = le16_to_cpu(priv->keys[priv->tx_key].len); keylen = priv->keys[priv->tx_key].key_len;
if (keylen > LARGE_KEY_SIZE) { if (keylen > LARGE_KEY_SIZE) {
printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n",
priv->ndev->name, priv->tx_key, keylen); priv->ndev->name, priv->tx_key, keylen);
return -E2BIG; return -E2BIG;
} } else if (keylen > SMALL_KEY_SIZE)
keylen = LARGE_KEY_SIZE;
else if (keylen > 0)
keylen = SMALL_KEY_SIZE;
else
keylen = 0;
/* Write all 4 keys */ /* Write all 4 keys */
for (i = 0; i < ORINOCO_MAX_KEYS; i++) { for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
u8 key[LARGE_KEY_SIZE] = { 0 };
memcpy(key, priv->keys[i].key,
priv->keys[i].key_len);
err = hermes_write_ltv(hw, USER_BAP, err = hermes_write_ltv(hw, USER_BAP,
HERMES_RID_CNFDEFAULTKEY0 + i, HERMES_RID_CNFDEFAULTKEY0 + i,
HERMES_BYTES_TO_RECLEN(keylen), HERMES_BYTES_TO_RECLEN(keylen),
priv->keys[i].data); key);
if (err) if (err)
return err; return err;
} }
...@@ -829,8 +856,8 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv) ...@@ -829,8 +856,8 @@ int __orinoco_hw_setup_enc(struct orinoco_private *priv)
int auth_flag; int auth_flag;
int enc_flag; int enc_flag;
/* Setup WEP keys for WEP and WPA */ /* Setup WEP keys */
if (priv->encode_alg) if (priv->encode_alg == ORINOCO_ALG_WEP)
__orinoco_hw_setup_wepkeys(priv); __orinoco_hw_setup_wepkeys(priv);
if (priv->wep_restrict) if (priv->wep_restrict)
...@@ -976,7 +1003,6 @@ int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx) ...@@ -976,7 +1003,6 @@ int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx)
hermes_t *hw = &priv->hw; hermes_t *hw = &priv->hw;
int err; int err;
memset(&priv->tkip_key[key_idx], 0, sizeof(priv->tkip_key[key_idx]));
err = hermes_write_wordrec(hw, USER_BAP, err = hermes_write_wordrec(hw, USER_BAP,
HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE, HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE,
key_idx); key_idx);
......
...@@ -341,12 +341,14 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -341,12 +341,14 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
struct orinoco_private *priv = ndev_priv(dev); struct orinoco_private *priv = ndev_priv(dev);
struct net_device_stats *stats = &priv->stats; struct net_device_stats *stats = &priv->stats;
struct orinoco_tkip_key *key;
hermes_t *hw = &priv->hw; hermes_t *hw = &priv->hw;
int err = 0; int err = 0;
u16 txfid = priv->txfid; u16 txfid = priv->txfid;
struct ethhdr *eh; struct ethhdr *eh;
int tx_control; int tx_control;
unsigned long flags; unsigned long flags;
int do_mic;
if (!netif_running(dev)) { if (!netif_running(dev)) {
printk(KERN_ERR "%s: Tx on stopped device!\n", printk(KERN_ERR "%s: Tx on stopped device!\n",
...@@ -378,9 +380,14 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -378,9 +380,14 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb->len < ETH_HLEN) if (skb->len < ETH_HLEN)
goto drop; goto drop;
key = (struct orinoco_tkip_key *) priv->keys[priv->tx_key].key;
do_mic = ((priv->encode_alg == ORINOCO_ALG_TKIP) &&
(key != NULL));
tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX; tx_control = HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX;
if (priv->encode_alg == ORINOCO_ALG_TKIP) if (do_mic)
tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) | tx_control |= (priv->tx_key << HERMES_MIC_KEY_ID_SHIFT) |
HERMES_TXCTRL_MIC; HERMES_TXCTRL_MIC;
...@@ -462,7 +469,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -462,7 +469,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
} }
/* Calculate Michael MIC */ /* Calculate Michael MIC */
if (priv->encode_alg == ORINOCO_ALG_TKIP) { if (do_mic) {
u8 mic_buf[MICHAEL_MIC_LEN + 1]; u8 mic_buf[MICHAEL_MIC_LEN + 1];
u8 *mic; u8 *mic;
size_t offset; size_t offset;
...@@ -480,8 +487,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -480,8 +487,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
len = MICHAEL_MIC_LEN; len = MICHAEL_MIC_LEN;
} }
orinoco_mic(priv->tx_tfm_mic, orinoco_mic(priv->tx_tfm_mic, key->tx_mic,
priv->tkip_key[priv->tx_key].tx_mic,
eh->h_dest, eh->h_source, 0 /* priority */, eh->h_dest, eh->h_source, 0 /* priority */,
skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic); skb->data + ETH_HLEN, skb->len - ETH_HLEN, mic);
...@@ -926,6 +932,7 @@ static void orinoco_rx(struct net_device *dev, ...@@ -926,6 +932,7 @@ static void orinoco_rx(struct net_device *dev,
/* Calculate and check MIC */ /* Calculate and check MIC */
if (status & HERMES_RXSTAT_MIC) { if (status & HERMES_RXSTAT_MIC) {
struct orinoco_tkip_key *key;
int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >> int key_id = ((status & HERMES_RXSTAT_MIC_KEY_ID) >>
HERMES_MIC_KEY_ID_SHIFT); HERMES_MIC_KEY_ID_SHIFT);
u8 mic[MICHAEL_MIC_LEN]; u8 mic[MICHAEL_MIC_LEN];
...@@ -939,14 +946,18 @@ static void orinoco_rx(struct net_device *dev, ...@@ -939,14 +946,18 @@ static void orinoco_rx(struct net_device *dev,
skb_trim(skb, skb->len - MICHAEL_MIC_LEN); skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
length -= MICHAEL_MIC_LEN; length -= MICHAEL_MIC_LEN;
orinoco_mic(priv->rx_tfm_mic, key = (struct orinoco_tkip_key *) priv->keys[key_id].key;
priv->tkip_key[key_id].rx_mic,
desc->addr1, if (!key) {
src, printk(KERN_WARNING "%s: Received encrypted frame from "
"%pM using key %i, but key is not installed\n",
dev->name, src, key_id);
goto drop;
}
orinoco_mic(priv->rx_tfm_mic, key->rx_mic, desc->addr1, src,
0, /* priority or QoS? */ 0, /* priority or QoS? */
skb->data, skb->data, skb->len, &mic[0]);
skb->len,
&mic[0]);
if (memcmp(mic, rxmic, if (memcmp(mic, rxmic,
MICHAEL_MIC_LEN)) { MICHAEL_MIC_LEN)) {
......
...@@ -120,7 +120,8 @@ struct orinoco_private { ...@@ -120,7 +120,8 @@ struct orinoco_private {
enum nl80211_iftype iw_mode; enum nl80211_iftype iw_mode;
enum orinoco_alg encode_alg; enum orinoco_alg encode_alg;
u16 wep_restrict, tx_key; u16 wep_restrict, tx_key;
struct orinoco_key keys[ORINOCO_MAX_KEYS]; struct key_params keys[ORINOCO_MAX_KEYS];
int bitratemode; int bitratemode;
char nick[IW_ESSID_MAX_SIZE+1]; char nick[IW_ESSID_MAX_SIZE+1];
char desired_essid[IW_ESSID_MAX_SIZE+1]; char desired_essid[IW_ESSID_MAX_SIZE+1];
...@@ -150,7 +151,6 @@ struct orinoco_private { ...@@ -150,7 +151,6 @@ struct orinoco_private {
u8 *wpa_ie; u8 *wpa_ie;
int wpa_ie_len; int wpa_ie_len;
struct orinoco_tkip_key tkip_key[ORINOCO_MAX_KEYS];
struct crypto_hash *rx_tfm_mic; struct crypto_hash *rx_tfm_mic;
struct crypto_hash *tx_tfm_mic; struct crypto_hash *tx_tfm_mic;
......
...@@ -22,6 +22,67 @@ ...@@ -22,6 +22,67 @@
#define MAX_RID_LEN 1024 #define MAX_RID_LEN 1024
/* Helper routine to record keys
* Do not call from interrupt context */
static int orinoco_set_key(struct orinoco_private *priv, int index,
enum orinoco_alg alg, const u8 *key, int key_len,
const u8 *seq, int seq_len)
{
kzfree(priv->keys[index].key);
kzfree(priv->keys[index].seq);
if (key_len) {
priv->keys[index].key = kzalloc(key_len, GFP_KERNEL);
if (!priv->keys[index].key)
goto nomem;
} else
priv->keys[index].key = NULL;
if (seq_len) {
priv->keys[index].seq = kzalloc(seq_len, GFP_KERNEL);
if (!priv->keys[index].seq)
goto free_key;
} else
priv->keys[index].seq = NULL;
priv->keys[index].key_len = key_len;
priv->keys[index].seq_len = seq_len;
if (key_len)
memcpy(priv->keys[index].key, key, key_len);
if (seq_len)
memcpy(priv->keys[index].seq, seq, seq_len);
switch (alg) {
case ORINOCO_ALG_TKIP:
priv->keys[index].cipher = WLAN_CIPHER_SUITE_TKIP;
break;
case ORINOCO_ALG_WEP:
priv->keys[index].cipher = (key_len > SMALL_KEY_SIZE) ?
WLAN_CIPHER_SUITE_WEP104 : WLAN_CIPHER_SUITE_WEP40;
break;
case ORINOCO_ALG_NONE:
default:
priv->keys[index].cipher = 0;
break;
}
return 0;
free_key:
kfree(priv->keys[index].key);
priv->keys[index].key = NULL;
nomem:
priv->keys[index].key_len = 0;
priv->keys[index].seq_len = 0;
priv->keys[index].cipher = 0;
return -ENOMEM;
}
static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
{ {
struct orinoco_private *priv = ndev_priv(dev); struct orinoco_private *priv = ndev_priv(dev);
...@@ -180,7 +241,6 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, ...@@ -180,7 +241,6 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev,
int setindex = priv->tx_key; int setindex = priv->tx_key;
enum orinoco_alg encode_alg = priv->encode_alg; enum orinoco_alg encode_alg = priv->encode_alg;
int restricted = priv->wep_restrict; int restricted = priv->wep_restrict;
u16 xlen = 0;
int err = -EINPROGRESS; /* Call commit handler */ int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags; unsigned long flags;
...@@ -207,12 +267,6 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, ...@@ -207,12 +267,6 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev,
if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
index = priv->tx_key; index = priv->tx_key;
/* Adjust key length to a supported value */
if (erq->length > SMALL_KEY_SIZE)
xlen = LARGE_KEY_SIZE;
else /* (erq->length > 0) */
xlen = SMALL_KEY_SIZE;
/* Switch on WEP if off */ /* Switch on WEP if off */
if (encode_alg != ORINOCO_ALG_WEP) { if (encode_alg != ORINOCO_ALG_WEP) {
setindex = index; setindex = index;
...@@ -229,7 +283,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, ...@@ -229,7 +283,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev,
} }
} else { } else {
/* Set the index : Check that the key is valid */ /* Set the index : Check that the key is valid */
if (priv->keys[index].len == 0) { if (priv->keys[index].key_len == 0) {
err = -EINVAL; err = -EINVAL;
goto out; goto out;
} }
...@@ -245,10 +299,8 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, ...@@ -245,10 +299,8 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev,
restricted = 1; restricted = 1;
if (erq->pointer && erq->length > 0) { if (erq->pointer && erq->length > 0) {
priv->keys[index].len = cpu_to_le16(xlen); err = orinoco_set_key(priv, index, ORINOCO_ALG_WEP, keybuf,
memset(priv->keys[index].data, 0, erq->length, NULL, 0);
sizeof(priv->keys[index].data));
memcpy(priv->keys[index].data, keybuf, erq->length);
} }
priv->tx_key = setindex; priv->tx_key = setindex;
...@@ -277,7 +329,6 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, ...@@ -277,7 +329,6 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev,
{ {
struct orinoco_private *priv = ndev_priv(dev); struct orinoco_private *priv = ndev_priv(dev);
int index = (erq->flags & IW_ENCODE_INDEX) - 1; int index = (erq->flags & IW_ENCODE_INDEX) - 1;
u16 xlen = 0;
unsigned long flags; unsigned long flags;
if (!priv->has_wep) if (!priv->has_wep)
...@@ -299,11 +350,9 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, ...@@ -299,11 +350,9 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev,
else else
erq->flags |= IW_ENCODE_OPEN; erq->flags |= IW_ENCODE_OPEN;
xlen = le16_to_cpu(priv->keys[index].len); erq->length = priv->keys[index].key_len;
erq->length = xlen; memcpy(keybuf, priv->keys[index].key, erq->length);
memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE);
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
return 0; return 0;
...@@ -789,7 +838,6 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, ...@@ -789,7 +838,6 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
int idx, alg = ext->alg, set_key = 1; int idx, alg = ext->alg, set_key = 1;
unsigned long flags; unsigned long flags;
int err = -EINVAL; int err = -EINVAL;
u16 key_len;
if (orinoco_lock(priv, &flags) != 0) if (orinoco_lock(priv, &flags) != 0)
return -EBUSY; return -EBUSY;
...@@ -822,24 +870,17 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, ...@@ -822,24 +870,17 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
switch (alg) { switch (alg) {
case IW_ENCODE_ALG_NONE: case IW_ENCODE_ALG_NONE:
priv->encode_alg = ORINOCO_ALG_NONE; priv->encode_alg = ORINOCO_ALG_NONE;
priv->keys[idx].len = 0; err = orinoco_set_key(priv, idx, ORINOCO_ALG_NONE,
NULL, 0, NULL, 0);
break; break;
case IW_ENCODE_ALG_WEP: case IW_ENCODE_ALG_WEP:
if (ext->key_len > SMALL_KEY_SIZE) if (ext->key_len <= 0)
key_len = LARGE_KEY_SIZE;
else if (ext->key_len > 0)
key_len = SMALL_KEY_SIZE;
else
goto out; goto out;
priv->encode_alg = ORINOCO_ALG_WEP; priv->encode_alg = ORINOCO_ALG_WEP;
priv->keys[idx].len = cpu_to_le16(key_len); err = orinoco_set_key(priv, idx, ORINOCO_ALG_WEP,
ext->key, ext->key_len, NULL, 0);
key_len = min(ext->key_len, key_len);
memset(priv->keys[idx].data, 0, ORINOCO_MAX_KEY_SIZE);
memcpy(priv->keys[idx].data, ext->key, key_len);
break; break;
case IW_ENCODE_ALG_TKIP: case IW_ENCODE_ALG_TKIP:
...@@ -847,20 +888,21 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, ...@@ -847,20 +888,21 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev,
u8 *tkip_iv = NULL; u8 *tkip_iv = NULL;
if (!priv->has_wpa || if (!priv->has_wpa ||
(ext->key_len > sizeof(priv->tkip_key[0]))) (ext->key_len > sizeof(struct orinoco_tkip_key)))
goto out; goto out;
priv->encode_alg = ORINOCO_ALG_TKIP; priv->encode_alg = ORINOCO_ALG_TKIP;
memset(&priv->tkip_key[idx], 0,
sizeof(priv->tkip_key[idx]));
memcpy(&priv->tkip_key[idx], ext->key, ext->key_len);
if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID)
tkip_iv = &ext->rx_seq[0]; tkip_iv = &ext->rx_seq[0];
err = orinoco_set_key(priv, idx, ORINOCO_ALG_TKIP,
ext->key, ext->key_len, tkip_iv,
ORINOCO_SEQ_LEN);
err = __orinoco_hw_set_tkip_key(priv, idx, err = __orinoco_hw_set_tkip_key(priv, idx,
ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
(u8 *) &priv->tkip_key[idx], priv->keys[idx].key,
tkip_iv, ORINOCO_SEQ_LEN, NULL, 0); tkip_iv, ORINOCO_SEQ_LEN, NULL, 0);
if (err) if (err)
printk(KERN_ERR "%s: Error %d setting TKIP key" printk(KERN_ERR "%s: Error %d setting TKIP key"
...@@ -918,16 +960,14 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev, ...@@ -918,16 +960,14 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev,
break; break;
case ORINOCO_ALG_WEP: case ORINOCO_ALG_WEP:
ext->alg = IW_ENCODE_ALG_WEP; ext->alg = IW_ENCODE_ALG_WEP;
ext->key_len = min_t(u16, le16_to_cpu(priv->keys[idx].len), ext->key_len = min(priv->keys[idx].key_len, max_key_len);
max_key_len); memcpy(ext->key, priv->keys[idx].key, ext->key_len);
memcpy(ext->key, priv->keys[idx].data, ext->key_len);
encoding->flags |= IW_ENCODE_ENABLED; encoding->flags |= IW_ENCODE_ENABLED;
break; break;
case ORINOCO_ALG_TKIP: case ORINOCO_ALG_TKIP:
ext->alg = IW_ENCODE_ALG_TKIP; ext->alg = IW_ENCODE_ALG_TKIP;
ext->key_len = min_t(u16, sizeof(struct orinoco_tkip_key), ext->key_len = min(priv->keys[idx].key_len, max_key_len);
max_key_len); memcpy(ext->key, priv->keys[idx].key, ext->key_len);
memcpy(ext->key, &priv->tkip_key[idx], ext->key_len);
encoding->flags |= IW_ENCODE_ENABLED; encoding->flags |= IW_ENCODE_ENABLED;
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment