]>
Commit | Line | Data |
---|---|---|
6039f6d2 JM |
1 | /* |
2 | * cfg80211 MLME SAP interface | |
3 | * | |
4 | * Copyright (c) 2009, Jouni Malinen <j@w1.fi> | |
5 | */ | |
6 | ||
7 | #include <linux/kernel.h> | |
8 | #include <linux/module.h> | |
9 | #include <linux/netdevice.h> | |
10 | #include <linux/nl80211.h> | |
11 | #include <net/cfg80211.h> | |
12 | #include "core.h" | |
13 | #include "nl80211.h" | |
14 | ||
e6d6e342 | 15 | void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) |
6039f6d2 | 16 | { |
19957bb3 JB |
17 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
18 | struct wiphy *wiphy = wdev->wiphy; | |
6039f6d2 | 19 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
19957bb3 JB |
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); | |
6829c878 | 43 | |
e6d6e342 | 44 | nl80211_send_rx_auth(rdev, dev, buf, len, gfp); |
6829c878 | 45 | cfg80211_sme_rx_auth(dev, buf, len); |
6039f6d2 JM |
46 | } |
47 | EXPORT_SYMBOL(cfg80211_send_rx_auth); | |
48 | ||
e6d6e342 | 49 | void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) |
6039f6d2 | 50 | { |
6829c878 JB |
51 | u16 status_code; |
52 | struct wireless_dev *wdev = dev->ieee80211_ptr; | |
53 | struct wiphy *wiphy = wdev->wiphy; | |
6039f6d2 | 54 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
6829c878 JB |
55 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
56 | u8 *ie = mgmt->u.assoc_resp.variable; | |
19957bb3 JB |
57 | int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable); |
58 | bool done; | |
6829c878 JB |
59 | |
60 | status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); | |
61 | ||
e6d6e342 | 62 | nl80211_send_rx_assoc(rdev, dev, buf, len, gfp); |
6829c878 JB |
63 | |
64 | cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs, | |
65 | status_code, gfp); | |
19957bb3 JB |
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 | } | |
6039f6d2 JM |
80 | } |
81 | EXPORT_SYMBOL(cfg80211_send_rx_assoc); | |
82 | ||
e6d6e342 | 83 | void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) |
6039f6d2 | 84 | { |
6829c878 JB |
85 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
86 | struct wiphy *wiphy = wdev->wiphy; | |
6039f6d2 | 87 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
6829c878 | 88 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
19957bb3 JB |
89 | const u8 *bssid = mgmt->bssid; |
90 | int i; | |
91 | bool done = false; | |
6829c878 | 92 | |
e6d6e342 | 93 | nl80211_send_deauth(rdev, dev, buf, len, gfp); |
6829c878 | 94 | |
19957bb3 JB |
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 | ||
6829c878 JB |
128 | if (wdev->sme_state == CFG80211_SME_CONNECTED) { |
129 | u16 reason_code; | |
130 | bool from_ap; | |
131 | ||
132 | reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); | |
133 | ||
134 | from_ap = memcmp(mgmt->da, dev->dev_addr, ETH_ALEN) == 0; | |
135 | __cfg80211_disconnected(dev, gfp, NULL, 0, | |
136 | reason_code, from_ap); | |
6829c878 JB |
137 | } else if (wdev->sme_state == CFG80211_SME_CONNECTING) { |
138 | cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0, | |
139 | WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); | |
140 | } | |
6039f6d2 | 141 | } |
53b46b84 | 142 | EXPORT_SYMBOL(cfg80211_send_deauth); |
6039f6d2 | 143 | |
e6d6e342 | 144 | void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len, gfp_t gfp) |
6039f6d2 | 145 | { |
6829c878 JB |
146 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
147 | struct wiphy *wiphy = wdev->wiphy; | |
6039f6d2 | 148 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
6829c878 | 149 | struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; |
19957bb3 JB |
150 | const u8 *bssid = mgmt->bssid; |
151 | int i; | |
152 | u16 reason_code; | |
153 | bool from_ap; | |
154 | bool done = false; | |
6829c878 | 155 | |
e6d6e342 | 156 | nl80211_send_disassoc(rdev, dev, buf, len, gfp); |
a3b8b056 | 157 | |
19957bb3 JB |
158 | if (!wdev->sme_state == CFG80211_SME_CONNECTED) |
159 | return; | |
6829c878 | 160 | |
19957bb3 JB |
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); | |
6829c878 | 175 | |
6829c878 | 176 | |
19957bb3 JB |
177 | reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); |
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); | |
1965c853 | 182 | } |
6829c878 | 183 | EXPORT_SYMBOL(cfg80211_send_disassoc); |
1965c853 | 184 | |
e6d6e342 | 185 | void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp) |
1965c853 | 186 | { |
6829c878 JB |
187 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
188 | struct wiphy *wiphy = wdev->wiphy; | |
1965c853 | 189 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
19957bb3 JB |
190 | int i; |
191 | bool done = false; | |
192 | ||
e6d6e342 | 193 | nl80211_send_auth_timeout(rdev, dev, addr, gfp); |
6829c878 JB |
194 | if (wdev->sme_state == CFG80211_SME_CONNECTING) |
195 | cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, | |
196 | WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); | |
19957bb3 JB |
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); | |
1965c853 JM |
211 | } |
212 | EXPORT_SYMBOL(cfg80211_send_auth_timeout); | |
213 | ||
e6d6e342 | 214 | void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr, gfp_t gfp) |
1965c853 | 215 | { |
6829c878 JB |
216 | struct wireless_dev *wdev = dev->ieee80211_ptr; |
217 | struct wiphy *wiphy = wdev->wiphy; | |
1965c853 | 218 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); |
19957bb3 JB |
219 | int i; |
220 | bool done = false; | |
221 | ||
e6d6e342 | 222 | nl80211_send_assoc_timeout(rdev, dev, addr, gfp); |
6829c878 JB |
223 | if (wdev->sme_state == CFG80211_SME_CONNECTING) |
224 | cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0, | |
225 | WLAN_STATUS_UNSPECIFIED_FAILURE, gfp); | |
19957bb3 JB |
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); | |
1965c853 JM |
240 | } |
241 | EXPORT_SYMBOL(cfg80211_send_assoc_timeout); | |
242 | ||
a3b8b056 JM |
243 | void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr, |
244 | enum nl80211_key_type key_type, int key_id, | |
e6d6e342 | 245 | const u8 *tsc, gfp_t gfp) |
a3b8b056 JM |
246 | { |
247 | struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; | |
248 | struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); | |
f58d4ed9 JB |
249 | #ifdef CONFIG_WIRELESS_EXT |
250 | union iwreq_data wrqu; | |
e6d6e342 | 251 | char *buf = kmalloc(128, gfp); |
f58d4ed9 JB |
252 | |
253 | if (buf) { | |
254 | sprintf(buf, "MLME-MICHAELMICFAILURE.indication(" | |
255 | "keyid=%d %scast addr=%pM)", key_id, | |
256 | key_type == NL80211_KEYTYPE_GROUP ? "broad" : "uni", | |
257 | addr); | |
258 | memset(&wrqu, 0, sizeof(wrqu)); | |
259 | wrqu.data.length = strlen(buf); | |
260 | wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); | |
261 | kfree(buf); | |
262 | } | |
263 | #endif | |
264 | ||
e6d6e342 | 265 | nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp); |
a3b8b056 JM |
266 | } |
267 | EXPORT_SYMBOL(cfg80211_michael_mic_failure); | |
19957bb3 JB |
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 | ||
0a9b5e17 JB |
281 | if (wdev->current_bss && |
282 | memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0) | |
283 | return -EALREADY; | |
284 | ||
285 | for (i = 0; i < MAX_AUTH_BSSES; i++) { | |
286 | if (wdev->authtry_bsses[i] && | |
287 | memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, | |
288 | ETH_ALEN) == 0) | |
289 | return -EALREADY; | |
290 | if (wdev->auth_bsses[i] && | |
291 | memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, | |
292 | ETH_ALEN) == 0) | |
293 | return -EALREADY; | |
294 | } | |
295 | ||
19957bb3 JB |
296 | memset(&req, 0, sizeof(req)); |
297 | ||
298 | req.ie = ie; | |
299 | req.ie_len = ie_len; | |
300 | req.auth_type = auth_type; | |
301 | req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, | |
302 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); | |
303 | if (!req.bss) | |
304 | return -ENOENT; | |
305 | ||
306 | bss = bss_from_pub(req.bss); | |
307 | ||
19957bb3 JB |
308 | for (i = 0; i < MAX_AUTH_BSSES; i++) { |
309 | if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) { | |
310 | slot = i; | |
311 | nfree++; | |
312 | } | |
313 | } | |
314 | ||
315 | /* we need one free slot for disassoc and one for this auth */ | |
316 | if (nfree < 2) { | |
317 | err = -ENOSPC; | |
318 | goto out; | |
319 | } | |
320 | ||
321 | wdev->authtry_bsses[slot] = bss; | |
322 | cfg80211_hold_bss(bss); | |
323 | ||
324 | err = rdev->ops->auth(&rdev->wiphy, dev, &req); | |
325 | if (err) { | |
326 | wdev->authtry_bsses[slot] = NULL; | |
327 | cfg80211_unhold_bss(bss); | |
328 | } | |
329 | ||
330 | out: | |
331 | if (err) | |
332 | cfg80211_put_bss(req.bss); | |
333 | return err; | |
334 | } | |
335 | ||
336 | int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, | |
337 | struct net_device *dev, struct ieee80211_channel *chan, | |
3e5d7649 JB |
338 | const u8 *bssid, const u8 *prev_bssid, |
339 | const u8 *ssid, int ssid_len, | |
19957bb3 JB |
340 | const u8 *ie, int ie_len, bool use_mfp, |
341 | struct cfg80211_crypto_settings *crypt) | |
342 | { | |
343 | struct wireless_dev *wdev = dev->ieee80211_ptr; | |
344 | struct cfg80211_assoc_request req; | |
345 | struct cfg80211_internal_bss *bss; | |
346 | int i, err, slot = -1; | |
347 | ||
348 | memset(&req, 0, sizeof(req)); | |
349 | ||
350 | if (wdev->current_bss) | |
351 | return -EALREADY; | |
352 | ||
353 | req.ie = ie; | |
354 | req.ie_len = ie_len; | |
355 | memcpy(&req.crypto, crypt, sizeof(req.crypto)); | |
356 | req.use_mfp = use_mfp; | |
3e5d7649 | 357 | req.prev_bssid = prev_bssid; |
19957bb3 JB |
358 | req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len, |
359 | WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); | |
360 | if (!req.bss) | |
361 | return -ENOENT; | |
362 | ||
363 | bss = bss_from_pub(req.bss); | |
364 | ||
365 | for (i = 0; i < MAX_AUTH_BSSES; i++) { | |
366 | if (bss == wdev->auth_bsses[i]) { | |
367 | slot = i; | |
368 | break; | |
369 | } | |
370 | } | |
371 | ||
372 | if (slot < 0) { | |
373 | err = -ENOTCONN; | |
374 | goto out; | |
375 | } | |
376 | ||
377 | err = rdev->ops->assoc(&rdev->wiphy, dev, &req); | |
378 | out: | |
379 | /* still a reference in wdev->auth_bsses[slot] */ | |
380 | cfg80211_put_bss(req.bss); | |
381 | return err; | |
382 | } | |
383 | ||
384 | int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev, | |
385 | struct net_device *dev, const u8 *bssid, | |
386 | const u8 *ie, int ie_len, u16 reason) | |
387 | { | |
388 | struct wireless_dev *wdev = dev->ieee80211_ptr; | |
389 | struct cfg80211_deauth_request req; | |
390 | int i; | |
391 | ||
392 | memset(&req, 0, sizeof(req)); | |
393 | req.reason_code = reason; | |
394 | req.ie = ie; | |
395 | req.ie_len = ie_len; | |
396 | if (wdev->current_bss && | |
397 | memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) { | |
398 | req.bss = &wdev->current_bss->pub; | |
399 | } else for (i = 0; i < MAX_AUTH_BSSES; i++) { | |
400 | if (wdev->auth_bsses[i] && | |
401 | memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, ETH_ALEN) == 0) { | |
402 | req.bss = &wdev->auth_bsses[i]->pub; | |
403 | break; | |
404 | } | |
405 | if (wdev->authtry_bsses[i] && | |
406 | memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, ETH_ALEN) == 0) { | |
407 | req.bss = &wdev->authtry_bsses[i]->pub; | |
408 | break; | |
409 | } | |
410 | } | |
411 | ||
412 | if (!req.bss) | |
413 | return -ENOTCONN; | |
414 | ||
415 | return rdev->ops->deauth(&rdev->wiphy, dev, &req); | |
416 | } | |
417 | ||
418 | int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev, | |
419 | struct net_device *dev, const u8 *bssid, | |
420 | const u8 *ie, int ie_len, u16 reason) | |
421 | { | |
422 | struct wireless_dev *wdev = dev->ieee80211_ptr; | |
423 | struct cfg80211_disassoc_request req; | |
424 | ||
425 | memset(&req, 0, sizeof(req)); | |
426 | req.reason_code = reason; | |
427 | req.ie = ie; | |
428 | req.ie_len = ie_len; | |
429 | if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) | |
430 | req.bss = &wdev->current_bss->pub; | |
431 | else | |
432 | return -ENOTCONN; | |
433 | ||
434 | return rdev->ops->disassoc(&rdev->wiphy, dev, &req); | |
435 | } | |
436 | ||
437 | void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, | |
438 | struct net_device *dev) | |
439 | { | |
440 | struct wireless_dev *wdev = dev->ieee80211_ptr; | |
441 | struct cfg80211_deauth_request req; | |
442 | int i; | |
443 | ||
444 | if (!rdev->ops->deauth) | |
445 | return; | |
446 | ||
447 | memset(&req, 0, sizeof(req)); | |
448 | req.reason_code = WLAN_REASON_DEAUTH_LEAVING; | |
449 | req.ie = NULL; | |
450 | req.ie_len = 0; | |
451 | ||
452 | if (wdev->current_bss) { | |
453 | req.bss = &wdev->current_bss->pub; | |
454 | rdev->ops->deauth(&rdev->wiphy, dev, &req); | |
455 | if (wdev->current_bss) { | |
456 | cfg80211_unhold_bss(wdev->current_bss); | |
457 | cfg80211_put_bss(&wdev->current_bss->pub); | |
458 | wdev->current_bss = NULL; | |
459 | } | |
460 | } | |
461 | ||
462 | for (i = 0; i < MAX_AUTH_BSSES; i++) { | |
463 | if (wdev->auth_bsses[i]) { | |
464 | req.bss = &wdev->auth_bsses[i]->pub; | |
465 | rdev->ops->deauth(&rdev->wiphy, dev, &req); | |
466 | if (wdev->auth_bsses[i]) { | |
467 | cfg80211_unhold_bss(wdev->auth_bsses[i]); | |
468 | cfg80211_put_bss(&wdev->auth_bsses[i]->pub); | |
469 | wdev->auth_bsses[i] = NULL; | |
470 | } | |
471 | } | |
472 | if (wdev->authtry_bsses[i]) { | |
473 | req.bss = &wdev->authtry_bsses[i]->pub; | |
474 | rdev->ops->deauth(&rdev->wiphy, dev, &req); | |
475 | if (wdev->authtry_bsses[i]) { | |
476 | cfg80211_unhold_bss(wdev->authtry_bsses[i]); | |
477 | cfg80211_put_bss(&wdev->authtry_bsses[i]->pub); | |
478 | wdev->authtry_bsses[i] = NULL; | |
479 | } | |
480 | } | |
481 | } | |
482 | } |