aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/wext-sme.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-07-01 15:26:56 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-07-10 15:01:51 -0400
commitf21293549f60f88c74fcb9944737f11048896dc4 (patch)
treed4a00663f87816c0c742e74d7b2c9bad31a18816 /net/wireless/wext-sme.c
parent6829c878ecd24ff0ae41b4668c7e9d0f11b66942 (diff)
cfg80211: managed mode wext compatibility
This adds code to make it possible to use the cfg80211 connect() API with wireless extensions, and because the previous patch added emulation of that API with auth() and assoc(), by extension also supports wext on that. At the same time, removes code from mac80211 for wext, but doesn't yet clean up mac80211's mlme code more. Signed-off-by: Samuel Ortiz <samuel.ortiz@intel.com> Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/wext-sme.c')
-rw-r--r--net/wireless/wext-sme.c329
1 files changed, 329 insertions, 0 deletions
diff --git a/net/wireless/wext-sme.c b/net/wireless/wext-sme.c
new file mode 100644
index 00000000000..3b531d572b6
--- /dev/null
+++ b/net/wireless/wext-sme.c
@@ -0,0 +1,329 @@
1/*
2 * cfg80211 wext compat for managed mode.
3 *
4 * Copyright 2009 Johannes Berg <johannes@sipsolutions.net>
5 * Copyright (C) 2009 Intel Corporation. All rights reserved.
6 */
7
8#include <linux/etherdevice.h>
9#include <linux/if_arp.h>
10#include <net/cfg80211.h>
11#include "nl80211.h"
12
13static int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev,
14 struct wireless_dev *wdev)
15{
16 int err;
17
18 if (!netif_running(wdev->netdev))
19 return 0;
20
21 wdev->wext.connect.ie = wdev->wext.ie;
22 wdev->wext.connect.ie_len = wdev->wext.ie_len;
23 wdev->wext.connect.privacy = wdev->wext.default_key != -1;
24
25 err = 0;
26 if (wdev->wext.connect.ssid_len != 0)
27 err = cfg80211_connect(rdev, wdev->netdev,
28 &wdev->wext.connect);
29
30 return err;
31}
32
33int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
34 struct iw_request_info *info,
35 struct iw_freq *freq, char *extra)
36{
37 struct wireless_dev *wdev = dev->ieee80211_ptr;
38 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
39 struct ieee80211_channel *chan;
40 int err;
41
42 /* call only for station! */
43 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
44 return -EINVAL;
45
46 chan = cfg80211_wext_freq(wdev->wiphy, freq);
47 if (chan && IS_ERR(chan))
48 return PTR_ERR(chan);
49
50 if (chan && (chan->flags & IEEE80211_CHAN_DISABLED))
51 return -EINVAL;
52
53 if (wdev->wext.connect.channel == chan)
54 return 0;
55
56 if (wdev->sme_state != CFG80211_SME_IDLE) {
57 bool event = true;
58 /* if SSID set, we'll try right again, avoid event */
59 if (wdev->wext.connect.ssid_len)
60 event = false;
61 err = cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
62 dev, WLAN_REASON_DEAUTH_LEAVING,
63 event);
64 if (err)
65 return err;
66 }
67
68 wdev->wext.connect.channel = chan;
69
70 /* SSID is not set, we just want to switch channel */
71 if (wdev->wext.connect.ssid_len && chan) {
72 if (!rdev->ops->set_channel)
73 return -EOPNOTSUPP;
74
75 return rdev->ops->set_channel(wdev->wiphy, chan,
76 NL80211_CHAN_NO_HT);
77 }
78
79 return cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
80}
81/* temporary symbol - mark GPL - in the future the handler won't be */
82EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwfreq);
83
84int cfg80211_mgd_wext_giwfreq(struct net_device *dev,
85 struct iw_request_info *info,
86 struct iw_freq *freq, char *extra)
87{
88 struct wireless_dev *wdev = dev->ieee80211_ptr;
89 struct ieee80211_channel *chan = NULL;
90
91 /* call only for station! */
92 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
93 return -EINVAL;
94
95 if (wdev->current_bss)
96 chan = wdev->current_bss->channel;
97 else if (wdev->wext.connect.channel)
98 chan = wdev->wext.connect.channel;
99
100 if (chan) {
101 freq->m = chan->center_freq;
102 freq->e = 6;
103 return 0;
104 }
105
106 /* no channel if not joining */
107 return -EINVAL;
108}
109/* temporary symbol - mark GPL - in the future the handler won't be */
110EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwfreq);
111
112int cfg80211_mgd_wext_siwessid(struct net_device *dev,
113 struct iw_request_info *info,
114 struct iw_point *data, char *ssid)
115{
116 struct wireless_dev *wdev = dev->ieee80211_ptr;
117 size_t len = data->length;
118 int err;
119
120 /* call only for station! */
121 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
122 return -EINVAL;
123
124 if (!data->flags)
125 len = 0;
126
127 /* iwconfig uses nul termination in SSID.. */
128 if (len > 0 && ssid[len - 1] == '\0')
129 len--;
130
131 if (wdev->wext.connect.ssid && len &&
132 len == wdev->wext.connect.ssid_len &&
133 memcmp(wdev->wext.connect.ssid, ssid, len))
134 return 0;
135
136 if (wdev->sme_state != CFG80211_SME_IDLE) {
137 bool event = true;
138 /* if SSID set now, we'll try to connect, avoid event */
139 if (len)
140 event = false;
141 err = cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
142 dev, WLAN_REASON_DEAUTH_LEAVING,
143 event);
144 if (err)
145 return err;
146 }
147
148 wdev->wext.connect.ssid = wdev->wext.ssid;
149 memcpy(wdev->wext.ssid, ssid, len);
150 wdev->wext.connect.ssid_len = len;
151
152 wdev->wext.connect.crypto.control_port = false;
153
154 return cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
155}
156/* temporary symbol - mark GPL - in the future the handler won't be */
157EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwessid);
158
159int cfg80211_mgd_wext_giwessid(struct net_device *dev,
160 struct iw_request_info *info,
161 struct iw_point *data, char *ssid)
162{
163 struct wireless_dev *wdev = dev->ieee80211_ptr;
164
165 /* call only for station! */
166 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
167 return -EINVAL;
168
169 data->flags = 0;
170
171 if (wdev->ssid_len) {
172 data->flags = 1;
173 data->length = wdev->ssid_len;
174 memcpy(ssid, wdev->ssid, data->length);
175 } else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) {
176 data->flags = 1;
177 data->length = wdev->wext.connect.ssid_len;
178 memcpy(ssid, wdev->wext.connect.ssid, data->length);
179 } else
180 data->flags = 0;
181
182 return 0;
183}
184/* temporary symbol - mark GPL - in the future the handler won't be */
185EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwessid);
186
187int cfg80211_mgd_wext_siwap(struct net_device *dev,
188 struct iw_request_info *info,
189 struct sockaddr *ap_addr, char *extra)
190{
191 struct wireless_dev *wdev = dev->ieee80211_ptr;
192 u8 *bssid = ap_addr->sa_data;
193 int err;
194
195 /* call only for station! */
196 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
197 return -EINVAL;
198
199 if (ap_addr->sa_family != ARPHRD_ETHER)
200 return -EINVAL;
201
202 /* automatic mode */
203 if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
204 bssid = NULL;
205
206 /* both automatic */
207 if (!bssid && !wdev->wext.connect.bssid)
208 return 0;
209
210 /* fixed already - and no change */
211 if (wdev->wext.connect.bssid && bssid &&
212 compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0)
213 return 0;
214
215 if (wdev->sme_state != CFG80211_SME_IDLE) {
216 err = cfg80211_disconnect(wiphy_to_dev(wdev->wiphy),
217 dev, WLAN_REASON_DEAUTH_LEAVING,
218 false);
219 if (err)
220 return err;
221 }
222
223 if (bssid) {
224 memcpy(wdev->wext.bssid, bssid, ETH_ALEN);
225 wdev->wext.connect.bssid = wdev->wext.bssid;
226 } else
227 wdev->wext.connect.bssid = NULL;
228
229 return cfg80211_mgd_wext_connect(wiphy_to_dev(wdev->wiphy), wdev);
230}
231/* temporary symbol - mark GPL - in the future the handler won't be */
232EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwap);
233
234int cfg80211_mgd_wext_giwap(struct net_device *dev,
235 struct iw_request_info *info,
236 struct sockaddr *ap_addr, char *extra)
237{
238 struct wireless_dev *wdev = dev->ieee80211_ptr;
239
240 /* call only for station! */
241 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION))
242 return -EINVAL;
243
244 ap_addr->sa_family = ARPHRD_ETHER;
245
246 if (wdev->current_bss)
247 memcpy(ap_addr->sa_data, wdev->current_bss->bssid, ETH_ALEN);
248 else if (wdev->wext.connect.bssid)
249 memcpy(ap_addr->sa_data, wdev->wext.connect.bssid, ETH_ALEN);
250 else
251 memset(ap_addr->sa_data, 0, ETH_ALEN);
252
253 return 0;
254}
255/* temporary symbol - mark GPL - in the future the handler won't be */
256EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwap);
257
258int cfg80211_wext_siwgenie(struct net_device *dev,
259 struct iw_request_info *info,
260 struct iw_point *data, char *extra)
261{
262 struct wireless_dev *wdev = dev->ieee80211_ptr;
263 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
264 u8 *ie = extra;
265 int ie_len = data->length, err;
266
267 if (wdev->iftype != NL80211_IFTYPE_STATION)
268 return -EOPNOTSUPP;
269
270 if (!ie_len)
271 ie = NULL;
272
273 /* no change */
274 if (wdev->wext.ie_len == ie_len &&
275 memcmp(wdev->wext.ie, ie, ie_len) == 0)
276 return 0;
277
278 if (ie_len) {
279 ie = kmemdup(extra, ie_len, GFP_KERNEL);
280 if (!ie)
281 return -ENOMEM;
282 } else
283 ie = NULL;
284
285 kfree(wdev->wext.ie);
286 wdev->wext.ie = ie;
287 wdev->wext.ie_len = ie_len;
288
289 if (wdev->sme_state != CFG80211_SME_IDLE) {
290 err = cfg80211_disconnect(rdev, dev,
291 WLAN_REASON_DEAUTH_LEAVING, false);
292 if (err)
293 return err;
294 }
295
296 /* userspace better not think we'll reconnect */
297 return 0;
298}
299EXPORT_SYMBOL_GPL(cfg80211_wext_siwgenie);
300
301int cfg80211_wext_siwmlme(struct net_device *dev,
302 struct iw_request_info *info,
303 struct iw_point *data, char *extra)
304{
305 struct wireless_dev *wdev = dev->ieee80211_ptr;
306 struct iw_mlme *mlme = (struct iw_mlme *)extra;
307 struct cfg80211_registered_device *rdev;
308
309 if (!wdev)
310 return -EOPNOTSUPP;
311
312 rdev = wiphy_to_dev(wdev->wiphy);
313
314 if (wdev->iftype != NL80211_IFTYPE_STATION)
315 return -EINVAL;
316
317 if (mlme->addr.sa_family != ARPHRD_ETHER)
318 return -EINVAL;
319
320 switch (mlme->cmd) {
321 case IW_MLME_DEAUTH:
322 case IW_MLME_DISASSOC:
323 return cfg80211_disconnect(rdev, dev, mlme->reason_code,
324 true);
325 default:
326 return -EOPNOTSUPP;
327 }
328}
329EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme);