[PATCH] p2p: rely on kernel for offchannel TX
Johannes Berg
johannes
Thu Nov 25 01:02:15 PST 2010
From: Johannes Berg <johannes.berg at intel.com>
With the new kernel functionality 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 at intel.com>
---
NOTE: This depends on nl80211.h updates -- wasn't sure how you want to
handle these, I myself prefer not getting them in the same patch.
src/drivers/driver.h | 27 ++++++++++++++++---
src/drivers/driver_ndis.c | 1
src/drivers/driver_nl80211.c | 54 +++++++++++++++++++++++++++++++++-----
src/drivers/driver_test.c | 1
wpa_supplicant/driver_i.h | 11 ++++++-
wpa_supplicant/p2p_supplicant.c | 22 ++++++++++++++-
wpa_supplicant/wpa_supplicant_i.h | 1
7 files changed, 103 insertions(+), 14 deletions(-)
--- hostap.orig/src/drivers/driver.h 2010-11-24 16:34:52.000000000 +0100
+++ hostap/src/drivers/driver.h 2010-11-24 16:44:00.000000000 +0100
@@ -547,6 +547,8 @@ struct wpa_driver_capa {
#define WPA_DRIVER_FLAGS_P2P_CAPABLE 0x00000800
/* Driver supports concurrent operations on multiple channels */
#define WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT 0x00001000
+/* Driver supports off-channel TX */
+#define WPA_DRIVER_FLAGS_OFFCHANNEL_TX 0x00002000
unsigned int flags;
int max_scan_ssids;
@@ -1712,6 +1714,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)
@@ -1723,14 +1726,32 @@ struct wpa_driver_ops {
* 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.
+ * associated state in station mode or if operating as an AP. If the
+ * %WPA_DRIVER_FLAGS_OFFCHANNEL_TX is not set and none of these
+ * conditions is in effect, send_action() cannot be used. The wait time
+ * is completely ignored.
+ *
+ * If %WPA_DRIVER_FLAGS_OFFCHANNEL_TX is set, then this can be used
+ * even while remain-on-channel is not in progress, and the driver
+ * will handle will handle temporarily switching to the specified
+ * frequency to transmit the frame, waiting there for the specified
+ * wait time.
*/
- 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 wait associated with action frame TX
+ * @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
--- hostap.orig/src/drivers/driver_nl80211.c 2010-11-24 16:34:52.000000000 +0100
+++ hostap/src/drivers/driver_nl80211.c 2010-11-25 09:55:36.000000000 +0100
@@ -183,7 +183,8 @@ static int wpa_driver_nl80211_mlme(struc
static void nl80211_remove_monitor_interface(
struct wpa_driver_nl80211_data *drv);
static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv,
- unsigned int freq, const u8 *buf,
+ unsigned int freq, unsigned int wait,
+ const u8 *buf,
size_t buf_len, u64 *cookie);
static int wpa_driver_nl80211_probe_req_report(void *priv, int report);
@@ -1386,6 +1387,7 @@ struct wiphy_info_data {
int ap_supported;
int auth_supported;
int connect_supported;
+ int offchan_tx_supported;
};
@@ -1428,6 +1430,9 @@ static int wiphy_info_handler(struct nl_
}
}
+ if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK])
+ info->offchan_tx_supported = 1;
+
return NL_SKIP;
}
@@ -1487,6 +1492,9 @@ static int wpa_driver_nl80211_capa(struc
return -1;
}
+ if (info.offchan_tx_supported)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
+
drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
drv->capa.max_remain_on_chan = 5000;
@@ -3339,7 +3347,7 @@ static int wpa_driver_nl80211_send_mlme(
* but it works due to the single-threaded nature
* of wpa_supplicant.
*/
- return nl80211_send_frame_cmd(drv, drv->last_mgmt_freq,
+ return nl80211_send_frame_cmd(drv, drv->last_mgmt_freq, 0,
data, data_len, NULL);
}
@@ -5523,7 +5531,8 @@ static int cookie_handler(struct nl_msg
static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv,
- unsigned int freq, const u8 *buf,
+ unsigned int freq, unsigned int wait,
+ const u8 *buf,
size_t buf_len, u64 *cookie_out)
{
struct nl_msg *msg;
@@ -5539,6 +5548,8 @@ static int nl80211_send_frame_cmd(struct
NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+ NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
+ NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
NLA_PUT(msg, NL80211_ATTR_FRAME, buf_len, buf);
cookie = 0;
@@ -5562,6 +5573,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)
@@ -5572,8 +5584,8 @@ static int wpa_driver_nl80211_send_actio
u8 *buf;
struct ieee80211_hdr *hdr;
- wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d)",
- drv->ifindex);
+ wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, wait=%dms)",
+ drv->ifindex, wait_time);
buf = os_zalloc(24 + data_len);
if (buf == NULL)
@@ -5589,13 +5601,39 @@ static int wpa_driver_nl80211_send_actio
if (drv->nlmode == NL80211_IFTYPE_AP)
ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len);
else
- ret = nl80211_send_frame_cmd(drv, freq, buf, 24 + data_len,
+ ret = nl80211_send_frame_cmd(drv, freq, wait_time, buf, 24 + data_len,
&drv->send_action_cookie);
os_free(buf);
return ret;
}
+static void wpa_driver_nl80211_send_action_cancel_wait(void *priv)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_FRAME_WAIT_CANCEL, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+
+ nla_put_failure:
+ nlmsg_free(msg);
+}
static int wpa_driver_nl80211_remain_on_channel(void *priv, unsigned int freq,
unsigned int duration)
@@ -5873,7 +5911,8 @@ static int nl80211_send_ft_action(void *
pos += ETH_ALEN;
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,
+ drv->bssid,
own_addr, drv->bssid,
data, data_len);
os_free(data);
@@ -6000,6 +6039,7 @@ const struct wpa_driver_ops wpa_driver_n
#endif /* HOSTAPD */
.set_freq = i802_set_freq,
.send_action = wpa_driver_nl80211_send_action,
+ .send_action_cancel_wait = wpa_driver_nl80211_send_action_cancel_wait,
.remain_on_channel = wpa_driver_nl80211_remain_on_channel,
.cancel_remain_on_channel =
wpa_driver_nl80211_cancel_remain_on_channel,
--- hostap.orig/wpa_supplicant/driver_i.h 2010-11-24 16:34:52.000000000 +0100
+++ hostap/wpa_supplicant/driver_i.h 2010-11-24 16:34:54.000000000 +0100
@@ -383,17 +383,24 @@ static inline int wpa_drv_set_supp_port(
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)
{
--- hostap.orig/src/drivers/driver_test.c 2010-11-24 16:34:52.000000000 +0100
+++ hostap/src/drivers/driver_test.c 2010-11-24 16:34:54.000000000 +0100
@@ -2598,6 +2598,7 @@ static int wpa_driver_test_set_freq(void
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)
--- hostap.orig/src/drivers/driver_ndis.c 2010-11-24 16:34:52.000000000 +0100
+++ hostap/src/drivers/driver_ndis.c 2010-11-24 16:34:54.000000000 +0100
@@ -3295,6 +3295,7 @@ const struct wpa_driver_ops wpa_driver_n
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 */,
--- hostap.orig/wpa_supplicant/p2p_supplicant.c 2010-11-24 16:34:52.000000000 +0100
+++ hostap/wpa_supplicant/p2p_supplicant.c 2010-11-24 16:34:54.000000000 +0100
@@ -614,7 +614,7 @@ static void wpas_send_action_cb(void *el
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, u
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 *
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;
--- hostap.orig/wpa_supplicant/wpa_supplicant_i.h 2010-11-24 16:34:52.000000000 +0100
+++ hostap/wpa_supplicant/wpa_supplicant_i.h 2010-11-24 16:34:54.000000000 +0100
@@ -494,6 +494,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;
/*
More information about the Hostap
mailing list