[PATCH v2] p2p: rely on kernel for offchannel TX

Johannes Berg johannes at sipsolutions.net
Thu Nov 25 04:43:31 EST 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>
---
v2 just changes the driver callback docs

 src/drivers/driver.h              |   31 +++++++++++++++++----
 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, 104 insertions(+), 17 deletions(-)

--- hostap.orig/src/drivers/driver.h	2010-11-24 16:34:52.000000000 +0100
+++ hostap/src/drivers/driver.h	2010-11-25 10:37:32.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)
@@ -1720,17 +1723,33 @@ 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 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