mlme.c 17 KB

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