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