Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 158826
b: refs/heads/master
c: 13e0fe7
h: refs/heads/master
v: v3
  • Loading branch information
Samuel Ortiz authored and John W. Linville committed Jul 10, 2009
1 parent 5ed1dc4 commit 0337aeb
Show file tree
Hide file tree
Showing 7 changed files with 220 additions and 333 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a70742f167424bab794ca74b9e99b598b358bb7d
refs/heads/master: 13e0fe70960e95cdea89b71aa3d046ec71efac8c
172 changes: 172 additions & 0 deletions trunk/drivers/net/wireless/iwmc3200wifi/cfg80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/wireless.h>
#include <linux/ieee80211.h>
#include <net/cfg80211.h>
Expand Down Expand Up @@ -130,6 +131,173 @@ static struct ieee80211_supported_band iwm_band_5ghz = {
.n_bitrates = iwm_a_rates_size,
};

static int iwm_key_init(struct iwm_key *key, u8 key_index,
const u8 *mac_addr, struct key_params *params)
{
key->hdr.key_idx = key_index;
if (!mac_addr || is_broadcast_ether_addr(mac_addr)) {
key->hdr.multicast = 1;
memset(key->hdr.mac, 0xff, ETH_ALEN);
} else {
key->hdr.multicast = 0;
memcpy(key->hdr.mac, mac_addr, ETH_ALEN);
}

if (params) {
if (params->key_len > WLAN_MAX_KEY_LEN ||
params->seq_len > IW_ENCODE_SEQ_MAX_SIZE)
return -EINVAL;

key->cipher = params->cipher;
key->key_len = params->key_len;
key->seq_len = params->seq_len;
memcpy(key->key, params->key, key->key_len);
memcpy(key->seq, params->seq, key->seq_len);
}

return 0;
}

static int iwm_reset_profile(struct iwm_priv *iwm)
{
int ret;

if (!iwm->umac_profile_active)
return 0;

/*
* If there is a current active profile, but no
* default key, it's not worth trying to associate again.
*/
if (iwm->default_key < 0)
return 0;

/*
* Here we have an active profile, but a key setting changed.
* We thus have to invalidate the current profile, and push the
* new one. Keys will be pushed when association takes place.
*/
ret = iwm_invalidate_mlme_profile(iwm);
if (ret < 0) {
IWM_ERR(iwm, "Couldn't invalidate profile\n");
return ret;
}

return iwm_send_mlme_profile(iwm);
}

static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
u8 key_index, const u8 *mac_addr,
struct key_params *params)
{
struct iwm_priv *iwm = ndev_to_iwm(ndev);
struct iwm_key *key = &iwm->keys[key_index];
int ret;

IWM_DBG_WEXT(iwm, DBG, "Adding key for %pM\n", mac_addr);

memset(key, 0, sizeof(struct iwm_key));
ret = iwm_key_init(key, key_index, mac_addr, params);
if (ret < 0) {
IWM_ERR(iwm, "Invalid key_params\n");
return ret;
}

/*
* The WEP keys can be set before or after setting the essid.
* We need to handle both cases by simply pushing the keys after
* we send the profile.
* If the profile is not set yet (i.e. we're pushing keys before
* the essid), we set the cipher appropriately.
* If the profile is set, we havent associated yet because our
* cipher was incorrectly set. So we invalidate and send the
* profile again.
*/
if (key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
key->cipher == WLAN_CIPHER_SUITE_WEP104) {
u8 *ucast_cipher = &iwm->umac_profile->sec.ucast_cipher;
u8 *mcast_cipher = &iwm->umac_profile->sec.mcast_cipher;

IWM_DBG_WEXT(iwm, DBG, "WEP key\n");

if (key->cipher == WLAN_CIPHER_SUITE_WEP40)
*ucast_cipher = *mcast_cipher = UMAC_CIPHER_TYPE_WEP_40;
if (key->cipher == WLAN_CIPHER_SUITE_WEP104)
*ucast_cipher = *mcast_cipher =
UMAC_CIPHER_TYPE_WEP_104;

return iwm_reset_profile(iwm);
}

return iwm_set_key(iwm, 0, key);
}

static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
u8 key_index, const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie,
struct key_params*))
{
struct iwm_priv *iwm = ndev_to_iwm(ndev);
struct iwm_key *key = &iwm->keys[key_index];
struct key_params params;

IWM_DBG_WEXT(iwm, DBG, "Getting key %d\n", key_index);

memset(&params, 0, sizeof(params));

params.cipher = key->cipher;
params.key_len = key->key_len;
params.seq_len = key->seq_len;
params.seq = key->seq;
params.key = key->key;

callback(cookie, &params);

return key->key_len ? 0 : -ENOENT;
}


static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
u8 key_index, const u8 *mac_addr)
{
struct iwm_priv *iwm = ndev_to_iwm(ndev);
struct iwm_key *key = &iwm->keys[key_index];

if (!iwm->keys[key_index].key_len) {
IWM_DBG_WEXT(iwm, DBG, "Key %d not used\n", key_index);
return 0;
}

if (key_index == iwm->default_key)
iwm->default_key = -1;

return iwm_set_key(iwm, 1, key);
}

static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
struct net_device *ndev,
u8 key_index)
{
struct iwm_priv *iwm = ndev_to_iwm(ndev);
int ret;

IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index);

if (!iwm->keys[key_index].key_len) {
IWM_ERR(iwm, "Key %d not used\n", key_index);
return -EINVAL;
}

ret = iwm_set_tx_key(iwm, key_index);
if (ret < 0)
return ret;

iwm->default_key = key_index;

return iwm_reset_profile(iwm);
}


int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
{
struct wiphy *wiphy = iwm_to_wiphy(iwm);
Expand Down Expand Up @@ -326,6 +494,10 @@ static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)

static struct cfg80211_ops iwm_cfg80211_ops = {
.change_virtual_intf = iwm_cfg80211_change_iface,
.add_key = iwm_cfg80211_add_key,
.get_key = iwm_cfg80211_get_key,
.del_key = iwm_cfg80211_del_key,
.set_default_key = iwm_cfg80211_set_default_key,
.scan = iwm_cfg80211_scan,
.set_wiphy_params = iwm_cfg80211_set_wiphy_params,
.join_ibss = iwm_cfg80211_join_ibss,
Expand Down
72 changes: 25 additions & 47 deletions trunk/drivers/net/wireless/iwmc3200wifi/commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -524,9 +524,6 @@ int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx)
{
struct iwm_umac_tx_key_id tx_key_id;

if (!iwm->default_key || !iwm->default_key->in_use)
return -EINVAL;

tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID;
tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) -
sizeof(struct iwm_umac_wifi_if));
Expand Down Expand Up @@ -569,10 +566,9 @@ static int iwm_check_profile(struct iwm_priv *iwm)
return 0;
}

int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
struct iwm_key *key)
int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key)
{
int ret;
int ret = 0;
u8 cmd[64], *sta_addr, *key_data, key_len;
s8 key_idx;
u16 cmd_size = 0;
Expand All @@ -582,9 +578,6 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd;
struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd;

if (set_tx_key)
iwm->default_key = key;

/*
* We check if our current profile is valid.
* If not, we dont push the key, we just cache them,
Expand All @@ -603,8 +596,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
key_idx = key->hdr.key_idx;

if (!remove) {
IWM_DBG_WEXT(iwm, DBG, "key_idx:%d set tx key:%d\n",
key_idx, set_tx_key);
IWM_DBG_WEXT(iwm, DBG, "key_idx:%d\n", key_idx);
IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len);
IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n",
key_hdr->mac, key_hdr->key_idx, key_hdr->multicast);
Expand All @@ -616,8 +608,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
iwm->umac_profile->sec.auth_type,
iwm->umac_profile->sec.flags);

switch (key->alg) {
case UMAC_CIPHER_TYPE_WEP_40:
switch (key->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY;
wep40->hdr.buf_size =
cpu_to_le16(sizeof(struct iwm_umac_key_wep40) -
Expand All @@ -631,7 +623,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
cmd_size = sizeof(struct iwm_umac_key_wep40);
break;

case UMAC_CIPHER_TYPE_WEP_104:
case WLAN_CIPHER_SUITE_WEP104:
wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY;
wep104->hdr.buf_size =
cpu_to_le16(sizeof(struct iwm_umac_key_wep104) -
Expand All @@ -645,7 +637,7 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
cmd_size = sizeof(struct iwm_umac_key_wep104);
break;

case UMAC_CIPHER_TYPE_CCMP:
case WLAN_CIPHER_SUITE_CCMP:
key_hdr->key_idx++;
ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY;
ccmp->hdr.buf_size =
Expand All @@ -657,13 +649,13 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,

memcpy(ccmp->key, key_data, key_len);

if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID)
memcpy(ccmp->iv_count, key->rx_seq, 6);
if (key->seq_len)
memcpy(ccmp->iv_count, key->seq, key->seq_len);

cmd_size = sizeof(struct iwm_umac_key_ccmp);
break;

case UMAC_CIPHER_TYPE_TKIP:
case WLAN_CIPHER_SUITE_TKIP:
key_hdr->key_idx++;
tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY;
tkip->hdr.buf_size =
Expand All @@ -680,8 +672,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE,
IWM_TKIP_MIC_SIZE);

if (key->flags & IW_ENCODE_EXT_RX_SEQ_VALID)
memcpy(ccmp->iv_count, key->rx_seq, 6);
if (key->seq_len)
memcpy(ccmp->iv_count, key->seq, key->seq_len);

cmd_size = sizeof(struct iwm_umac_key_tkip);
break;
Expand All @@ -690,8 +682,8 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
return -ENOTSUPP;
}

if ((key->alg == UMAC_CIPHER_TYPE_CCMP) ||
(key->alg == UMAC_CIPHER_TYPE_TKIP))
if ((key->cipher == WLAN_CIPHER_SUITE_TKIP) ||
(key->cipher == WLAN_CIPHER_SUITE_CCMP))
/*
* UGLY_UGLY_UGLY
* Copied HACK from the MWG driver.
Expand All @@ -702,23 +694,11 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
schedule_timeout_interruptible(usecs_to_jiffies(300));

ret = iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1);
if (ret < 0)
goto err;

/*
* We need a default key only if it is set and
* if we're doing WEP.
*/
if (iwm->default_key == key &&
((key->alg == UMAC_CIPHER_TYPE_WEP_40) ||
(key->alg == UMAC_CIPHER_TYPE_WEP_104))) {
ret = iwm_set_tx_key(iwm, key_idx);
if (ret < 0)
goto err;
}
} else {
struct iwm_umac_key_remove key_remove;

IWM_DBG_WEXT(iwm, ERR, "Removing key_idx:%d\n", key_idx);

key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY;
key_remove.hdr.buf_size =
cpu_to_le16(sizeof(struct iwm_umac_key_remove) -
Expand All @@ -732,13 +712,9 @@ int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
if (ret < 0)
return ret;

iwm->keys[key_idx].in_use = 0;
iwm->keys[key_idx].key_len = 0;
}

return 0;

err:
kfree(key);
return ret;
}

Expand All @@ -761,22 +737,24 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm)
}

for (i = 0; i < IWM_NUM_KEYS; i++)
if (iwm->keys[i].in_use) {
int default_key = 0;
if (iwm->keys[i].key_len) {
struct iwm_key *key = &iwm->keys[i];

if (key == iwm->default_key)
default_key = 1;

/* Wait for the profile before sending the keys */
wait_event_interruptible_timeout(iwm->mlme_queue,
(test_bit(IWM_STATUS_ASSOCIATING, &iwm->status) ||
test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)),
3 * HZ);

ret = iwm_set_key(iwm, 0, default_key, key);
ret = iwm_set_key(iwm, 0, key);
if (ret < 0)
return ret;

if (iwm->default_key == i) {
ret = iwm_set_tx_key(iwm, i);
if (ret < 0)
return ret;
}
}

return 0;
Expand Down
3 changes: 1 addition & 2 deletions trunk/drivers/net/wireless/iwmc3200wifi/commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -406,8 +406,7 @@ int iwm_send_mlme_profile(struct iwm_priv *iwm);
int iwm_invalidate_mlme_profile(struct iwm_priv *iwm);
int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id);
int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx);
int iwm_set_key(struct iwm_priv *iwm, bool remove, bool set_tx_key,
struct iwm_key *key);
int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key);
int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags);
int iwm_send_umac_channel_list(struct iwm_priv *iwm);
int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids,
Expand Down
Loading

0 comments on commit 0337aeb

Please sign in to comment.