blob: aa1b734a5e998aee4d8baace2e4f6a58211202c3 [file] [log] [blame]
Johannes Berg1f5a7e42007-07-27 15:43:23 +02001/*
2 * Copyright 2002-2005, Instant802 Networks, Inc.
3 * Copyright 2005-2006, Devicescape Software, Inc.
4 * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
Johannes Berg3b967662008-04-08 17:56:52 +02005 * Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net>
Johannes Berg1f5a7e42007-07-27 15:43:23 +02006 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
Johannes Berg11a843b2007-08-28 17:01:55 -040012#include <linux/if_ether.h>
13#include <linux/etherdevice.h>
14#include <linux/list.h>
Johannes Bergd4e46a32007-09-14 11:10:24 -040015#include <linux/rcupdate.h>
Johannes Bergdb4d1162008-02-25 16:27:45 +010016#include <linux/rtnetlink.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090017#include <linux/slab.h>
Johannes Berg1f5a7e42007-07-27 15:43:23 +020018#include <net/mac80211.h>
19#include "ieee80211_i.h"
Johannes Berg24487982009-04-23 18:52:52 +020020#include "driver-ops.h"
Johannes Berg1f5a7e42007-07-27 15:43:23 +020021#include "debugfs_key.h"
22#include "aes_ccm.h"
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +020023#include "aes_cmac.h"
Johannes Berg1f5a7e42007-07-27 15:43:23 +020024
Johannes Berg11a843b2007-08-28 17:01:55 -040025
Johannes Bergdbbea672008-02-26 14:34:06 +010026/**
27 * DOC: Key handling basics
Johannes Berg11a843b2007-08-28 17:01:55 -040028 *
29 * Key handling in mac80211 is done based on per-interface (sub_if_data)
30 * keys and per-station keys. Since each station belongs to an interface,
31 * each station key also belongs to that interface.
32 *
33 * Hardware acceleration is done on a best-effort basis, for each key
34 * that is eligible the hardware is asked to enable that key but if
35 * it cannot do that they key is simply kept for software encryption.
36 * There is currently no way of knowing this except by looking into
37 * debugfs.
38 *
Johannes Bergad0e2b52010-06-01 10:19:19 +020039 * All key operations are protected internally.
Johannes Bergdb4d1162008-02-25 16:27:45 +010040 *
Johannes Berg3b967662008-04-08 17:56:52 +020041 * Within mac80211, key references are, just as STA structure references,
42 * protected by RCU. Note, however, that some things are unprotected,
43 * namely the key->sta dereferences within the hardware acceleration
Johannes Bergad0e2b52010-06-01 10:19:19 +020044 * functions. This means that sta_info_destroy() must remove the key
45 * which waits for an RCU grace period.
Johannes Berg11a843b2007-08-28 17:01:55 -040046 */
47
48static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
Johannes Berg11a843b2007-08-28 17:01:55 -040049
Johannes Bergad0e2b52010-06-01 10:19:19 +020050static void assert_key_lock(struct ieee80211_local *local)
Johannes Berg3b967662008-04-08 17:56:52 +020051{
Johannes Berg46a5eba2010-09-15 13:28:15 +020052 lockdep_assert_held(&local->key_mtx);
Johannes Berg3b967662008-04-08 17:56:52 +020053}
54
Johannes Bergdc822b52008-12-29 12:55:09 +010055static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key)
Johannes Berg11a843b2007-08-28 17:01:55 -040056{
Johannes Berg11a843b2007-08-28 17:01:55 -040057 if (key->sta)
Johannes Bergdc822b52008-12-29 12:55:09 +010058 return &key->sta->sta;
Johannes Berg11a843b2007-08-28 17:01:55 -040059
Johannes Bergdc822b52008-12-29 12:55:09 +010060 return NULL;
Johannes Berg11a843b2007-08-28 17:01:55 -040061}
62
Johannes Berg3ffc2a92010-08-27 14:26:52 +030063static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
Johannes Berg11a843b2007-08-28 17:01:55 -040064{
Johannes Bergdc822b52008-12-29 12:55:09 +010065 struct ieee80211_sub_if_data *sdata;
66 struct ieee80211_sta *sta;
Johannes Berg11a843b2007-08-28 17:01:55 -040067 int ret;
68
Johannes Berg3b967662008-04-08 17:56:52 +020069 might_sleep();
70
Johannes Berge31b8212010-10-05 19:39:30 +020071 if (!key->local->ops->set_key)
Johannes Berg3ffc2a92010-08-27 14:26:52 +030072 goto out_unsupported;
Johannes Berg11a843b2007-08-28 17:01:55 -040073
Johannes Bergad0e2b52010-06-01 10:19:19 +020074 assert_key_lock(key->local);
75
Johannes Bergdc822b52008-12-29 12:55:09 +010076 sta = get_sta_for_key(key);
77
Johannes Berge31b8212010-10-05 19:39:30 +020078 /*
79 * If this is a per-STA GTK, check if it
80 * is supported; if not, return.
81 */
82 if (sta && !(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE) &&
83 !(key->local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK))
84 goto out_unsupported;
85
Johannes Bergdc822b52008-12-29 12:55:09 +010086 sdata = key->sdata;
87 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
88 sdata = container_of(sdata->bss,
89 struct ieee80211_sub_if_data,
90 u.ap);
Johannes Berg11a843b2007-08-28 17:01:55 -040091
Johannes Berg12375ef2009-11-25 20:30:31 +010092 ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf);
Johannes Berg11a843b2007-08-28 17:01:55 -040093
Johannes Berge31b8212010-10-05 19:39:30 +020094 if (!ret) {
Johannes Berg11a843b2007-08-28 17:01:55 -040095 key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
Johannes Berge31b8212010-10-05 19:39:30 +020096 return 0;
97 }
Johannes Berg11a843b2007-08-28 17:01:55 -040098
Johannes Berge31b8212010-10-05 19:39:30 +020099 if (ret != -ENOSPC && ret != -EOPNOTSUPP)
Joe Perches0fb9a9e2010-08-20 16:25:38 -0700100 wiphy_err(key->local->hw.wiphy,
101 "failed to set key (%d, %pM) to hardware (%d)\n",
102 key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
Johannes Berg3ffc2a92010-08-27 14:26:52 +0300103
Johannes Berge31b8212010-10-05 19:39:30 +0200104 out_unsupported:
105 switch (key->conf.cipher) {
106 case WLAN_CIPHER_SUITE_WEP40:
107 case WLAN_CIPHER_SUITE_WEP104:
108 case WLAN_CIPHER_SUITE_TKIP:
109 case WLAN_CIPHER_SUITE_CCMP:
110 case WLAN_CIPHER_SUITE_AES_CMAC:
111 /* all of these we can do in software */
112 return 0;
113 default:
114 return -EINVAL;
Johannes Berg3ffc2a92010-08-27 14:26:52 +0300115 }
Johannes Berg11a843b2007-08-28 17:01:55 -0400116}
117
118static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
119{
Johannes Bergdc822b52008-12-29 12:55:09 +0100120 struct ieee80211_sub_if_data *sdata;
121 struct ieee80211_sta *sta;
Johannes Berg11a843b2007-08-28 17:01:55 -0400122 int ret;
123
Johannes Berg3b967662008-04-08 17:56:52 +0200124 might_sleep();
125
Johannes Bergdb4d1162008-02-25 16:27:45 +0100126 if (!key || !key->local->ops->set_key)
Johannes Berg11a843b2007-08-28 17:01:55 -0400127 return;
128
Johannes Bergad0e2b52010-06-01 10:19:19 +0200129 assert_key_lock(key->local);
130
131 if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
Johannes Berg11a843b2007-08-28 17:01:55 -0400132 return;
133
Johannes Bergdc822b52008-12-29 12:55:09 +0100134 sta = get_sta_for_key(key);
135 sdata = key->sdata;
136
137 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
138 sdata = container_of(sdata->bss,
139 struct ieee80211_sub_if_data,
140 u.ap);
Johannes Berg11a843b2007-08-28 17:01:55 -0400141
Johannes Berg12375ef2009-11-25 20:30:31 +0100142 ret = drv_set_key(key->local, DISABLE_KEY, sdata,
Johannes Berg24487982009-04-23 18:52:52 +0200143 sta, &key->conf);
Johannes Berg11a843b2007-08-28 17:01:55 -0400144
145 if (ret)
Joe Perches0fb9a9e2010-08-20 16:25:38 -0700146 wiphy_err(key->local->hw.wiphy,
147 "failed to remove key (%d, %pM) from hardware (%d)\n",
148 key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
Johannes Berg11a843b2007-08-28 17:01:55 -0400149
Johannes Berg3b967662008-04-08 17:56:52 +0200150 key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
Johannes Berg3b967662008-04-08 17:56:52 +0200151}
152
Johannes Berge31b8212010-10-05 19:39:30 +0200153void ieee80211_key_removed(struct ieee80211_key_conf *key_conf)
154{
155 struct ieee80211_key *key;
156
157 key = container_of(key_conf, struct ieee80211_key, conf);
158
159 might_sleep();
160 assert_key_lock(key->local);
161
162 key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
163
164 /*
165 * Flush TX path to avoid attempts to use this key
166 * after this function returns. Until then, drivers
167 * must be prepared to handle the key.
168 */
169 synchronize_rcu();
170}
171EXPORT_SYMBOL_GPL(ieee80211_key_removed);
172
Johannes Berg3b967662008-04-08 17:56:52 +0200173static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
174 int idx)
175{
176 struct ieee80211_key *key = NULL;
177
Johannes Bergad0e2b52010-06-01 10:19:19 +0200178 assert_key_lock(sdata->local);
179
Johannes Berg3b967662008-04-08 17:56:52 +0200180 if (idx >= 0 && idx < NUM_DEFAULT_KEYS)
181 key = sdata->keys[idx];
182
183 rcu_assign_pointer(sdata->default_key, key);
184
Johannes Bergad0e2b52010-06-01 10:19:19 +0200185 if (key) {
186 ieee80211_debugfs_key_remove_default(key->sdata);
187 ieee80211_debugfs_key_add_default(key->sdata);
188 }
Johannes Berg3b967662008-04-08 17:56:52 +0200189}
190
191void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx)
192{
Johannes Bergad0e2b52010-06-01 10:19:19 +0200193 mutex_lock(&sdata->local->key_mtx);
Johannes Berg3b967662008-04-08 17:56:52 +0200194 __ieee80211_set_default_key(sdata, idx);
Johannes Bergad0e2b52010-06-01 10:19:19 +0200195 mutex_unlock(&sdata->local->key_mtx);
Johannes Berg3b967662008-04-08 17:56:52 +0200196}
197
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +0200198static void
199__ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, int idx)
200{
201 struct ieee80211_key *key = NULL;
202
Johannes Bergad0e2b52010-06-01 10:19:19 +0200203 assert_key_lock(sdata->local);
204
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +0200205 if (idx >= NUM_DEFAULT_KEYS &&
206 idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
207 key = sdata->keys[idx];
208
209 rcu_assign_pointer(sdata->default_mgmt_key, key);
210
Johannes Bergad0e2b52010-06-01 10:19:19 +0200211 if (key) {
212 ieee80211_debugfs_key_remove_mgmt_default(key->sdata);
213 ieee80211_debugfs_key_add_mgmt_default(key->sdata);
214 }
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +0200215}
216
217void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
218 int idx)
219{
Johannes Bergad0e2b52010-06-01 10:19:19 +0200220 mutex_lock(&sdata->local->key_mtx);
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +0200221 __ieee80211_set_default_mgmt_key(sdata, idx);
Johannes Bergad0e2b52010-06-01 10:19:19 +0200222 mutex_unlock(&sdata->local->key_mtx);
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +0200223}
224
Johannes Berg3b967662008-04-08 17:56:52 +0200225
226static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
227 struct sta_info *sta,
Johannes Berge31b8212010-10-05 19:39:30 +0200228 bool pairwise,
Johannes Berg3b967662008-04-08 17:56:52 +0200229 struct ieee80211_key *old,
230 struct ieee80211_key *new)
231{
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +0200232 int idx, defkey, defmgmtkey;
Johannes Berg3b967662008-04-08 17:56:52 +0200233
234 if (new)
235 list_add(&new->list, &sdata->key_list);
236
Johannes Berge31b8212010-10-05 19:39:30 +0200237 if (sta && pairwise) {
238 rcu_assign_pointer(sta->ptk, new);
239 } else if (sta) {
240 if (old)
241 idx = old->conf.keyidx;
242 else
243 idx = new->conf.keyidx;
244 rcu_assign_pointer(sta->gtk[idx], new);
Johannes Berg3b967662008-04-08 17:56:52 +0200245 } else {
246 WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx);
247
248 if (old)
249 idx = old->conf.keyidx;
250 else
251 idx = new->conf.keyidx;
252
253 defkey = old && sdata->default_key == old;
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +0200254 defmgmtkey = old && sdata->default_mgmt_key == old;
Johannes Berg3b967662008-04-08 17:56:52 +0200255
256 if (defkey && !new)
257 __ieee80211_set_default_key(sdata, -1);
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +0200258 if (defmgmtkey && !new)
259 __ieee80211_set_default_mgmt_key(sdata, -1);
Johannes Berg3b967662008-04-08 17:56:52 +0200260
261 rcu_assign_pointer(sdata->keys[idx], new);
262 if (defkey && new)
263 __ieee80211_set_default_key(sdata, new->conf.keyidx);
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +0200264 if (defmgmtkey && new)
265 __ieee80211_set_default_mgmt_key(sdata,
266 new->conf.keyidx);
Johannes Berg3b967662008-04-08 17:56:52 +0200267 }
268
269 if (old) {
270 /*
271 * We'll use an empty list to indicate that the key
272 * has already been removed.
273 */
274 list_del_init(&old->list);
275 }
Johannes Berg11a843b2007-08-28 17:01:55 -0400276}
277
Johannes Berg97359d12010-08-10 09:46:38 +0200278struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
Jouni Malinenfaa8fdc2009-05-11 21:57:58 +0300279 const u8 *key_data,
280 size_t seq_len, const u8 *seq)
Johannes Berg1f5a7e42007-07-27 15:43:23 +0200281{
282 struct ieee80211_key *key;
Ben Hutchings1ac62ba2010-08-01 17:37:03 +0100283 int i, j, err;
Johannes Berg1f5a7e42007-07-27 15:43:23 +0200284
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +0200285 BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS);
Johannes Berg11a843b2007-08-28 17:01:55 -0400286
287 key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL);
Johannes Berg1f5a7e42007-07-27 15:43:23 +0200288 if (!key)
Ben Hutchings1ac62ba2010-08-01 17:37:03 +0100289 return ERR_PTR(-ENOMEM);
Johannes Berg11a843b2007-08-28 17:01:55 -0400290
291 /*
292 * Default to software encryption; we'll later upload the
293 * key to the hardware if possible.
294 */
Johannes Berg11a843b2007-08-28 17:01:55 -0400295 key->conf.flags = 0;
296 key->flags = 0;
297
Johannes Berg97359d12010-08-10 09:46:38 +0200298 key->conf.cipher = cipher;
Johannes Berg11a843b2007-08-28 17:01:55 -0400299 key->conf.keyidx = idx;
300 key->conf.keylen = key_len;
Johannes Berg97359d12010-08-10 09:46:38 +0200301 switch (cipher) {
302 case WLAN_CIPHER_SUITE_WEP40:
303 case WLAN_CIPHER_SUITE_WEP104:
Felix Fietkau76708de2008-10-05 18:02:48 +0200304 key->conf.iv_len = WEP_IV_LEN;
305 key->conf.icv_len = WEP_ICV_LEN;
306 break;
Johannes Berg97359d12010-08-10 09:46:38 +0200307 case WLAN_CIPHER_SUITE_TKIP:
Felix Fietkau76708de2008-10-05 18:02:48 +0200308 key->conf.iv_len = TKIP_IV_LEN;
309 key->conf.icv_len = TKIP_ICV_LEN;
Jouni Malinen9f26a952009-05-15 12:38:32 +0300310 if (seq) {
Jouni Malinenfaa8fdc2009-05-11 21:57:58 +0300311 for (i = 0; i < NUM_RX_DATA_QUEUES; i++) {
312 key->u.tkip.rx[i].iv32 =
313 get_unaligned_le32(&seq[2]);
314 key->u.tkip.rx[i].iv16 =
315 get_unaligned_le16(seq);
316 }
317 }
Felix Fietkau76708de2008-10-05 18:02:48 +0200318 break;
Johannes Berg97359d12010-08-10 09:46:38 +0200319 case WLAN_CIPHER_SUITE_CCMP:
Felix Fietkau76708de2008-10-05 18:02:48 +0200320 key->conf.iv_len = CCMP_HDR_LEN;
321 key->conf.icv_len = CCMP_MIC_LEN;
Jouni Malinen9f26a952009-05-15 12:38:32 +0300322 if (seq) {
Jouni Malinen91902522010-06-11 10:27:33 -0700323 for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++)
Jouni Malinenfaa8fdc2009-05-11 21:57:58 +0300324 for (j = 0; j < CCMP_PN_LEN; j++)
325 key->u.ccmp.rx_pn[i][j] =
326 seq[CCMP_PN_LEN - j - 1];
327 }
Johannes Berg11a843b2007-08-28 17:01:55 -0400328 /*
329 * Initialize AES key state here as an optimization so that
330 * it does not need to be initialized for every packet.
331 */
332 key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(key_data);
Ben Hutchings1ac62ba2010-08-01 17:37:03 +0100333 if (IS_ERR(key->u.ccmp.tfm)) {
334 err = PTR_ERR(key->u.ccmp.tfm);
Johannes Berg3b967662008-04-08 17:56:52 +0200335 kfree(key);
Ben Hutchings1ac62ba2010-08-01 17:37:03 +0100336 key = ERR_PTR(err);
Johannes Berg11a843b2007-08-28 17:01:55 -0400337 }
Johannes Berg60ae0f22010-08-10 09:46:39 +0200338 break;
339 case WLAN_CIPHER_SUITE_AES_CMAC:
340 key->conf.iv_len = 0;
341 key->conf.icv_len = sizeof(struct ieee80211_mmie);
342 if (seq)
343 for (j = 0; j < 6; j++)
344 key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1];
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +0200345 /*
346 * Initialize AES key state here as an optimization so that
347 * it does not need to be initialized for every packet.
348 */
349 key->u.aes_cmac.tfm =
350 ieee80211_aes_cmac_key_setup(key_data);
Ben Hutchings1ac62ba2010-08-01 17:37:03 +0100351 if (IS_ERR(key->u.aes_cmac.tfm)) {
352 err = PTR_ERR(key->u.aes_cmac.tfm);
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +0200353 kfree(key);
Ben Hutchings1ac62ba2010-08-01 17:37:03 +0100354 key = ERR_PTR(err);
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +0200355 }
Johannes Berg60ae0f22010-08-10 09:46:39 +0200356 break;
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +0200357 }
Johannes Berg60ae0f22010-08-10 09:46:39 +0200358 memcpy(key->conf.key, key_data, key_len);
359 INIT_LIST_HEAD(&key->list);
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +0200360
Johannes Bergdb4d1162008-02-25 16:27:45 +0100361 return key;
362}
Johannes Berg11a843b2007-08-28 17:01:55 -0400363
Johannes Bergad0e2b52010-06-01 10:19:19 +0200364static void __ieee80211_key_destroy(struct ieee80211_key *key)
365{
366 if (!key)
367 return;
368
Johannes Bergd2460f42011-01-03 19:42:24 +0100369 /*
370 * Synchronize so the TX path can no longer be using
371 * this key before we free/remove it.
372 */
373 synchronize_rcu();
374
Jouni Malinen32162a42010-07-26 15:52:03 -0700375 if (key->local)
376 ieee80211_key_disable_hw_accel(key);
Johannes Bergad0e2b52010-06-01 10:19:19 +0200377
Johannes Berg97359d12010-08-10 09:46:38 +0200378 if (key->conf.cipher == WLAN_CIPHER_SUITE_CCMP)
Johannes Bergad0e2b52010-06-01 10:19:19 +0200379 ieee80211_aes_key_free(key->u.ccmp.tfm);
Johannes Berg97359d12010-08-10 09:46:38 +0200380 if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
Johannes Bergad0e2b52010-06-01 10:19:19 +0200381 ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
Jouni Malinen32162a42010-07-26 15:52:03 -0700382 if (key->local)
383 ieee80211_debugfs_key_remove(key);
Johannes Bergad0e2b52010-06-01 10:19:19 +0200384
385 kfree(key);
386}
387
Johannes Berg3ffc2a92010-08-27 14:26:52 +0300388int ieee80211_key_link(struct ieee80211_key *key,
389 struct ieee80211_sub_if_data *sdata,
390 struct sta_info *sta)
Johannes Bergdb4d1162008-02-25 16:27:45 +0100391{
392 struct ieee80211_key *old_key;
Johannes Berg3ffc2a92010-08-27 14:26:52 +0300393 int idx, ret;
Johannes Berge31b8212010-10-05 19:39:30 +0200394 bool pairwise = key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE;
Johannes Bergdb4d1162008-02-25 16:27:45 +0100395
Johannes Bergdb4d1162008-02-25 16:27:45 +0100396 BUG_ON(!sdata);
397 BUG_ON(!key);
398
399 idx = key->conf.keyidx;
400 key->local = sdata->local;
401 key->sdata = sdata;
402 key->sta = sta;
403
Johannes Berg11a843b2007-08-28 17:01:55 -0400404 if (sta) {
Johannes Berg11a843b2007-08-28 17:01:55 -0400405 /*
406 * some hardware cannot handle TKIP with QoS, so
407 * we indicate whether QoS could be in use.
408 */
Johannes Berg07346f812008-05-03 01:02:02 +0200409 if (test_sta_flags(sta, WLAN_STA_WME))
Johannes Berg11a843b2007-08-28 17:01:55 -0400410 key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA;
411 } else {
Johannes Berg05c914f2008-09-11 00:01:58 +0200412 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
Johannes Berg11a843b2007-08-28 17:01:55 -0400413 struct sta_info *ap;
414
Johannes Berg3b967662008-04-08 17:56:52 +0200415 /*
416 * We're getting a sta pointer in,
417 * so must be under RCU read lock.
418 */
Johannes Bergd0709a62008-02-25 16:27:46 +0100419
Johannes Berg11a843b2007-08-28 17:01:55 -0400420 /* same here, the AP could be using QoS */
Johannes Bergabe60632009-11-25 17:46:18 +0100421 ap = sta_info_get(key->sdata, key->sdata->u.mgd.bssid);
Johannes Berg11a843b2007-08-28 17:01:55 -0400422 if (ap) {
Johannes Berg07346f812008-05-03 01:02:02 +0200423 if (test_sta_flags(ap, WLAN_STA_WME))
Johannes Berg11a843b2007-08-28 17:01:55 -0400424 key->conf.flags |=
425 IEEE80211_KEY_FLAG_WMM_STA;
Johannes Berg11a843b2007-08-28 17:01:55 -0400426 }
427 }
Johannes Berg11a843b2007-08-28 17:01:55 -0400428 }
429
Johannes Bergad0e2b52010-06-01 10:19:19 +0200430 mutex_lock(&sdata->local->key_mtx);
Johannes Berg3b967662008-04-08 17:56:52 +0200431
Johannes Berge31b8212010-10-05 19:39:30 +0200432 if (sta && pairwise)
433 old_key = sta->ptk;
434 else if (sta)
435 old_key = sta->gtk[idx];
Johannes Bergd4e46a32007-09-14 11:10:24 -0400436 else
Johannes Bergdb4d1162008-02-25 16:27:45 +0100437 old_key = sdata->keys[idx];
438
Johannes Berge31b8212010-10-05 19:39:30 +0200439 __ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
Johannes Bergad0e2b52010-06-01 10:19:19 +0200440 __ieee80211_key_destroy(old_key);
Johannes Bergd4e46a32007-09-14 11:10:24 -0400441
Johannes Bergad0e2b52010-06-01 10:19:19 +0200442 ieee80211_debugfs_key_add(key);
Johannes Berg3b967662008-04-08 17:56:52 +0200443
Johannes Berg3ffc2a92010-08-27 14:26:52 +0300444 ret = ieee80211_key_enable_hw_accel(key);
Johannes Berg523d2f62009-07-01 21:26:43 +0200445
Johannes Bergad0e2b52010-06-01 10:19:19 +0200446 mutex_unlock(&sdata->local->key_mtx);
Johannes Berg3ffc2a92010-08-27 14:26:52 +0300447
448 return ret;
Johannes Berg3a245762008-04-09 16:45:37 +0200449}
450
451static void __ieee80211_key_free(struct ieee80211_key *key)
452{
453 /*
454 * Replace key with nothingness if it was ever used.
455 */
456 if (key->sdata)
457 __ieee80211_key_replace(key->sdata, key->sta,
Johannes Berge31b8212010-10-05 19:39:30 +0200458 key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE,
459 key, NULL);
Johannes Bergad0e2b52010-06-01 10:19:19 +0200460 __ieee80211_key_destroy(key);
Johannes Berg1f5a7e42007-07-27 15:43:23 +0200461}
462
Jouni Malinen32162a42010-07-26 15:52:03 -0700463void ieee80211_key_free(struct ieee80211_local *local,
464 struct ieee80211_key *key)
Johannes Berg1f5a7e42007-07-27 15:43:23 +0200465{
Johannes Berg8f371712007-08-28 17:01:54 -0400466 if (!key)
467 return;
468
Johannes Bergad0e2b52010-06-01 10:19:19 +0200469 mutex_lock(&local->key_mtx);
Johannes Berg3a245762008-04-09 16:45:37 +0200470 __ieee80211_key_free(key);
Johannes Bergad0e2b52010-06-01 10:19:19 +0200471 mutex_unlock(&local->key_mtx);
Johannes Berg3b967662008-04-08 17:56:52 +0200472}
473
474void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
475{
Johannes Bergad0e2b52010-06-01 10:19:19 +0200476 struct ieee80211_key *key;
477
Johannes Berg3a245762008-04-09 16:45:37 +0200478 ASSERT_RTNL();
Johannes Berg3b967662008-04-08 17:56:52 +0200479
Johannes Berg9607e6b662009-12-23 13:15:31 +0100480 if (WARN_ON(!ieee80211_sdata_running(sdata)))
Johannes Berg3b967662008-04-08 17:56:52 +0200481 return;
482
Johannes Bergad0e2b52010-06-01 10:19:19 +0200483 mutex_lock(&sdata->local->key_mtx);
484
485 list_for_each_entry(key, &sdata->key_list, list)
486 ieee80211_key_enable_hw_accel(key);
487
488 mutex_unlock(&sdata->local->key_mtx);
Johannes Berg3b967662008-04-08 17:56:52 +0200489}
490
491void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata)
492{
Johannes Bergad0e2b52010-06-01 10:19:19 +0200493 struct ieee80211_key *key;
494
Johannes Berg3a245762008-04-09 16:45:37 +0200495 ASSERT_RTNL();
Johannes Berg3b967662008-04-08 17:56:52 +0200496
Johannes Bergad0e2b52010-06-01 10:19:19 +0200497 mutex_lock(&sdata->local->key_mtx);
Johannes Berg3b967662008-04-08 17:56:52 +0200498
Johannes Bergad0e2b52010-06-01 10:19:19 +0200499 list_for_each_entry(key, &sdata->key_list, list)
500 ieee80211_key_disable_hw_accel(key);
Johannes Berg3b967662008-04-08 17:56:52 +0200501
Johannes Bergad0e2b52010-06-01 10:19:19 +0200502 mutex_unlock(&sdata->local->key_mtx);
Johannes Berg11a843b2007-08-28 17:01:55 -0400503}
504
505void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
506{
507 struct ieee80211_key *key, *tmp;
Johannes Bergdb4d1162008-02-25 16:27:45 +0100508
Johannes Bergad0e2b52010-06-01 10:19:19 +0200509 mutex_lock(&sdata->local->key_mtx);
Johannes Berg3b967662008-04-08 17:56:52 +0200510
511 ieee80211_debugfs_key_remove_default(sdata);
Jouni Malinen3cfcf6ac2009-01-08 13:32:02 +0200512 ieee80211_debugfs_key_remove_mgmt_default(sdata);
Johannes Berg11a843b2007-08-28 17:01:55 -0400513
514 list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
Johannes Berg3a245762008-04-09 16:45:37 +0200515 __ieee80211_key_free(key);
Johannes Berg11a843b2007-08-28 17:01:55 -0400516
Johannes Bergad0e2b52010-06-01 10:19:19 +0200517 mutex_unlock(&sdata->local->key_mtx);
Johannes Berg11a843b2007-08-28 17:01:55 -0400518}