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, 2020-2022 Intel Corporation 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 kfree_sensitive(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 if (wdev->valid_links) 128 return -EOPNOTSUPP; 129 130 wdev_lock(wdev); 131 if (wdev->links[0].client.current_bss) 132 chan = wdev->links[0].client.current_bss->pub.channel; 133 else if (wdev->wext.connect.channel) 134 chan = wdev->wext.connect.channel; 135 wdev_unlock(wdev); 136 137 if (chan) { 138 freq->m = chan->center_freq; 139 freq->e = 6; 140 return 0; 141 } 142 143 /* no channel if not joining */ 144 return -EINVAL; 145 } 146 147 int cfg80211_mgd_wext_siwessid(struct net_device *dev, 148 struct iw_request_info *info, 149 struct iw_point *data, char *ssid) 150 { 151 struct wireless_dev *wdev = dev->ieee80211_ptr; 152 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); 153 size_t len = data->length; 154 int err; 155 156 /* call only for station! */ 157 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) 158 return -EINVAL; 159 160 if (!data->flags) 161 len = 0; 162 163 /* iwconfig uses nul termination in SSID.. */ 164 if (len > 0 && ssid[len - 1] == '\0') 165 len--; 166 167 wdev_lock(wdev); 168 169 err = 0; 170 171 if (wdev->conn) { 172 bool event = true; 173 174 if (wdev->wext.connect.ssid && len && 175 len == wdev->wext.connect.ssid_len && 176 memcmp(wdev->wext.connect.ssid, ssid, len) == 0) 177 goto out; 178 179 /* if SSID set now, we'll try to connect, avoid event */ 180 if (len) 181 event = false; 182 err = cfg80211_disconnect(rdev, dev, 183 WLAN_REASON_DEAUTH_LEAVING, event); 184 if (err) 185 goto out; 186 } 187 188 wdev->wext.prev_bssid_valid = false; 189 wdev->wext.connect.ssid = wdev->wext.ssid; 190 memcpy(wdev->wext.ssid, ssid, len); 191 wdev->wext.connect.ssid_len = len; 192 193 wdev->wext.connect.crypto.control_port = false; 194 wdev->wext.connect.crypto.control_port_ethertype = 195 cpu_to_be16(ETH_P_PAE); 196 197 err = cfg80211_mgd_wext_connect(rdev, wdev); 198 out: 199 wdev_unlock(wdev); 200 return err; 201 } 202 203 int cfg80211_mgd_wext_giwessid(struct net_device *dev, 204 struct iw_request_info *info, 205 struct iw_point *data, char *ssid) 206 { 207 struct wireless_dev *wdev = dev->ieee80211_ptr; 208 int ret = 0; 209 210 /* call only for station! */ 211 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) 212 return -EINVAL; 213 214 if (wdev->valid_links) 215 return -EINVAL; 216 217 data->flags = 0; 218 219 wdev_lock(wdev); 220 if (wdev->links[0].client.current_bss) { 221 const struct element *ssid_elem; 222 223 rcu_read_lock(); 224 ssid_elem = ieee80211_bss_get_elem( 225 &wdev->links[0].client.current_bss->pub, 226 WLAN_EID_SSID); 227 if (ssid_elem) { 228 data->flags = 1; 229 data->length = ssid_elem->datalen; 230 if (data->length > IW_ESSID_MAX_SIZE) 231 ret = -EINVAL; 232 else 233 memcpy(ssid, ssid_elem->data, data->length); 234 } 235 rcu_read_unlock(); 236 } else if (wdev->wext.connect.ssid && wdev->wext.connect.ssid_len) { 237 data->flags = 1; 238 data->length = wdev->wext.connect.ssid_len; 239 memcpy(ssid, wdev->wext.connect.ssid, data->length); 240 } 241 wdev_unlock(wdev); 242 243 return ret; 244 } 245 246 int cfg80211_mgd_wext_siwap(struct net_device *dev, 247 struct iw_request_info *info, 248 struct sockaddr *ap_addr, char *extra) 249 { 250 struct wireless_dev *wdev = dev->ieee80211_ptr; 251 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); 252 u8 *bssid = ap_addr->sa_data; 253 int err; 254 255 /* call only for station! */ 256 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) 257 return -EINVAL; 258 259 if (ap_addr->sa_family != ARPHRD_ETHER) 260 return -EINVAL; 261 262 /* automatic mode */ 263 if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) 264 bssid = NULL; 265 266 wdev_lock(wdev); 267 268 if (wdev->conn) { 269 err = 0; 270 /* both automatic */ 271 if (!bssid && !wdev->wext.connect.bssid) 272 goto out; 273 274 /* fixed already - and no change */ 275 if (wdev->wext.connect.bssid && bssid && 276 ether_addr_equal(bssid, wdev->wext.connect.bssid)) 277 goto out; 278 279 err = cfg80211_disconnect(rdev, dev, 280 WLAN_REASON_DEAUTH_LEAVING, false); 281 if (err) 282 goto out; 283 } 284 285 if (bssid) { 286 memcpy(wdev->wext.bssid, bssid, ETH_ALEN); 287 wdev->wext.connect.bssid = wdev->wext.bssid; 288 } else 289 wdev->wext.connect.bssid = NULL; 290 291 err = cfg80211_mgd_wext_connect(rdev, wdev); 292 out: 293 wdev_unlock(wdev); 294 return err; 295 } 296 297 int cfg80211_mgd_wext_giwap(struct net_device *dev, 298 struct iw_request_info *info, 299 struct sockaddr *ap_addr, char *extra) 300 { 301 struct wireless_dev *wdev = dev->ieee80211_ptr; 302 303 /* call only for station! */ 304 if (WARN_ON(wdev->iftype != NL80211_IFTYPE_STATION)) 305 return -EINVAL; 306 307 ap_addr->sa_family = ARPHRD_ETHER; 308 309 wdev_lock(wdev); 310 if (wdev->valid_links) { 311 wdev_unlock(wdev); 312 return -EOPNOTSUPP; 313 } 314 if (wdev->links[0].client.current_bss) 315 memcpy(ap_addr->sa_data, 316 wdev->links[0].client.current_bss->pub.bssid, 317 ETH_ALEN); 318 else 319 eth_zero_addr(ap_addr->sa_data); 320 wdev_unlock(wdev); 321 322 return 0; 323 } 324 325 int cfg80211_wext_siwgenie(struct net_device *dev, 326 struct iw_request_info *info, 327 struct iw_point *data, char *extra) 328 { 329 struct wireless_dev *wdev = dev->ieee80211_ptr; 330 struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); 331 u8 *ie = extra; 332 int ie_len = data->length, err; 333 334 if (wdev->iftype != NL80211_IFTYPE_STATION) 335 return -EOPNOTSUPP; 336 337 if (!ie_len) 338 ie = NULL; 339 340 wdev_lock(wdev); 341 342 /* no change */ 343 err = 0; 344 if (wdev->wext.ie_len == ie_len && 345 memcmp(wdev->wext.ie, ie, ie_len) == 0) 346 goto out; 347 348 if (ie_len) { 349 ie = kmemdup(extra, ie_len, GFP_KERNEL); 350 if (!ie) { 351 err = -ENOMEM; 352 goto out; 353 } 354 } else 355 ie = NULL; 356 357 kfree(wdev->wext.ie); 358 wdev->wext.ie = ie; 359 wdev->wext.ie_len = ie_len; 360 361 if (wdev->conn) { 362 err = cfg80211_disconnect(rdev, dev, 363 WLAN_REASON_DEAUTH_LEAVING, false); 364 if (err) 365 goto out; 366 } 367 368 /* userspace better not think we'll reconnect */ 369 err = 0; 370 out: 371 wdev_unlock(wdev); 372 return err; 373 } 374 375 int cfg80211_wext_siwmlme(struct net_device *dev, 376 struct iw_request_info *info, 377 struct iw_point *data, char *extra) 378 { 379 struct wireless_dev *wdev = dev->ieee80211_ptr; 380 struct iw_mlme *mlme = (struct iw_mlme *)extra; 381 struct cfg80211_registered_device *rdev; 382 int err; 383 384 if (!wdev) 385 return -EOPNOTSUPP; 386 387 rdev = wiphy_to_rdev(wdev->wiphy); 388 389 if (wdev->iftype != NL80211_IFTYPE_STATION) 390 return -EINVAL; 391 392 if (mlme->addr.sa_family != ARPHRD_ETHER) 393 return -EINVAL; 394 395 wiphy_lock(&rdev->wiphy); 396 wdev_lock(wdev); 397 switch (mlme->cmd) { 398 case IW_MLME_DEAUTH: 399 case IW_MLME_DISASSOC: 400 err = cfg80211_disconnect(rdev, dev, mlme->reason_code, true); 401 break; 402 default: 403 err = -EOPNOTSUPP; 404 break; 405 } 406 wdev_unlock(wdev); 407 wiphy_unlock(&rdev->wiphy); 408 409 return err; 410 } 411