aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless
diff options
context:
space:
mode:
Diffstat (limited to 'net/wireless')
-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
8 files changed, 557 insertions, 193 deletions
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