diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2007-12-18 20:03:31 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-01-28 17:59:50 -0500 |
commit | 62da92fb75c346b503bca765fd1337e08771c9fe (patch) | |
tree | 86246464a61297e4df2e593c31b2e2dda325cf5c | |
parent | e8cbb4cbeb7642d179b01c35adf036ddb65f3dd0 (diff) |
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>
-rw-r--r-- | include/net/mac80211.h | 14 | ||||
-rw-r--r-- | net/mac80211/cfg.c | 85 |
2 files changed, 89 insertions, 10 deletions
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5b9e7a26244..a762a75ae62 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h | |||
@@ -647,9 +647,6 @@ struct ieee80211_key_conf { | |||
647 | u8 key[0]; | 647 | u8 key[0]; |
648 | }; | 648 | }; |
649 | 649 | ||
650 | #define IEEE80211_SEQ_COUNTER_RX 0 | ||
651 | #define IEEE80211_SEQ_COUNTER_TX 1 | ||
652 | |||
653 | /** | 650 | /** |
654 | * enum set_key_cmd - key command | 651 | * enum set_key_cmd - key command |
655 | * | 652 | * |
@@ -996,9 +993,9 @@ enum ieee80211_erp_change_flags { | |||
996 | * | 993 | * |
997 | * @get_stats: return low-level statistics | 994 | * @get_stats: return low-level statistics |
998 | * | 995 | * |
999 | * @get_sequence_counter: For devices that have internal sequence counters this | 996 | * @get_tkip_seq: If your device implements TKIP encryption in hardware this |
1000 | * callback allows mac80211 to access the current value of a counter. | 997 | * callback should be provided to read the TKIP transmit IVs (both IV32 |
1001 | * This callback seems not well-defined, tell us if you need it. | 998 | * and IV16) for the given key from hardware. |
1002 | * | 999 | * |
1003 | * @set_rts_threshold: Configuration of RTS threshold (if device needs it) | 1000 | * @set_rts_threshold: Configuration of RTS threshold (if device needs it) |
1004 | * | 1001 | * |
@@ -1073,9 +1070,8 @@ struct ieee80211_ops { | |||
1073 | int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len); | 1070 | int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len); |
1074 | int (*get_stats)(struct ieee80211_hw *hw, | 1071 | int (*get_stats)(struct ieee80211_hw *hw, |
1075 | struct ieee80211_low_level_stats *stats); | 1072 | struct ieee80211_low_level_stats *stats); |
1076 | int (*get_sequence_counter)(struct ieee80211_hw *hw, | 1073 | void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx, |
1077 | u8* addr, u8 keyidx, u8 txrx, | 1074 | u32 *iv32, u16 *iv16); |
1078 | u32* iv32, u16* iv16); | ||
1079 | int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value); | 1075 | int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value); |
1080 | int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value); | 1076 | int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value); |
1081 | int (*set_retry_limit)(struct ieee80211_hw *hw, | 1077 | int (*set_retry_limit)(struct ieee80211_hw *hw, |
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index d49f7b58b05..4c1ce353c66 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * mac80211 configuration hooks for cfg80211 | 2 | * mac80211 configuration hooks for cfg80211 |
3 | * | 3 | * |
4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> |
5 | * | 5 | * |
6 | * This file is GPLv2 as found in COPYING. | 6 | * This file is GPLv2 as found in COPYING. |
7 | */ | 7 | */ |
@@ -175,6 +175,88 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
175 | return 0; | 175 | return 0; |
176 | } | 176 | } |
177 | 177 | ||
178 | static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | ||
179 | u8 key_idx, u8 *mac_addr, void *cookie, | ||
180 | void (*callback)(void *cookie, | ||
181 | struct key_params *params)) | ||
182 | { | ||
183 | struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); | ||
184 | struct sta_info *sta = NULL; | ||
185 | u8 seq[6] = {0}; | ||
186 | struct key_params params; | ||
187 | struct ieee80211_key *key; | ||
188 | u32 iv32; | ||
189 | u16 iv16; | ||
190 | int err = -ENOENT; | ||
191 | |||
192 | if (mac_addr) { | ||
193 | sta = sta_info_get(sdata->local, mac_addr); | ||
194 | if (!sta) | ||
195 | goto out; | ||
196 | |||
197 | key = sta->key; | ||
198 | } else | ||
199 | key = sdata->keys[key_idx]; | ||
200 | |||
201 | if (!key) | ||
202 | goto out; | ||
203 | |||
204 | memset(¶ms, 0, sizeof(params)); | ||
205 | |||
206 | switch (key->conf.alg) { | ||
207 | case ALG_TKIP: | ||
208 | params.cipher = WLAN_CIPHER_SUITE_TKIP; | ||
209 | |||
210 | iv32 = key->u.tkip.iv32; | ||
211 | iv16 = key->u.tkip.iv16; | ||
212 | |||
213 | if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && | ||
214 | sdata->local->ops->get_tkip_seq) | ||
215 | sdata->local->ops->get_tkip_seq( | ||
216 | local_to_hw(sdata->local), | ||
217 | key->conf.hw_key_idx, | ||
218 | &iv32, &iv16); | ||
219 | |||
220 | seq[0] = iv16 & 0xff; | ||
221 | seq[1] = (iv16 >> 8) & 0xff; | ||
222 | seq[2] = iv32 & 0xff; | ||
223 | seq[3] = (iv32 >> 8) & 0xff; | ||
224 | seq[4] = (iv32 >> 16) & 0xff; | ||
225 | seq[5] = (iv32 >> 24) & 0xff; | ||
226 | params.seq = seq; | ||
227 | params.seq_len = 6; | ||
228 | break; | ||
229 | case ALG_CCMP: | ||
230 | params.cipher = WLAN_CIPHER_SUITE_CCMP; | ||
231 | seq[0] = key->u.ccmp.tx_pn[5]; | ||
232 | seq[1] = key->u.ccmp.tx_pn[4]; | ||
233 | seq[2] = key->u.ccmp.tx_pn[3]; | ||
234 | seq[3] = key->u.ccmp.tx_pn[2]; | ||
235 | seq[4] = key->u.ccmp.tx_pn[1]; | ||
236 | seq[5] = key->u.ccmp.tx_pn[0]; | ||
237 | params.seq = seq; | ||
238 | params.seq_len = 6; | ||
239 | break; | ||
240 | case ALG_WEP: | ||
241 | if (key->conf.keylen == 5) | ||
242 | params.cipher = WLAN_CIPHER_SUITE_WEP40; | ||
243 | else | ||
244 | params.cipher = WLAN_CIPHER_SUITE_WEP104; | ||
245 | break; | ||
246 | } | ||
247 | |||
248 | params.key = key->conf.key; | ||
249 | params.key_len = key->conf.keylen; | ||
250 | |||
251 | callback(cookie, ¶ms); | ||
252 | err = 0; | ||
253 | |||
254 | out: | ||
255 | if (sta) | ||
256 | sta_info_put(sta); | ||
257 | return err; | ||
258 | } | ||
259 | |||
178 | static int ieee80211_config_default_key(struct wiphy *wiphy, | 260 | static int ieee80211_config_default_key(struct wiphy *wiphy, |
179 | struct net_device *dev, | 261 | struct net_device *dev, |
180 | u8 key_idx) | 262 | u8 key_idx) |
@@ -193,5 +275,6 @@ struct cfg80211_ops mac80211_config_ops = { | |||
193 | .change_virtual_intf = ieee80211_change_iface, | 275 | .change_virtual_intf = ieee80211_change_iface, |
194 | .add_key = ieee80211_add_key, | 276 | .add_key = ieee80211_add_key, |
195 | .del_key = ieee80211_del_key, | 277 | .del_key = ieee80211_del_key, |
278 | .get_key = ieee80211_get_key, | ||
196 | .set_default_key = ieee80211_config_default_key, | 279 | .set_default_key = ieee80211_config_default_key, |
197 | }; | 280 | }; |