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