* operation does not end up getting completed successfully later.
*/
#define WPA_DRIVER_FLAGS_SANE_ERROR_CODES 0x00004000
+/* Driver supports off-channel TX */
+#define WPA_DRIVER_FLAGS_OFFCHANNEL_TX 0x00008000
unsigned int flags;
int max_scan_ssids;
* send_action - Transmit an Action frame
* @priv: Private driver interface data
* @freq: Frequency (in MHz) of the channel
+ * @wait: Time to wait off-channel for a response (in ms), or zero
* @dst: Destination MAC address (Address 1)
* @src: Source MAC address (Address 2)
* @bssid: BSSID (Address 3)
* Returns: 0 on success, -1 on failure
*
* This command can be used to request the driver to transmit an action
- * frame to the specified destination. If a remain-on-channel duration
- * is in progress, the frame is transmitted on that channel. Otherwise,
- * the frame is transmitted on the current operational channel if in
- * associated state in station mode or if operating as an AP. If none
- * of these conditions is in effect, send_action() cannot be used.
+ * frame to the specified destination.
+ *
+ * If the %WPA_DRIVER_FLAGS_OFFCHANNEL_TX flag is set, the frame will
+ * be transmitted on the given channel and the device will wait for a
+ * response on that channel for the given wait time.
+ *
+ * If the flag is not set, the wait time will be ignored. In this case,
+ * if a remain-on-channel duration is in progress, the frame must be
+ * transmitted on that channel; alternatively the frame may be sent on
+ * the current operational channel (if in associated state in station
+ * mode or while operating as an AP.)
*/
- int (*send_action)(void *priv, unsigned int freq,
+ int (*send_action)(void *priv, unsigned int freq, unsigned int wait,
const u8 *dst, const u8 *src, const u8 *bssid,
const u8 *data, size_t data_len);
/**
+ * send_action_cancel_wait - Cancel action frame TX wait
+ * @priv: Private driver interface data
+ *
+ * This command cancels the wait time associated with sending an action
+ * frame. It is only available when %WPA_DRIVER_FLAGS_OFFCHANNEL_TX is
+ * set in the driver flags.
+ */
+ void (*send_action_cancel_wait)(void *priv);
+
+ /**
* remain_on_channel - Remain awake on a channel
* @priv: Private driver interface data
* @freq: Frequency (in MHz) of the channel
NULL /* set_supp_port */,
NULL /* set_wds_sta */,
NULL /* send_action */,
+ NULL /* send_action_cancel_wait */,
NULL /* remain_on_channel */,
NULL /* cancel_remain_on_channel */,
NULL /* probe_req_report */,
static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
+ unsigned int wait_time,
const u8 *dst, const u8 *src,
const u8 *bssid,
const u8 *data, size_t data_len)
pos += ETH_ALEN;
os_memcpy(pos, ies, ies_len);
- ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, drv->bssid,
- own_addr, drv->bssid,
+ ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, 0,
+ drv->bssid, own_addr, drv->bssid,
data, data_len);
os_free(data);
static int wpa_driver_test_send_action(void *priv, unsigned int freq,
+ unsigned int wait,
const u8 *dst, const u8 *src,
const u8 *bssid,
const u8 *data, size_t data_len)
static inline int wpa_drv_send_action(struct wpa_supplicant *wpa_s,
unsigned int freq,
+ unsigned int wait,
const u8 *dst, const u8 *src,
const u8 *bssid,
const u8 *data, size_t data_len)
{
if (wpa_s->driver->send_action)
return wpa_s->driver->send_action(wpa_s->drv_priv, freq,
- dst, src, bssid, data,
- data_len);
+ wait, dst, src, bssid,
+ data, data_len);
return -1;
}
+static inline void wpa_drv_send_action_cancel_wait(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->driver->send_action_cancel_wait)
+ wpa_s->driver->send_action_cancel_wait(wpa_s->drv_priv);
+}
+
static inline int wpa_drv_set_freq(struct wpa_supplicant *wpa_s,
struct hostapd_freq_params *freq)
{
wpa_printf(MSG_DEBUG, "P2P: Sending pending Action frame to "
MACSTR " using interface %s",
MAC2STR(wpa_s->pending_action_dst), iface->ifname);
- res = wpa_drv_send_action(iface, wpa_s->pending_action_freq,
+ res = wpa_drv_send_action(iface, wpa_s->pending_action_freq, 0,
wpa_s->pending_action_dst,
wpa_s->pending_action_src,
wpa_s->pending_action_bssid,
os_memcpy(wpa_s->pending_action_bssid, bssid, ETH_ALEN);
wpa_s->pending_action_freq = freq;
+ if (freq != 0 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
+ struct wpa_supplicant *iface;
+
+ iface = wpas_get_tx_interface(wpa_s, wpa_s->pending_action_src);
+ wpa_s->action_tx_wait_time = wait_time;
+
+ return wpa_drv_send_action(iface, wpa_s->pending_action_freq,
+ wait_time, wpa_s->pending_action_dst,
+ wpa_s->pending_action_src,
+ wpa_s->pending_action_bssid,
+ wpabuf_head(wpa_s->pending_action_tx),
+ wpabuf_len(wpa_s->pending_action_tx));
+ }
+
if (freq) {
struct wpa_supplicant *tx_iface;
tx_iface = wpas_get_tx_interface(wpa_s, src);
wpa_printf(MSG_DEBUG, "P2P: Action frame sequence done notification");
wpabuf_free(wpa_s->pending_action_tx);
wpa_s->pending_action_tx = NULL;
- if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
+ if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
+ if (wpa_s->action_tx_wait_time)
+ wpa_drv_send_action_cancel_wait(wpa_s);
+ wpa_s->off_channel_freq = 0;
+ } else if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
wpa_drv_cancel_remain_on_channel(wpa_s);
wpa_s->off_channel_freq = 0;
wpa_s->roc_waiting_drv_freq = 0;
req[0] = WLAN_ACTION_SA_QUERY;
req[1] = WLAN_SA_QUERY_REQUEST;
os_memcpy(req + 2, trans_id, WLAN_SA_QUERY_TR_ID_LEN);
- if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, wpa_s->bssid,
+ if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
wpa_s->own_addr, wpa_s->bssid,
req, sizeof(req)) < 0)
wpa_printf(MSG_INFO, "SME: Failed to send SA Query Request");
int pending_join_wps_method;
int p2p_join_scan_count;
unsigned int roc_waiting_drv_freq;
+ int action_tx_wait_time;
int force_long_sd;
/*