P2P: Add option for offloading off-channel TX to the driver
With the new kernel functionality coming to Linux to allow off-channel TX, we can take advantage of that in the P2P code that currently uses remain-on-channel. If a driver advertises support for it, it will be asked to handle off-channel TX by itself. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
0d7e5a3a29
commit
190b9062b2
8 changed files with 61 additions and 13 deletions
|
@ -559,6 +559,8 @@ struct wpa_driver_capa {
|
|||
* 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;
|
||||
|
@ -1724,6 +1726,7 @@ struct wpa_driver_ops {
|
|||
* 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)
|
||||
|
@ -1732,16 +1735,32 @@ struct wpa_driver_ops {
|
|||
* 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
|
||||
|
|
|
@ -3295,6 +3295,7 @@ const struct wpa_driver_ops wpa_driver_ndis_ops = {
|
|||
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 */,
|
||||
|
|
|
@ -5835,6 +5835,7 @@ nla_put_failure:
|
|||
|
||||
|
||||
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)
|
||||
|
@ -6146,8 +6147,8 @@ static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap,
|
|||
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);
|
||||
|
||||
|
|
|
@ -2598,6 +2598,7 @@ static int wpa_driver_test_set_freq(void *priv,
|
|||
|
||||
|
||||
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)
|
||||
|
|
|
@ -383,17 +383,24 @@ static inline int wpa_drv_set_supp_port(struct wpa_supplicant *wpa_s,
|
|||
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -614,7 +614,7 @@ static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
|
|||
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,
|
||||
|
@ -705,6 +705,20 @@ static int wpas_send_action(void *ctx, unsigned int freq, const u8 *dst,
|
|||
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);
|
||||
|
@ -757,7 +771,11 @@ static void wpas_send_action_done(void *ctx)
|
|||
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;
|
||||
|
|
|
@ -538,7 +538,7 @@ static void sme_send_sa_query_req(struct wpa_supplicant *wpa_s,
|
|||
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");
|
||||
|
|
|
@ -503,6 +503,7 @@ struct wpa_supplicant {
|
|||
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;
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue