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