Blame view
net/wireless/wext-sme.c
9.17 KB
f21293549 cfg80211: managed... |
1 2 3 4 5 6 |
/* * cfg80211 wext compat for managed mode. * * Copyright 2009 Johannes Berg <johannes@sipsolutions.net> * Copyright (C) 2009 Intel Corporation. All rights reserved. */ |
bc3b2d7fb net: Add export.h... |
7 |
#include <linux/export.h> |
f21293549 cfg80211: managed... |
8 9 |
#include <linux/etherdevice.h> #include <linux/if_arp.h> |
5a0e3ad6a include cleanup: ... |
10 |
#include <linux/slab.h> |
f21293549 cfg80211: managed... |
11 |
#include <net/cfg80211.h> |
262eb9b22 cfg80211: split w... |
12 |
#include <net/cfg80211-wext.h> |
0e82ffe3b cfg80211: combine... |
13 |
#include "wext-compat.h" |
f21293549 cfg80211: managed... |
14 |
#include "nl80211.h" |
fffd0934b cfg80211: rework ... |
15 16 |
int cfg80211_mgd_wext_connect(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev) |
f21293549 cfg80211: managed... |
17 |
{ |
fffd0934b cfg80211: rework ... |
18 |
struct cfg80211_cached_keys *ck = NULL; |
f401a6f7e cfg80211: use rea... |
19 |
const u8 *prev_bssid = NULL; |
fffd0934b cfg80211: rework ... |
20 |
int err, i; |
f21293549 cfg80211: managed... |
21 |
|
667503ddc cfg80211: fix loc... |
22 23 |
ASSERT_RDEV_LOCK(rdev); ASSERT_WDEV_LOCK(wdev); |
f21293549 cfg80211: managed... |
24 25 26 27 28 |
if (!netif_running(wdev->netdev)) return 0; wdev->wext.connect.ie = wdev->wext.ie; wdev->wext.connect.ie_len = wdev->wext.ie_len; |
f21293549 cfg80211: managed... |
29 |
|
fffd0934b cfg80211: rework ... |
30 31 32 |
if (wdev->wext.keys) { wdev->wext.keys->def = wdev->wext.default_key; wdev->wext.keys->defmgmt = wdev->wext.default_mgmt_key; |
4be3bd8cc cfg80211: don't s... |
33 34 |
if (wdev->wext.default_key != -1) wdev->wext.connect.privacy = true; |
fffd0934b cfg80211: rework ... |
35 36 37 38 39 40 41 42 43 44 45 46 |
} if (!wdev->wext.connect.ssid_len) return 0; if (wdev->wext.keys) { ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL); if (!ck) return -ENOMEM; for (i = 0; i < 6; i++) ck->params[i].key = ck->data[i]; } |
f401a6f7e cfg80211: use rea... |
47 48 49 |
if (wdev->wext.prev_bssid_valid) prev_bssid = wdev->wext.prev_bssid; |
fffd0934b cfg80211: rework ... |
50 |
err = __cfg80211_connect(rdev, wdev->netdev, |
f401a6f7e cfg80211: use rea... |
51 |
&wdev->wext.connect, ck, prev_bssid); |
fffd0934b cfg80211: rework ... |
52 53 |
if (err) kfree(ck); |
f21293549 cfg80211: managed... |
54 55 56 57 58 59 |
return err; } int cfg80211_mgd_wext_siwfreq(struct net_device *dev, struct iw_request_info *info, |
59bbb6f75 cfg80211: validat... |
60 |
struct iw_freq *wextfreq, char *extra) |
f21293549 cfg80211: managed... |
61 62 63 |
{ struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
59bbb6f75 cfg80211: validat... |
64 65 |
struct ieee80211_channel *chan = NULL; int err, freq; |
f21293549 cfg80211: managed... |
66 67 68 69 |
/* call only for station! */ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return -EINVAL; |
59bbb6f75 cfg80211: validat... |
70 71 72 |
freq = cfg80211_wext_freq(wdev->wiphy, wextfreq); if (freq < 0) return freq; |
f21293549 cfg80211: managed... |
73 |
|
59bbb6f75 cfg80211: validat... |
74 75 76 77 78 79 80 |
if (freq) { chan = ieee80211_get_channel(wdev->wiphy, freq); if (!chan) return -EINVAL; if (chan->flags & IEEE80211_CHAN_DISABLED) return -EINVAL; } |
f21293549 cfg80211: managed... |
81 |
|
667503ddc cfg80211: fix loc... |
82 |
cfg80211_lock_rdev(rdev); |
59bbb6f75 cfg80211: validat... |
83 |
mutex_lock(&rdev->devlist_mtx); |
667503ddc cfg80211: fix loc... |
84 |
wdev_lock(wdev); |
f21293549 cfg80211: managed... |
85 86 |
if (wdev->sme_state != CFG80211_SME_IDLE) { bool event = true; |
25e83c490 cfg80211: don't o... |
87 88 89 90 91 |
if (wdev->wext.connect.channel == chan) { err = 0; goto out; } |
f21293549 cfg80211: managed... |
92 93 94 |
/* if SSID set, we'll try right again, avoid event */ if (wdev->wext.connect.ssid_len) event = false; |
59bbb6f75 cfg80211: validat... |
95 96 |
err = __cfg80211_disconnect(rdev, dev, WLAN_REASON_DEAUTH_LEAVING, event); |
f21293549 cfg80211: managed... |
97 |
if (err) |
667503ddc cfg80211: fix loc... |
98 |
goto out; |
f21293549 cfg80211: managed... |
99 |
} |
667503ddc cfg80211: fix loc... |
100 |
|
f21293549 cfg80211: managed... |
101 102 103 |
wdev->wext.connect.channel = chan; /* SSID is not set, we just want to switch channel */ |
59bbb6f75 cfg80211: validat... |
104 |
if (chan && !wdev->wext.connect.ssid_len) { |
f444de05d cfg80211/mac80211... |
105 |
err = cfg80211_set_freq(rdev, wdev, freq, NL80211_CHAN_NO_HT); |
667503ddc cfg80211: fix loc... |
106 |
goto out; |
f21293549 cfg80211: managed... |
107 |
} |
59bbb6f75 cfg80211: validat... |
108 |
err = cfg80211_mgd_wext_connect(rdev, wdev); |
667503ddc cfg80211: fix loc... |
109 110 |
out: wdev_unlock(wdev); |
59bbb6f75 cfg80211: validat... |
111 |
mutex_unlock(&rdev->devlist_mtx); |
667503ddc cfg80211: fix loc... |
112 113 |
cfg80211_unlock_rdev(rdev); return err; |
f21293549 cfg80211: managed... |
114 |
} |
f21293549 cfg80211: managed... |
115 116 117 118 119 120 121 122 123 124 125 |
int cfg80211_mgd_wext_giwfreq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct ieee80211_channel *chan = NULL; /* call only for station! */ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return -EINVAL; |
667503ddc cfg80211: fix loc... |
126 |
wdev_lock(wdev); |
f21293549 cfg80211: managed... |
127 |
if (wdev->current_bss) |
19957bb39 cfg80211: keep tr... |
128 |
chan = wdev->current_bss->pub.channel; |
f21293549 cfg80211: managed... |
129 130 |
else if (wdev->wext.connect.channel) chan = wdev->wext.connect.channel; |
667503ddc cfg80211: fix loc... |
131 |
wdev_unlock(wdev); |
f21293549 cfg80211: managed... |
132 133 134 135 136 137 138 139 140 141 |
if (chan) { freq->m = chan->center_freq; freq->e = 6; return 0; } /* no channel if not joining */ return -EINVAL; } |
f21293549 cfg80211: managed... |
142 143 144 145 146 147 |
int cfg80211_mgd_wext_siwessid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid) { struct wireless_dev *wdev = dev->ieee80211_ptr; |
59bbb6f75 cfg80211: validat... |
148 |
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
f21293549 cfg80211: managed... |
149 150 151 152 153 154 155 156 157 158 159 160 161 |
size_t len = data->length; int err; /* call only for station! */ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return -EINVAL; if (!data->flags) len = 0; /* iwconfig uses nul termination in SSID.. */ if (len > 0 && ssid[len - 1] == '\0') len--; |
59bbb6f75 cfg80211: validat... |
162 163 |
cfg80211_lock_rdev(rdev); mutex_lock(&rdev->devlist_mtx); |
667503ddc cfg80211: fix loc... |
164 165 166 |
wdev_lock(wdev); err = 0; |
f21293549 cfg80211: managed... |
167 168 |
if (wdev->sme_state != CFG80211_SME_IDLE) { bool event = true; |
25e83c490 cfg80211: don't o... |
169 170 171 172 173 |
if (wdev->wext.connect.ssid && len && len == wdev->wext.connect.ssid_len && memcmp(wdev->wext.connect.ssid, ssid, len) == 0) goto out; |
f21293549 cfg80211: managed... |
174 175 176 |
/* if SSID set now, we'll try to connect, avoid event */ if (len) event = false; |
59bbb6f75 cfg80211: validat... |
177 178 |
err = __cfg80211_disconnect(rdev, dev, WLAN_REASON_DEAUTH_LEAVING, event); |
f21293549 cfg80211: managed... |
179 |
if (err) |
667503ddc cfg80211: fix loc... |
180 |
goto out; |
f21293549 cfg80211: managed... |
181 |
} |
f401a6f7e cfg80211: use rea... |
182 |
wdev->wext.prev_bssid_valid = false; |
f21293549 cfg80211: managed... |
183 184 185 186 187 |
wdev->wext.connect.ssid = wdev->wext.ssid; memcpy(wdev->wext.ssid, ssid, len); wdev->wext.connect.ssid_len = len; wdev->wext.connect.crypto.control_port = false; |
c0692b8fe cfg80211: allow c... |
188 189 |
wdev->wext.connect.crypto.control_port_ethertype = cpu_to_be16(ETH_P_PAE); |
f21293549 cfg80211: managed... |
190 |
|
59bbb6f75 cfg80211: validat... |
191 |
err = cfg80211_mgd_wext_connect(rdev, wdev); |
667503ddc cfg80211: fix loc... |
192 193 |
out: wdev_unlock(wdev); |
59bbb6f75 cfg80211: validat... |
194 195 |
mutex_unlock(&rdev->devlist_mtx); cfg80211_unlock_rdev(rdev); |
667503ddc cfg80211: fix loc... |
196 |
return err; |
f21293549 cfg80211: managed... |
197 |
} |
f21293549 cfg80211: managed... |
198 199 200 201 202 203 204 205 206 207 208 209 |
int cfg80211_mgd_wext_giwessid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *ssid) { struct wireless_dev *wdev = dev->ieee80211_ptr; /* call only for station! */ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return -EINVAL; data->flags = 0; |
667503ddc cfg80211: fix loc... |
210 |
wdev_lock(wdev); |
a42dd7efd wireless: display... |
211 212 213 214 215 216 217 218 219 |
if (wdev->current_bss) { const u8 *ie = ieee80211_bss_get_ie(&wdev->current_bss->pub, WLAN_EID_SSID); if (ie) { data->flags = 1; data->length = ie[1]; memcpy(ssid, ie + 2, data->length); } } else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) { |
f21293549 cfg80211: managed... |
220 221 222 |
data->flags = 1; data->length = wdev->wext.connect.ssid_len; memcpy(ssid, wdev->wext.connect.ssid, data->length); |
33de4f9d7 cfg80211: wext: d... |
223 |
} |
667503ddc cfg80211: fix loc... |
224 |
wdev_unlock(wdev); |
f21293549 cfg80211: managed... |
225 226 227 |
return 0; } |
f21293549 cfg80211: managed... |
228 229 230 231 232 233 |
int cfg80211_mgd_wext_siwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; |
59bbb6f75 cfg80211: validat... |
234 |
struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); |
f21293549 cfg80211: managed... |
235 236 237 238 239 240 241 242 243 244 245 246 247 |
u8 *bssid = ap_addr->sa_data; int err; /* call only for station! */ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return -EINVAL; if (ap_addr->sa_family != ARPHRD_ETHER) return -EINVAL; /* automatic mode */ if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) bssid = NULL; |
59bbb6f75 cfg80211: validat... |
248 249 |
cfg80211_lock_rdev(rdev); mutex_lock(&rdev->devlist_mtx); |
667503ddc cfg80211: fix loc... |
250 |
wdev_lock(wdev); |
25e83c490 cfg80211: don't o... |
251 252 253 254 255 |
if (wdev->sme_state != CFG80211_SME_IDLE) { err = 0; /* both automatic */ if (!bssid && !wdev->wext.connect.bssid) goto out; |
f21293549 cfg80211: managed... |
256 |
|
25e83c490 cfg80211: don't o... |
257 258 259 260 |
/* fixed already - and no change */ if (wdev->wext.connect.bssid && bssid && compare_ether_addr(bssid, wdev->wext.connect.bssid) == 0) goto out; |
f21293549 cfg80211: managed... |
261 |
|
59bbb6f75 cfg80211: validat... |
262 263 |
err = __cfg80211_disconnect(rdev, dev, WLAN_REASON_DEAUTH_LEAVING, false); |
f21293549 cfg80211: managed... |
264 |
if (err) |
667503ddc cfg80211: fix loc... |
265 |
goto out; |
f21293549 cfg80211: managed... |
266 267 268 269 270 271 272 |
} if (bssid) { memcpy(wdev->wext.bssid, bssid, ETH_ALEN); wdev->wext.connect.bssid = wdev->wext.bssid; } else wdev->wext.connect.bssid = NULL; |
59bbb6f75 cfg80211: validat... |
273 |
err = cfg80211_mgd_wext_connect(rdev, wdev); |
667503ddc cfg80211: fix loc... |
274 275 |
out: wdev_unlock(wdev); |
59bbb6f75 cfg80211: validat... |
276 277 |
mutex_unlock(&rdev->devlist_mtx); cfg80211_unlock_rdev(rdev); |
667503ddc cfg80211: fix loc... |
278 |
return err; |
f21293549 cfg80211: managed... |
279 |
} |
f21293549 cfg80211: managed... |
280 281 282 283 284 285 286 287 288 289 290 291 |
int cfg80211_mgd_wext_giwap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; /* call only for station! */ if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) return -EINVAL; ap_addr->sa_family = ARPHRD_ETHER; |
667503ddc cfg80211: fix loc... |
292 |
wdev_lock(wdev); |
f21293549 cfg80211: managed... |
293 |
if (wdev->current_bss) |
19957bb39 cfg80211: keep tr... |
294 |
memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); |
f21293549 cfg80211: managed... |
295 296 |
else memset(ap_addr->sa_data, 0, ETH_ALEN); |
667503ddc cfg80211: fix loc... |
297 |
wdev_unlock(wdev); |
f21293549 cfg80211: managed... |
298 299 300 |
return 0; } |
f21293549 cfg80211: managed... |
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
int cfg80211_wext_siwgenie(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); u8 *ie = extra; int ie_len = data->length, err; if (wdev->iftype != NL80211_IFTYPE_STATION) return -EOPNOTSUPP; if (!ie_len) ie = NULL; |
667503ddc cfg80211: fix loc... |
316 |
wdev_lock(wdev); |
f21293549 cfg80211: managed... |
317 |
/* no change */ |
667503ddc cfg80211: fix loc... |
318 |
err = 0; |
f21293549 cfg80211: managed... |
319 320 |
if (wdev->wext.ie_len == ie_len && memcmp(wdev->wext.ie, ie, ie_len) == 0) |
667503ddc cfg80211: fix loc... |
321 |
goto out; |
f21293549 cfg80211: managed... |
322 323 324 |
if (ie_len) { ie = kmemdup(extra, ie_len, GFP_KERNEL); |
667503ddc cfg80211: fix loc... |
325 326 327 328 |
if (!ie) { err = -ENOMEM; goto out; } |
f21293549 cfg80211: managed... |
329 330 331 332 333 334 335 336 |
} else ie = NULL; kfree(wdev->wext.ie); wdev->wext.ie = ie; wdev->wext.ie_len = ie_len; if (wdev->sme_state != CFG80211_SME_IDLE) { |
667503ddc cfg80211: fix loc... |
337 338 |
err = __cfg80211_disconnect(rdev, dev, WLAN_REASON_DEAUTH_LEAVING, false); |
f21293549 cfg80211: managed... |
339 |
if (err) |
667503ddc cfg80211: fix loc... |
340 |
goto out; |
f21293549 cfg80211: managed... |
341 342 343 |
} /* userspace better not think we'll reconnect */ |
667503ddc cfg80211: fix loc... |
344 345 346 347 |
err = 0; out: wdev_unlock(wdev); return err; |
f21293549 cfg80211: managed... |
348 |
} |
f21293549 cfg80211: managed... |
349 350 351 352 353 354 355 356 |
int cfg80211_wext_siwmlme(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra) { struct wireless_dev *wdev = dev->ieee80211_ptr; struct iw_mlme *mlme = (struct iw_mlme *)extra; struct cfg80211_registered_device *rdev; |
667503ddc cfg80211: fix loc... |
357 |
int err; |
f21293549 cfg80211: managed... |
358 359 360 361 362 363 364 365 366 367 368 |
if (!wdev) return -EOPNOTSUPP; rdev = wiphy_to_dev(wdev->wiphy); if (wdev->iftype != NL80211_IFTYPE_STATION) return -EINVAL; if (mlme->addr.sa_family != ARPHRD_ETHER) return -EINVAL; |
667503ddc cfg80211: fix loc... |
369 |
wdev_lock(wdev); |
f21293549 cfg80211: managed... |
370 371 372 |
switch (mlme->cmd) { case IW_MLME_DEAUTH: case IW_MLME_DISASSOC: |
667503ddc cfg80211: fix loc... |
373 374 375 |
err = __cfg80211_disconnect(rdev, dev, mlme->reason_code, true); break; |
f21293549 cfg80211: managed... |
376 |
default: |
667503ddc cfg80211: fix loc... |
377 378 |
err = -EOPNOTSUPP; break; |
f21293549 cfg80211: managed... |
379 |
} |
667503ddc cfg80211: fix loc... |
380 381 382 |
wdev_unlock(wdev); return err; |
f21293549 cfg80211: managed... |
383 |
} |