p2p.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. /*
  2. * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
  3. * Copyright (c) 2018, The Linux Foundation. All rights reserved.
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include "wil6210.h"
  18. #include "wmi.h"
  19. #define P2P_WILDCARD_SSID "DIRECT-"
  20. #define P2P_DMG_SOCIAL_CHANNEL 2
  21. #define P2P_SEARCH_DURATION_MS 500
  22. #define P2P_DEFAULT_BI 100
  23. static int wil_p2p_start_listen(struct wil6210_vif *vif)
  24. {
  25. struct wil6210_priv *wil = vif_to_wil(vif);
  26. struct wil_p2p_info *p2p = &vif->p2p;
  27. u8 channel = p2p->listen_chan.hw_value;
  28. int rc;
  29. lockdep_assert_held(&wil->mutex);
  30. rc = wmi_p2p_cfg(vif, channel, P2P_DEFAULT_BI);
  31. if (rc) {
  32. wil_err(wil, "wmi_p2p_cfg failed\n");
  33. goto out;
  34. }
  35. rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
  36. if (rc) {
  37. wil_err(wil, "wmi_set_ssid failed\n");
  38. goto out_stop;
  39. }
  40. rc = wmi_start_listen(vif);
  41. if (rc) {
  42. wil_err(wil, "wmi_start_listen failed\n");
  43. goto out_stop;
  44. }
  45. INIT_WORK(&p2p->discovery_expired_work, wil_p2p_listen_expired);
  46. mod_timer(&p2p->discovery_timer,
  47. jiffies + msecs_to_jiffies(p2p->listen_duration));
  48. out_stop:
  49. if (rc)
  50. wmi_stop_discovery(vif);
  51. out:
  52. return rc;
  53. }
  54. bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request)
  55. {
  56. return (request->n_channels == 1) &&
  57. (request->channels[0]->hw_value == P2P_DMG_SOCIAL_CHANNEL);
  58. }
  59. int wil_p2p_search(struct wil6210_vif *vif,
  60. struct cfg80211_scan_request *request)
  61. {
  62. struct wil6210_priv *wil = vif_to_wil(vif);
  63. int rc;
  64. struct wil_p2p_info *p2p = &vif->p2p;
  65. wil_dbg_misc(wil, "p2p_search: channel %d\n", P2P_DMG_SOCIAL_CHANNEL);
  66. lockdep_assert_held(&wil->mutex);
  67. if (p2p->discovery_started) {
  68. wil_err(wil, "search failed. discovery already ongoing\n");
  69. rc = -EBUSY;
  70. goto out;
  71. }
  72. rc = wmi_p2p_cfg(vif, P2P_DMG_SOCIAL_CHANNEL, P2P_DEFAULT_BI);
  73. if (rc) {
  74. wil_err(wil, "wmi_p2p_cfg failed\n");
  75. goto out;
  76. }
  77. rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
  78. if (rc) {
  79. wil_err(wil, "wmi_set_ssid failed\n");
  80. goto out_stop;
  81. }
  82. /* Set application IE to probe request and probe response */
  83. rc = wmi_set_ie(vif, WMI_FRAME_PROBE_REQ,
  84. request->ie_len, request->ie);
  85. if (rc) {
  86. wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_REQ) failed\n");
  87. goto out_stop;
  88. }
  89. /* supplicant doesn't provide Probe Response IEs. As a workaround -
  90. * re-use Probe Request IEs
  91. */
  92. rc = wmi_set_ie(vif, WMI_FRAME_PROBE_RESP,
  93. request->ie_len, request->ie);
  94. if (rc) {
  95. wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n");
  96. goto out_stop;
  97. }
  98. rc = wmi_start_search(vif);
  99. if (rc) {
  100. wil_err(wil, "wmi_start_search failed\n");
  101. goto out_stop;
  102. }
  103. p2p->discovery_started = 1;
  104. INIT_WORK(&p2p->discovery_expired_work, wil_p2p_search_expired);
  105. mod_timer(&p2p->discovery_timer,
  106. jiffies + msecs_to_jiffies(P2P_SEARCH_DURATION_MS));
  107. out_stop:
  108. if (rc)
  109. wmi_stop_discovery(vif);
  110. out:
  111. return rc;
  112. }
  113. int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
  114. unsigned int duration, struct ieee80211_channel *chan,
  115. u64 *cookie)
  116. {
  117. struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
  118. struct wil_p2p_info *p2p = &vif->p2p;
  119. int rc;
  120. if (!chan)
  121. return -EINVAL;
  122. wil_dbg_misc(wil, "p2p_listen: duration %d\n", duration);
  123. mutex_lock(&wil->mutex);
  124. if (p2p->discovery_started) {
  125. wil_err(wil, "discovery already ongoing\n");
  126. rc = -EBUSY;
  127. goto out;
  128. }
  129. memcpy(&p2p->listen_chan, chan, sizeof(*chan));
  130. *cookie = ++p2p->cookie;
  131. p2p->listen_duration = duration;
  132. mutex_lock(&wil->vif_mutex);
  133. if (vif->scan_request) {
  134. wil_dbg_misc(wil, "Delaying p2p listen until scan done\n");
  135. p2p->pending_listen_wdev = wdev;
  136. p2p->discovery_started = 1;
  137. rc = 0;
  138. mutex_unlock(&wil->vif_mutex);
  139. goto out;
  140. }
  141. mutex_unlock(&wil->vif_mutex);
  142. rc = wil_p2p_start_listen(vif);
  143. if (rc)
  144. goto out;
  145. p2p->discovery_started = 1;
  146. if (vif->mid == 0)
  147. wil->radio_wdev = wdev;
  148. cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
  149. GFP_KERNEL);
  150. out:
  151. mutex_unlock(&wil->mutex);
  152. return rc;
  153. }
  154. u8 wil_p2p_stop_discovery(struct wil6210_vif *vif)
  155. {
  156. struct wil_p2p_info *p2p = &vif->p2p;
  157. u8 started = p2p->discovery_started;
  158. if (p2p->discovery_started) {
  159. if (p2p->pending_listen_wdev) {
  160. /* discovery not really started, only pending */
  161. p2p->pending_listen_wdev = NULL;
  162. } else {
  163. del_timer_sync(&p2p->discovery_timer);
  164. wmi_stop_discovery(vif);
  165. }
  166. p2p->discovery_started = 0;
  167. }
  168. return started;
  169. }
  170. int wil_p2p_cancel_listen(struct wil6210_vif *vif, u64 cookie)
  171. {
  172. struct wil6210_priv *wil = vif_to_wil(vif);
  173. struct wil_p2p_info *p2p = &vif->p2p;
  174. u8 started;
  175. mutex_lock(&wil->mutex);
  176. if (cookie != p2p->cookie) {
  177. wil_info(wil, "Cookie mismatch: 0x%016llx vs. 0x%016llx\n",
  178. p2p->cookie, cookie);
  179. mutex_unlock(&wil->mutex);
  180. return -ENOENT;
  181. }
  182. started = wil_p2p_stop_discovery(vif);
  183. mutex_unlock(&wil->mutex);
  184. if (!started) {
  185. wil_err(wil, "listen not started\n");
  186. return -ENOENT;
  187. }
  188. mutex_lock(&wil->vif_mutex);
  189. cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif),
  190. p2p->cookie,
  191. &p2p->listen_chan,
  192. GFP_KERNEL);
  193. if (vif->mid == 0)
  194. wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
  195. mutex_unlock(&wil->vif_mutex);
  196. return 0;
  197. }
  198. void wil_p2p_listen_expired(struct work_struct *work)
  199. {
  200. struct wil_p2p_info *p2p = container_of(work,
  201. struct wil_p2p_info, discovery_expired_work);
  202. struct wil6210_vif *vif = container_of(p2p,
  203. struct wil6210_vif, p2p);
  204. struct wil6210_priv *wil = vif_to_wil(vif);
  205. u8 started;
  206. wil_dbg_misc(wil, "p2p_listen_expired\n");
  207. mutex_lock(&wil->mutex);
  208. started = wil_p2p_stop_discovery(vif);
  209. mutex_unlock(&wil->mutex);
  210. if (!started)
  211. return;
  212. mutex_lock(&wil->vif_mutex);
  213. cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif),
  214. p2p->cookie,
  215. &p2p->listen_chan,
  216. GFP_KERNEL);
  217. if (vif->mid == 0)
  218. wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
  219. mutex_unlock(&wil->vif_mutex);
  220. }
  221. void wil_p2p_search_expired(struct work_struct *work)
  222. {
  223. struct wil_p2p_info *p2p = container_of(work,
  224. struct wil_p2p_info, discovery_expired_work);
  225. struct wil6210_vif *vif = container_of(p2p,
  226. struct wil6210_vif, p2p);
  227. struct wil6210_priv *wil = vif_to_wil(vif);
  228. u8 started;
  229. wil_dbg_misc(wil, "p2p_search_expired\n");
  230. mutex_lock(&wil->mutex);
  231. started = wil_p2p_stop_discovery(vif);
  232. mutex_unlock(&wil->mutex);
  233. if (started) {
  234. struct cfg80211_scan_info info = {
  235. .aborted = false,
  236. };
  237. mutex_lock(&wil->vif_mutex);
  238. if (vif->scan_request) {
  239. cfg80211_scan_done(vif->scan_request, &info);
  240. vif->scan_request = NULL;
  241. if (vif->mid == 0)
  242. wil->radio_wdev =
  243. wil->main_ndev->ieee80211_ptr;
  244. }
  245. mutex_unlock(&wil->vif_mutex);
  246. }
  247. }
  248. void wil_p2p_delayed_listen_work(struct work_struct *work)
  249. {
  250. struct wil_p2p_info *p2p = container_of(work,
  251. struct wil_p2p_info, delayed_listen_work);
  252. struct wil6210_vif *vif = container_of(p2p,
  253. struct wil6210_vif, p2p);
  254. struct wil6210_priv *wil = vif_to_wil(vif);
  255. int rc;
  256. mutex_lock(&wil->mutex);
  257. wil_dbg_misc(wil, "Checking delayed p2p listen\n");
  258. if (!p2p->discovery_started || !p2p->pending_listen_wdev)
  259. goto out;
  260. mutex_lock(&wil->vif_mutex);
  261. if (vif->scan_request) {
  262. /* another scan started, wait again... */
  263. mutex_unlock(&wil->vif_mutex);
  264. goto out;
  265. }
  266. mutex_unlock(&wil->vif_mutex);
  267. rc = wil_p2p_start_listen(vif);
  268. mutex_lock(&wil->vif_mutex);
  269. if (rc) {
  270. cfg80211_remain_on_channel_expired(p2p->pending_listen_wdev,
  271. p2p->cookie,
  272. &p2p->listen_chan,
  273. GFP_KERNEL);
  274. if (vif->mid == 0)
  275. wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
  276. } else {
  277. cfg80211_ready_on_channel(p2p->pending_listen_wdev, p2p->cookie,
  278. &p2p->listen_chan,
  279. p2p->listen_duration, GFP_KERNEL);
  280. if (vif->mid == 0)
  281. wil->radio_wdev = p2p->pending_listen_wdev;
  282. }
  283. p2p->pending_listen_wdev = NULL;
  284. mutex_unlock(&wil->vif_mutex);
  285. out:
  286. mutex_unlock(&wil->mutex);
  287. }
  288. void wil_p2p_stop_radio_operations(struct wil6210_priv *wil)
  289. {
  290. struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
  291. struct wil_p2p_info *p2p = &vif->p2p;
  292. struct cfg80211_scan_info info = {
  293. .aborted = true,
  294. };
  295. lockdep_assert_held(&wil->mutex);
  296. lockdep_assert_held(&wil->vif_mutex);
  297. if (wil->radio_wdev != wil->p2p_wdev)
  298. goto out;
  299. if (!p2p->discovery_started) {
  300. /* Regular scan on the p2p device */
  301. if (vif->scan_request &&
  302. vif->scan_request->wdev == wil->p2p_wdev)
  303. wil_abort_scan(vif, true);
  304. goto out;
  305. }
  306. /* Search or listen on p2p device */
  307. mutex_unlock(&wil->vif_mutex);
  308. wil_p2p_stop_discovery(vif);
  309. mutex_lock(&wil->vif_mutex);
  310. if (vif->scan_request) {
  311. /* search */
  312. cfg80211_scan_done(vif->scan_request, &info);
  313. vif->scan_request = NULL;
  314. } else {
  315. /* listen */
  316. cfg80211_remain_on_channel_expired(wil->radio_wdev,
  317. p2p->cookie,
  318. &p2p->listen_chan,
  319. GFP_KERNEL);
  320. }
  321. out:
  322. wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
  323. }