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