diff options
author | Johannes Berg <johannes@sipsolutions.net> | 2009-07-02 11:20:43 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-07-10 15:01:53 -0400 |
commit | 19957bb399e2722719c0e20c9ae91cf8b6aaff04 (patch) | |
tree | 9c4d53fe5938ceee41333a1afd5be0ed5c1ce313 /net/wireless | |
parent | 517357c685ccc4b5783cc7dbdae8824ada19a97f (diff) |
cfg80211: keep track of BSSes
In order to avoid problems with BSS structs going away
while they're in use, I've long wanted to make cfg80211
keep track of them. Without the SME, that wasn't doable
but now that we have the SME we can do this too. It can
keep track of up to four separate authentications and
one association, regardless of whether it's controlled
by the cfg80211 SME or the userspace SME.
Signed-off-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless')
-rw-r--r-- | net/wireless/core.c | 5 | ||||
-rw-r--r-- | net/wireless/core.h | 41 | ||||
-rw-r--r-- | net/wireless/ibss.c | 12 | ||||
-rw-r--r-- | net/wireless/mlme.c | 357 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 144 | ||||
-rw-r--r-- | net/wireless/scan.c | 31 | ||||
-rw-r--r-- | net/wireless/sme.c | 156 | ||||
-rw-r--r-- | net/wireless/wext-sme.c | 4 |
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 | ||
120 | static inline struct cfg80211_internal_bss *bss_from_pub(struct cfg80211_bss *pub) | ||
121 | { | ||
122 | return container_of(pub, struct cfg80211_internal_bss, pub); | ||
123 | } | ||
124 | |||
125 | static inline void cfg80211_hold_bss(struct cfg80211_internal_bss *bss) | ||
126 | { | ||
127 | atomic_inc(&bss->hold); | ||
128 | } | ||
129 | |||
130 | static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss) | ||
131 | { | ||
132 | int r = atomic_dec_return(&bss->hold); | ||
133 | WARN_ON(r < 0); | ||
134 | } | ||
135 | |||
136 | |||
119 | struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx); | 137 | struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx); |
120 | int get_wiphy_idx(struct wiphy *wiphy); | 138 | int get_wiphy_idx(struct wiphy *wiphy); |
121 | 139 | ||
@@ -176,6 +194,26 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext); | |||
176 | int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, | 194 | int 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 */ | ||
198 | int 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); | ||
203 | int 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); | ||
208 | int 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); | ||
211 | int 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); | ||
214 | void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | ||
215 | struct net_device *dev); | ||
216 | |||
179 | /* SME */ | 217 | /* SME */ |
180 | int cfg80211_connect(struct cfg80211_registered_device *rdev, | 218 | int 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); |
194 | void cfg80211_sme_scan_done(struct net_device *dev); | 232 | void cfg80211_sme_scan_done(struct net_device *dev); |
195 | void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); | 233 | void cfg80211_sme_rx_auth(struct net_device *dev, const u8 *buf, size_t len); |
234 | void 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 | ||
15 | void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) | 15 | void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) |
16 | { | 16 | { |
17 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | 17 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
18 | struct wiphy *wiphy = wdev->wiphy; | ||
18 | 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 | } |
42 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); | 81 | EXPORT_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 | } |
93 | EXPORT_SYMBOL(cfg80211_send_disassoc); | 183 | EXPORT_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 | } |
106 | EXPORT_SYMBOL(cfg80211_send_auth_timeout); | 212 | EXPORT_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 | } |
119 | EXPORT_SYMBOL(cfg80211_send_assoc_timeout); | 241 | EXPORT_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 | } |
145 | EXPORT_SYMBOL(cfg80211_michael_mic_failure); | 267 | EXPORT_SYMBOL(cfg80211_michael_mic_failure); |
268 | |||
269 | /* some MLME handling for userspace SME */ | ||
270 | int 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 | |||
328 | int 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 | |||
374 | int 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 | |||
408 | int 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 | |||
427 | void 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 | ||
3114 | out: | 3113 | out: |
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 | ||
3184 | static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | 3183 | static 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 | ||
3258 | out: | 3256 | out: |
3259 | cfg80211_put_dev(drv); | 3257 | cfg80211_put_dev(rdev); |
3260 | dev_put(dev); | 3258 | dev_put(dev); |
3261 | unlock_rtnl: | 3259 | unlock_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 | ||
3323 | out: | 3318 | out: |
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 | ||
3388 | out: | 3380 | out: |
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 | } |
554 | EXPORT_SYMBOL(cfg80211_unlink_bss); | 557 | EXPORT_SYMBOL(cfg80211_unlink_bss); |
555 | 558 | ||
556 | void 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 | } | ||
566 | EXPORT_SYMBOL(cfg80211_hold_bss); | ||
567 | |||
568 | void 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 | } | ||
578 | EXPORT_SYMBOL(cfg80211_unhold_bss); | ||
579 | |||
580 | #ifdef CONFIG_WIRELESS_EXT | 559 | #ifdef CONFIG_WIRELESS_EXT |
581 | int cfg80211_wext_siwscan(struct net_device *dev, | 560 | int 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) | |||
103 | static int cfg80211_conn_do_work(struct wireless_dev *wdev) | 103 | static 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, ¶ms->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 | ||
358 | void cfg80211_connect_result(struct net_device *dev, const u8 *bssid, | 354 | void 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 | |||
618 | void cfg80211_sme_disassoc(struct net_device *dev, int idx) | ||
619 | { | ||
620 | struct wireless_dev *wdev = dev->ieee80211_ptr; | ||
621 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); | ||
622 | u8 bssid[ETH_ALEN]; | ||
623 | |||
624 | if (!wdev->conn) | ||
625 | return; | ||
626 | |||
627 | if (wdev->conn->state == CFG80211_CONN_IDLE) | ||
628 | return; | ||
629 | |||
630 | /* | ||
631 | * Ok, so the association was made by this SME -- we don't | ||
632 | * want it any more so deauthenticate too. | ||
633 | */ | ||
634 | |||
635 | if (!wdev->auth_bsses[idx]) | ||
636 | return; | ||
637 | |||
638 | memcpy(bssid, wdev->auth_bsses[idx]->pub.bssid, ETH_ALEN); | ||
639 | if (cfg80211_mlme_deauth(rdev, dev, bssid, | ||
640 | NULL, 0, WLAN_REASON_DEAUTH_LEAVING)) { | ||
641 | /* whatever -- assume gone anyway */ | ||
642 | cfg80211_unhold_bss(wdev->auth_bsses[idx]); | ||
643 | cfg80211_put_bss(&wdev->auth_bsses[idx]->pub); | ||
644 | wdev->auth_bsses[idx] = NULL; | ||
645 | } | ||
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 |