mac80211: support getting key sequence counters via cfg80211

This implements cfg80211's get_key() to allow retrieving the sequence
counter for a TKIP or CCMP key from userspace. It also cleans up and
documents the associated low-level driver interface.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Johannes Berg 2007-12-19 02:03:31 +01:00 committed by David S. Miller
parent e8cbb4cbeb
commit 62da92fb75
2 changed files with 89 additions and 10 deletions

View File

@ -647,9 +647,6 @@ struct ieee80211_key_conf {
u8 key[0]; u8 key[0];
}; };
#define IEEE80211_SEQ_COUNTER_RX 0
#define IEEE80211_SEQ_COUNTER_TX 1
/** /**
* enum set_key_cmd - key command * enum set_key_cmd - key command
* *
@ -996,9 +993,9 @@ enum ieee80211_erp_change_flags {
* *
* @get_stats: return low-level statistics * @get_stats: return low-level statistics
* *
* @get_sequence_counter: For devices that have internal sequence counters this * @get_tkip_seq: If your device implements TKIP encryption in hardware this
* callback allows mac80211 to access the current value of a counter. * callback should be provided to read the TKIP transmit IVs (both IV32
* This callback seems not well-defined, tell us if you need it. * and IV16) for the given key from hardware.
* *
* @set_rts_threshold: Configuration of RTS threshold (if device needs it) * @set_rts_threshold: Configuration of RTS threshold (if device needs it)
* *
@ -1073,9 +1070,8 @@ struct ieee80211_ops {
int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len); int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len);
int (*get_stats)(struct ieee80211_hw *hw, int (*get_stats)(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats); struct ieee80211_low_level_stats *stats);
int (*get_sequence_counter)(struct ieee80211_hw *hw, void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx,
u8* addr, u8 keyidx, u8 txrx, u32 *iv32, u16 *iv16);
u32* iv32, u16* iv16);
int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value); int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value);
int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value); int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value);
int (*set_retry_limit)(struct ieee80211_hw *hw, int (*set_retry_limit)(struct ieee80211_hw *hw,

View File

@ -1,7 +1,7 @@
/* /*
* mac80211 configuration hooks for cfg80211 * mac80211 configuration hooks for cfg80211
* *
* Copyright 2006 Johannes Berg <johannes@sipsolutions.net> * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net>
* *
* This file is GPLv2 as found in COPYING. * This file is GPLv2 as found in COPYING.
*/ */
@ -175,6 +175,88 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
return 0; return 0;
} }
static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
u8 key_idx, u8 *mac_addr, void *cookie,
void (*callback)(void *cookie,
struct key_params *params))
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct sta_info *sta = NULL;
u8 seq[6] = {0};
struct key_params params;
struct ieee80211_key *key;
u32 iv32;
u16 iv16;
int err = -ENOENT;
if (mac_addr) {
sta = sta_info_get(sdata->local, mac_addr);
if (!sta)
goto out;
key = sta->key;
} else
key = sdata->keys[key_idx];
if (!key)
goto out;
memset(&params, 0, sizeof(params));
switch (key->conf.alg) {
case ALG_TKIP:
params.cipher = WLAN_CIPHER_SUITE_TKIP;
iv32 = key->u.tkip.iv32;
iv16 = key->u.tkip.iv16;
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
sdata->local->ops->get_tkip_seq)
sdata->local->ops->get_tkip_seq(
local_to_hw(sdata->local),
key->conf.hw_key_idx,
&iv32, &iv16);
seq[0] = iv16 & 0xff;
seq[1] = (iv16 >> 8) & 0xff;
seq[2] = iv32 & 0xff;
seq[3] = (iv32 >> 8) & 0xff;
seq[4] = (iv32 >> 16) & 0xff;
seq[5] = (iv32 >> 24) & 0xff;
params.seq = seq;
params.seq_len = 6;
break;
case ALG_CCMP:
params.cipher = WLAN_CIPHER_SUITE_CCMP;
seq[0] = key->u.ccmp.tx_pn[5];
seq[1] = key->u.ccmp.tx_pn[4];
seq[2] = key->u.ccmp.tx_pn[3];
seq[3] = key->u.ccmp.tx_pn[2];
seq[4] = key->u.ccmp.tx_pn[1];
seq[5] = key->u.ccmp.tx_pn[0];
params.seq = seq;
params.seq_len = 6;
break;
case ALG_WEP:
if (key->conf.keylen == 5)
params.cipher = WLAN_CIPHER_SUITE_WEP40;
else
params.cipher = WLAN_CIPHER_SUITE_WEP104;
break;
}
params.key = key->conf.key;
params.key_len = key->conf.keylen;
callback(cookie, &params);
err = 0;
out:
if (sta)
sta_info_put(sta);
return err;
}
static int ieee80211_config_default_key(struct wiphy *wiphy, static int ieee80211_config_default_key(struct wiphy *wiphy,
struct net_device *dev, struct net_device *dev,
u8 key_idx) u8 key_idx)
@ -193,5 +275,6 @@ struct cfg80211_ops mac80211_config_ops = {
.change_virtual_intf = ieee80211_change_iface, .change_virtual_intf = ieee80211_change_iface,
.add_key = ieee80211_add_key, .add_key = ieee80211_add_key,
.del_key = ieee80211_del_key, .del_key = ieee80211_del_key,
.get_key = ieee80211_get_key,
.set_default_key = ieee80211_config_default_key, .set_default_key = ieee80211_config_default_key,
}; };