p2p.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /*
  2. * Copyright (c) 2014-2016 Qualcomm Atheros, Inc.
  3. *
  4. * Permission to use, copy, modify, and/or distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include "wil6210.h"
  17. #include "wmi.h"
  18. #define P2P_WILDCARD_SSID "DIRECT-"
  19. #define P2P_DMG_SOCIAL_CHANNEL 2
  20. #define P2P_SEARCH_DURATION_MS 500
  21. #define P2P_DEFAULT_BI 100
  22. bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request)
  23. {
  24. return (request->n_channels == 1) &&
  25. (request->channels[0]->hw_value == P2P_DMG_SOCIAL_CHANNEL);
  26. }
  27. void wil_p2p_discovery_timer_fn(ulong x)
  28. {
  29. struct wil6210_priv *wil = (void *)x;
  30. wil_dbg_misc(wil, "%s\n", __func__);
  31. schedule_work(&wil->p2p.discovery_expired_work);
  32. }
  33. int wil_p2p_search(struct wil6210_priv *wil,
  34. struct cfg80211_scan_request *request)
  35. {
  36. int rc;
  37. struct wil_p2p_info *p2p = &wil->p2p;
  38. wil_dbg_misc(wil, "%s: channel %d\n",
  39. __func__, P2P_DMG_SOCIAL_CHANNEL);
  40. mutex_lock(&wil->mutex);
  41. if (p2p->discovery_started) {
  42. wil_err(wil, "%s: search failed. discovery already ongoing\n",
  43. __func__);
  44. rc = -EBUSY;
  45. goto out;
  46. }
  47. rc = wmi_p2p_cfg(wil, P2P_DMG_SOCIAL_CHANNEL, P2P_DEFAULT_BI);
  48. if (rc) {
  49. wil_err(wil, "%s: wmi_p2p_cfg failed\n", __func__);
  50. goto out;
  51. }
  52. rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
  53. if (rc) {
  54. wil_err(wil, "%s: wmi_set_ssid failed\n", __func__);
  55. goto out_stop;
  56. }
  57. /* Set application IE to probe request and probe response */
  58. rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ,
  59. request->ie_len, request->ie);
  60. if (rc) {
  61. wil_err(wil, "%s: wmi_set_ie(WMI_FRAME_PROBE_REQ) failed\n",
  62. __func__);
  63. goto out_stop;
  64. }
  65. /* supplicant doesn't provide Probe Response IEs. As a workaround -
  66. * re-use Probe Request IEs
  67. */
  68. rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP,
  69. request->ie_len, request->ie);
  70. if (rc) {
  71. wil_err(wil, "%s: wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n",
  72. __func__);
  73. goto out_stop;
  74. }
  75. rc = wmi_start_search(wil);
  76. if (rc) {
  77. wil_err(wil, "%s: wmi_start_search failed\n", __func__);
  78. goto out_stop;
  79. }
  80. p2p->discovery_started = 1;
  81. INIT_WORK(&p2p->discovery_expired_work, wil_p2p_search_expired);
  82. mod_timer(&p2p->discovery_timer,
  83. jiffies + msecs_to_jiffies(P2P_SEARCH_DURATION_MS));
  84. out_stop:
  85. if (rc)
  86. wmi_stop_discovery(wil);
  87. out:
  88. mutex_unlock(&wil->mutex);
  89. return rc;
  90. }
  91. int wil_p2p_listen(struct wil6210_priv *wil, unsigned int duration,
  92. struct ieee80211_channel *chan, u64 *cookie)
  93. {
  94. struct wil_p2p_info *p2p = &wil->p2p;
  95. u8 channel = P2P_DMG_SOCIAL_CHANNEL;
  96. int rc;
  97. if (!chan)
  98. return -EINVAL;
  99. channel = chan->hw_value;
  100. wil_dbg_misc(wil, "%s: duration %d\n", __func__, duration);
  101. mutex_lock(&wil->mutex);
  102. if (p2p->discovery_started) {
  103. wil_err(wil, "%s: discovery already ongoing\n", __func__);
  104. rc = -EBUSY;
  105. goto out;
  106. }
  107. rc = wmi_p2p_cfg(wil, channel, P2P_DEFAULT_BI);
  108. if (rc) {
  109. wil_err(wil, "%s: wmi_p2p_cfg failed\n", __func__);
  110. goto out;
  111. }
  112. rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
  113. if (rc) {
  114. wil_err(wil, "%s: wmi_set_ssid failed\n", __func__);
  115. goto out_stop;
  116. }
  117. rc = wmi_start_listen(wil);
  118. if (rc) {
  119. wil_err(wil, "%s: wmi_start_listen failed\n", __func__);
  120. goto out_stop;
  121. }
  122. memcpy(&p2p->listen_chan, chan, sizeof(*chan));
  123. *cookie = ++p2p->cookie;
  124. p2p->discovery_started = 1;
  125. INIT_WORK(&p2p->discovery_expired_work, wil_p2p_listen_expired);
  126. mod_timer(&p2p->discovery_timer,
  127. jiffies + msecs_to_jiffies(duration));
  128. out_stop:
  129. if (rc)
  130. wmi_stop_discovery(wil);
  131. out:
  132. mutex_unlock(&wil->mutex);
  133. return rc;
  134. }
  135. u8 wil_p2p_stop_discovery(struct wil6210_priv *wil)
  136. {
  137. struct wil_p2p_info *p2p = &wil->p2p;
  138. u8 started = p2p->discovery_started;
  139. if (p2p->discovery_started) {
  140. del_timer_sync(&p2p->discovery_timer);
  141. p2p->discovery_started = 0;
  142. wmi_stop_discovery(wil);
  143. }
  144. return started;
  145. }
  146. int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie)
  147. {
  148. struct wil_p2p_info *p2p = &wil->p2p;
  149. u8 started;
  150. mutex_lock(&wil->mutex);
  151. if (cookie != p2p->cookie) {
  152. wil_info(wil, "%s: Cookie mismatch: 0x%016llx vs. 0x%016llx\n",
  153. __func__, p2p->cookie, cookie);
  154. mutex_unlock(&wil->mutex);
  155. return -ENOENT;
  156. }
  157. started = wil_p2p_stop_discovery(wil);
  158. mutex_unlock(&wil->mutex);
  159. if (!started) {
  160. wil_err(wil, "%s: listen not started\n", __func__);
  161. return -ENOENT;
  162. }
  163. mutex_lock(&wil->p2p_wdev_mutex);
  164. cfg80211_remain_on_channel_expired(wil->radio_wdev,
  165. p2p->cookie,
  166. &p2p->listen_chan,
  167. GFP_KERNEL);
  168. wil->radio_wdev = wil->wdev;
  169. mutex_unlock(&wil->p2p_wdev_mutex);
  170. return 0;
  171. }
  172. void wil_p2p_listen_expired(struct work_struct *work)
  173. {
  174. struct wil_p2p_info *p2p = container_of(work,
  175. struct wil_p2p_info, discovery_expired_work);
  176. struct wil6210_priv *wil = container_of(p2p,
  177. struct wil6210_priv, p2p);
  178. u8 started;
  179. wil_dbg_misc(wil, "%s()\n", __func__);
  180. mutex_lock(&wil->mutex);
  181. started = wil_p2p_stop_discovery(wil);
  182. mutex_unlock(&wil->mutex);
  183. if (started) {
  184. mutex_lock(&wil->p2p_wdev_mutex);
  185. cfg80211_remain_on_channel_expired(wil->radio_wdev,
  186. p2p->cookie,
  187. &p2p->listen_chan,
  188. GFP_KERNEL);
  189. wil->radio_wdev = wil->wdev;
  190. mutex_unlock(&wil->p2p_wdev_mutex);
  191. }
  192. }
  193. void wil_p2p_search_expired(struct work_struct *work)
  194. {
  195. struct wil_p2p_info *p2p = container_of(work,
  196. struct wil_p2p_info, discovery_expired_work);
  197. struct wil6210_priv *wil = container_of(p2p,
  198. struct wil6210_priv, p2p);
  199. u8 started;
  200. wil_dbg_misc(wil, "%s()\n", __func__);
  201. mutex_lock(&wil->mutex);
  202. started = wil_p2p_stop_discovery(wil);
  203. mutex_unlock(&wil->mutex);
  204. if (started) {
  205. struct cfg80211_scan_info info = {
  206. .aborted = false,
  207. };
  208. mutex_lock(&wil->p2p_wdev_mutex);
  209. cfg80211_scan_done(wil->scan_request, &info);
  210. wil->scan_request = NULL;
  211. wil->radio_wdev = wil->wdev;
  212. mutex_unlock(&wil->p2p_wdev_mutex);
  213. }
  214. }