offchannel.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  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. if (res) {
  110. wpa_printf(MSG_DEBUG, "Off-channel: Failed to send the "
  111. "pending Action frame");
  112. /*
  113. * Use fake TX status event to allow state machines to
  114. * continue.
  115. */
  116. offchannel_send_action_tx_status(
  117. wpa_s, wpa_s->pending_action_dst,
  118. wpabuf_head(wpa_s->pending_action_tx),
  119. wpabuf_len(wpa_s->pending_action_tx),
  120. OFFCHANNEL_SEND_ACTION_FAILED);
  121. }
  122. }
  123. void offchannel_send_action_tx_status(
  124. struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data,
  125. size_t data_len, enum offchannel_send_action_result result)
  126. {
  127. if (wpa_s->pending_action_tx == NULL) {
  128. wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
  129. "no pending operation");
  130. return;
  131. }
  132. if (os_memcmp(dst, wpa_s->pending_action_dst, ETH_ALEN) != 0) {
  133. wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
  134. "unknown destination address");
  135. return;
  136. }
  137. wpabuf_free(wpa_s->pending_action_tx);
  138. wpa_s->pending_action_tx = NULL;
  139. wpa_printf(MSG_DEBUG, "Off-channel: TX status result=%d cb=%p",
  140. result, wpa_s->pending_action_tx_status_cb);
  141. if (wpa_s->pending_action_tx_status_cb) {
  142. wpa_s->pending_action_tx_status_cb(
  143. wpa_s, wpa_s->pending_action_freq,
  144. wpa_s->pending_action_dst, wpa_s->pending_action_src,
  145. wpa_s->pending_action_bssid,
  146. data, data_len, result);
  147. }
  148. }
  149. int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
  150. const u8 *dst, const u8 *src, const u8 *bssid,
  151. const u8 *buf, size_t len, unsigned int wait_time,
  152. void (*tx_cb)(struct wpa_supplicant *wpa_s,
  153. unsigned int freq, const u8 *dst,
  154. const u8 *src, const u8 *bssid,
  155. const u8 *data, size_t data_len,
  156. enum offchannel_send_action_result
  157. result))
  158. {
  159. wpa_printf(MSG_DEBUG, "Off-channel: Send action frame: freq=%d dst="
  160. MACSTR " src=" MACSTR " bssid=" MACSTR " len=%d",
  161. freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
  162. (int) len);
  163. wpa_s->pending_action_tx_status_cb = tx_cb;
  164. if (wpa_s->pending_action_tx) {
  165. wpa_printf(MSG_DEBUG, "Off-channel: Dropped pending Action "
  166. "frame TX to " MACSTR,
  167. MAC2STR(wpa_s->pending_action_dst));
  168. wpabuf_free(wpa_s->pending_action_tx);
  169. }
  170. wpa_s->pending_action_tx = wpabuf_alloc(len);
  171. if (wpa_s->pending_action_tx == NULL) {
  172. wpa_printf(MSG_DEBUG, "Off-channel: Failed to allocate Action "
  173. "frame TX buffer (len=%llu)",
  174. (unsigned long long) len);
  175. return -1;
  176. }
  177. wpabuf_put_data(wpa_s->pending_action_tx, buf, len);
  178. os_memcpy(wpa_s->pending_action_src, src, ETH_ALEN);
  179. os_memcpy(wpa_s->pending_action_dst, dst, ETH_ALEN);
  180. os_memcpy(wpa_s->pending_action_bssid, bssid, ETH_ALEN);
  181. wpa_s->pending_action_freq = freq;
  182. if (freq != 0 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
  183. struct wpa_supplicant *iface;
  184. iface = wpas_get_tx_interface(wpa_s,
  185. wpa_s->pending_action_src);
  186. wpa_s->action_tx_wait_time = wait_time;
  187. return wpa_drv_send_action(iface, wpa_s->pending_action_freq,
  188. wait_time, wpa_s->pending_action_dst,
  189. wpa_s->pending_action_src,
  190. wpa_s->pending_action_bssid,
  191. wpabuf_head(wpa_s->pending_action_tx),
  192. wpabuf_len(wpa_s->pending_action_tx));
  193. }
  194. if (freq) {
  195. struct wpa_supplicant *tx_iface;
  196. tx_iface = wpas_get_tx_interface(wpa_s, src);
  197. if (tx_iface->assoc_freq == freq) {
  198. wpa_printf(MSG_DEBUG, "Off-channel: Already on "
  199. "requested channel (TX interface operating "
  200. "channel)");
  201. freq = 0;
  202. }
  203. }
  204. if (wpa_s->off_channel_freq == freq || freq == 0) {
  205. wpa_printf(MSG_DEBUG, "Off-channel: Already on requested "
  206. "channel; send Action frame immediately");
  207. /* TODO: Would there ever be need to extend the current
  208. * duration on the channel? */
  209. wpa_s->pending_action_without_roc = 1;
  210. eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
  211. eloop_register_timeout(0, 0, wpas_send_action_cb, wpa_s, NULL);
  212. return 0;
  213. }
  214. wpa_s->pending_action_without_roc = 0;
  215. if (wpa_s->roc_waiting_drv_freq == freq) {
  216. wpa_printf(MSG_DEBUG, "Off-channel: Already waiting for "
  217. "driver to get to frequency %u MHz; continue "
  218. "waiting to send the Action frame", freq);
  219. return 0;
  220. }
  221. wpa_printf(MSG_DEBUG, "Off-channel: Schedule Action frame to be "
  222. "transmitted once the driver gets to the requested "
  223. "channel");
  224. if (wait_time > wpa_s->max_remain_on_chan)
  225. wait_time = wpa_s->max_remain_on_chan;
  226. if (wpa_drv_remain_on_channel(wpa_s, freq, wait_time) < 0) {
  227. wpa_printf(MSG_DEBUG, "Off-channel: Failed to request driver "
  228. "to remain on channel (%u MHz) for Action "
  229. "Frame TX", freq);
  230. return -1;
  231. }
  232. wpa_s->off_channel_freq = 0;
  233. wpa_s->roc_waiting_drv_freq = freq;
  234. return 0;
  235. }
  236. void offchannel_send_action_done(struct wpa_supplicant *wpa_s)
  237. {
  238. wpa_printf(MSG_DEBUG, "Off-channel: Action frame sequence done "
  239. "notification");
  240. wpabuf_free(wpa_s->pending_action_tx);
  241. wpa_s->pending_action_tx = NULL;
  242. if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX &&
  243. wpa_s->action_tx_wait_time)
  244. wpa_drv_send_action_cancel_wait(wpa_s);
  245. if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
  246. wpa_drv_cancel_remain_on_channel(wpa_s);
  247. wpa_s->off_channel_freq = 0;
  248. wpa_s->roc_waiting_drv_freq = 0;
  249. }
  250. }
  251. void offchannel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
  252. unsigned int freq, unsigned int duration)
  253. {
  254. wpa_s->roc_waiting_drv_freq = 0;
  255. wpa_s->off_channel_freq = freq;
  256. wpas_send_action_cb(wpa_s, NULL);
  257. }
  258. void offchannel_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
  259. unsigned int freq)
  260. {
  261. wpa_s->off_channel_freq = 0;
  262. }
  263. void offchannel_deinit(struct wpa_supplicant *wpa_s)
  264. {
  265. wpabuf_free(wpa_s->pending_action_tx);
  266. wpa_s->pending_action_tx = NULL;
  267. eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
  268. }