Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cfg80211: keep track of BSSes

In order to avoid problems with BSS structs going away
while they're in use, I've long wanted to make cfg80211
keep track of them. Without the SME, that wasn't doable
but now that we have the SME we can do this too. It can
keep track of up to four separate authentications and
one association, regardless of whether it's controlled
by the cfg80211 SME or the userspace SME.

Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Johannes Berg and committed by
John W. Linville
19957bb3 517357c6

+594 -280
+21 -63
include/net/cfg80211.h
··· 584 584 * is no guarantee that these are well-formed!) 585 585 * @len_information_elements: total length of the information elements 586 586 * @signal: signal strength value (type depends on the wiphy's signal_type) 587 - * @hold: BSS should not expire 588 587 * @free_priv: function pointer to free private data 589 588 * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes 590 589 */ ··· 641 642 * 642 643 * This structure provides information needed to complete IEEE 802.11 643 644 * authentication. 644 - * NOTE: This structure will likely change when more code from mac80211 is 645 - * moved into cfg80211 so that non-mac80211 drivers can benefit from it, too. 646 - * Before using this in a driver that does not use mac80211, it would be better 647 - * to check the status of that work and better yet, volunteer to work on it. 648 645 * 649 - * @chan: The channel to use or %NULL if not specified (auto-select based on 650 - * scan results) 651 - * @peer_addr: The address of the peer STA (AP BSSID in infrastructure case); 652 - * this field is required to be present; if the driver wants to help with 653 - * BSS selection, it should use (yet to be added) MLME event to allow user 654 - * space SME to be notified of roaming candidate, so that the SME can then 655 - * use the authentication request with the recommended BSSID and whatever 656 - * other data may be needed for authentication/association 657 - * @ssid: SSID or %NULL if not yet available 658 - * @ssid_len: Length of ssid in octets 646 + * @bss: The BSS to authenticate with. 659 647 * @auth_type: Authentication type (algorithm) 660 648 * @ie: Extra IEs to add to Authentication frame or %NULL 661 649 * @ie_len: Length of ie buffer in octets 662 650 */ 663 651 struct cfg80211_auth_request { 664 - struct ieee80211_channel *chan; 665 - u8 *peer_addr; 666 - const u8 *ssid; 667 - size_t ssid_len; 668 - enum nl80211_auth_type auth_type; 652 + struct cfg80211_bss *bss; 669 653 const u8 *ie; 670 654 size_t ie_len; 655 + enum nl80211_auth_type auth_type; 671 656 }; 672 657 673 658 /** ··· 659 676 * 660 677 * This structure provides information needed to complete IEEE 802.11 661 678 * (re)association. 662 - * NOTE: This structure will likely change when more code from mac80211 is 663 - * moved into cfg80211 so that non-mac80211 drivers can benefit from it, too. 664 - * Before using this in a driver that does not use mac80211, it would be better 665 - * to check the status of that work and better yet, volunteer to work on it. 666 - * 667 - * @chan: The channel to use or %NULL if not specified (auto-select based on 668 - * scan results) 669 - * @peer_addr: The address of the peer STA (AP BSSID); this field is required 670 - * to be present and the STA must be in State 2 (authenticated) with the 671 - * peer STA 672 - * @ssid: SSID 673 - * @ssid_len: Length of ssid in octets 679 + * @bss: The BSS to associate with. 674 680 * @ie: Extra IEs to add to (Re)Association Request frame or %NULL 675 681 * @ie_len: Length of ie buffer in octets 676 682 * @use_mfp: Use management frame protection (IEEE 802.11w) in this association 677 683 * @crypto: crypto settings 678 684 */ 679 685 struct cfg80211_assoc_request { 680 - struct ieee80211_channel *chan; 681 - u8 *peer_addr; 682 - const u8 *ssid; 683 - size_t ssid_len; 686 + struct cfg80211_bss *bss; 684 687 const u8 *ie; 685 688 size_t ie_len; 686 - bool use_mfp; 687 689 struct cfg80211_crypto_settings crypto; 690 + bool use_mfp; 688 691 }; 689 692 690 693 /** ··· 679 710 * This structure provides information needed to complete IEEE 802.11 680 711 * deauthentication. 681 712 * 682 - * @peer_addr: The address of the peer STA (AP BSSID); this field is required 683 - * to be present and the STA must be authenticated with the peer STA 713 + * @bss: the BSS to deauthenticate from 684 714 * @ie: Extra IEs to add to Deauthentication frame or %NULL 685 715 * @ie_len: Length of ie buffer in octets 716 + * @reason_code: The reason code for the deauthentication 686 717 */ 687 718 struct cfg80211_deauth_request { 688 - u8 *peer_addr; 689 - u16 reason_code; 719 + struct cfg80211_bss *bss; 690 720 const u8 *ie; 691 721 size_t ie_len; 722 + u16 reason_code; 692 723 }; 693 724 694 725 /** ··· 697 728 * This structure provides information needed to complete IEEE 802.11 698 729 * disassocation. 699 730 * 700 - * @peer_addr: The address of the peer STA (AP BSSID); this field is required 701 - * to be present and the STA must be associated with the peer STA 731 + * @bss: the BSS to disassociate from 702 732 * @ie: Extra IEs to add to Disassociation frame or %NULL 703 733 * @ie_len: Length of ie buffer in octets 734 + * @reason_code: The reason code for the disassociation 704 735 */ 705 736 struct cfg80211_disassoc_request { 706 - u8 *peer_addr; 707 - u16 reason_code; 737 + struct cfg80211_bss *bss; 708 738 const u8 *ie; 709 739 size_t ie_len; 740 + u16 reason_code; 710 741 }; 711 742 712 743 /** ··· 1221 1252 1222 1253 /* internal struct */ 1223 1254 struct cfg80211_conn; 1255 + struct cfg80211_internal_bss; 1256 + 1257 + #define MAX_AUTH_BSSES 4 1224 1258 1225 1259 /** 1226 1260 * struct wireless_dev - wireless per-netdev state ··· 1253 1281 struct net_device *netdev; 1254 1282 1255 1283 /* currently used for IBSS and SME - might be rearranged later */ 1256 - struct cfg80211_bss *current_bss; 1257 1284 u8 ssid[IEEE80211_MAX_SSID_LEN]; 1258 1285 u8 ssid_len; 1259 1286 enum { ··· 1261 1290 CFG80211_SME_CONNECTED, 1262 1291 } sme_state; 1263 1292 struct cfg80211_conn *conn; 1293 + 1294 + struct cfg80211_internal_bss *authtry_bsses[MAX_AUTH_BSSES]; 1295 + struct cfg80211_internal_bss *auth_bsses[MAX_AUTH_BSSES]; 1296 + struct cfg80211_internal_bss *current_bss; /* associated / joined */ 1264 1297 1265 1298 #ifdef CONFIG_WIRELESS_EXT 1266 1299 /* wext data */ ··· 1786 1811 * generated ones. 1787 1812 */ 1788 1813 void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp); 1789 - 1790 - /** 1791 - * cfg80211_hold_bss - exclude bss from expiration 1792 - * @bss: bss which should not expire 1793 - * 1794 - * In a case when the BSS is not updated but it shouldn't expire this 1795 - * function can be used to mark the BSS to be excluded from expiration. 1796 - */ 1797 - void cfg80211_hold_bss(struct cfg80211_bss *bss); 1798 - 1799 - /** 1800 - * cfg80211_unhold_bss - remove expiration exception from the BSS 1801 - * @bss: bss which can expire again 1802 - * 1803 - * This function marks the BSS to be expirable again. 1804 - */ 1805 - void cfg80211_unhold_bss(struct cfg80211_bss *bss); 1806 1814 1807 1815 /** 1808 1816 * cfg80211_michael_mic_failure - notification of Michael MIC failure (TKIP)
+9 -13
net/mac80211/cfg.c
··· 1173 1173 struct cfg80211_auth_request *req) 1174 1174 { 1175 1175 struct ieee80211_sub_if_data *sdata; 1176 + const u8 *ssid; 1176 1177 1177 1178 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 1178 1179 ··· 1194 1193 return -EOPNOTSUPP; 1195 1194 } 1196 1195 1197 - memcpy(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN); 1196 + memcpy(sdata->u.mgd.bssid, req->bss->bssid, ETH_ALEN); 1198 1197 1199 - sdata->local->oper_channel = req->chan; 1198 + sdata->local->oper_channel = req->bss->channel; 1200 1199 ieee80211_hw_config(sdata->local, 0); 1201 1200 1202 - if (!req->ssid) 1201 + ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); 1202 + if (!ssid) 1203 1203 return -EINVAL; 1204 - memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len); 1205 - sdata->u.mgd.ssid_len = req->ssid_len; 1204 + sdata->u.mgd.ssid_len = *(ssid + 1); 1205 + memcpy(sdata->u.mgd.ssid, ssid + 2, sdata->u.mgd.ssid_len); 1206 1206 1207 1207 kfree(sdata->u.mgd.sme_auth_ie); 1208 1208 sdata->u.mgd.sme_auth_ie = NULL; ··· 1229 1227 1230 1228 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 1231 1229 1232 - if (memcmp(sdata->u.mgd.bssid, req->peer_addr, ETH_ALEN) != 0 || 1230 + if (memcmp(sdata->u.mgd.bssid, req->bss->bssid, ETH_ALEN) != 0 || 1233 1231 !(sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED)) 1234 1232 return -ENOLINK; /* not authenticated */ 1235 1233 ··· 1241 1239 req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) 1242 1240 sdata->u.mgd.flags |= IEEE80211_STA_DISABLE_11N; 1243 1241 1244 - sdata->local->oper_channel = req->chan; 1242 + sdata->local->oper_channel = req->bss->channel; 1245 1243 ieee80211_hw_config(sdata->local, 0); 1246 - 1247 - if (!req->ssid) 1248 - return -EINVAL; 1249 - 1250 - memcpy(sdata->u.mgd.ssid, req->ssid, req->ssid_len); 1251 - sdata->u.mgd.ssid_len = req->ssid_len; 1252 1244 1253 1245 ret = ieee80211_sta_set_extra_ie(sdata, req->ie, req->ie_len); 1254 1246 if (ret && ret != -EALREADY)
+1 -5
net/mac80211/mlme.c
··· 876 876 bss_info_changed |= ieee80211_handle_bss_capability(sdata, 877 877 bss->cbss.capability, bss->has_erp_value, bss->erp_value); 878 878 879 - cfg80211_hold_bss(&bss->cbss); 880 - 881 879 ieee80211_rx_bss_put(local, bss); 882 880 } 883 881 ··· 1029 1031 conf->channel->center_freq, 1030 1032 ifmgd->ssid, ifmgd->ssid_len); 1031 1033 1032 - if (bss) { 1033 - cfg80211_unhold_bss(&bss->cbss); 1034 + if (bss) 1034 1035 ieee80211_rx_bss_put(local, bss); 1035 - } 1036 1036 1037 1037 if (self_disconnected) { 1038 1038 if (deauth)
+1 -4
net/wireless/core.c
··· 583 583 #endif 584 584 cfg80211_disconnect(rdev, dev, 585 585 WLAN_REASON_DEAUTH_LEAVING, true); 586 + cfg80211_mlme_down(rdev, dev); 586 587 break; 587 588 default: 588 589 break; 589 590 } 590 - break; 591 - case NETDEV_DOWN: 592 - kfree(wdev->conn); 593 - wdev->conn = NULL; 594 591 break; 595 592 case NETDEV_UP: 596 593 #ifdef CONFIG_WIRELESS_EXT
+40 -1
net/wireless/core.h
··· 110 110 struct rb_node rbn; 111 111 unsigned long ts; 112 112 struct kref ref; 113 - bool hold, ies_allocated; 113 + atomic_t hold; 114 + bool ies_allocated; 114 115 115 116 /* must be last because of priv member */ 116 117 struct cfg80211_bss pub; 117 118 }; 119 + 120 + static inline struct cfg80211_internal_bss *bss_from_pub(struct cfg80211_bss *pub) 121 + { 122 + return container_of(pub, struct cfg80211_internal_bss, pub); 123 + } 124 + 125 + static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss) 126 + { 127 + atomic_inc(&bss->hold); 128 + } 129 + 130 + static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss) 131 + { 132 + int r = atomic_dec_return(&bss->hold); 133 + WARN_ON(r < 0); 134 + } 135 + 118 136 119 137 struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx); 120 138 int get_wiphy_idx(struct wiphy *wiphy); ··· 194 176 int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, 195 177 struct net_device *dev, bool nowext); 196 178 179 + /* MLME */ 180 + int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, 181 + struct net_device *dev, struct ieee80211_channel *chan, 182 + enum nl80211_auth_type auth_type, const u8 *bssid, 183 + const u8 *ssid, int ssid_len, 184 + const u8 *ie, int ie_len); 185 + int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, 186 + struct net_device *dev, struct ieee80211_channel *chan, 187 + const u8 *bssid, const u8 *ssid, int ssid_len, 188 + const u8 *ie, int ie_len, bool use_mfp, 189 + struct cfg80211_crypto_settings *crypt); 190 + int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, 191 + struct net_device *dev, const u8 *bssid, 192 + const u8 *ie, int ie_len, u16 reason); 193 + int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, 194 + struct net_device *dev, const u8 *bssid, 195 + const u8 *ie, int ie_len, u16 reason); 196 + void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, 197 + struct net_device *dev); 198 + 197 199 /* SME */ 198 200 int cfg80211_connect(struct cfg80211_registered_device *rdev, 199 201 struct net_device *dev, ··· 231 193 size_t ie_len, u16 reason, bool from_ap); 232 194 void cfg80211_sme_scan_done(struct net_device *dev); 233 195 void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); 196 + void cfg80211_sme_disassoc(struct net_device *dev, int idx); 234 197 235 198 #endif /* __NET_WIRELESS_CORE_H */
+6 -6
net/wireless/ibss.c
··· 33 33 34 34 if (wdev->current_bss) { 35 35 cfg80211_unhold_bss(wdev->current_bss); 36 - cfg80211_put_bss(wdev->current_bss); 36 + cfg80211_put_bss(&wdev->current_bss->pub); 37 37 } 38 38 39 - cfg80211_hold_bss(bss); 40 - wdev->current_bss = bss; 39 + cfg80211_hold_bss(bss_from_pub(bss)); 40 + wdev->current_bss = bss_from_pub(bss); 41 41 42 42 nl80211_send_ibss_bssid(wiphy_to_dev(wdev->wiphy), dev, bssid, gfp); 43 43 #ifdef CONFIG_WIRELESS_EXT ··· 78 78 79 79 if (wdev->current_bss) { 80 80 cfg80211_unhold_bss(wdev->current_bss); 81 - cfg80211_put_bss(wdev->current_bss); 81 + cfg80211_put_bss(&wdev->current_bss->pub); 82 82 } 83 83 84 84 wdev->current_bss = NULL; ··· 212 212 return -EINVAL; 213 213 214 214 if (wdev->current_bss) 215 - chan = wdev->current_bss->channel; 215 + chan = wdev->current_bss->pub.channel; 216 216 else if (wdev->wext.ibss.channel) 217 217 chan = wdev->wext.ibss.channel; 218 218 ··· 352 352 ap_addr->sa_family = ARPHRD_ETHER; 353 353 354 354 if (wdev->current_bss) 355 - memcpy(ap_addr->sa_data, wdev->current_bss->bssid, ETH_ALEN); 355 + memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); 356 356 else 357 357 memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN); 358 358 return 0;
+342 -15
net/wireless/mlme.c
··· 14 14 15 15 void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) 16 16 { 17 - struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; 17 + struct wireless_dev *wdev = dev->ieee80211_ptr; 18 + struct wiphy *wiphy = wdev->wiphy; 18 19 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 20 + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; 21 + u8 *bssid = mgmt->bssid; 22 + int i; 23 + u16 status = le16_to_cpu(mgmt->u.auth.status_code); 24 + bool done = false; 25 + 26 + for (i = 0; i < MAX_AUTH_BSSES; i++) { 27 + if (wdev->authtry_bsses[i] && 28 + memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, 29 + ETH_ALEN) == 0) { 30 + if (status == WLAN_STATUS_SUCCESS) { 31 + wdev->auth_bsses[i] = wdev->authtry_bsses[i]; 32 + } else { 33 + cfg80211_unhold_bss(wdev->authtry_bsses[i]); 34 + cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); 35 + } 36 + wdev->authtry_bsses[i] = NULL; 37 + done = true; 38 + break; 39 + } 40 + } 41 + 42 + WARN_ON(!done); 19 43 20 44 nl80211_send_rx_auth(rdev, dev, buf, len, gfp); 21 45 cfg80211_sme_rx_auth(dev, buf, len); ··· 54 30 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 55 31 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; 56 32 u8 *ie = mgmt->u.assoc_resp.variable; 57 - int ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); 33 + int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); 34 + bool done; 58 35 59 36 status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); 60 37 ··· 63 38 64 39 cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, 65 40 status_code, gfp); 41 + 42 + if (status_code == WLAN_STATUS_SUCCESS) { 43 + for (i = 0; wdev->current_bss && i < MAX_AUTH_BSSES; i++) { 44 + if (wdev->auth_bsses[i] == wdev->current_bss) { 45 + cfg80211_unhold_bss(wdev->auth_bsses[i]); 46 + cfg80211_put_bss(&wdev->auth_bsses[i]->pub); 47 + wdev->auth_bsses[i] = NULL; 48 + done = true; 49 + break; 50 + } 51 + } 52 + 53 + WARN_ON(!done); 54 + } 66 55 } 67 56 EXPORT_SYMBOL(cfg80211_send_rx_assoc); 68 57 ··· 86 47 struct wiphy *wiphy = wdev->wiphy; 87 48 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 88 49 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; 50 + const u8 *bssid = mgmt->bssid; 51 + int i; 52 + bool done = false; 89 53 90 54 nl80211_send_deauth(rdev, dev, buf, len, gfp); 55 + 56 + if (wdev->current_bss && 57 + memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { 58 + done = true; 59 + cfg80211_unhold_bss(wdev->current_bss); 60 + cfg80211_put_bss(&wdev->current_bss->pub); 61 + wdev->current_bss = NULL; 62 + } else for (i = 0; i < MAX_AUTH_BSSES; i++) { 63 + if (wdev->auth_bsses[i] && 64 + memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) { 65 + cfg80211_unhold_bss(wdev->auth_bsses[i]); 66 + cfg80211_put_bss(&wdev->auth_bsses[i]->pub); 67 + wdev->auth_bsses[i] = NULL; 68 + done = true; 69 + break; 70 + } 71 + if (wdev->authtry_bsses[i] && 72 + memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) { 73 + cfg80211_unhold_bss(wdev->authtry_bsses[i]); 74 + cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); 75 + wdev->authtry_bsses[i] = NULL; 76 + done = true; 77 + break; 78 + } 79 + } 80 + /* 81 + * mac80211 currently triggers this warning, 82 + * so disable for now (it's harmless, just 83 + * means that we got a spurious event) 84 + 85 + WARN_ON(!done); 86 + 87 + */ 91 88 92 89 if (wdev->sme_state == CFG80211_SME_CONNECTED) { 93 90 u16 reason_code; ··· 134 59 from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; 135 60 __cfg80211_disconnected(dev, gfp, NULL, 0, 136 61 reason_code, from_ap); 137 - 138 - wdev->sme_state = CFG80211_SME_IDLE; 139 62 } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { 140 63 cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, 141 64 WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); ··· 147 74 struct wiphy *wiphy = wdev->wiphy; 148 75 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 149 76 struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; 77 + const u8 *bssid = mgmt->bssid; 78 + int i; 79 + u16 reason_code; 80 + bool from_ap; 81 + bool done = false; 150 82 151 83 nl80211_send_disassoc(rdev, dev, buf, len, gfp); 152 84 153 - if (wdev->sme_state == CFG80211_SME_CONNECTED) { 154 - u16 reason_code; 155 - bool from_ap; 85 + if (!wdev->sme_state == CFG80211_SME_CONNECTED) 86 + return; 156 87 157 - reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); 88 + if (wdev->current_bss && 89 + memcmp(wdev->current_bss, bssid, ETH_ALEN) == 0) { 90 + for (i = 0; i < MAX_AUTH_BSSES; i++) { 91 + if (wdev->authtry_bsses[i] || wdev->auth_bsses[i]) 92 + continue; 93 + wdev->auth_bsses[i] = wdev->current_bss; 94 + wdev->current_bss = NULL; 95 + done = true; 96 + cfg80211_sme_disassoc(dev, i); 97 + break; 98 + } 99 + WARN_ON(!done); 100 + } else 101 + WARN_ON(1); 158 102 159 - from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; 160 - __cfg80211_disconnected(dev, gfp, NULL, 0, 161 - reason_code, from_ap); 162 103 163 - wdev->sme_state = CFG80211_SME_IDLE; 164 - } 104 + reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); 105 + 106 + from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; 107 + __cfg80211_disconnected(dev, gfp, NULL, 0, 108 + reason_code, from_ap); 165 109 } 166 110 EXPORT_SYMBOL(cfg80211_send_disassoc); 167 111 ··· 187 97 struct wireless_dev *wdev = dev->ieee80211_ptr; 188 98 struct wiphy *wiphy = wdev->wiphy; 189 99 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 100 + int i; 101 + bool done = false; 102 + 190 103 nl80211_send_auth_timeout(rdev, dev, addr, gfp); 191 104 if (wdev->sme_state == CFG80211_SME_CONNECTING) 192 105 cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, 193 106 WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); 194 - wdev->sme_state = CFG80211_SME_IDLE; 107 + 108 + for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { 109 + if (wdev->authtry_bsses[i] && 110 + memcmp(wdev->authtry_bsses[i]->pub.bssid, 111 + addr, ETH_ALEN) == 0) { 112 + cfg80211_unhold_bss(wdev->authtry_bsses[i]); 113 + cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); 114 + wdev->authtry_bsses[i] = NULL; 115 + done = true; 116 + break; 117 + } 118 + } 119 + 120 + WARN_ON(!done); 195 121 } 196 122 EXPORT_SYMBOL(cfg80211_send_auth_timeout); 197 123 ··· 216 110 struct wireless_dev *wdev = dev->ieee80211_ptr; 217 111 struct wiphy *wiphy = wdev->wiphy; 218 112 struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); 113 + int i; 114 + bool done = false; 115 + 219 116 nl80211_send_assoc_timeout(rdev, dev, addr, gfp); 220 117 if (wdev->sme_state == CFG80211_SME_CONNECTING) 221 118 cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, 222 119 WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); 223 - wdev->sme_state = CFG80211_SME_IDLE; 120 + 121 + for (i = 0; addr && i < MAX_AUTH_BSSES; i++) { 122 + if (wdev->auth_bsses[i] && 123 + memcmp(wdev->auth_bsses[i]->pub.bssid, 124 + addr, ETH_ALEN) == 0) { 125 + cfg80211_unhold_bss(wdev->auth_bsses[i]); 126 + cfg80211_put_bss(&wdev->auth_bsses[i]->pub); 127 + wdev->auth_bsses[i] = NULL; 128 + done = true; 129 + break; 130 + } 131 + } 132 + 133 + WARN_ON(!done); 224 134 } 225 135 EXPORT_SYMBOL(cfg80211_send_assoc_timeout); 226 136 ··· 265 143 nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp); 266 144 } 267 145 EXPORT_SYMBOL(cfg80211_michael_mic_failure); 146 + 147 + /* some MLME handling for userspace SME */ 148 + int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, 149 + struct net_device *dev, struct ieee80211_channel *chan, 150 + enum nl80211_auth_type auth_type, const u8 *bssid, 151 + const u8 *ssid, int ssid_len, 152 + const u8 *ie, int ie_len) 153 + { 154 + struct wireless_dev *wdev = dev->ieee80211_ptr; 155 + struct cfg80211_auth_request req; 156 + struct cfg80211_internal_bss *bss; 157 + int i, err, slot = -1, nfree = 0; 158 + 159 + memset(&req, 0, sizeof(req)); 160 + 161 + req.ie = ie; 162 + req.ie_len = ie_len; 163 + req.auth_type = auth_type; 164 + req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, 165 + WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); 166 + if (!req.bss) 167 + return -ENOENT; 168 + 169 + bss = bss_from_pub(req.bss); 170 + 171 + for (i = 0; i < MAX_AUTH_BSSES; i++) { 172 + if (bss == wdev->auth_bsses[i]) { 173 + err = -EALREADY; 174 + goto out; 175 + } 176 + } 177 + 178 + for (i = 0; i < MAX_AUTH_BSSES; i++) { 179 + if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) { 180 + slot = i; 181 + nfree++; 182 + } 183 + } 184 + 185 + /* we need one free slot for disassoc and one for this auth */ 186 + if (nfree < 2) { 187 + err = -ENOSPC; 188 + goto out; 189 + } 190 + 191 + wdev->authtry_bsses[slot] = bss; 192 + cfg80211_hold_bss(bss); 193 + 194 + err = rdev->ops->auth(&rdev->wiphy, dev, &req); 195 + if (err) { 196 + wdev->authtry_bsses[slot] = NULL; 197 + cfg80211_unhold_bss(bss); 198 + } 199 + 200 + out: 201 + if (err) 202 + cfg80211_put_bss(req.bss); 203 + return err; 204 + } 205 + 206 + int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, 207 + struct net_device *dev, struct ieee80211_channel *chan, 208 + const u8 *bssid, const u8 *ssid, int ssid_len, 209 + const u8 *ie, int ie_len, bool use_mfp, 210 + struct cfg80211_crypto_settings *crypt) 211 + { 212 + struct wireless_dev *wdev = dev->ieee80211_ptr; 213 + struct cfg80211_assoc_request req; 214 + struct cfg80211_internal_bss *bss; 215 + int i, err, slot = -1; 216 + 217 + memset(&req, 0, sizeof(req)); 218 + 219 + if (wdev->current_bss) 220 + return -EALREADY; 221 + 222 + req.ie = ie; 223 + req.ie_len = ie_len; 224 + memcpy(&req.crypto, crypt, sizeof(req.crypto)); 225 + req.use_mfp = use_mfp; 226 + req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, 227 + WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); 228 + if (!req.bss) 229 + return -ENOENT; 230 + 231 + bss = bss_from_pub(req.bss); 232 + 233 + for (i = 0; i < MAX_AUTH_BSSES; i++) { 234 + if (bss == wdev->auth_bsses[i]) { 235 + slot = i; 236 + break; 237 + } 238 + } 239 + 240 + if (slot < 0) { 241 + err = -ENOTCONN; 242 + goto out; 243 + } 244 + 245 + err = rdev->ops->assoc(&rdev->wiphy, dev, &req); 246 + out: 247 + /* still a reference in wdev->auth_bsses[slot] */ 248 + cfg80211_put_bss(req.bss); 249 + return err; 250 + } 251 + 252 + int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, 253 + struct net_device *dev, const u8 *bssid, 254 + const u8 *ie, int ie_len, u16 reason) 255 + { 256 + struct wireless_dev *wdev = dev->ieee80211_ptr; 257 + struct cfg80211_deauth_request req; 258 + int i; 259 + 260 + memset(&req, 0, sizeof(req)); 261 + req.reason_code = reason; 262 + req.ie = ie; 263 + req.ie_len = ie_len; 264 + if (wdev->current_bss && 265 + memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { 266 + req.bss = &wdev->current_bss->pub; 267 + } else for (i = 0; i < MAX_AUTH_BSSES; i++) { 268 + if (wdev->auth_bsses[i] && 269 + memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, ETH_ALEN) == 0) { 270 + req.bss = &wdev->auth_bsses[i]->pub; 271 + break; 272 + } 273 + if (wdev->authtry_bsses[i] && 274 + memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, ETH_ALEN) == 0) { 275 + req.bss = &wdev->authtry_bsses[i]->pub; 276 + break; 277 + } 278 + } 279 + 280 + if (!req.bss) 281 + return -ENOTCONN; 282 + 283 + return rdev->ops->deauth(&rdev->wiphy, dev, &req); 284 + } 285 + 286 + int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, 287 + struct net_device *dev, const u8 *bssid, 288 + const u8 *ie, int ie_len, u16 reason) 289 + { 290 + struct wireless_dev *wdev = dev->ieee80211_ptr; 291 + struct cfg80211_disassoc_request req; 292 + 293 + memset(&req, 0, sizeof(req)); 294 + req.reason_code = reason; 295 + req.ie = ie; 296 + req.ie_len = ie_len; 297 + if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) 298 + req.bss = &wdev->current_bss->pub; 299 + else 300 + return -ENOTCONN; 301 + 302 + return rdev->ops->disassoc(&rdev->wiphy, dev, &req); 303 + } 304 + 305 + void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, 306 + struct net_device *dev) 307 + { 308 + struct wireless_dev *wdev = dev->ieee80211_ptr; 309 + struct cfg80211_deauth_request req; 310 + int i; 311 + 312 + if (!rdev->ops->deauth) 313 + return; 314 + 315 + memset(&req, 0, sizeof(req)); 316 + req.reason_code = WLAN_REASON_DEAUTH_LEAVING; 317 + req.ie = NULL; 318 + req.ie_len = 0; 319 + 320 + if (wdev->current_bss) { 321 + req.bss = &wdev->current_bss->pub; 322 + rdev->ops->deauth(&rdev->wiphy, dev, &req); 323 + if (wdev->current_bss) { 324 + cfg80211_unhold_bss(wdev->current_bss); 325 + cfg80211_put_bss(&wdev->current_bss->pub); 326 + wdev->current_bss = NULL; 327 + } 328 + } 329 + 330 + for (i = 0; i < MAX_AUTH_BSSES; i++) { 331 + if (wdev->auth_bsses[i]) { 332 + req.bss = &wdev->auth_bsses[i]->pub; 333 + rdev->ops->deauth(&rdev->wiphy, dev, &req); 334 + if (wdev->auth_bsses[i]) { 335 + cfg80211_unhold_bss(wdev->auth_bsses[i]); 336 + cfg80211_put_bss(&wdev->auth_bsses[i]->pub); 337 + wdev->auth_bsses[i] = NULL; 338 + } 339 + } 340 + if (wdev->authtry_bsses[i]) { 341 + req.bss = &wdev->authtry_bsses[i]->pub; 342 + rdev->ops->deauth(&rdev->wiphy, dev, &req); 343 + if (wdev->authtry_bsses[i]) { 344 + cfg80211_unhold_bss(wdev->authtry_bsses[i]); 345 + cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); 346 + wdev->authtry_bsses[i] = NULL; 347 + } 348 + } 349 + } 350 + }
+74 -82
net/wireless/nl80211.c
··· 3044 3044 { 3045 3045 struct cfg80211_registered_device *drv; 3046 3046 struct net_device *dev; 3047 - struct cfg80211_auth_request req; 3048 - struct wiphy *wiphy; 3049 - int err; 3047 + struct ieee80211_channel *chan; 3048 + const u8 *bssid, *ssid, *ie = NULL; 3049 + int err, ssid_len, ie_len = 0; 3050 + enum nl80211_auth_type auth_type; 3050 3051 3051 3052 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) 3052 3053 return -EINVAL; ··· 3056 3055 return -EINVAL; 3057 3056 3058 3057 if (!info->attrs[NL80211_ATTR_AUTH_TYPE]) 3058 + return -EINVAL; 3059 + 3060 + if (!info->attrs[NL80211_ATTR_SSID]) 3061 + return -EINVAL; 3062 + 3063 + if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) 3059 3064 return -EINVAL; 3060 3065 3061 3066 rtnl_lock(); ··· 3085 3078 goto out; 3086 3079 } 3087 3080 3088 - wiphy = &drv->wiphy; 3089 - memset(&req, 0, sizeof(req)); 3090 - 3091 - req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); 3092 - 3093 - if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { 3094 - req.chan = ieee80211_get_channel( 3095 - wiphy, 3096 - nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); 3097 - if (!req.chan) { 3098 - err = -EINVAL; 3099 - goto out; 3100 - } 3101 - } 3102 - 3103 - if (info->attrs[NL80211_ATTR_SSID]) { 3104 - req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); 3105 - req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); 3106 - } 3107 - 3108 - if (info->attrs[NL80211_ATTR_IE]) { 3109 - req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); 3110 - req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); 3111 - } 3112 - 3113 - req.auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); 3114 - if (!nl80211_valid_auth_type(req.auth_type)) { 3081 + bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); 3082 + chan = ieee80211_get_channel(&drv->wiphy, 3083 + nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); 3084 + if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { 3115 3085 err = -EINVAL; 3116 3086 goto out; 3117 3087 } 3118 3088 3119 - err = drv->ops->auth(&drv->wiphy, dev, &req); 3089 + ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); 3090 + ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); 3091 + 3092 + if (info->attrs[NL80211_ATTR_IE]) { 3093 + ie = nla_data(info->attrs[NL80211_ATTR_IE]); 3094 + ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); 3095 + } 3096 + 3097 + auth_type = nla_get_u32(info->attrs[NL80211_ATTR_AUTH_TYPE]); 3098 + if (!nl80211_valid_auth_type(auth_type)) { 3099 + err = -EINVAL; 3100 + goto out; 3101 + } 3102 + 3103 + err = cfg80211_mlme_auth(drv, dev, chan, auth_type, bssid, 3104 + ssid, ssid_len, ie, ie_len); 3120 3105 3121 3106 out: 3122 3107 cfg80211_put_dev(drv); ··· 3182 3183 3183 3184 static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) 3184 3185 { 3185 - struct cfg80211_registered_device *drv; 3186 + struct cfg80211_registered_device *rdev; 3186 3187 struct net_device *dev; 3187 - struct cfg80211_assoc_request req; 3188 - struct wiphy *wiphy; 3189 - int err; 3188 + struct cfg80211_crypto_settings crypto; 3189 + struct ieee80211_channel *chan; 3190 + const u8 *bssid, *ssid, *ie = NULL; 3191 + int err, ssid_len, ie_len = 0; 3192 + bool use_mfp = false; 3190 3193 3191 3194 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) 3192 3195 return -EINVAL; 3193 3196 3194 3197 if (!info->attrs[NL80211_ATTR_MAC] || 3195 - !info->attrs[NL80211_ATTR_SSID]) 3198 + !info->attrs[NL80211_ATTR_SSID] || 3199 + !info->attrs[NL80211_ATTR_WIPHY_FREQ]) 3196 3200 return -EINVAL; 3197 3201 3198 3202 rtnl_lock(); 3199 3203 3200 - err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 3204 + err = get_drv_dev_by_info_ifindex(info->attrs, &rdev, &dev); 3201 3205 if (err) 3202 3206 goto unlock_rtnl; 3203 3207 3204 - if (!drv->ops->assoc) { 3208 + if (!rdev->ops->assoc) { 3205 3209 err = -EOPNOTSUPP; 3206 3210 goto out; 3207 3211 } ··· 3219 3217 goto out; 3220 3218 } 3221 3219 3222 - wiphy = &drv->wiphy; 3223 - memset(&req, 0, sizeof(req)); 3220 + bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); 3224 3221 3225 - req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); 3226 - 3227 - if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { 3228 - req.chan = ieee80211_get_channel( 3229 - wiphy, 3230 - nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); 3231 - if (!req.chan) { 3232 - err = -EINVAL; 3233 - goto out; 3234 - } 3222 + chan = ieee80211_get_channel(&rdev->wiphy, 3223 + nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ])); 3224 + if (!chan || (chan->flags & IEEE80211_CHAN_DISABLED)) { 3225 + err = -EINVAL; 3226 + goto out; 3235 3227 } 3236 3228 3237 - req.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); 3238 - req.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); 3229 + ssid = nla_data(info->attrs[NL80211_ATTR_SSID]); 3230 + ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]); 3239 3231 3240 3232 if (info->attrs[NL80211_ATTR_IE]) { 3241 - req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); 3242 - req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); 3233 + ie = nla_data(info->attrs[NL80211_ATTR_IE]); 3234 + ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); 3243 3235 } 3244 3236 3245 3237 if (info->attrs[NL80211_ATTR_USE_MFP]) { 3246 3238 enum nl80211_mfp use_mfp = 3247 3239 nla_get_u32(info->attrs[NL80211_ATTR_USE_MFP]); 3248 3240 if (use_mfp == NL80211_MFP_REQUIRED) 3249 - req.use_mfp = true; 3241 + use_mfp = true; 3250 3242 else if (use_mfp != NL80211_MFP_NO) { 3251 3243 err = -EINVAL; 3252 3244 goto out; 3253 3245 } 3254 3246 } 3255 3247 3256 - err = nl80211_crypto_settings(info, &req.crypto); 3248 + err = nl80211_crypto_settings(info, &crypto); 3257 3249 if (!err) 3258 - err = drv->ops->assoc(&drv->wiphy, dev, &req); 3250 + err = cfg80211_mlme_assoc(rdev, dev, chan, bssid, ssid, 3251 + ssid_len, ie, ie_len, use_mfp, 3252 + &crypto); 3259 3253 3260 3254 out: 3261 - cfg80211_put_dev(drv); 3255 + cfg80211_put_dev(rdev); 3262 3256 dev_put(dev); 3263 3257 unlock_rtnl: 3264 3258 rtnl_unlock(); ··· 3265 3267 { 3266 3268 struct cfg80211_registered_device *drv; 3267 3269 struct net_device *dev; 3268 - struct cfg80211_deauth_request req; 3269 - struct wiphy *wiphy; 3270 - int err; 3270 + const u8 *ie = NULL, *bssid; 3271 + int err, ie_len = 0; 3272 + u16 reason_code; 3271 3273 3272 3274 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) 3273 3275 return -EINVAL; ··· 3299 3301 goto out; 3300 3302 } 3301 3303 3302 - wiphy = &drv->wiphy; 3303 - memset(&req, 0, sizeof(req)); 3304 + bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); 3304 3305 3305 - req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); 3306 - 3307 - req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); 3308 - if (req.reason_code == 0) { 3306 + reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); 3307 + if (reason_code == 0) { 3309 3308 /* Reason Code 0 is reserved */ 3310 3309 err = -EINVAL; 3311 3310 goto out; 3312 3311 } 3313 3312 3314 3313 if (info->attrs[NL80211_ATTR_IE]) { 3315 - req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); 3316 - req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); 3314 + ie = nla_data(info->attrs[NL80211_ATTR_IE]); 3315 + ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); 3317 3316 } 3318 3317 3319 - err = drv->ops->deauth(&drv->wiphy, dev, &req); 3318 + err = cfg80211_mlme_deauth(drv, dev, bssid, ie, ie_len, reason_code); 3320 3319 3321 3320 out: 3322 3321 cfg80211_put_dev(drv); ··· 3327 3332 { 3328 3333 struct cfg80211_registered_device *drv; 3329 3334 struct net_device *dev; 3330 - struct cfg80211_disassoc_request req; 3331 - struct wiphy *wiphy; 3332 - int err; 3335 + const u8 *ie = NULL, *bssid; 3336 + int err, ie_len = 0; 3337 + u16 reason_code; 3333 3338 3334 3339 if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) 3335 3340 return -EINVAL; ··· 3361 3366 goto out; 3362 3367 } 3363 3368 3364 - wiphy = &drv->wiphy; 3365 - memset(&req, 0, sizeof(req)); 3369 + bssid = nla_data(info->attrs[NL80211_ATTR_MAC]); 3366 3370 3367 - req.peer_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); 3368 - 3369 - req.reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); 3370 - if (req.reason_code == 0) { 3371 + reason_code = nla_get_u16(info->attrs[NL80211_ATTR_REASON_CODE]); 3372 + if (reason_code == 0) { 3371 3373 /* Reason Code 0 is reserved */ 3372 3374 err = -EINVAL; 3373 3375 goto out; 3374 3376 } 3375 3377 3376 3378 if (info->attrs[NL80211_ATTR_IE]) { 3377 - req.ie = nla_data(info->attrs[NL80211_ATTR_IE]); 3378 - req.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); 3379 + ie = nla_data(info->attrs[NL80211_ATTR_IE]); 3380 + ie_len = nla_len(info->attrs[NL80211_ATTR_IE]); 3379 3381 } 3380 3382 3381 - err = drv->ops->disassoc(&drv->wiphy, dev, &req); 3383 + err = cfg80211_mlme_disassoc(drv, dev, bssid, ie, ie_len, reason_code); 3382 3384 3383 3385 out: 3384 3386 cfg80211_put_dev(drv);
+5 -26
net/wireless/scan.c
··· 70 70 if (bss->ies_allocated) 71 71 kfree(bss->pub.information_elements); 72 72 73 + BUG_ON(atomic_read(&bss->hold)); 74 + 73 75 kfree(bss); 74 76 } 75 77 ··· 94 92 bool expired = false; 95 93 96 94 list_for_each_entry_safe(bss, tmp, &dev->bss_list, list) { 97 - if (bss->hold || 98 - !time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE)) 95 + if (atomic_read(&bss->hold)) 96 + continue; 97 + if (!time_after(jiffies, bss->ts + IEEE80211_SCAN_RESULT_EXPIRE)) 99 98 continue; 100 99 list_del(&bss->list); 101 100 rb_erase(&bss->rbn, &dev->bss_tree); ··· 555 552 kref_put(&bss->ref, bss_release); 556 553 } 557 554 EXPORT_SYMBOL(cfg80211_unlink_bss); 558 - 559 - void cfg80211_hold_bss(struct cfg80211_bss *pub) 560 - { 561 - struct cfg80211_internal_bss *bss; 562 - 563 - if (!pub) 564 - return; 565 - 566 - bss = container_of(pub, struct cfg80211_internal_bss, pub); 567 - bss->hold = true; 568 - } 569 - EXPORT_SYMBOL(cfg80211_hold_bss); 570 - 571 - void cfg80211_unhold_bss(struct cfg80211_bss *pub) 572 - { 573 - struct cfg80211_internal_bss *bss; 574 - 575 - if (!pub) 576 - return; 577 - 578 - bss = container_of(pub, struct cfg80211_internal_bss, pub); 579 - bss->hold = false; 580 - } 581 - EXPORT_SYMBOL(cfg80211_unhold_bss); 582 555 583 556 #ifdef CONFIG_WIRELESS_EXT 584 557 int cfg80211_wext_siwscan(struct net_device *dev,
+93 -63
net/wireless/sme.c
··· 103 103 static int cfg80211_conn_do_work(struct wireless_dev *wdev) 104 104 { 105 105 struct cfg80211_registered_device *drv = wiphy_to_dev(wdev->wiphy); 106 - union { 107 - struct cfg80211_auth_request auth_req; 108 - struct cfg80211_assoc_request assoc_req; 109 - } u; 110 - 111 - memset(&u, 0, sizeof(u)); 106 + struct cfg80211_connect_params *params; 107 + int err; 112 108 113 109 if (!wdev->conn) 114 110 return 0; 111 + 112 + params = &wdev->conn->params; 115 113 116 114 switch (wdev->conn->state) { 117 115 case CFG80211_CONN_SCAN_AGAIN: 118 116 return cfg80211_conn_scan(wdev); 119 117 case CFG80211_CONN_AUTHENTICATE_NEXT: 120 - u.auth_req.chan = wdev->conn->params.channel; 121 - u.auth_req.peer_addr = wdev->conn->params.bssid; 122 - u.auth_req.ssid = wdev->conn->params.ssid; 123 - u.auth_req.ssid_len = wdev->conn->params.ssid_len; 124 - u.auth_req.auth_type = wdev->conn->params.auth_type; 125 - u.auth_req.ie = NULL; 126 - u.auth_req.ie_len = 0; 127 - wdev->conn->state = CFG80211_CONN_AUTHENTICATING; 128 118 BUG_ON(!drv->ops->auth); 129 - return drv->ops->auth(wdev->wiphy, wdev->netdev, &u.auth_req); 119 + wdev->conn->state = CFG80211_CONN_AUTHENTICATING; 120 + return cfg80211_mlme_auth(drv, wdev->netdev, 121 + params->channel, params->auth_type, 122 + params->bssid, 123 + params->ssid, params->ssid_len, 124 + NULL, 0); 130 125 case CFG80211_CONN_ASSOCIATE_NEXT: 131 - u.assoc_req.chan = wdev->conn->params.channel; 132 - u.assoc_req.peer_addr = wdev->conn->params.bssid; 133 - u.assoc_req.ssid = wdev->conn->params.ssid; 134 - u.assoc_req.ssid_len = wdev->conn->params.ssid_len; 135 - u.assoc_req.ie = wdev->conn->params.ie; 136 - u.assoc_req.ie_len = wdev->conn->params.ie_len; 137 - u.assoc_req.use_mfp = false; 138 - memcpy(&u.assoc_req.crypto, &wdev->conn->params.crypto, 139 - sizeof(u.assoc_req.crypto)); 140 - wdev->conn->state = CFG80211_CONN_ASSOCIATING; 141 126 BUG_ON(!drv->ops->assoc); 142 - return drv->ops->assoc(wdev->wiphy, wdev->netdev, 143 - &u.assoc_req); 127 + wdev->conn->state = CFG80211_CONN_ASSOCIATING; 128 + err = cfg80211_mlme_assoc(drv, wdev->netdev, 129 + params->channel, params->bssid, 130 + params->ssid, params->ssid_len, 131 + params->ie, params->ie_len, 132 + false, &params->crypto); 133 + if (err) 134 + cfg80211_mlme_deauth(drv, wdev->netdev, params->bssid, 135 + NULL, 0, WLAN_REASON_DEAUTH_LEAVING); 136 + return err; 144 137 default: 145 138 return 0; 146 139 } ··· 179 186 wdev->conn->params.ssid_len, 180 187 WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_PRIVACY, 181 188 capa); 182 - 183 189 if (!bss) 184 190 return false; 185 191 ··· 256 264 } 257 265 wdev->conn->state = CFG80211_CONN_AUTHENTICATE_NEXT; 258 266 schedule_work(&rdev->conn_work); 259 - } else if (status_code != WLAN_STATUS_SUCCESS) 267 + } else if (status_code != WLAN_STATUS_SUCCESS) { 260 268 wdev->sme_state = CFG80211_SME_IDLE; 261 - else if (wdev->sme_state == CFG80211_SME_CONNECTING && 269 + kfree(wdev->conn); 270 + wdev->conn = NULL; 271 + } else if (wdev->sme_state == CFG80211_SME_CONNECTING && 262 272 wdev->conn->state == CFG80211_CONN_AUTHENTICATING) { 263 273 wdev->conn->state = CFG80211_CONN_ASSOCIATE_NEXT; 264 274 schedule_work(&rdev->conn_work); ··· 324 330 325 331 if (wdev->current_bss) { 326 332 cfg80211_unhold_bss(wdev->current_bss); 327 - cfg80211_put_bss(wdev->current_bss); 333 + cfg80211_put_bss(&wdev->current_bss->pub); 328 334 wdev->current_bss = NULL; 329 335 } 336 + 337 + if (wdev->conn) 338 + wdev->conn->state = CFG80211_CONN_IDLE; 330 339 331 340 if (status == WLAN_STATUS_SUCCESS) { 332 341 bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, ··· 340 343 if (WARN_ON(!bss)) 341 344 return; 342 345 343 - cfg80211_hold_bss(bss); 344 - wdev->current_bss = bss; 346 + cfg80211_hold_bss(bss_from_pub(bss)); 347 + wdev->current_bss = bss_from_pub(bss); 345 348 346 349 wdev->sme_state = CFG80211_SME_CONNECTED; 347 350 } else { 348 351 wdev->sme_state = CFG80211_SME_IDLE; 352 + kfree(wdev->conn); 353 + wdev->conn = NULL; 349 354 } 350 - 351 - if (wdev->conn) 352 - wdev->conn->state = CFG80211_CONN_IDLE; 353 355 } 354 356 355 357 void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, ··· 383 387 } 384 388 385 389 cfg80211_unhold_bss(wdev->current_bss); 386 - cfg80211_put_bss(wdev->current_bss); 390 + cfg80211_put_bss(&wdev->current_bss->pub); 387 391 wdev->current_bss = NULL; 388 392 389 393 bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid, ··· 393 397 if (WARN_ON(!bss)) 394 398 return; 395 399 396 - cfg80211_hold_bss(bss); 397 - wdev->current_bss = bss; 400 + cfg80211_hold_bss(bss_from_pub(bss)); 401 + wdev->current_bss = bss_from_pub(bss); 398 402 399 403 nl80211_send_roamed(wiphy_to_dev(wdev->wiphy), dev, bssid, 400 404 req_ie, req_ie_len, resp_ie, resp_ie_len, gfp); ··· 436 440 437 441 if (wdev->current_bss) { 438 442 cfg80211_unhold_bss(wdev->current_bss); 439 - cfg80211_put_bss(wdev->current_bss); 443 + cfg80211_put_bss(&wdev->current_bss->pub); 440 444 } 441 445 442 446 wdev->current_bss = NULL; ··· 445 449 if (wdev->conn) { 446 450 kfree(wdev->conn->ie); 447 451 wdev->conn->ie = NULL; 452 + kfree(wdev->conn); 453 + wdev->conn = NULL; 448 454 } 449 455 450 456 nl80211_send_disconnected(wiphy_to_dev(wdev->wiphy), dev, ··· 480 482 if (!rdev->ops->auth || !rdev->ops->assoc) 481 483 return -EOPNOTSUPP; 482 484 483 - if (!wdev->conn) { 484 - wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL); 485 - if (!wdev->conn) 486 - return -ENOMEM; 487 - } else 488 - memset(wdev->conn, 0, sizeof(*wdev->conn)); 485 + if (WARN_ON(wdev->conn)) 486 + return -EINPROGRESS; 487 + 488 + wdev->conn = kzalloc(sizeof(*wdev->conn), GFP_KERNEL); 489 + if (!wdev->conn) 490 + return -ENOMEM; 489 491 490 492 /* 491 493 * Copy all parameters, and treat explicitly IEs, BSSID, SSID. ··· 500 502 wdev->conn->ie = kmemdup(connect->ie, connect->ie_len, 501 503 GFP_KERNEL); 502 504 wdev->conn->params.ie = wdev->conn->ie; 503 - if (!wdev->conn->ie) 505 + if (!wdev->conn->ie) { 506 + kfree(wdev->conn); 507 + wdev->conn = NULL; 504 508 return -ENOMEM; 509 + } 505 510 } 506 511 507 512 if (connect->auth_type == NL80211_AUTHTYPE_AUTOMATIC) { ··· 544 543 wdev->conn->state = CFG80211_CONN_SCAN_AGAIN; 545 544 } 546 545 } 547 - if (err) 546 + if (err) { 547 + kfree(wdev->conn); 548 + wdev->conn = NULL; 548 549 wdev->sme_state = CFG80211_SME_IDLE; 550 + } 549 551 550 552 return err; 551 553 } else { ··· 576 572 return -EINVAL; 577 573 578 574 if (!rdev->ops->disconnect) { 579 - struct cfg80211_deauth_request deauth; 580 - u8 bssid[ETH_ALEN]; 575 + if (!rdev->ops->deauth) 576 + return -EOPNOTSUPP; 581 577 582 - /* internal bug. */ 583 - if (WARN_ON(!wdev->conn)) 584 - return -EINVAL; 578 + /* was it connected by userspace SME? */ 579 + if (!wdev->conn) { 580 + cfg80211_mlme_down(rdev, dev); 581 + return 0; 582 + } 585 583 586 584 if (wdev->sme_state == CFG80211_SME_CONNECTING && 587 585 (wdev->conn->state == CFG80211_CONN_SCANNING || 588 586 wdev->conn->state == CFG80211_CONN_SCAN_AGAIN)) { 589 587 wdev->sme_state = CFG80211_SME_IDLE; 588 + kfree(wdev->conn); 589 + wdev->conn = NULL; 590 590 return 0; 591 591 } 592 592 593 - if (!rdev->ops->deauth) 594 - return -EOPNOTSUPP; 595 - 596 - memset(&deauth, 0, sizeof(deauth)); 597 - 598 593 /* wdev->conn->params.bssid must be set if > SCANNING */ 599 - memcpy(bssid, wdev->conn->params.bssid, ETH_ALEN); 600 - deauth.peer_addr = bssid; 601 - deauth.reason_code = reason; 602 - 603 - err = rdev->ops->deauth(&rdev->wiphy, dev, &deauth); 594 + err = cfg80211_mlme_deauth(rdev, dev, wdev->conn->params.bssid, 595 + NULL, 0, reason); 604 596 if (err) 605 597 return err; 606 598 } else { ··· 613 613 wextev, GFP_KERNEL); 614 614 615 615 return 0; 616 + } 617 + 618 + void cfg80211_sme_disassoc(struct net_device *dev, int idx) 619 + { 620 + struct wireless_dev *wdev = dev->ieee80211_ptr; 621 + struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); 622 + u8 bssid[ETH_ALEN]; 623 + 624 + if (!wdev->conn) 625 + return; 626 + 627 + if (wdev->conn->state == CFG80211_CONN_IDLE) 628 + return; 629 + 630 + /* 631 + * Ok, so the association was made by this SME -- we don't 632 + * want it any more so deauthenticate too. 633 + */ 634 + 635 + if (!wdev->auth_bsses[idx]) 636 + return; 637 + 638 + memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN); 639 + if (cfg80211_mlme_deauth(rdev, dev, bssid, 640 + NULL, 0, WLAN_REASON_DEAUTH_LEAVING)) { 641 + /* whatever -- assume gone anyway */ 642 + cfg80211_unhold_bss(wdev->auth_bsses[idx]); 643 + cfg80211_put_bss(&wdev->auth_bsses[idx]->pub); 644 + wdev->auth_bsses[idx] = NULL; 645 + } 616 646 }
+2 -2
net/wireless/wext-sme.c
··· 93 93 return -EINVAL; 94 94 95 95 if (wdev->current_bss) 96 - chan = wdev->current_bss->channel; 96 + chan = wdev->current_bss->pub.channel; 97 97 else if (wdev->wext.connect.channel) 98 98 chan = wdev->wext.connect.channel; 99 99 ··· 244 244 ap_addr->sa_family = ARPHRD_ETHER; 245 245 246 246 if (wdev->current_bss) 247 - memcpy(ap_addr->sa_data, wdev->current_bss->bssid, ETH_ALEN); 247 + memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN); 248 248 else if (wdev->wext.connect.bssid) 249 249 memcpy(ap_addr->sa_data, wdev->wext.connect.bssid, ETH_ALEN); 250 250 else