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.
|
* operation does not end up getting completed successfully later.
|
||||||
*/
|
*/
|
||||||
#define WPA_DRIVER_FLAGS_SANE_ERROR_CODES 0x00004000
|
#define WPA_DRIVER_FLAGS_SANE_ERROR_CODES 0x00004000
|
||||||
|
/* Driver supports off-channel TX */
|
||||||
|
#define WPA_DRIVER_FLAGS_OFFCHANNEL_TX 0x00008000
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
|
|
||||||
int max_scan_ssids;
|
int max_scan_ssids;
|
||||||
|
@ -1724,6 +1726,7 @@ struct wpa_driver_ops {
|
||||||
* send_action - Transmit an Action frame
|
* send_action - Transmit an Action frame
|
||||||
* @priv: Private driver interface data
|
* @priv: Private driver interface data
|
||||||
* @freq: Frequency (in MHz) of the channel
|
* @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)
|
* @dst: Destination MAC address (Address 1)
|
||||||
* @src: Source MAC address (Address 2)
|
* @src: Source MAC address (Address 2)
|
||||||
* @bssid: BSSID (Address 3)
|
* @bssid: BSSID (Address 3)
|
||||||
|
@ -1732,16 +1735,32 @@ struct wpa_driver_ops {
|
||||||
* Returns: 0 on success, -1 on failure
|
* Returns: 0 on success, -1 on failure
|
||||||
*
|
*
|
||||||
* This command can be used to request the driver to transmit an action
|
* This command can be used to request the driver to transmit an action
|
||||||
* frame to the specified destination. If a remain-on-channel duration
|
* frame to the specified destination.
|
||||||
* is in progress, the frame is transmitted on that channel. Otherwise,
|
*
|
||||||
* the frame is transmitted on the current operational channel if in
|
* If the %WPA_DRIVER_FLAGS_OFFCHANNEL_TX flag is set, the frame will
|
||||||
* associated state in station mode or if operating as an AP. If none
|
* be transmitted on the given channel and the device will wait for a
|
||||||
* of these conditions is in effect, send_action() cannot be used.
|
* 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 *dst, const u8 *src, const u8 *bssid,
|
||||||
const u8 *data, size_t data_len);
|
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
|
* remain_on_channel - Remain awake on a channel
|
||||||
* @priv: Private driver interface data
|
* @priv: Private driver interface data
|
||||||
|
|
|
@ -3295,6 +3295,7 @@ const struct wpa_driver_ops wpa_driver_ndis_ops = {
|
||||||
NULL /* set_supp_port */,
|
NULL /* set_supp_port */,
|
||||||
NULL /* set_wds_sta */,
|
NULL /* set_wds_sta */,
|
||||||
NULL /* send_action */,
|
NULL /* send_action */,
|
||||||
|
NULL /* send_action_cancel_wait */,
|
||||||
NULL /* remain_on_channel */,
|
NULL /* remain_on_channel */,
|
||||||
NULL /* cancel_remain_on_channel */,
|
NULL /* cancel_remain_on_channel */,
|
||||||
NULL /* probe_req_report */,
|
NULL /* probe_req_report */,
|
||||||
|
|
|
@ -5835,6 +5835,7 @@ nla_put_failure:
|
||||||
|
|
||||||
|
|
||||||
static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
|
static int wpa_driver_nl80211_send_action(void *priv, unsigned int freq,
|
||||||
|
unsigned int wait_time,
|
||||||
const u8 *dst, const u8 *src,
|
const u8 *dst, const u8 *src,
|
||||||
const u8 *bssid,
|
const u8 *bssid,
|
||||||
const u8 *data, size_t data_len)
|
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;
|
pos += ETH_ALEN;
|
||||||
os_memcpy(pos, ies, ies_len);
|
os_memcpy(pos, ies, ies_len);
|
||||||
|
|
||||||
ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, drv->bssid,
|
ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, 0,
|
||||||
own_addr, drv->bssid,
|
drv->bssid, own_addr, drv->bssid,
|
||||||
data, data_len);
|
data, data_len);
|
||||||
os_free(data);
|
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,
|
static int wpa_driver_test_send_action(void *priv, unsigned int freq,
|
||||||
|
unsigned int wait,
|
||||||
const u8 *dst, const u8 *src,
|
const u8 *dst, const u8 *src,
|
||||||
const u8 *bssid,
|
const u8 *bssid,
|
||||||
const u8 *data, size_t data_len)
|
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,
|
static inline int wpa_drv_send_action(struct wpa_supplicant *wpa_s,
|
||||||
unsigned int freq,
|
unsigned int freq,
|
||||||
|
unsigned int wait,
|
||||||
const u8 *dst, const u8 *src,
|
const u8 *dst, const u8 *src,
|
||||||
const u8 *bssid,
|
const u8 *bssid,
|
||||||
const u8 *data, size_t data_len)
|
const u8 *data, size_t data_len)
|
||||||
{
|
{
|
||||||
if (wpa_s->driver->send_action)
|
if (wpa_s->driver->send_action)
|
||||||
return wpa_s->driver->send_action(wpa_s->drv_priv, freq,
|
return wpa_s->driver->send_action(wpa_s->drv_priv, freq,
|
||||||
dst, src, bssid, data,
|
wait, dst, src, bssid,
|
||||||
data_len);
|
data, data_len);
|
||||||
return -1;
|
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,
|
static inline int wpa_drv_set_freq(struct wpa_supplicant *wpa_s,
|
||||||
struct hostapd_freq_params *freq)
|
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 "
|
wpa_printf(MSG_DEBUG, "P2P: Sending pending Action frame to "
|
||||||
MACSTR " using interface %s",
|
MACSTR " using interface %s",
|
||||||
MAC2STR(wpa_s->pending_action_dst), iface->ifname);
|
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_dst,
|
||||||
wpa_s->pending_action_src,
|
wpa_s->pending_action_src,
|
||||||
wpa_s->pending_action_bssid,
|
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);
|
os_memcpy(wpa_s->pending_action_bssid, bssid, ETH_ALEN);
|
||||||
wpa_s->pending_action_freq = freq;
|
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) {
|
if (freq) {
|
||||||
struct wpa_supplicant *tx_iface;
|
struct wpa_supplicant *tx_iface;
|
||||||
tx_iface = wpas_get_tx_interface(wpa_s, src);
|
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");
|
wpa_printf(MSG_DEBUG, "P2P: Action frame sequence done notification");
|
||||||
wpabuf_free(wpa_s->pending_action_tx);
|
wpabuf_free(wpa_s->pending_action_tx);
|
||||||
wpa_s->pending_action_tx = NULL;
|
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_drv_cancel_remain_on_channel(wpa_s);
|
||||||
wpa_s->off_channel_freq = 0;
|
wpa_s->off_channel_freq = 0;
|
||||||
wpa_s->roc_waiting_drv_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[0] = WLAN_ACTION_SA_QUERY;
|
||||||
req[1] = WLAN_SA_QUERY_REQUEST;
|
req[1] = WLAN_SA_QUERY_REQUEST;
|
||||||
os_memcpy(req + 2, trans_id, WLAN_SA_QUERY_TR_ID_LEN);
|
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,
|
wpa_s->own_addr, wpa_s->bssid,
|
||||||
req, sizeof(req)) < 0)
|
req, sizeof(req)) < 0)
|
||||||
wpa_printf(MSG_INFO, "SME: Failed to send SA Query Request");
|
wpa_printf(MSG_INFO, "SME: Failed to send SA Query Request");
|
||||||
|
|
|
@ -503,6 +503,7 @@ struct wpa_supplicant {
|
||||||
int pending_join_wps_method;
|
int pending_join_wps_method;
|
||||||
int p2p_join_scan_count;
|
int p2p_join_scan_count;
|
||||||
unsigned int roc_waiting_drv_freq;
|
unsigned int roc_waiting_drv_freq;
|
||||||
|
int action_tx_wait_time;
|
||||||
int force_long_sd;
|
int force_long_sd;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue