diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2008-02-25 10:27:45 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-02-29 15:42:04 -0500 |
commit | db4d1169d0b893bfb7923b6526748fe2c5a7373f (patch) | |
tree | ebd5ac06685bacc069b162b31f99b33c6191b4c3 /net/mac80211/cfg.c | |
parent | 6f48422a29714ed92f6136d9e7d3ff39c75607d7 (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/cfg.c')
-rw-r--r-- | net/mac80211/cfg.c | 27 |
1 files changed, 19 insertions, 8 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index b0c41a0cee79..e7535ffc8e1c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -123,6 +123,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
123 | struct sta_info *sta = NULL; | 123 | struct sta_info *sta = NULL; |
124 | enum ieee80211_key_alg alg; | 124 | enum ieee80211_key_alg alg; |
125 | int ret; | 125 | int ret; |
126 | struct ieee80211_key *key; | ||
126 | 127 | ||
127 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 128 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
128 | 129 | ||
@@ -141,16 +142,21 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
141 | return -EINVAL; | 142 | return -EINVAL; |
142 | } | 143 | } |
143 | 144 | ||
145 | key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key); | ||
146 | if (!key) | ||
147 | return -ENOMEM; | ||
148 | |||
144 | if (mac_addr) { | 149 | if (mac_addr) { |
145 | sta = sta_info_get(sdata->local, mac_addr); | 150 | sta = sta_info_get(sdata->local, mac_addr); |
146 | if (!sta) | 151 | if (!sta) { |
152 | ieee80211_key_free(key); | ||
147 | return -ENOENT; | 153 | return -ENOENT; |
154 | } | ||
148 | } | 155 | } |
149 | 156 | ||
157 | ieee80211_key_link(key, sdata, sta); | ||
158 | |||
150 | ret = 0; | 159 | ret = 0; |
151 | if (!ieee80211_key_alloc(sdata, sta, alg, key_idx, | ||
152 | params->key_len, params->key)) | ||
153 | ret = -ENOMEM; | ||
154 | 160 | ||
155 | if (sta) | 161 | if (sta) |
156 | sta_info_put(sta); | 162 | sta_info_put(sta); |
@@ -164,6 +170,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
164 | struct ieee80211_sub_if_data *sdata; | 170 | struct ieee80211_sub_if_data *sdata; |
165 | struct sta_info *sta; | 171 | struct sta_info *sta; |
166 | int ret; | 172 | int ret; |
173 | struct ieee80211_key *key; | ||
167 | 174 | ||
168 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 175 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
169 | 176 | ||
@@ -173,9 +180,11 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
173 | return -ENOENT; | 180 | return -ENOENT; |
174 | 181 | ||
175 | ret = 0; | 182 | ret = 0; |
176 | if (sta->key) | 183 | if (sta->key) { |
177 | ieee80211_key_free(sta->key); | 184 | key = sta->key; |
178 | else | 185 | ieee80211_key_free(key); |
186 | WARN_ON(sta->key); | ||
187 | } else | ||
179 | ret = -ENOENT; | 188 | ret = -ENOENT; |
180 | 189 | ||
181 | sta_info_put(sta); | 190 | sta_info_put(sta); |
@@ -185,7 +194,9 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
185 | if (!sdata->keys[key_idx]) | 194 | if (!sdata->keys[key_idx]) |
186 | return -ENOENT; | 195 | return -ENOENT; |
187 | 196 | ||
188 | ieee80211_key_free(sdata->keys[key_idx]); | 197 | key = sdata->keys[key_idx]; |
198 | ieee80211_key_free(key); | ||
199 | WARN_ON(sdata->keys[key_idx]); | ||
189 | 200 | ||
190 | return 0; | 201 | return 0; |
191 | } | 202 | } |