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:
Johannes Berg 2010-12-29 13:59:17 +02:00 committed by Jouni Malinen
parent 0d7e5a3a29
commit 190b9062b2
8 changed files with 61 additions and 13 deletions

View file

@ -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

View file

@ -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 */,

View file

@ -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);

View file

@ -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)

View file

@ -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)
{ {

View file

@ -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;

View file

@ -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");

View file

@ -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;
/* /*