• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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