diff options
Diffstat (limited to 'net/wireless/wext-sme.c')
-rw-r--r-- | net/wireless/wext-sme.c | 329 |
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 000000000000..3b531d572b69 --- /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 | |||
13 | static 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 | |||
33 | int 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 */ | ||
82 | EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwfreq); | ||
83 | |||
84 | int 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 */ | ||
110 | EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwfreq); | ||
111 | |||
112 | int 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 */ | ||
157 | EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwessid); | ||
158 | |||
159 | int 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 */ | ||
185 | EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwessid); | ||
186 | |||
187 | int 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 */ | ||
232 | EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_siwap); | ||
233 | |||
234 | int 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 */ | ||
256 | EXPORT_SYMBOL_GPL(cfg80211_mgd_wext_giwap); | ||
257 | |||
258 | int 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 | } | ||
299 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwgenie); | ||
300 | |||
301 | int 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 | } | ||
329 | EXPORT_SYMBOL_GPL(cfg80211_wext_siwmlme); | ||