offchannel.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /*
  2. * wpa_supplicant - Off-channel Action frame TX/RX
  3. * Copyright (c) 2009-2010, Atheros Communications
  4. * Copyright (c) 2011, Qualcomm Atheros
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License version 2 as
  8. * published by the Free Software Foundation.
  9. *
  10. * Alternatively, this software may be distributed under the terms of BSD
  11. * license.
  12. *
  13. * See README and COPYING for more details.
  14. */
  15. #include "includes.h"
  16. #include "common.h"
  17. #include "utils/eloop.h"
  18. #include "wpa_supplicant_i.h"
  19. #include "driver_i.h"
  20. #include "offchannel.h"
  21. static struct wpa_supplicant *
  22. wpas_get_tx_interface(struct wpa_supplicant *wpa_s, const u8 *src)
  23. {
  24. struct wpa_supplicant *iface;
  25. if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0)
  26. return wpa_s;
  27. /*
  28. * Try to find a group interface that matches with the source address.
  29. */
  30. iface = wpa_s->global->ifaces;
  31. while (iface) {
  32. if (os_memcmp(wpa_s->pending_action_src,
  33. iface->own_addr, ETH_ALEN) == 0)
  34. break;
  35. iface = iface->next;
  36. }
  37. if (iface) {
  38. wpa_printf(MSG_DEBUG, "P2P: Use group interface %s "
  39. "instead of interface %s for Action TX",
  40. iface->ifname, wpa_s->ifname);
  41. return iface;
  42. }
  43. return wpa_s;
  44. }
  45. static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
  46. {
  47. struct wpa_supplicant *wpa_s = eloop_ctx;
  48. struct wpa_supplicant *iface;
  49. int res;
  50. int without_roc;
  51. without_roc = wpa_s->pending_action_without_roc;
  52. wpa_s->pending_action_without_roc = 0;
  53. wpa_printf(MSG_DEBUG, "Off-channel: Send Action callback "
  54. "(without_roc=%d pending_action_tx=%p)",
  55. without_roc, wpa_s->pending_action_tx);
  56. if (wpa_s->pending_action_tx == NULL)
  57. return;
  58. /*
  59. * This call is likely going to be on the P2P device instance if the
  60. * driver uses a separate interface for that purpose. However, some
  61. * Action frames are actually sent within a P2P Group and when that is
  62. * the case, we need to follow power saving (e.g., GO buffering the
  63. * frame for a client in PS mode or a client following the advertised
  64. * NoA from its GO). To make that easier for the driver, select the
  65. * correct group interface here.
  66. */
  67. iface = wpas_get_tx_interface(wpa_s, wpa_s->pending_action_src);
  68. if (wpa_s->off_channel_freq != wpa_s->pending_action_freq &&
  69. wpa_s->pending_action_freq != 0 &&
  70. wpa_s->pending_action_freq != iface->assoc_freq) {
  71. wpa_printf(MSG_DEBUG, "Off-channel: Pending Action frame TX "
  72. "waiting for another freq=%u (off_channel_freq=%u "
  73. "assoc_freq=%u)",
  74. wpa_s->pending_action_freq,
  75. wpa_s->off_channel_freq,
  76. iface->assoc_freq);
  77. if (without_roc && wpa_s->off_channel_freq == 0) {
  78. /*
  79. * We may get here if wpas_send_action() found us to be
  80. * on the correct channel, but remain-on-channel cancel
  81. * event was received before getting here.
  82. */
  83. wpa_printf(MSG_DEBUG, "Off-channel: Schedule "
  84. "remain-on-channel to send Action frame");
  85. if (wpa_drv_remain_on_channel(
  86. wpa_s, wpa_s->pending_action_freq, 200) <
  87. 0) {
  88. wpa_printf(MSG_DEBUG, "Off-channel: Failed to "
  89. "request driver to remain on "
  90. "channel (%u MHz) for Action Frame "
  91. "TX", wpa_s->pending_action_freq);
  92. } else {
  93. wpa_s->off_channel_freq = 0;
  94. wpa_s->roc_waiting_drv_freq =
  95. wpa_s->pending_action_freq;
  96. }
  97. }
  98. return;
  99. }
  100. wpa_printf(MSG_DEBUG, "Off-channel: Sending pending Action frame to "
  101. MACSTR " using interface %s",
  102. MAC2STR(wpa_s->pending_action_dst), iface->ifname);
  103. res = wpa_drv_send_action(iface, wpa_s->pending_action_freq, 0,
  104. wpa_s->pending_action_dst,
  105. wpa_s->pending_action_src,
  106. wpa_s->pending_action_bssid,
  107. wpabuf_head(wpa_s->pending_action_tx),
  108. wpabuf_len(wpa_s->pending_action_tx),
  109. wpa_s->pending_action_no_cck);
  110. if (res) {
  111. wpa_printf(MSG_DEBUG, "Off-channel: Failed to send the "
  112. "pending Action frame");
  113. /*
  114. * Use fake TX status event to allow state machines to
  115. * continue.
  116. */
  117. offchannel_send_action_tx_status(
  118. wpa_s, wpa_s->pending_action_dst,
  119. wpabuf_head(wpa_s->pending_action_tx),
  120. wpabuf_len(wpa_s->pending_action_tx),
  121. OFFCHANNEL_SEND_ACTION_FAILED);
  122. }
  123. }
  124. void offchannel_send_action_tx_status(
  125. struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data,
  126. size_t data_len, enum offchannel_send_action_result result)
  127. {
  128. if (wpa_s->pending_action_tx == NULL) {
  129. wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
  130. "no pending operation");
  131. return;
  132. }
  133. if (os_memcmp(dst, wpa_s->pending_action_dst, ETH_ALEN) != 0) {
  134. wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
  135. "unknown destination address");
  136. return;
  137. }
  138. wpabuf_free(wpa_s->pending_action_tx);
  139. wpa_s->pending_action_tx = NULL;
  140. wpa_printf(MSG_DEBUG, "Off-channel: TX status result=%d cb=%p",
  141. result, wpa_s->pending_action_tx_status_cb);
  142. if (wpa_s->pending_action_tx_status_cb) {
  143. wpa_s->pending_action_tx_status_cb(
  144. wpa_s, wpa_s->pending_action_freq,
  145. wpa_s->pending_action_dst, wpa_s->pending_action_src,
  146. wpa_s->pending_action_bssid,
  147. data, data_len, result);
  148. }
  149. }
  150. int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
  151. const u8 *dst, const u8 *src, const u8 *bssid,
  152. const u8 *buf, size_t len, unsigned int wait_time,
  153. void (*tx_cb)(struct wpa_supplicant *wpa_s,
  154. unsigned int freq, const u8 *dst,
  155. const u8 *src, const u8 *bssid,
  156. const u8 *data, size_t data_len,
  157. enum offchannel_send_action_result
  158. result),
  159. int no_cck)
  160. {
  161. wpa_printf(MSG_DEBUG, "Off-channel: Send action frame: freq=%d dst="
  162. MACSTR " src=" MACSTR " bssid=" MACSTR " len=%d",
  163. freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
  164. (int) len);
  165. wpa_s->pending_action_tx_status_cb = tx_cb;
  166. if (wpa_s->pending_action_tx) {
  167. wpa_printf(MSG_DEBUG, "Off-channel: Dropped pending Action "
  168. "frame TX to " MACSTR,
  169. MAC2STR(wpa_s->pending_action_dst));
  170. wpabuf_free(wpa_s->pending_action_tx);
  171. }
  172. wpa_s->pending_action_tx = wpabuf_alloc(len);
  173. if (wpa_s->pending_action_tx == NULL) {
  174. wpa_printf(MSG_DEBUG, "Off-channel: Failed to allocate Action "
  175. "frame TX buffer (len=%llu)",
  176. (unsigned long long) len);
  177. return -1;
  178. }
  179. wpabuf_put_data(wpa_s->pending_action_tx, buf, len);
  180. os_memcpy(wpa_s->pending_action_src, src, ETH_ALEN);
  181. os_memcpy(wpa_s->pending_action_dst, dst, ETH_ALEN);
  182. os_memcpy(wpa_s->pending_action_bssid, bssid, ETH_ALEN);
  183. wpa_s->pending_action_freq = freq;
  184. wpa_s->pending_action_no_cck = no_cck;
  185. if (freq != 0 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
  186. struct wpa_supplicant *iface;
  187. iface = wpas_get_tx_interface(wpa_s,
  188. wpa_s->pending_action_src);
  189. wpa_s->action_tx_wait_time = wait_time;
  190. return wpa_drv_send_action(
  191. iface, wpa_s->pending_action_freq,
  192. wait_time, wpa_s->pending_action_dst,
  193. wpa_s->pending_action_src, wpa_s->pending_action_bssid,
  194. wpabuf_head(wpa_s->pending_action_tx),
  195. wpabuf_len(wpa_s->pending_action_tx),
  196. wpa_s->pending_action_no_cck);
  197. }
  198. if (freq) {
  199. struct wpa_supplicant *tx_iface;
  200. tx_iface = wpas_get_tx_interface(wpa_s, src);
  201. if (tx_iface->assoc_freq == freq) {
  202. wpa_printf(MSG_DEBUG, "Off-channel: Already on "
  203. "requested channel (TX interface operating "
  204. "channel)");
  205. freq = 0;
  206. }
  207. }
  208. if (wpa_s->off_channel_freq == freq || freq == 0) {
  209. wpa_printf(MSG_DEBUG, "Off-channel: Already on requested "
  210. "channel; send Action frame immediately");
  211. /* TODO: Would there ever be need to extend the current
  212. * duration on the channel? */
  213. wpa_s->pending_action_without_roc = 1;
  214. eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
  215. eloop_register_timeout(0, 0, wpas_send_action_cb, wpa_s, NULL);
  216. return 0;
  217. }
  218. wpa_s->pending_action_without_roc = 0;
  219. if (wpa_s->roc_waiting_drv_freq == freq) {
  220. wpa_printf(MSG_DEBUG, "Off-channel: Already waiting for "
  221. "driver to get to frequency %u MHz; continue "
  222. "waiting to send the Action frame", freq);
  223. return 0;
  224. }
  225. wpa_printf(MSG_DEBUG, "Off-channel: Schedule Action frame to be "
  226. "transmitted once the driver gets to the requested "
  227. "channel");
  228. if (wait_time > wpa_s->max_remain_on_chan)
  229. wait_time = wpa_s->max_remain_on_chan;
  230. if (wpa_drv_remain_on_channel(wpa_s, freq, wait_time) < 0) {
  231. wpa_printf(MSG_DEBUG, "Off-channel: Failed to request driver "
  232. "to remain on channel (%u MHz) for Action "
  233. "Frame TX", freq);
  234. return -1;
  235. }
  236. wpa_s->off_channel_freq = 0;
  237. wpa_s->roc_waiting_drv_freq = freq;
  238. return 0;
  239. }
  240. void offchannel_send_action_done(struct wpa_supplicant *wpa_s)
  241. {
  242. wpa_printf(MSG_DEBUG, "Off-channel: Action frame sequence done "
  243. "notification");
  244. wpabuf_free(wpa_s->pending_action_tx);
  245. wpa_s->pending_action_tx = NULL;
  246. if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX &&
  247. wpa_s->action_tx_wait_time)
  248. wpa_drv_send_action_cancel_wait(wpa_s);
  249. if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
  250. wpa_drv_cancel_remain_on_channel(wpa_s);
  251. wpa_s->off_channel_freq = 0;
  252. wpa_s->roc_waiting_drv_freq = 0;
  253. }
  254. }
  255. void offchannel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
  256. unsigned int freq, unsigned int duration)
  257. {
  258. wpa_s->roc_waiting_drv_freq = 0;
  259. wpa_s->off_channel_freq = freq;
  260. wpas_send_action_cb(wpa_s, NULL);
  261. }
  262. void offchannel_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
  263. unsigned int freq)
  264. {
  265. wpa_s->off_channel_freq = 0;
  266. }
  267. void offchannel_deinit(struct wpa_supplicant *wpa_s)
  268. {
  269. wpabuf_free(wpa_s->pending_action_tx);
  270. wpa_s->pending_action_tx = NULL;
  271. eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
  272. }