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 software may be distributed under the terms of the BSD license.
7 * See README for more details.
8 */
9
10 #include "includes.h"
11
12 #include "common.h"
13 #include "utils/eloop.h"
14 #include "wpa_supplicant_i.h"
15 #include "p2p_supplicant.h"
16 #include "driver_i.h"
17 #include "offchannel.h"
18
19 #if defined(CONFIG_OPEN_HARMONY_PATCH) && defined(OPEN_HARMONY_MIRACAST_SINK_OPT)
20 #include "hm_miracast_sink.h"
21 #endif
22
23 static struct wpa_supplicant *
wpas_get_tx_interface(struct wpa_supplicant * wpa_s,const u8 * src)24 wpas_get_tx_interface(struct wpa_supplicant *wpa_s, const u8 *src)
25 {
26 struct wpa_supplicant *iface;
27
28 if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0) {
29 #ifdef CONFIG_P2P
30 if (wpa_s->p2p_mgmt && wpa_s != wpa_s->parent &&
31 wpa_s->parent->ap_iface &&
32 os_memcmp(wpa_s->parent->own_addr,
33 wpa_s->own_addr, ETH_ALEN) == 0 &&
34 wpabuf_len(wpa_s->pending_action_tx) >= 2 &&
35 *wpabuf_head_u8(wpa_s->pending_action_tx) !=
36 WLAN_ACTION_PUBLIC) {
37 /*
38 * When P2P Device interface has same MAC address as
39 * the GO interface, make sure non-Public Action frames
40 * are sent through the GO interface. The P2P Device
41 * interface can only send Public Action frames.
42 */
43 wpa_printf(MSG_DEBUG,
44 "P2P: Use GO interface %s instead of interface %s for Action TX",
45 wpa_s->parent->ifname, wpa_s->ifname);
46 return wpa_s->parent;
47 }
48 #endif /* CONFIG_P2P */
49 return wpa_s;
50 }
51
52 /*
53 * Try to find a group interface that matches with the source address.
54 */
55 iface = wpa_s->global->ifaces;
56 while (iface) {
57 if (os_memcmp(src, iface->own_addr, ETH_ALEN) == 0)
58 break;
59 iface = iface->next;
60 }
61 if (iface) {
62 wpa_printf(MSG_DEBUG, "P2P: Use group interface %s "
63 "instead of interface %s for Action TX",
64 iface->ifname, wpa_s->ifname);
65 return iface;
66 }
67
68 return wpa_s;
69 }
70
71
wpas_send_action_cb(void * eloop_ctx,void * timeout_ctx)72 static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
73 {
74 struct wpa_supplicant *wpa_s = eloop_ctx;
75 struct wpa_supplicant *iface;
76 int res;
77 int without_roc;
78
79 without_roc = wpa_s->pending_action_without_roc;
80 wpa_s->pending_action_without_roc = 0;
81 wpa_printf(MSG_DEBUG,
82 "Off-channel: Send Action callback (without_roc=%d pending_action_tx=%p pending_action_tx_done=%d)",
83 without_roc, wpa_s->pending_action_tx,
84 !!wpa_s->pending_action_tx_done);
85
86 if (wpa_s->pending_action_tx == NULL || wpa_s->pending_action_tx_done)
87 return;
88
89 /*
90 * This call is likely going to be on the P2P device instance if the
91 * driver uses a separate interface for that purpose. However, some
92 * Action frames are actually sent within a P2P Group and when that is
93 * the case, we need to follow power saving (e.g., GO buffering the
94 * frame for a client in PS mode or a client following the advertised
95 * NoA from its GO). To make that easier for the driver, select the
96 * correct group interface here.
97 */
98 iface = wpas_get_tx_interface(wpa_s, wpa_s->pending_action_src);
99
100 if (wpa_s->off_channel_freq != wpa_s->pending_action_freq &&
101 wpa_s->pending_action_freq != 0 &&
102 wpa_s->pending_action_freq != iface->assoc_freq) {
103 wpa_printf(MSG_DEBUG, "Off-channel: Pending Action frame TX "
104 "waiting for another freq=%u (off_channel_freq=%u "
105 "assoc_freq=%u)",
106 wpa_s->pending_action_freq,
107 wpa_s->off_channel_freq,
108 iface->assoc_freq);
109 if (without_roc && wpa_s->off_channel_freq == 0) {
110 unsigned int duration = 200;
111 /*
112 * We may get here if wpas_send_action() found us to be
113 * on the correct channel, but remain-on-channel cancel
114 * event was received before getting here.
115 */
116 wpa_printf(MSG_DEBUG, "Off-channel: Schedule "
117 "remain-on-channel to send Action frame");
118 #ifdef CONFIG_TESTING_OPTIONS
119 if (wpa_s->extra_roc_dur) {
120 wpa_printf(MSG_DEBUG,
121 "TESTING: Increase ROC duration %u -> %u",
122 duration,
123 duration + wpa_s->extra_roc_dur);
124 duration += wpa_s->extra_roc_dur;
125 }
126 #endif /* CONFIG_TESTING_OPTIONS */
127 if (wpa_drv_remain_on_channel(
128 wpa_s, wpa_s->pending_action_freq,
129 duration) < 0) {
130 wpa_printf(MSG_DEBUG, "Off-channel: Failed to "
131 "request driver to remain on "
132 "channel (%u MHz) for Action Frame "
133 "TX", wpa_s->pending_action_freq);
134 } else {
135 wpa_s->off_channel_freq = 0;
136 wpa_s->roc_waiting_drv_freq =
137 wpa_s->pending_action_freq;
138 }
139 }
140 return;
141 }
142
143 wpa_printf(MSG_DEBUG, "Off-channel: Sending pending Action frame to "
144 MACSTR_SEC " using interface %s (pending_action_tx=%p)",
145 MAC2STR_SEC(wpa_s->pending_action_dst), iface->ifname,
146 wpa_s->pending_action_tx);
147 res = wpa_drv_send_action(iface, wpa_s->pending_action_freq, 0,
148 wpa_s->pending_action_dst,
149 wpa_s->pending_action_src,
150 wpa_s->pending_action_bssid,
151 wpabuf_head(wpa_s->pending_action_tx),
152 wpabuf_len(wpa_s->pending_action_tx),
153 wpa_s->pending_action_no_cck);
154 if (res) {
155 wpa_printf(MSG_DEBUG, "Off-channel: Failed to send the "
156 "pending Action frame");
157 /*
158 * Use fake TX status event to allow state machines to
159 * continue.
160 */
161 offchannel_send_action_tx_status(
162 wpa_s, wpa_s->pending_action_dst,
163 wpabuf_head(wpa_s->pending_action_tx),
164 wpabuf_len(wpa_s->pending_action_tx),
165 OFFCHANNEL_SEND_ACTION_FAILED);
166 }
167 }
168
169
170 /**
171 * offchannel_send_action_tx_status - TX status callback
172 * @wpa_s: Pointer to wpa_supplicant data
173 * @dst: Destination MAC address of the transmitted Action frame
174 * @data: Transmitted frame payload
175 * @data_len: Length of @data in bytes
176 * @result: TX status
177 *
178 * This function is called whenever the driver indicates a TX status event for
179 * a frame sent by offchannel_send_action() using wpa_drv_send_action().
180 */
offchannel_send_action_tx_status(struct wpa_supplicant * wpa_s,const u8 * dst,const u8 * data,size_t data_len,enum offchannel_send_action_result result)181 void offchannel_send_action_tx_status(
182 struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data,
183 size_t data_len, enum offchannel_send_action_result result)
184 {
185 if (wpa_s->pending_action_tx == NULL) {
186 wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
187 "no pending operation");
188 return;
189 }
190
191 if (os_memcmp(dst, wpa_s->pending_action_dst, ETH_ALEN) != 0) {
192 wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
193 "unknown destination address");
194 return;
195 }
196
197 /* Accept report only if the contents of the frame matches */
198 if (data_len - wpabuf_len(wpa_s->pending_action_tx) != 24 ||
199 os_memcmp(data + 24, wpabuf_head(wpa_s->pending_action_tx),
200 wpabuf_len(wpa_s->pending_action_tx)) != 0) {
201 wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
202 "mismatching contents with pending frame");
203 wpa_hexdump(MSG_MSGDUMP, "TX status frame data",
204 data, data_len);
205 wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame",
206 wpa_s->pending_action_tx);
207 return;
208 }
209
210 wpa_printf(MSG_EXCESSIVE,
211 "Off-channel: Delete matching pending action frame (dst="
212 MACSTR_SEC " pending_action_tx=%p)", MAC2STR_SEC(dst),
213 wpa_s->pending_action_tx);
214 wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame",
215 wpa_s->pending_action_tx);
216 wpabuf_free(wpa_s->pending_action_tx);
217 wpa_s->pending_action_tx = NULL;
218
219 wpa_printf(MSG_EXCESSIVE, "Off-channel: TX status result=%d cb=%p",
220 result, wpa_s->pending_action_tx_status_cb);
221
222 if (wpa_s->pending_action_tx_status_cb) {
223 wpa_s->pending_action_tx_status_cb(
224 wpa_s, wpa_s->pending_action_freq,
225 wpa_s->pending_action_dst, wpa_s->pending_action_src,
226 wpa_s->pending_action_bssid,
227 data, data_len, result);
228 }
229
230 #ifdef CONFIG_P2P
231 if (wpa_s->global->p2p_long_listen > 0) {
232 /* Continue the listen */
233 wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state");
234 wpas_p2p_listen_start(wpa_s, wpa_s->global->p2p_long_listen);
235 }
236 #endif /* CONFIG_P2P */
237 }
238
239
240 /**
241 * offchannel_send_action - Request off-channel Action frame TX
242 * @wpa_s: Pointer to wpa_supplicant data
243 * @freq: The frequency in MHz indicating the channel on which the frame is to
244 * transmitted or 0 for the current channel (only if associated)
245 * @dst: Action frame destination MAC address
246 * @src: Action frame source MAC address
247 * @bssid: Action frame BSSID
248 * @buf: Frame to transmit starting from the Category field
249 * @len: Length of @buf in bytes
250 * @wait_time: Wait time for response in milliseconds
251 * @tx_cb: Callback function for indicating TX status or %NULL for no callback
252 * @no_cck: Whether CCK rates are to be disallowed for TX rate selection
253 * Returns: 0 on success or -1 on failure
254 *
255 * This function is used to request an Action frame to be transmitted on the
256 * current operating channel or on another channel (off-channel). The actual
257 * frame transmission will be delayed until the driver is ready on the specified
258 * channel. The @wait_time parameter can be used to request the driver to remain
259 * awake on the channel to wait for a response.
260 */
offchannel_send_action(struct wpa_supplicant * wpa_s,unsigned int freq,const u8 * dst,const u8 * src,const u8 * bssid,const u8 * buf,size_t len,unsigned int wait_time,void (* tx_cb)(struct wpa_supplicant * wpa_s,unsigned int freq,const u8 * dst,const u8 * src,const u8 * bssid,const u8 * data,size_t data_len,enum offchannel_send_action_result result),int no_cck)261 int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
262 const u8 *dst, const u8 *src, const u8 *bssid,
263 const u8 *buf, size_t len, unsigned int wait_time,
264 void (*tx_cb)(struct wpa_supplicant *wpa_s,
265 unsigned int freq, const u8 *dst,
266 const u8 *src, const u8 *bssid,
267 const u8 *data, size_t data_len,
268 enum offchannel_send_action_result
269 result),
270 int no_cck)
271 {
272 wpa_printf(MSG_DEBUG, "Off-channel: Send action frame: freq=%d dst="
273 MACSTR_SEC " src=" MACSTR_SEC " bssid=" MACSTR_SEC " len=%d",
274 freq, MAC2STR_SEC(dst), MAC2STR_SEC(src), MAC2STR_SEC(bssid),
275 (int) len);
276
277 wpa_s->pending_action_tx_status_cb = tx_cb;
278
279 if (wpa_s->pending_action_tx) {
280 wpa_printf(MSG_DEBUG, "Off-channel: Dropped pending Action "
281 "frame TX to " MACSTR_SEC " (pending_action_tx=%p)",
282 MAC2STR_SEC(wpa_s->pending_action_dst),
283 wpa_s->pending_action_tx);
284 wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame",
285 wpa_s->pending_action_tx);
286 wpabuf_free(wpa_s->pending_action_tx);
287 }
288 wpa_s->pending_action_tx_done = 0;
289 wpa_s->pending_action_tx = wpabuf_alloc(len);
290 if (wpa_s->pending_action_tx == NULL) {
291 wpa_printf(MSG_DEBUG, "Off-channel: Failed to allocate Action "
292 "frame TX buffer (len=%llu)",
293 (unsigned long long) len);
294 return -1;
295 }
296 wpabuf_put_data(wpa_s->pending_action_tx, buf, len);
297 os_memcpy(wpa_s->pending_action_src, src, ETH_ALEN);
298 os_memcpy(wpa_s->pending_action_dst, dst, ETH_ALEN);
299 os_memcpy(wpa_s->pending_action_bssid, bssid, ETH_ALEN);
300 wpa_s->pending_action_freq = freq;
301 wpa_s->pending_action_no_cck = no_cck;
302 wpa_printf(MSG_EXCESSIVE,
303 "Off-channel: Stored pending action frame (dst=" MACSTR_SEC
304 " pending_action_tx=%p)",
305 MAC2STR_SEC(dst), wpa_s->pending_action_tx);
306 wpa_hexdump_buf(MSG_MSGDUMP, "Pending TX frame",
307 wpa_s->pending_action_tx);
308
309 if (freq != 0 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
310 struct wpa_supplicant *iface;
311 int ret;
312
313 iface = wpas_get_tx_interface(wpa_s, src);
314 wpa_s->action_tx_wait_time = wait_time;
315 if (wait_time)
316 wpa_s->action_tx_wait_time_used = 1;
317
318 ret = wpa_drv_send_action(
319 iface, wpa_s->pending_action_freq,
320 wait_time, wpa_s->pending_action_dst,
321 wpa_s->pending_action_src, wpa_s->pending_action_bssid,
322 wpabuf_head(wpa_s->pending_action_tx),
323 wpabuf_len(wpa_s->pending_action_tx),
324 wpa_s->pending_action_no_cck);
325 if (ret == 0)
326 wpa_s->pending_action_tx_done = 1;
327 return ret;
328 }
329
330 if (freq) {
331 struct wpa_supplicant *tx_iface;
332 tx_iface = wpas_get_tx_interface(wpa_s, src);
333 if (tx_iface->assoc_freq == freq) {
334 wpa_printf(MSG_DEBUG, "Off-channel: Already on "
335 "requested channel (TX interface operating "
336 "channel)");
337 freq = 0;
338 }
339 }
340
341 if (wpa_s->off_channel_freq == freq || freq == 0) {
342 wpa_printf(MSG_DEBUG, "Off-channel: Already on requested "
343 "channel; send Action frame immediately");
344 /* TODO: Would there ever be need to extend the current
345 * duration on the channel? */
346 wpa_s->pending_action_without_roc = 1;
347 eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
348 eloop_register_timeout(0, 0, wpas_send_action_cb, wpa_s, NULL);
349 return 0;
350 }
351 wpa_s->pending_action_without_roc = 0;
352
353 if (wpa_s->roc_waiting_drv_freq == freq) {
354 wpa_printf(MSG_DEBUG, "Off-channel: Already waiting for "
355 "driver to get to frequency %u MHz; continue "
356 "waiting to send the Action frame", freq);
357 return 0;
358 }
359
360 wpa_printf(MSG_DEBUG, "Off-channel: Schedule Action frame to be "
361 "transmitted once the driver gets to the requested "
362 "channel");
363 if (wait_time > wpa_s->max_remain_on_chan)
364 wait_time = wpa_s->max_remain_on_chan;
365 else if (wait_time == 0)
366 wait_time = 20;
367 #ifdef CONFIG_TESTING_OPTIONS
368 if (wpa_s->extra_roc_dur) {
369 wpa_printf(MSG_DEBUG, "TESTING: Increase ROC duration %u -> %u",
370 wait_time, wait_time + wpa_s->extra_roc_dur);
371 wait_time += wpa_s->extra_roc_dur;
372 }
373 #endif /* CONFIG_TESTING_OPTIONS */
374 if (wpa_drv_remain_on_channel(wpa_s, freq, wait_time) < 0) {
375 wpa_printf(MSG_DEBUG, "Off-channel: Failed to request driver "
376 "to remain on channel (%u MHz) for Action "
377 "Frame TX", freq);
378 return -1;
379 }
380 wpa_s->off_channel_freq = 0;
381 wpa_s->roc_waiting_drv_freq = freq;
382
383 return 0;
384 }
385
386
387 /**
388 * offchannel_send_send_action_done - Notify completion of Action frame sequence
389 * @wpa_s: Pointer to wpa_supplicant data
390 *
391 * This function can be used to cancel a wait for additional response frames on
392 * the channel that was used with offchannel_send_action().
393 */
offchannel_send_action_done(struct wpa_supplicant * wpa_s)394 void offchannel_send_action_done(struct wpa_supplicant *wpa_s)
395 {
396 wpa_printf(MSG_EXCESSIVE,
397 "Off-channel: Action frame sequence done notification: pending_action_tx=%p drv_offchan_tx=%d action_tx_wait_time=%d off_channel_freq=%d roc_waiting_drv_freq=%d",
398 wpa_s->pending_action_tx,
399 !!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX),
400 wpa_s->action_tx_wait_time, wpa_s->off_channel_freq,
401 wpa_s->roc_waiting_drv_freq);
402 wpabuf_free(wpa_s->pending_action_tx);
403 wpa_s->pending_action_tx = NULL;
404 if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX &&
405 (wpa_s->action_tx_wait_time || wpa_s->action_tx_wait_time_used))
406 wpa_drv_send_action_cancel_wait(wpa_s);
407 else if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
408 wpa_drv_cancel_remain_on_channel(wpa_s);
409 wpa_s->off_channel_freq = 0;
410 wpa_s->roc_waiting_drv_freq = 0;
411 }
412 wpa_s->action_tx_wait_time_used = 0;
413 }
414
415
416 /**
417 * offchannel_remain_on_channel_cb - Remain-on-channel callback function
418 * @wpa_s: Pointer to wpa_supplicant data
419 * @freq: Frequency (in MHz) of the selected channel
420 * @duration: Duration of the remain-on-channel operation in milliseconds
421 *
422 * This function is called whenever the driver notifies beginning of a
423 * remain-on-channel operation.
424 */
offchannel_remain_on_channel_cb(struct wpa_supplicant * wpa_s,unsigned int freq,unsigned int duration)425 void offchannel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
426 unsigned int freq, unsigned int duration)
427 {
428 wpa_s->roc_waiting_drv_freq = 0;
429 wpa_s->off_channel_freq = freq;
430 wpas_send_action_cb(wpa_s, NULL);
431 }
432
433
434 /**
435 * offchannel_cancel_remain_on_channel_cb - Remain-on-channel stopped callback
436 * @wpa_s: Pointer to wpa_supplicant data
437 * @freq: Frequency (in MHz) of the selected channel
438 *
439 * This function is called whenever the driver notifies termination of a
440 * remain-on-channel operation.
441 */
offchannel_cancel_remain_on_channel_cb(struct wpa_supplicant * wpa_s,unsigned int freq)442 void offchannel_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
443 unsigned int freq)
444 {
445 wpa_s->off_channel_freq = 0;
446 }
447
448
449 /**
450 * offchannel_pending_action_tx - Check whether there is a pending Action TX
451 * @wpa_s: Pointer to wpa_supplicant data
452 * Returns: Pointer to pending frame or %NULL if no pending operation
453 *
454 * This function can be used to check whether there is a pending Action frame TX
455 * operation. The returned pointer should be used only for checking whether it
456 * is %NULL (no pending frame) or to print the pointer value in debug
457 * information (i.e., the pointer should not be dereferenced).
458 */
offchannel_pending_action_tx(struct wpa_supplicant * wpa_s)459 const void * offchannel_pending_action_tx(struct wpa_supplicant *wpa_s)
460 {
461 return wpa_s->pending_action_tx;
462 }
463
464
465 /**
466 * offchannel_clear_pending_action_tx - Clear pending Action frame TX
467 * @wpa_s: Pointer to wpa_supplicant data
468 */
offchannel_clear_pending_action_tx(struct wpa_supplicant * wpa_s)469 void offchannel_clear_pending_action_tx(struct wpa_supplicant *wpa_s)
470 {
471 wpa_printf(MSG_DEBUG,
472 "Off-channel: Clear pending Action frame TX (pending_action_tx=%p",
473 wpa_s->pending_action_tx);
474 wpabuf_free(wpa_s->pending_action_tx);
475 wpa_s->pending_action_tx = NULL;
476 }
477
478
479 /**
480 * offchannel_deinit - Deinit off-channel operations
481 * @wpa_s: Pointer to wpa_supplicant data
482 *
483 * This function is used to free up any allocated resources for off-channel
484 * operations.
485 */
offchannel_deinit(struct wpa_supplicant * wpa_s)486 void offchannel_deinit(struct wpa_supplicant *wpa_s)
487 {
488 offchannel_clear_pending_action_tx(wpa_s);
489 eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
490 }
491