mlme.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. /*
  2. * cfg80211 MLME SAP interface
  3. *
  4. * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
  5. */
  6. #include <linux/kernel.h>
  7. #include <linux/module.h>
  8. #include <linux/netdevice.h>
  9. #include <linux/nl80211.h>
  10. #include <linux/wireless.h>
  11. #include <net/cfg80211.h>
  12. #include <net/iw_handler.h>
  13. #include "core.h"
  14. #include "nl80211.h"
  15. void cfg80211_send_rx_auth(struct net_device *dev, const u8 *buf, size_t len)
  16. {
  17. struct wireless_dev *wdev = dev->ieee80211_ptr;
  18. struct wiphy *wiphy = wdev->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. wdev_lock(wdev);
  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. WARN_ON(!done);
  42. nl80211_send_rx_auth(rdev, dev, buf, len, GFP_KERNEL);
  43. cfg80211_sme_rx_auth(dev, buf, len);
  44. wdev_unlock(wdev);
  45. }
  46. EXPORT_SYMBOL(cfg80211_send_rx_auth);
  47. void cfg80211_send_rx_assoc(struct net_device *dev, const u8 *buf, size_t len)
  48. {
  49. u16 status_code;
  50. struct wireless_dev *wdev = dev->ieee80211_ptr;
  51. struct wiphy *wiphy = wdev->wiphy;
  52. struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
  53. struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
  54. u8 *ie = mgmt->u.assoc_resp.variable;
  55. int i, ieoffs = offsetof(struct ieee80211_mgmt, u.assoc_resp.variable);
  56. struct cfg80211_internal_bss *bss = NULL;
  57. bool need_connect_result = true;
  58. wdev_lock(wdev);
  59. status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
  60. /*
  61. * This is a bit of a hack, we don't notify userspace of
  62. * a (re-)association reply if we tried to send a reassoc
  63. * and got a reject -- we only try again with an assoc
  64. * frame instead of reassoc.
  65. */
  66. if (status_code != WLAN_STATUS_SUCCESS && wdev->conn &&
  67. cfg80211_sme_failed_reassoc(wdev))
  68. goto out;
  69. nl80211_send_rx_assoc(rdev, dev, buf, len, GFP_KERNEL);
  70. if (status_code == WLAN_STATUS_SUCCESS) {
  71. for (i = 0; i < MAX_AUTH_BSSES; i++) {
  72. if (!wdev->auth_bsses[i])
  73. continue;
  74. if (memcmp(wdev->auth_bsses[i]->pub.bssid, mgmt->bssid,
  75. ETH_ALEN) == 0) {
  76. bss = wdev->auth_bsses[i];
  77. wdev->auth_bsses[i] = NULL;
  78. /* additional reference to drop hold */
  79. cfg80211_ref_bss(bss);
  80. break;
  81. }
  82. }
  83. WARN_ON(!bss);
  84. } else if (wdev->conn) {
  85. cfg80211_sme_failed_assoc(wdev);
  86. need_connect_result = false;
  87. /*
  88. * do not call connect_result() now because the
  89. * sme will schedule work that does it later.
  90. */
  91. goto out;
  92. }
  93. if (!wdev->conn && wdev->sme_state == CFG80211_SME_IDLE) {
  94. /*
  95. * This is for the userspace SME, the CONNECTING
  96. * state will be changed to CONNECTED by
  97. * __cfg80211_connect_result() below.
  98. */
  99. wdev->sme_state = CFG80211_SME_CONNECTING;
  100. }
  101. /* this consumes one bss reference (unless bss is NULL) */
  102. __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, ie, len - ieoffs,
  103. status_code,
  104. status_code == WLAN_STATUS_SUCCESS,
  105. bss ? &bss->pub : NULL);
  106. /* drop hold now, and also reference acquired above */
  107. if (bss) {
  108. cfg80211_unhold_bss(bss);
  109. cfg80211_put_bss(&bss->pub);
  110. }
  111. out:
  112. wdev_unlock(wdev);
  113. }
  114. EXPORT_SYMBOL(cfg80211_send_rx_assoc);
  115. void __cfg80211_send_deauth(struct net_device *dev,
  116. const u8 *buf, size_t len)
  117. {
  118. struct wireless_dev *wdev = dev->ieee80211_ptr;
  119. struct wiphy *wiphy = wdev->wiphy;
  120. struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
  121. struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
  122. const u8 *bssid = mgmt->bssid;
  123. int i;
  124. ASSERT_WDEV_LOCK(wdev);
  125. nl80211_send_deauth(rdev, dev, buf, len, GFP_KERNEL);
  126. if (wdev->current_bss &&
  127. memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
  128. cfg80211_unhold_bss(wdev->current_bss);
  129. cfg80211_put_bss(&wdev->current_bss->pub);
  130. wdev->current_bss = NULL;
  131. } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
  132. if (wdev->auth_bsses[i] &&
  133. memcmp(wdev->auth_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
  134. cfg80211_unhold_bss(wdev->auth_bsses[i]);
  135. cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
  136. wdev->auth_bsses[i] = NULL;
  137. break;
  138. }
  139. if (wdev->authtry_bsses[i] &&
  140. memcmp(wdev->authtry_bsses[i]->pub.bssid, bssid, ETH_ALEN) == 0) {
  141. cfg80211_unhold_bss(wdev->authtry_bsses[i]);
  142. cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
  143. wdev->authtry_bsses[i] = NULL;
  144. break;
  145. }
  146. }
  147. if (wdev->sme_state == CFG80211_SME_CONNECTED) {
  148. u16 reason_code;
  149. bool from_ap;
  150. reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
  151. from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0;
  152. __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
  153. } else if (wdev->sme_state == CFG80211_SME_CONNECTING) {
  154. __cfg80211_connect_result(dev, mgmt->bssid, NULL, 0, NULL, 0,
  155. WLAN_STATUS_UNSPECIFIED_FAILURE,
  156. false, NULL);
  157. }
  158. }
  159. EXPORT_SYMBOL(__cfg80211_send_deauth);
  160. void cfg80211_send_deauth(struct net_device *dev, const u8 *buf, size_t len)
  161. {
  162. struct wireless_dev *wdev = dev->ieee80211_ptr;
  163. wdev_lock(wdev);
  164. __cfg80211_send_deauth(dev, buf, len);
  165. wdev_unlock(wdev);
  166. }
  167. EXPORT_SYMBOL(cfg80211_send_deauth);
  168. void __cfg80211_send_disassoc(struct net_device *dev,
  169. const u8 *buf, size_t len)
  170. {
  171. struct wireless_dev *wdev = dev->ieee80211_ptr;
  172. struct wiphy *wiphy = wdev->wiphy;
  173. struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
  174. struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf;
  175. const u8 *bssid = mgmt->bssid;
  176. int i;
  177. u16 reason_code;
  178. bool from_ap;
  179. bool done = false;
  180. ASSERT_WDEV_LOCK(wdev);
  181. nl80211_send_disassoc(rdev, dev, buf, len, GFP_KERNEL);
  182. if (wdev->sme_state != CFG80211_SME_CONNECTED)
  183. return;
  184. if (wdev->current_bss &&
  185. memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
  186. for (i = 0; i < MAX_AUTH_BSSES; i++) {
  187. if (wdev->authtry_bsses[i] || wdev->auth_bsses[i])
  188. continue;
  189. wdev->auth_bsses[i] = wdev->current_bss;
  190. wdev->current_bss = NULL;
  191. done = true;
  192. cfg80211_sme_disassoc(dev, i);
  193. break;
  194. }
  195. WARN_ON(!done);
  196. } else
  197. WARN_ON(1);
  198. reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
  199. from_ap = memcmp(mgmt->sa, dev->dev_addr, ETH_ALEN) != 0;
  200. __cfg80211_disconnected(dev, NULL, 0, reason_code, from_ap);
  201. }
  202. EXPORT_SYMBOL(__cfg80211_send_disassoc);
  203. void cfg80211_send_disassoc(struct net_device *dev, const u8 *buf, size_t len)
  204. {
  205. struct wireless_dev *wdev = dev->ieee80211_ptr;
  206. wdev_lock(wdev);
  207. __cfg80211_send_disassoc(dev, buf, len);
  208. wdev_unlock(wdev);
  209. }
  210. EXPORT_SYMBOL(cfg80211_send_disassoc);
  211. void cfg80211_send_auth_timeout(struct net_device *dev, const u8 *addr)
  212. {
  213. struct wireless_dev *wdev = dev->ieee80211_ptr;
  214. struct wiphy *wiphy = wdev->wiphy;
  215. struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
  216. int i;
  217. bool done = false;
  218. wdev_lock(wdev);
  219. nl80211_send_auth_timeout(rdev, dev, addr, GFP_KERNEL);
  220. if (wdev->sme_state == CFG80211_SME_CONNECTING)
  221. __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
  222. WLAN_STATUS_UNSPECIFIED_FAILURE,
  223. false, NULL);
  224. for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
  225. if (wdev->authtry_bsses[i] &&
  226. memcmp(wdev->authtry_bsses[i]->pub.bssid,
  227. addr, ETH_ALEN) == 0) {
  228. cfg80211_unhold_bss(wdev->authtry_bsses[i]);
  229. cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
  230. wdev->authtry_bsses[i] = NULL;
  231. done = true;
  232. break;
  233. }
  234. }
  235. WARN_ON(!done);
  236. wdev_unlock(wdev);
  237. }
  238. EXPORT_SYMBOL(cfg80211_send_auth_timeout);
  239. void cfg80211_send_assoc_timeout(struct net_device *dev, const u8 *addr)
  240. {
  241. struct wireless_dev *wdev = dev->ieee80211_ptr;
  242. struct wiphy *wiphy = wdev->wiphy;
  243. struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
  244. int i;
  245. bool done = false;
  246. wdev_lock(wdev);
  247. nl80211_send_assoc_timeout(rdev, dev, addr, GFP_KERNEL);
  248. if (wdev->sme_state == CFG80211_SME_CONNECTING)
  249. __cfg80211_connect_result(dev, addr, NULL, 0, NULL, 0,
  250. WLAN_STATUS_UNSPECIFIED_FAILURE,
  251. false, NULL);
  252. for (i = 0; addr && i < MAX_AUTH_BSSES; i++) {
  253. if (wdev->auth_bsses[i] &&
  254. memcmp(wdev->auth_bsses[i]->pub.bssid,
  255. addr, ETH_ALEN) == 0) {
  256. cfg80211_unhold_bss(wdev->auth_bsses[i]);
  257. cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
  258. wdev->auth_bsses[i] = NULL;
  259. done = true;
  260. break;
  261. }
  262. }
  263. WARN_ON(!done);
  264. wdev_unlock(wdev);
  265. }
  266. EXPORT_SYMBOL(cfg80211_send_assoc_timeout);
  267. void cfg80211_michael_mic_failure(struct net_device *dev, const u8 *addr,
  268. enum nl80211_key_type key_type, int key_id,
  269. const u8 *tsc, gfp_t gfp)
  270. {
  271. struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
  272. struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
  273. #ifdef CONFIG_CFG80211_WEXT
  274. union iwreq_data wrqu;
  275. char *buf = kmalloc(128, gfp);
  276. if (buf) {
  277. sprintf(buf, "MLME-MICHAELMICFAILURE.indication("
  278. "keyid=%d %scast addr=%pM)", key_id,
  279. key_type == NL80211_KEYTYPE_GROUP ? "broad" : "uni",
  280. addr);
  281. memset(&wrqu, 0, sizeof(wrqu));
  282. wrqu.data.length = strlen(buf);
  283. wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
  284. kfree(buf);
  285. }
  286. #endif
  287. nl80211_michael_mic_failure(rdev, dev, addr, key_type, key_id, tsc, gfp);
  288. }
  289. EXPORT_SYMBOL(cfg80211_michael_mic_failure);
  290. /* some MLME handling for userspace SME */
  291. int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
  292. struct net_device *dev,
  293. struct ieee80211_channel *chan,
  294. enum nl80211_auth_type auth_type,
  295. const u8 *bssid,
  296. const u8 *ssid, int ssid_len,
  297. const u8 *ie, int ie_len,
  298. const u8 *key, int key_len, int key_idx)
  299. {
  300. struct wireless_dev *wdev = dev->ieee80211_ptr;
  301. struct cfg80211_auth_request req;
  302. struct cfg80211_internal_bss *bss;
  303. int i, err, slot = -1, nfree = 0;
  304. ASSERT_WDEV_LOCK(wdev);
  305. if (auth_type == NL80211_AUTHTYPE_SHARED_KEY)
  306. if (!key || !key_len || key_idx < 0 || key_idx > 4)
  307. return -EINVAL;
  308. if (wdev->current_bss &&
  309. memcmp(bssid, wdev->current_bss->pub.bssid, ETH_ALEN) == 0)
  310. return -EALREADY;
  311. for (i = 0; i < MAX_AUTH_BSSES; i++) {
  312. if (wdev->authtry_bsses[i] &&
  313. memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid,
  314. ETH_ALEN) == 0)
  315. return -EALREADY;
  316. if (wdev->auth_bsses[i] &&
  317. memcmp(bssid, wdev->auth_bsses[i]->pub.bssid,
  318. ETH_ALEN) == 0)
  319. return -EALREADY;
  320. }
  321. memset(&req, 0, sizeof(req));
  322. req.ie = ie;
  323. req.ie_len = ie_len;
  324. req.auth_type = auth_type;
  325. req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
  326. WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
  327. req.key = key;
  328. req.key_len = key_len;
  329. req.key_idx = key_idx;
  330. if (!req.bss)
  331. return -ENOENT;
  332. bss = bss_from_pub(req.bss);
  333. for (i = 0; i < MAX_AUTH_BSSES; i++) {
  334. if (!wdev->auth_bsses[i] && !wdev->authtry_bsses[i]) {
  335. slot = i;
  336. nfree++;
  337. }
  338. }
  339. /* we need one free slot for disassoc and one for this auth */
  340. if (nfree < 2) {
  341. err = -ENOSPC;
  342. goto out;
  343. }
  344. wdev->authtry_bsses[slot] = bss;
  345. cfg80211_hold_bss(bss);
  346. err = rdev->ops->auth(&rdev->wiphy, dev, &req);
  347. if (err) {
  348. wdev->authtry_bsses[slot] = NULL;
  349. cfg80211_unhold_bss(bss);
  350. }
  351. out:
  352. if (err)
  353. cfg80211_put_bss(req.bss);
  354. return err;
  355. }
  356. int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev,
  357. struct net_device *dev, struct ieee80211_channel *chan,
  358. enum nl80211_auth_type auth_type, const u8 *bssid,
  359. const u8 *ssid, int ssid_len,
  360. const u8 *ie, int ie_len,
  361. const u8 *key, int key_len, int key_idx)
  362. {
  363. int err;
  364. wdev_lock(dev->ieee80211_ptr);
  365. err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid,
  366. ssid, ssid_len, ie, ie_len,
  367. key, key_len, key_idx);
  368. wdev_unlock(dev->ieee80211_ptr);
  369. return err;
  370. }
  371. int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
  372. struct net_device *dev,
  373. struct ieee80211_channel *chan,
  374. const u8 *bssid, const u8 *prev_bssid,
  375. const u8 *ssid, int ssid_len,
  376. const u8 *ie, int ie_len, bool use_mfp,
  377. struct cfg80211_crypto_settings *crypt)
  378. {
  379. struct wireless_dev *wdev = dev->ieee80211_ptr;
  380. struct cfg80211_assoc_request req;
  381. struct cfg80211_internal_bss *bss;
  382. int i, err, slot = -1;
  383. ASSERT_WDEV_LOCK(wdev);
  384. memset(&req, 0, sizeof(req));
  385. if (wdev->current_bss)
  386. return -EALREADY;
  387. req.ie = ie;
  388. req.ie_len = ie_len;
  389. memcpy(&req.crypto, crypt, sizeof(req.crypto));
  390. req.use_mfp = use_mfp;
  391. req.prev_bssid = prev_bssid;
  392. req.bss = cfg80211_get_bss(&rdev->wiphy, chan, bssid, ssid, ssid_len,
  393. WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
  394. if (!req.bss)
  395. return -ENOENT;
  396. bss = bss_from_pub(req.bss);
  397. for (i = 0; i < MAX_AUTH_BSSES; i++) {
  398. if (bss == wdev->auth_bsses[i]) {
  399. slot = i;
  400. break;
  401. }
  402. }
  403. if (slot < 0) {
  404. err = -ENOTCONN;
  405. goto out;
  406. }
  407. err = rdev->ops->assoc(&rdev->wiphy, dev, &req);
  408. out:
  409. /* still a reference in wdev->auth_bsses[slot] */
  410. cfg80211_put_bss(req.bss);
  411. return err;
  412. }
  413. int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev,
  414. struct net_device *dev,
  415. struct ieee80211_channel *chan,
  416. const u8 *bssid, const u8 *prev_bssid,
  417. const u8 *ssid, int ssid_len,
  418. const u8 *ie, int ie_len, bool use_mfp,
  419. struct cfg80211_crypto_settings *crypt)
  420. {
  421. struct wireless_dev *wdev = dev->ieee80211_ptr;
  422. int err;
  423. wdev_lock(wdev);
  424. err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid,
  425. ssid, ssid_len, ie, ie_len, use_mfp, crypt);
  426. wdev_unlock(wdev);
  427. return err;
  428. }
  429. int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
  430. struct net_device *dev, const u8 *bssid,
  431. const u8 *ie, int ie_len, u16 reason)
  432. {
  433. struct wireless_dev *wdev = dev->ieee80211_ptr;
  434. struct cfg80211_deauth_request req;
  435. int i;
  436. ASSERT_WDEV_LOCK(wdev);
  437. memset(&req, 0, sizeof(req));
  438. req.reason_code = reason;
  439. req.ie = ie;
  440. req.ie_len = ie_len;
  441. if (wdev->current_bss &&
  442. memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0) {
  443. req.bss = &wdev->current_bss->pub;
  444. } else for (i = 0; i < MAX_AUTH_BSSES; i++) {
  445. if (wdev->auth_bsses[i] &&
  446. memcmp(bssid, wdev->auth_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
  447. req.bss = &wdev->auth_bsses[i]->pub;
  448. break;
  449. }
  450. if (wdev->authtry_bsses[i] &&
  451. memcmp(bssid, wdev->authtry_bsses[i]->pub.bssid, ETH_ALEN) == 0) {
  452. req.bss = &wdev->authtry_bsses[i]->pub;
  453. break;
  454. }
  455. }
  456. if (!req.bss)
  457. return -ENOTCONN;
  458. return rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
  459. }
  460. int cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
  461. struct net_device *dev, const u8 *bssid,
  462. const u8 *ie, int ie_len, u16 reason)
  463. {
  464. struct wireless_dev *wdev = dev->ieee80211_ptr;
  465. int err;
  466. wdev_lock(wdev);
  467. err = __cfg80211_mlme_deauth(rdev, dev, bssid, ie, ie_len, reason);
  468. wdev_unlock(wdev);
  469. return err;
  470. }
  471. static int __cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
  472. struct net_device *dev, const u8 *bssid,
  473. const u8 *ie, int ie_len, u16 reason)
  474. {
  475. struct wireless_dev *wdev = dev->ieee80211_ptr;
  476. struct cfg80211_disassoc_request req;
  477. ASSERT_WDEV_LOCK(wdev);
  478. if (wdev->sme_state != CFG80211_SME_CONNECTED)
  479. return -ENOTCONN;
  480. if (WARN_ON(!wdev->current_bss))
  481. return -ENOTCONN;
  482. memset(&req, 0, sizeof(req));
  483. req.reason_code = reason;
  484. req.ie = ie;
  485. req.ie_len = ie_len;
  486. if (memcmp(wdev->current_bss->pub.bssid, bssid, ETH_ALEN) == 0)
  487. req.bss = &wdev->current_bss->pub;
  488. else
  489. return -ENOTCONN;
  490. return rdev->ops->disassoc(&rdev->wiphy, dev, &req, wdev);
  491. }
  492. int cfg80211_mlme_disassoc(struct cfg80211_registered_device *rdev,
  493. struct net_device *dev, const u8 *bssid,
  494. const u8 *ie, int ie_len, u16 reason)
  495. {
  496. struct wireless_dev *wdev = dev->ieee80211_ptr;
  497. int err;
  498. wdev_lock(wdev);
  499. err = __cfg80211_mlme_disassoc(rdev, dev, bssid, ie, ie_len, reason);
  500. wdev_unlock(wdev);
  501. return err;
  502. }
  503. void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
  504. struct net_device *dev)
  505. {
  506. struct wireless_dev *wdev = dev->ieee80211_ptr;
  507. struct cfg80211_deauth_request req;
  508. int i;
  509. ASSERT_WDEV_LOCK(wdev);
  510. if (!rdev->ops->deauth)
  511. return;
  512. memset(&req, 0, sizeof(req));
  513. req.reason_code = WLAN_REASON_DEAUTH_LEAVING;
  514. req.ie = NULL;
  515. req.ie_len = 0;
  516. if (wdev->current_bss) {
  517. req.bss = &wdev->current_bss->pub;
  518. rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
  519. if (wdev->current_bss) {
  520. cfg80211_unhold_bss(wdev->current_bss);
  521. cfg80211_put_bss(&wdev->current_bss->pub);
  522. wdev->current_bss = NULL;
  523. }
  524. }
  525. for (i = 0; i < MAX_AUTH_BSSES; i++) {
  526. if (wdev->auth_bsses[i]) {
  527. req.bss = &wdev->auth_bsses[i]->pub;
  528. rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
  529. if (wdev->auth_bsses[i]) {
  530. cfg80211_unhold_bss(wdev->auth_bsses[i]);
  531. cfg80211_put_bss(&wdev->auth_bsses[i]->pub);
  532. wdev->auth_bsses[i] = NULL;
  533. }
  534. }
  535. if (wdev->authtry_bsses[i]) {
  536. req.bss = &wdev->authtry_bsses[i]->pub;
  537. rdev->ops->deauth(&rdev->wiphy, dev, &req, wdev);
  538. if (wdev->authtry_bsses[i]) {
  539. cfg80211_unhold_bss(wdev->authtry_bsses[i]);
  540. cfg80211_put_bss(&wdev->authtry_bsses[i]->pub);
  541. wdev->authtry_bsses[i] = NULL;
  542. }
  543. }
  544. }
  545. }