aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/ieee80211_ioctl.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2008-02-25 10:27:45 -0500
committerJohn W. Linville <linville@tuxdriver.com>2008-02-29 15:42:04 -0500
commitdb4d1169d0b893bfb7923b6526748fe2c5a7373f (patch)
treeebd5ac06685bacc069b162b31f99b33c6191b4c3 /net/mac80211/ieee80211_ioctl.c
parent6f48422a29714ed92f6136d9e7d3ff39c75607d7 (diff)
mac80211: split ieee80211_key_alloc/free
In order to RCU-ify sta_info, we need to be able to allocate a key without linking it to an sdata/sta structure (because allocation cannot be done in an rcu critical section). This patch splits up ieee80211_key_alloc() and updates all users appropriately. While at it, this patch fixes a number of race conditions such as finally making key replacement atomic, unfortunately at the expense of more complex code. Note that this patch documents /existing/ bugs with sta info and key interaction, there is currently a race condition when a sta info is freed without holding the RTNL. This will finally be fixed by a followup patch. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/ieee80211_ioctl.c')
-rw-r--r--net/mac80211/ieee80211_ioctl.c90
1 files changed, 48 insertions, 42 deletions
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c
index 54ad07aafe2d..7551db3f3abc 100644
--- a/net/mac80211/ieee80211_ioctl.c
+++ b/net/mac80211/ieee80211_ioctl.c
@@ -33,8 +33,8 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
33 size_t key_len) 33 size_t key_len)
34{ 34{
35 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); 35 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
36 int ret = 0; 36 int ret;
37 struct sta_info *sta; 37 struct sta_info *sta = NULL;
38 struct ieee80211_key *key; 38 struct ieee80211_key *key;
39 struct ieee80211_sub_if_data *sdata; 39 struct ieee80211_sub_if_data *sdata;
40 40
@@ -46,58 +46,64 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
46 return -EINVAL; 46 return -EINVAL;
47 } 47 }
48 48
49 if (is_broadcast_ether_addr(sta_addr)) { 49 if (remove) {
50 sta = NULL; 50 if (is_broadcast_ether_addr(sta_addr)) {
51 key = sdata->keys[idx]; 51 key = sdata->keys[idx];
52 } else { 52 } else {
53 set_tx_key = 0; 53 sta = sta_info_get(local, sta_addr);
54 /* 54 if (!sta) {
55 * According to the standard, the key index of a pairwise 55 ret = -ENOENT;
56 * key must be zero. However, some AP are broken when it 56 key = NULL;
57 * comes to WEP key indices, so we work around this. 57 goto err_out;
58 */ 58 }
59 if (idx != 0 && alg != ALG_WEP) { 59
60 printk(KERN_DEBUG "%s: set_encrypt - non-zero idx for " 60 key = sta->key;
61 "individual key\n", dev->name);
62 return -EINVAL;
63 } 61 }
64 62
65 sta = sta_info_get(local, sta_addr); 63 if (!key)
66 if (!sta) { 64 ret = -ENOENT;
67#ifdef CONFIG_MAC80211_VERBOSE_DEBUG 65 else
68 DECLARE_MAC_BUF(mac); 66 ret = 0;
69 printk(KERN_DEBUG "%s: set_encrypt - unknown addr " 67 } else {
70 "%s\n", 68 key = ieee80211_key_alloc(alg, idx, key_len, _key);
71 dev->name, print_mac(mac, sta_addr)); 69 if (!key)
72#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ 70 return -ENOMEM;
71
72 if (!is_broadcast_ether_addr(sta_addr)) {
73 set_tx_key = 0;
74 /*
75 * According to the standard, the key index of a
76 * pairwise key must be zero. However, some AP are
77 * broken when it comes to WEP key indices, so we
78 * work around this.
79 */
80 if (idx != 0 && alg != ALG_WEP) {
81 ret = -EINVAL;
82 goto err_out;
83 }
73 84
74 return -ENOENT; 85 sta = sta_info_get(local, sta_addr);
86 if (!sta) {
87 ret = -ENOENT;
88 goto err_out;
89 }
75 } 90 }
76 91
77 key = sta->key; 92 ieee80211_key_link(key, sdata, sta);
78 }
79 93
80 if (remove) { 94 if (set_tx_key || (!sta && !sdata->default_key && key))
81 ieee80211_key_free(key); 95 ieee80211_set_default_key(sdata, idx);
96
97 /* don't free key later */
82 key = NULL; 98 key = NULL;
83 } else {
84 /*
85 * Automatically frees any old key if present.
86 */
87 key = ieee80211_key_alloc(sdata, sta, alg, idx, key_len, _key);
88 if (!key) {
89 ret = -ENOMEM;
90 goto err_out;
91 }
92 }
93 99
94 if (set_tx_key || (!sta && !sdata->default_key && key)) 100 ret = 0;
95 ieee80211_set_default_key(sdata, idx); 101 }
96 102
97 ret = 0;
98 err_out: 103 err_out:
99 if (sta) 104 if (sta)
100 sta_info_put(sta); 105 sta_info_put(sta);
106 ieee80211_key_free(key);
101 return ret; 107 return ret;
102} 108}
103 109