Skip to contentSkip to conversation

get rid of AP mode monitor interfaces

RFC In review Johannes Berg 5 participants 31 messages Oct 21, 2011 – Oct 29, 2011

Subsystems (15)
Networking Arm (32-bit) PowerPC MIPS +11 more subsystems
lore
Share & tools
lore

Johannes Berg

author maintainer
#0 lore raw

v2 cover get rid of AP mode monitor interfaces

Here's a resend, now with OBSS beacon receive that allows implementing the right protection logic in hostapd.

As far as I can tell, this is complete. Separate hostapd/wpa_s patchset will be on the way shortly.

johannes

author maintainer
#1 lore raw

RFC v2 1/12 mac80211: add helper to free TX skb

From: Johannes Berg <[email protected]>

Drivers that need to drop a frame before it can be transmitted will usually simply free that frame. This is currently fine, but in the future it'll be needed to tell mac80211 about this case, so add a new routine that frees a TX skb.

---
 include/net/mac80211.h |   10 ++++++++++
 net/mac80211/status.c  |    6 ++++++
 2 files changed, 16 insertions(+)
include/net/mac80211.h +10 -0
@@ -1304,6 +1304,16 @@ ieee80211_get_alt_retry_rate(const struc
 }
 
 /**
+ * ieee80211_free_txskb - free TX skb
+ * @hw: the hardware
+ * @skb: the skb
+ *
+ * Free a transmit skb. Use this funtion when some failure
+ * to transmit happened and thus status cannot be reported.
+ */
+void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
+
+/**
  * DOC: Hardware crypto acceleration
  *
  * mac80211 is capable of taking advantage of many hardware
net/mac80211/status.c +6 -0
@@ -609,3 +609,9 @@ void ieee80211_report_low_ack(struct iee
 				    num_packets, GFP_ATOMIC);
 }
 EXPORT_SYMBOL(ieee80211_report_low_ack);
+
+void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+	dev_kfree_skb_any(skb);
+}
+EXPORT_SYMBOL(ieee80211_free_txskb);
author maintainer
#2 lore raw

RFC v2 2/12 mac80211: add support for control port protocol in AP mode

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

This will allow us to support dynamic WEP with 802.1X properly in mac80211 by not encrypting outgoing and accepting unencrypted incoming frames.

---
 net/mac80211/cfg.c   |   21 ++++++++++++++++++++-
 net/mac80211/iface.c |   13 ++++++++++++-
 2 files changed, 32 insertions(+), 2 deletions(-)
net/mac80211/cfg.c +20 -1
@@ -594,6 +594,8 @@ static int ieee80211_add_beacon(struct w
 {
 	struct ieee80211_sub_if_data *sdata;
 	struct beacon_data *old;
+	struct ieee80211_sub_if_data *vlan;
+	int ret;
 
 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
@@ -601,7 +603,24 @@ static int ieee80211_add_beacon(struct w
 	if (old)
 		return -EALREADY;
 
-	return ieee80211_config_beacon(sdata, params);
+	ret = ieee80211_config_beacon(sdata, params);
+	if (ret)
+		return ret;
+
+	/*
+	 * Apply control port protocol, this allows us to
+	 * not encrypt dynamic WEP control frames.
+	 */
+	sdata->control_port_protocol = params->crypto.control_port_ethertype;
+	sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt;
+	list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
+		vlan->control_port_protocol =
+			params->crypto.control_port_ethertype;
+		vlan->control_port_no_encrypt =
+			params->crypto.control_port_no_encrypt;
+	}
+
+	return 0;
 }
 
 static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
net/mac80211/iface.c +12 -1
@@ -188,11 +188,22 @@ static int ieee80211_do_open(struct net_
 		if (!is_valid_ether_addr(sdata->u.wds.remote_addr))
 			return -ENOLINK;
 		break;
-	case NL80211_IFTYPE_AP_VLAN:
+	case NL80211_IFTYPE_AP_VLAN: {
+		struct ieee80211_sub_if_data *master;
+
 		if (!sdata->bss)
 			return -ENOLINK;
+
 		list_add(&sdata->u.vlan.list, &sdata->bss->vlans);
+
+		master = container_of(sdata->bss,
+				      struct ieee80211_sub_if_data, u.ap);
+		sdata->control_port_protocol =
+			master->control_port_protocol;
+		sdata->control_port_no_encrypt =
+			master->control_port_no_encrypt;
 		break;
+		}
 	case NL80211_IFTYPE_AP:
 		sdata->bss = &sdata->u.ap;
 		break;
author maintainer
#3 lore raw

RFC v2 3/12 nl80211: allow subscribing to unexpected class3 frames

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

To implement AP mode without monitor interfaces we need to be able to send a deauth to stations that send frames without being associated. Enable this by adding a new nl80211 event for such frames that an application can subscribe to.

---
 include/linux/nl80211.h |   13 +++++++++
 include/net/cfg80211.h  |   19 +++++++++++++
 net/wireless/mlme.c     |   16 +++++++++++
 net/wireless/nl80211.c  |   66 ++++++++++++++++++++++++++++++++++++++++++++++++
 net/wireless/nl80211.h  |    3 ++
 5 files changed, 117 insertions(+)
include/linux/nl80211.h +13 -0
@@ -509,6 +509,17 @@
  * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup).
  * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
  *
+ * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP
+ *	(or GO) interface (i.e. hostapd) to ask for unexpected frames to
+ *	implement sending deauth to stations that send unexpected class 3
+ *	frames. Also used as the event sent by the kernel when such a frame
+ *	is received. When 4 address mode is supported, it may also be used
+ *	to notify the AP controller about those frames.
+ *	For the event, the %NL80211_ATTR_MAC attribute carries TA along
+ *	with more information like the interface index.
+ *	If used as the command, must have an interface index, and you can
+ *	only unsubscribe from the event by closing the socket.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -638,6 +649,8 @@ enum nl80211_commands {
 	NL80211_CMD_TDLS_OPER,
 	NL80211_CMD_TDLS_MGMT,
 
+	NL80211_CMD_UNEXPECTED_FRAME,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
include/net/cfg80211.h +19 -0
@@ -2179,6 +2179,8 @@ struct wireless_dev {
 
 	int beacon_interval;
 
+	u32 ap_unexpected_nlpid;
+
 #ifdef CONFIG_CFG80211_WEXT
 	/* wext data */
 	struct {
@@ -3185,6 +3187,23 @@ void cfg80211_gtk_rekey_notify(struct ne
 void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
 				     const u8 *bssid, bool preauth, gfp_t gfp);
 
+/**
+ * cfg80211_rx_spurious_frame - inform userspace about a spurious frame
+ * @dev: The device the frame matched to
+ * @addr: the transmitter address
+ * @gfp: context flags
+ *
+ * This function is used in AP mode (only!) to inform userspace that
+ * a spurious class 3 frame was received, to be able to deauth the
+ * sender. If 4addr frames are supported in AP mode, these may also
+ * be passed here if they aren't yet allowed for the sender so that
+ * the userspace application can set up things properly.
+ * Returns %true if the frame was passed to userspace (or this failed
+ * for a reason other than not having a subscription.)
+ */
+bool cfg80211_rx_spurious_frame(struct net_device *dev,
+				const u8 *addr, gfp_t gfp);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
net/wireless/mlme.c +16 -0
@@ -879,6 +879,9 @@ void cfg80211_mlme_unregister_socket(str
 	}
 
 	spin_unlock_bh(&wdev->mgmt_registrations_lock);
+
+	if (nlpid == wdev->ap_unexpected_nlpid)
+		wdev->ap_unexpected_nlpid = 0;
 }
 
 void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
@@ -1107,3 +1110,16 @@ void cfg80211_pmksa_candidate_notify(str
 	nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
 }
 EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
+
+bool cfg80211_rx_spurious_frame(struct net_device *dev,
+				const u8 *addr, gfp_t gfp)
+{
+	struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+	if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
+		    wdev->iftype != NL80211_IFTYPE_P2P_GO))
+		return false;
+
+	return nl80211_unexpected_frame(dev, addr, gfp);
+}
+EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
net/wireless/nl80211.c +66 -0

84 lines not on this page · raw message

net/wireless/nl80211.h +3 -0
@@ -117,4 +117,7 @@ void nl80211_pmksa_candidate_notify(stru
 				    struct net_device *netdev, int index,
 				    const u8 *bssid, bool preauth, gfp_t gfp);
 
+bool nl80211_unexpected_frame(struct net_device *dev,
+			      const u8 *addr, gfp_t gfp);
+
 #endif /* __NET_WIRELESS_NL80211_H */
author maintainer
#4 lore raw

RFC v2 4/12 mac80211: support spurious class3 event

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

Add support for the spurious class3 frame event
to mac80211 to enable AP w/o monitor mode.

---
 net/mac80211/rx.c |    7 +++++++
 1 file changed, 7 insertions(+)
net/mac80211/rx.c +7 -0
@@ -854,6 +854,13 @@ ieee80211_rx_h_check(struct ieee80211_rx
 			    rx->sdata->control_port_protocol)
 				return RX_CONTINUE;
 		}
+
+		if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
+		    cfg80211_rx_spurious_frame(rx->sdata->dev,
+		    			       hdr->addr2,
+		    			       GFP_ATOMIC))
+			return RX_DROP_UNUSABLE;
+
 		return RX_DROP_MONITOR;
 	}
 
author maintainer
#5 lore raw

RFC v2 5/12 nl80211: advertise device AP SME

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

Add the ability to advertise that the device
contains the AP SME and what features it can
support.

---
 drivers/net/wireless/ath/ath6kl/init.c |    4 +++-
 include/linux/nl80211.h                |   20 ++++++++++++++++++++
 include/net/cfg80211.h                 |    6 ++++++
 net/wireless/core.c                    |    4 ++++
 net/wireless/nl80211.c                 |    4 ++++
 5 files changed, 37 insertions(+), 1 deletion(-)
include/linux/nl80211.h +20 -0
@@ -1122,6 +1122,11 @@ enum nl80211_commands {
  *	%NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be
  *	used for asking the driver to perform a TDLS operation.
  *
+ * @NL80211_ATTR_DEVICE_AP_SME: This u32 attribute may be listed for devices
+ *	that have AP support to indicate that the have the AP SME integrated
+ *	with support for the features listed in this attribute, see
+ *	&enum nl80211_ap_sme_features.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1350,6 +1355,8 @@ enum nl80211_attrs {
 	NL80211_ATTR_TDLS_SUPPORT,
 	NL80211_ATTR_TDLS_EXTERNAL_SETUP,
 
+	NL80211_ATTR_DEVICE_AP_MLME,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -2663,4 +2670,17 @@ enum nl80211_tdls_operation {
 	NL80211_TDLS_DISABLE_LINK,
 };
 
+/**
+ * enum nl80211_ap_sme_features - device-integrated AP features
+ * @NL80211_AP_SME_WSC: The driver is capable of indicating received probe
+ *	request frames to userspace via management frame subscription events
+ *	if the payload includes the WSC IE. The driver is capable of adding
+ *	the WSC IE as configured from userspace into beacons, probe responses
+ *	and (re)association reponse frame and allows userspace to update them
+ *	during the lifetime of the BSS.
+ */
+enum nl80211_ap_sme_features {
+	NL80211_AP_SME_WSC	= 1 << 0,
+};
+
 #endif /* __LINUX_NL80211_H */
include/net/cfg80211.h +6 -0
@@ -1675,6 +1675,7 @@ struct cfg80211_ops {
  *	teardown packets should be sent through the @NL80211_CMD_TDLS_MGMT
  *	command. When this flag is not set, @NL80211_CMD_TDLS_OPER should be
  *	used for asking the driver/firmware to perform a TDLS operation.
+ * @WIPHY_FLAG_HAVE_AP_SME: device integrates AP SME
  */
 enum wiphy_flags {
 	WIPHY_FLAG_CUSTOM_REGULATORY		= BIT(0),
@@ -1693,6 +1694,7 @@ enum wiphy_flags {
 	WIPHY_FLAG_AP_UAPSD			= BIT(14),
 	WIPHY_FLAG_SUPPORTS_TDLS		= BIT(15),
 	WIPHY_FLAG_TDLS_EXTERNAL_SETUP		= BIT(16),
+	WIPHY_FLAG_HAVE_AP_SME			= BIT(17),
 };
 
 /**
@@ -1903,6 +1905,8 @@ struct wiphy_wowlan_support {
  *	may request, if implemented.
  *
  * @wowlan: WoWLAN support information
+ *
+ * @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features.
  */
 struct wiphy {
 	/* assign these fields before you register the wiphy */
@@ -1926,6 +1930,8 @@ struct wiphy {
 
 	u32 flags;
 
+	u32 ap_sme_capa;
+
 	enum cfg80211_signal_type signal_type;
 
 	int bss_priv_size;
net/wireless/core.c +4 -0
@@ -492,6 +492,10 @@ int wiphy_register(struct wiphy *wiphy)
 		    !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY)))
 		return -EINVAL;
 
+	if (WARN_ON(wiphy->ap_sme_capa &&
+		    !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME)))
+		return -EINVAL;
+
 	if (WARN_ON(wiphy->addresses && !wiphy->n_addresses))
 		return -EINVAL;
 
net/wireless/nl80211.c +4 -0
@@ -1008,6 +1008,10 @@ static int nl80211_send_wiphy(struct sk_
 	if (nl80211_put_iface_combinations(&dev->wiphy, msg))
 		goto nla_put_failure;
 
+	if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME)
+		NLA_PUT_U32(msg, NL80211_ATTR_DEVICE_AP_MLME,
+			    dev->wiphy.ap_sme_capa);
+
 	return genlmsg_end(msg, hdr);
 
  nla_put_failure:
drivers/net/wireless/ath/ath6kl/init.c +3 -1
@@ -1548,7 +1548,9 @@ static int ath6kl_init(struct net_device
 	ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER |
 			 ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST;
 
-	ar->wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
+	ar->wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
+				  WIPHY_FLAG_HAVE_AP_SME;
+	ar->wdev->wiphy->ap_sme_capa = NL80211_AP_SME_WSC;
 
 	status = ath6kl_target_config_wlan_params(ar);
 	if (!status)
#6 lore raw

Re: [RFC v2 05/12] nl80211: advertise device AP SME

Quoted 8 lines · Johannes Berg

From: Johannes Berg <[email protected]>

Add the ability to advertise that the device
contains the AP SME and what features it can
support.

---

[...]

include/linux/nl80211.h   2011-10-21 12:07:41.000000000 +0200 enum nl80211_commands { · line 1126

Quoted 8 lines
include/linux/nl80211.h   2011-10-21 12:07:41.000000000 +0200 renamed from include/linux/nl80211.h   2011-10-21 12:07:39.000000000 +0200 +2 -0
@@ -1122,6 +1122,11 @@ enum nl80211_commands {
  *     %NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be
  *     used for asking the driver to perform a TDLS operation.
  *
+ * @NL80211_ATTR_DEVICE_AP_SME: This u32 attribute may be listed for devices
+ *     that have AP support to indicate that the have the AP SME integrated

s/the/they

include/linux/nl80211.h   2011-10-21 12:07:41.000000000 +0200 enum nl80211_attrs { · line 1359

Quoted 13 lines
include/linux/nl80211.h   2011-10-21 12:07:41.000000000 +0200 renamed from include/linux/nl80211.h   2011-10-21 12:07:39.000000000 +0200 +3 -0
+ *     with support for the features listed in this attribute, see
+ *     &enum nl80211_ap_sme_features.
+ *
 
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use

 */

include/linux/nl80211.h   2011-10-21 12:07:41.000000000 +0200 renamed from include/linux/nl80211.h   2011-10-21 12:07:39.000000000 +0200 +2 -0
@@ -1350,6 +1355,8 @@ enum nl80211_attrs {
        NL80211_ATTR_TDLS_SUPPORT,
        NL80211_ATTR_TDLS_EXTERNAL_SETUP,
 
+       NL80211_ATTR_DEVICE_AP_MLME,
+

the attribute name is different from the documented one (SME/MLME)

Eliad.

author maintainer
#7 lore raw

RFC v2 6/12 nl80211: add API to probe a client

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

When the AP SME in hostapd is used it wants to
probe the clients when they have been idle for
some time. Add explicit API to support this.

---
v2: - indicate both ack/non-ack status for cookie validity

 include/linux/nl80211.h |   10 ++++
 include/net/cfg80211.h  |   17 +++++++
 net/wireless/nl80211.c  |  104 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 131 insertions(+)
include/linux/nl80211.h +10 -0
@@ -520,6 +520,14 @@
  *	If used as the command, must have an interface index, and you can
  *	only unsubscribe from the event by closing the socket.
  *
+ * @NL80211_CMD_PROBE_CLIENT: Probe an associated station on an AP interface
+ *	by sending a null data frame to it and reporting when the frame is
+ *	acknowleged. This is used to allow timing out inactive clients. Uses
+ *	%NL80211_ATTR_IFINDEX and %NL80211_ATTR_MAC. The command returns a
+ *	direct reply with an %NL80211_ATTR_COOKIE that is later used to match
+ *	up the event with the request. The event includes the same data and
+ *	has %NL80211_ATTR_ACK set if the frame was ACKed.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -651,6 +659,8 @@ enum nl80211_commands {
 
 	NL80211_CMD_UNEXPECTED_FRAME,
 
+	NL80211_CMD_PROBE_CLIENT,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
include/net/cfg80211.h +17 -0
@@ -1428,6 +1428,9 @@ struct cfg80211_gtk_rekey_data {
  *
  * @tdls_mgmt: Transmit a TDLS management frame.
  * @tdls_oper: Perform a high-level TDLS operation (e.g. TDLS link setup).
+ *
+ * @probe_client: probe an associated client, must return a cookie that it
+ *	later passes to cfg80211_probe_status().
  */
 struct cfg80211_ops {
 	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -1617,6 +1620,9 @@ struct cfg80211_ops {
 			     u16 status_code, const u8 *buf, size_t len);
 	int	(*tdls_oper)(struct wiphy *wiphy, struct net_device *dev,
 			     u8 *peer, enum nl80211_tdls_operation oper);
+
+	int	(*probe_client)(struct wiphy *wiphy, struct net_device *dev,
+				const u8 *peer, u64 *cookie);
 };
 
 /*
@@ -3210,6 +3216,17 @@ void cfg80211_pmksa_candidate_notify(str
 bool cfg80211_rx_spurious_frame(struct net_device *dev,
 				const u8 *addr, gfp_t gfp);
 
+/**
+ * cfg80211_probe_status - notify userspace about probe status
+ * @dev: the device the probe was sent on
+ * @addr: the address of the peer
+ * @cookie: the cookie filled in @probe_client previously
+ * @acked: indicates whether probe was acked or not
+ * @gfp: allocation flags
+ */
+void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
+			   u64 cookie, bool acked, gfp_t gfp);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
net/wireless/nl80211.c +104 -0

128 lines not on this page · raw message

author maintainer
#8 lore raw

RFC v2 7/12 mac80211: support client probe

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

Support probing clients with null data frames
in AP mode.

---
v2: update to use cfg80211_probe_status

 net/mac80211/cfg.c    |   68 ++++++++++++++++++++++++++++++++++++++++++++++++++
 net/mac80211/status.c |   45 +++++++++++++++++++--------------
 2 files changed, 95 insertions(+), 18 deletions(-)
net/mac80211/cfg.c +68 -0
@@ -2507,6 +2507,73 @@ static int ieee80211_tdls_oper(struct wi
 	return 0;
 }
 
+static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
+				  const u8 *peer, u64 *cookie)
+{
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	struct ieee80211_local *local = sdata->local;
+	struct ieee80211_qos_hdr *nullfunc;
+	struct sk_buff *skb;
+	int size = sizeof(*nullfunc);
+	__le16 fc;
+	bool qos;
+	struct ieee80211_tx_info *info;
+	struct sta_info *sta;
+
+	rcu_read_lock();
+	sta = sta_info_get(sdata, peer);
+	if (sta)
+		qos = test_sta_flag(sta, WLAN_STA_WME);
+	rcu_read_unlock();
+
+	if (!sta)
+		return -ENOLINK;
+
+	if (qos) {
+		fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
+				 IEEE80211_STYPE_QOS_NULLFUNC |
+				 IEEE80211_FCTL_FROMDS);
+	} else {
+		size -= 2;
+		fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
+				 IEEE80211_STYPE_NULLFUNC |
+				 IEEE80211_FCTL_FROMDS);
+	}
+
+	skb = dev_alloc_skb(local->hw.extra_tx_headroom + size);
+	if (!skb)
+		return -ENOMEM;
+
+	skb->dev = dev;
+
+	skb_reserve(skb, local->hw.extra_tx_headroom);
+
+	nullfunc = (void *) skb_put(skb, size);
+	nullfunc->frame_control = fc;
+	nullfunc->duration_id = 0;
+	memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN);
+	memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
+	memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN);
+	nullfunc->seq_ctrl = 0;
+
+	info = IEEE80211_SKB_CB(skb);
+
+	info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS |
+		       IEEE80211_TX_INTFL_NL80211_FRAME_TX;
+
+	skb_set_queue_mapping(skb, IEEE80211_AC_VO);
+	skb->priority = 7;
+	if (qos)
+		nullfunc->qos_ctrl = cpu_to_le16(7);
+
+	local_bh_disable();
+	ieee80211_xmit(sdata, skb);
+	local_bh_enable();
+
+	*cookie = (unsigned long) skb;
+	return 0;
+}
+
 struct cfg80211_ops mac80211_config_ops = {
 	.add_virtual_intf = ieee80211_add_iface,
 	.del_virtual_intf = ieee80211_del_iface,
@@ -2572,4 +2639,5 @@ struct cfg80211_ops mac80211_config_ops
 	.set_rekey_data = ieee80211_set_rekey_data,
 	.tdls_oper = ieee80211_tdls_oper,
 	.tdls_mgmt = ieee80211_tdls_mgmt,
+	.probe_client = ieee80211_probe_client,
 };
net/mac80211/status.c +27 -18

54 lines not on this page · raw message

author maintainer
#9 lore raw

RFC v2 8/12 net: add wireless TX status socket option

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

The 802.1X EAPOL handshake hostapd does requires knowing whether the frame was ack'ed by the peer. Currently, we fudge this pretty badly by not even transmitting the frame as a normal data frame but injecting it with radiotap and getting the status out of radiotap monitor as well. This is rather complex, confuses users (mon.wlan0 presence) and doesn't work with all hardware.

To get rid of that hack, introduce a real wifi TX status option for data frame transmissions.

This works similar to the existing TX timestamping in that it reflects the SKB back to the socket's error queue with a SCM_WIFI_STATUS cmsg that has an int indicating ACK status (0/1).

Since it is possible that at some point we will want to have TX timestamping and wifi status in a single errqueue SKB (there's little point in not doing that), redefine SO_EE_ORIGIN_TIMESTAMPING to SO_EE_ORIGIN_TXSTATUS which can collect more than just the timestamp; keep the old constant as an alias of course. Currently the internal APIs don't make that possible, but it wouldn't be hard to split them up in a way that makes it possible.

Thanks to Neil Horman for helping me figure out the functions that add the control messages.

TODO:
* sock_tx_timestamp() function should be renamed, maybe to sock_tx_status()?
* sock_recv_timestamp() should also be renamed, I had a hard time figuring out the difference between that and sock_recv_ts_and_drops(). The former is generic, while the latter adds RX information only, maybe that should be reflected in new names?

---
 arch/alpha/include/asm/socket.h   |    3 +++
 arch/arm/include/asm/socket.h     |    3 +++
 arch/avr32/include/asm/socket.h   |    3 +++
 arch/cris/include/asm/socket.h    |    3 +++
 arch/frv/include/asm/socket.h     |    3 +++
 arch/h8300/include/asm/socket.h   |    3 +++
 arch/ia64/include/asm/socket.h    |    3 +++
 arch/m32r/include/asm/socket.h    |    3 +++
 arch/m68k/include/asm/socket.h    |    3 +++
 arch/mips/include/asm/socket.h    |    3 +++
 arch/mn10300/include/asm/socket.h |    3 +++
 arch/parisc/include/asm/socket.h  |    3 +++
 arch/powerpc/include/asm/socket.h |    3 +++
 arch/s390/include/asm/socket.h    |    3 +++
 arch/sparc/include/asm/socket.h   |    3 +++
 arch/xtensa/include/asm/socket.h  |    3 +++
 include/asm-generic/socket.h      |    3 +++
 include/linux/errqueue.h          |    3 ++-
 include/linux/skbuff.h            |   19 +++++++++++++++++--
 include/net/sock.h                |    7 +++++++
 net/core/skbuff.c                 |   20 ++++++++++++++++++++
 net/core/sock.c                   |    9 +++++++++
 net/socket.c                      |   19 +++++++++++++++++++
 23 files changed, 125 insertions(+), 3 deletions(-)
include/asm-generic/socket.h +3 -0
@@ -64,4 +64,7 @@
 #define SO_DOMAIN		39
 
 #define SO_RXQ_OVFL             40
+
+#define SO_WIFI_STATUS		41
+#define SCM_WIFI_STATUS	SO_WIFI_STATUS
 #endif /* __ASM_GENERIC_SOCKET_H */
net/core/sock.c +9 -0
@@ -743,6 +743,11 @@ set_rcvbuf:
 		else
 			sock_reset_flag(sk, SOCK_RXQ_OVFL);
 		break;
+
+	case SO_WIFI_STATUS:
+		sock_valbool_flag(sk, SOCK_WIFI_STATUS, valbool);
+		break;
+
 	default:
 		ret = -ENOPROTOOPT;
 		break;
@@ -964,6 +969,10 @@ int sock_getsockopt(struct socket *sock,
 		v.val = !!sock_flag(sk, SOCK_RXQ_OVFL);
 		break;
 
+	case SO_WIFI_STATUS:
+		v.val = !!sock_flag(sk, SOCK_WIFI_STATUS);
+		break;
+
 	default:
 		return -ENOPROTOOPT;
 	}
include/net/sock.h +7 -0
@@ -564,6 +564,7 @@ enum sock_flags {
 	SOCK_FASYNC, /* fasync() active */
 	SOCK_RXQ_OVFL,
 	SOCK_ZEROCOPY, /* buffers from userspace */
+	SOCK_WIFI_STATUS, /* push wifi status to userspace */
 };
 
 static inline void sock_copy_flags(struct sock *nsk, struct sock *osk)
@@ -1705,7 +1706,10 @@ static inline int sock_intr_errno(long t
 
 extern void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
 	struct sk_buff *skb);
+extern void __sock_recv_wifi_status(struct msghdr *msg, struct sock *sk,
+	struct sk_buff *skb);
 
+/* XXX: rename this function now? */
 static __inline__ void
 sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
 {
@@ -1732,6 +1736,9 @@ sock_recv_timestamp(struct msghdr *msg,
 		__sock_recv_timestamp(msg, sk, skb);
 	else
 		sk->sk_stamp = kt;
+
+	if (sock_flag(sk, SOCK_WIFI_STATUS) && skb->wifi_acked_valid)
+		__sock_recv_wifi_status(msg, sk, skb);
 }
 
 extern void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
arch/alpha/include/asm/socket.h +3 -0
@@ -69,6 +69,9 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS		41
+#define SCM_WIFI_STATUS		SO_WIFI_STATUS
+
 /* O_NONBLOCK clashes with the bits used for socket types.  Therefore we
  * have to define SOCK_NONBLOCK to a different value here.
  */
arch/arm/include/asm/socket.h +3 -0
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS		41
+#define SCM_WIFI_STATUS		SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
arch/avr32/include/asm/socket.h +3 -0
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS		41
+#define SCM_WIFI_STATUS		SO_WIFI_STATUS
+
 #endif /* __ASM_AVR32_SOCKET_H */
arch/cris/include/asm/socket.h +3 -0
@@ -64,6 +64,9 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS		41
+#define SCM_WIFI_STATUS		SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
 
 
arch/frv/include/asm/socket.h +3 -0
@@ -62,5 +62,8 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS		41
+#define SCM_WIFI_STATUS		SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
 
arch/h8300/include/asm/socket.h +3 -0
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS		41
+#define SCM_WIFI_STATUS		SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
arch/ia64/include/asm/socket.h +3 -0
@@ -71,4 +71,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS		41
+#define SCM_WIFI_STATUS		SO_WIFI_STATUS
+
 #endif /* _ASM_IA64_SOCKET_H */
arch/m32r/include/asm/socket.h +3 -0
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS		41
+#define SCM_WIFI_STATUS		SO_WIFI_STATUS
+
 #endif /* _ASM_M32R_SOCKET_H */
arch/m68k/include/asm/socket.h +3 -0
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS		41
+#define SCM_WIFI_STATUS		SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
arch/mips/include/asm/socket.h +3 -0
@@ -82,6 +82,9 @@ To add: #define SO_REUSEPORT 0x0200	/* A
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS		41
+#define SCM_WIFI_STATUS		SO_WIFI_STATUS
+
 #ifdef __KERNEL__
 
 /** sock_type - Socket types
arch/mn10300/include/asm/socket.h +3 -0
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS		41
+#define SCM_WIFI_STATUS		SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
arch/parisc/include/asm/socket.h +3 -0
@@ -61,6 +61,9 @@
 
 #define SO_RXQ_OVFL             0x4021
 
+#define SO_WIFI_STATUS		0x4022
+#define SCM_WIFI_STATUS		SO_WIFI_STATUS
+
 /* O_NONBLOCK clashes with the bits used for socket types.  Therefore we
  * have to define SOCK_NONBLOCK to a different value here.
  */
arch/powerpc/include/asm/socket.h +3 -0
@@ -69,4 +69,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS		41
+#define SCM_WIFI_STATUS		SO_WIFI_STATUS
+
 #endif	/* _ASM_POWERPC_SOCKET_H */
arch/s390/include/asm/socket.h +3 -0
@@ -70,4 +70,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS		41
+#define SCM_WIFI_STATUS		SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
arch/sparc/include/asm/socket.h +3 -0
@@ -58,6 +58,9 @@
 
 #define SO_RXQ_OVFL             0x0024
 
+#define SO_WIFI_STATUS		0x0025
+#define SCM_WIFI_STATUS		SO_WIFI_STATUS
+
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION		0x5001
 #define SO_SECURITY_ENCRYPTION_TRANSPORT	0x5002
arch/xtensa/include/asm/socket.h +3 -0
@@ -73,4 +73,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS		41
+#define SCM_WIFI_STATUS		SO_WIFI_STATUS
+
 #endif	/* _XTENSA_SOCKET_H */
include/linux/errqueue.h +2 -1
@@ -17,7 +17,8 @@ struct sock_extended_err {
 #define SO_EE_ORIGIN_LOCAL	1
 #define SO_EE_ORIGIN_ICMP	2
 #define SO_EE_ORIGIN_ICMP6	3
-#define SO_EE_ORIGIN_TIMESTAMPING 4
+#define SO_EE_ORIGIN_TXSTATUS	4
+#define SO_EE_ORIGIN_TIMESTAMPING SO_EE_ORIGIN_TXSTATUS
 
 #define SO_EE_OFFENDER(ee)	((struct sockaddr*)((ee)+1))
 
include/linux/skbuff.h +17 -2
@@ -190,6 +190,9 @@ enum {
 
 	/* device driver supports TX zero-copy buffers */
 	SKBTX_DEV_ZEROCOPY = 1 << 4,
+
+	/* generate wifi status information (where possible) */
+	SKBTX_WIFI_STATUS = 1 << 5,
 };
 
 /*
@@ -322,6 +325,8 @@ typedef unsigned char *sk_buff_data_t;
  *	@queue_mapping: Queue mapping for multiqueue devices
  *	@ndisc_nodetype: router type (from link layer)
  *	@ooo_okay: allow the mapping of a socket to a queue to be changed
+ *	@wifi_acked_valid: wifi_acked was set
+ *	@wifi_acked: whether frame was acked on wifi or not
  *	@dma_cookie: a cookie to one of several possible DMA operations
  *		done by skb DMA functions
  *	@secmark: security marking
@@ -414,10 +419,11 @@ struct sk_buff {
 	__u8			ndisc_nodetype:2;
 #endif
 	__u8			ooo_okay:1;
+	__u8			wifi_acked_valid:1;
+	__u8			wifi_acked:1;
+	/* 11/13 bit hole (depending on nodetype presence) */
 	kmemcheck_bitfield_end(flags2);
 
-	/* 0/13 bit hole */
-
 #ifdef CONFIG_NET_DMA
 	dma_cookie_t		dma_cookie;
 #endif
@@ -2062,6 +2068,15 @@ static inline void skb_tx_timestamp(stru
 	sw_tx_timestamp(skb);
 }
 
+/**
+ * skb_complete_wifi_ack - deliver skb with wifi status
+ *
+ * @skb: the original outgoing packet
+ * @acked: ack status
+ *
+ */
+void skb_complete_wifi_ack(struct sk_buff *skb, bool acked);
+
 extern __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len);
 extern __sum16 __skb_checksum_complete(struct sk_buff *skb);
 
net/core/skbuff.c +20 -0
@@ -3150,6 +3150,26 @@ void skb_tstamp_tx(struct sk_buff *orig_
 }
 EXPORT_SYMBOL_GPL(skb_tstamp_tx);
 
+void skb_complete_wifi_ack(struct sk_buff *skb, bool acked)
+{
+	struct sock *sk = skb->sk;
+	struct sock_exterr_skb *serr;
+	int err;
+
+	skb->wifi_acked_valid = 1;
+	skb->wifi_acked = acked;
+
+	serr = SKB_EXT_ERR(skb);
+	memset(serr, 0, sizeof(*serr));
+	serr->ee.ee_errno = ENOMSG;
+	serr->ee.ee_origin = SO_EE_ORIGIN_TXSTATUS;
+
+	err = sock_queue_err_skb(sk, skb);
+	if (err)
+		kfree_skb(skb);
+}
+EXPORT_SYMBOL_GPL(skb_complete_wifi_ack);
+
 
 /**
  * skb_partial_csum_set - set up and verify partial csum values for packet
net/socket.c +19 -0
@@ -531,6 +531,7 @@ void sock_release(struct socket *sock)
 }
 EXPORT_SYMBOL(sock_release);
 
+/* XXX: rename this function now */
 int sock_tx_timestamp(struct sock *sk, __u8 *tx_flags)
 {
 	*tx_flags = 0;
@@ -538,6 +539,8 @@ int sock_tx_timestamp(struct sock *sk, _
 		*tx_flags |= SKBTX_HW_TSTAMP;
 	if (sock_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE))
 		*tx_flags |= SKBTX_SW_TSTAMP;
+	if (sock_flag(sk, SOCK_WIFI_STATUS))
+		*tx_flags |= SKBTX_WIFI_STATUS;
 	return 0;
 }
 EXPORT_SYMBOL(sock_tx_timestamp);
@@ -674,6 +677,22 @@ void __sock_recv_timestamp(struct msghdr
 }
 EXPORT_SYMBOL_GPL(__sock_recv_timestamp);
 
+void __sock_recv_wifi_status(struct msghdr *msg, struct sock *sk,
+	struct sk_buff *skb)
+{
+	int ack;
+
+	if (!sock_flag(sk, SOCK_WIFI_STATUS))
+		return;
+	if (!skb->wifi_acked_valid)
+		return;
+
+	ack = skb->wifi_acked;
+
+	put_cmsg(msg, SOL_SOCKET, SCM_WIFI_STATUS, sizeof(ack), &ack);
+}
+EXPORT_SYMBOL_GPL(__sock_recv_wifi_status);
+
 static inline void sock_recv_drops(struct msghdr *msg, struct sock *sk,
 				   struct sk_buff *skb)
 {
#10 lore raw

Re: [RFC v2 08/12] net: add wireless TX status socket option

Quoted 44 lines · Johannes Berg

From: Johannes Berg <[email protected]>

The 802.1X EAPOL handshake hostapd does requires knowing whether the frame was ack'ed by the peer. Currently, we fudge this pretty badly by not even transmitting the frame as a normal data frame but injecting it with radiotap and getting the status out of radiotap monitor as well. This is rather complex, confuses users (mon.wlan0 presence) and doesn't work with all hardware.

To get rid of that hack, introduce a real wifi TX status option for data frame transmissions.

This works similar to the existing TX timestamping in that it reflects the SKB back to the socket's error queue with a SCM_WIFI_STATUS cmsg that has an int indicating ACK status (0/1).

Since it is possible that at some point we will want to have TX timestamping and wifi status in a single errqueue SKB (there's little point in not doing that), redefine SO_EE_ORIGIN_TIMESTAMPING to SO_EE_ORIGIN_TXSTATUS which can collect more than just the timestamp; keep the old constant as an alias of course. Currently the internal APIs don't make that possible, but it wouldn't be hard to split them up in a way that makes it possible.

Thanks to Neil Horman for helping me figure out the functions that add the control messages.

TODO:
 * sock_tx_timestamp() function should be renamed, maybe to sock_tx_status()?
 * sock_recv_timestamp() should also be renamed, I had a hard time figuring out the difference between that and sock_recv_ts_and_drops(). The former is generic, while the latter adds RX information only, maybe that should be reflected in new names?

---

[...]

Quoted 7 lines

       __u8                    ooo_okay:1;
+       __u8                    wifi_acked_valid:1;
+       __u8                    wifi_acked:1;
+       /* 11/13 bit hole (depending on nodetype presence) */ kmemcheck_bitfield_end(flags2);

net/core/skbuff.c void skb_tstamp_tx(struct sk_buff *orig_ · line 3161

Quoted 9 lines
net/core/skbuff.c +9 -0
+void skb_complete_wifi_ack(struct sk_buff *skb, bool acked)
+{
+       struct sock *sk = skb->sk;
+       struct sock_exterr_skb *serr;
+       int err;
+
+       skb->wifi_acked_valid = 1;
+       skb->wifi_acked = acked;
+

i'm not sure it's an actual issue, but setting (u8:1) = (bool) seems wrong?

Eliad.

author maintainer
#11 lore raw

RFC v2 9/12 nl80211: advertise socket TX status capability

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

The new wifi socket TX capability should be
supported by wifi drivers, let them advertise
whether they do or not.

---
 include/linux/nl80211.h |   15 +++++++++++++++
 include/net/cfg80211.h  |    3 ++-
 net/wireless/nl80211.c  |    2 ++
 3 files changed, 19 insertions(+), 1 deletion(-)
include/linux/nl80211.h +15 -0
@@ -1137,6 +1137,9 @@ enum nl80211_commands {
  *	with support for the features listed in this attribute, see
  *	&enum nl80211_ap_sme_features.
  *
+ * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from
+ *	&enum nl80211_feature_flags and is advertised in wiphy information.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1367,6 +1370,8 @@ enum nl80211_attrs {
 
 	NL80211_ATTR_DEVICE_AP_MLME,
 
+	NL80211_ATTR_FEATURE_FLAGS,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -2693,4 +2698,14 @@ enum nl80211_ap_sme_features {
 	NL80211_AP_SME_WSC	= 1 << 0,
 };
 
+/**
+ * enum nl80211_feature_flags - device/driver features
+ * @NL80211_FEATURE_SK_TX_STATUS: This driver supports reflecting back
+ *	TX status to the socket error queue when requested with the
+ *	socket option.
+ */
+enum nl80211_feature_flags {
+	NL80211_FEATURE_SK_TX_STATUS	= 1 << 0,
+};
+
 #endif /* __LINUX_NL80211_H */
include/net/cfg80211.h +2 -1
@@ -1873,6 +1873,7 @@ struct wiphy_wowlan_support {
  * @software_iftypes: bitmask of software interface types, these are not
  *	subject to any restrictions since they are purely managed in SW.
  * @flags: wiphy flags, see &enum wiphy_flags
+ * @features: features advertised to nl80211, see &enum nl80211_feature_flags.
  * @bss_priv_size: each BSS struct has private data allocated with it,
  *	this variable determines its size
  * @max_scan_ssids: maximum number of SSIDs the device can scan for in
@@ -1934,7 +1935,7 @@ struct wiphy {
 	/* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
 	u16 interface_modes;
 
-	u32 flags;
+	u32 flags, features;
 
 	u32 ap_sme_capa;
 
net/wireless/nl80211.c +2 -0
@@ -1013,6 +1013,8 @@ static int nl80211_send_wiphy(struct sk_
 		NLA_PUT_U32(msg, NL80211_ATTR_DEVICE_AP_MLME,
 			    dev->wiphy.ap_sme_capa);
 
+	NLA_PUT_U32(msg, NL80211_ATTR_FEATURE_FLAGS, dev->wiphy.features);
+
 	return genlmsg_end(msg, hdr);
 
  nla_put_failure:
author maintainer
#12 lore raw

RFC v2 10/12 mac80211: implement wifi TX status

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

Implement the socket wifi TX status error
queue reflection in mac80211.

---
 include/net/mac80211.h     |    5 +---
 net/mac80211/ieee80211_i.h |    4 +++
 net/mac80211/main.c        |   18 ++++++++++++++
 net/mac80211/status.c      |   38 ++++++++++++++++++++++++++++++
 net/mac80211/tx.c          |   56 ++++++++++++++++++++++++++++++++++++++++++---
 5 files changed, 115 insertions(+), 6 deletions(-)
net/mac80211/status.c +38 -0
@@ -548,6 +548,24 @@ void ieee80211_tx_status(struct ieee8021
 		}
 	}
 
+	if (unlikely(info->ack_frame_id)) {
+		struct sk_buff *ack_skb;
+		unsigned long flags;
+
+		spin_lock_irqsave(&local->ack_status_lock, flags);
+		ack_skb = idr_find(&local->ack_status_frames,
+				   info->ack_frame_id);
+		if (ack_skb)
+			idr_remove(&local->ack_status_frames,
+				   info->ack_frame_id);
+		spin_unlock_irqrestore(&local->ack_status_lock, flags);
+
+		/* consumes ack_skb */
+		if (ack_skb)
+			skb_complete_wifi_ack(ack_skb,
+				info->flags & IEEE80211_TX_STAT_ACK);
+	}
+
 	/* this was a transmitted frame, but now we want to reuse it */
 	skb_orphan(skb);
 
@@ -621,6 +639,26 @@ EXPORT_SYMBOL(ieee80211_report_low_ack);
 
 void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
+	struct ieee80211_local *local = hw_to_local(hw);
+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+	if (unlikely(info->ack_frame_id)) {
+		struct sk_buff *ack_skb;
+		unsigned long flags;
+
+		spin_lock_irqsave(&local->ack_status_lock, flags);
+		ack_skb = idr_find(&local->ack_status_frames,
+				   info->ack_frame_id);
+		if (ack_skb)
+			idr_remove(&local->ack_status_frames,
+				   info->ack_frame_id);
+		spin_unlock_irqrestore(&local->ack_status_lock, flags);
+
+		/* consumes ack_skb */
+		if (ack_skb)
+			dev_kfree_skb_any(ack_skb);
+	}
+
 	dev_kfree_skb_any(skb);
 }
 EXPORT_SYMBOL(ieee80211_free_txskb);
net/mac80211/tx.c +53 -3

85 lines not on this page · raw message

include/net/mac80211.h +2 -3
@@ -518,7 +518,7 @@ struct ieee80211_tx_rate {
  * @flags: transmit info flags, defined above
  * @band: the band to transmit on (use for checking for races)
  * @antenna_sel_tx: antenna to use, 0 for automatic diversity
- * @pad: padding, ignore
+ * @ack_frame_id: internal frame ID for TX status, used internally
  * @control: union for control data
  * @status: union for status data
  * @driver_data: array of driver_data pointers
@@ -535,8 +535,7 @@ struct ieee80211_tx_info {
 
 	u8 antenna_sel_tx;
 
-	/* 2 byte hole */
-	u8 pad[2];
+	u16 ack_frame_id;
 
 	union {
 		struct {
net/mac80211/ieee80211_i.h +4 -0
@@ -24,6 +24,7 @@
 #include <linux/spinlock.h>
 #include <linux/etherdevice.h>
 #include <linux/leds.h>
+#include <linux/idr.h>
 #include <net/ieee80211_radiotap.h>
 #include <net/cfg80211.h>
 #include <net/mac80211.h>
@@ -1013,6 +1014,9 @@ struct ieee80211_local {
 	u32 hw_roc_cookie;
 	bool hw_roc_for_tx;
 
+	struct idr ack_status_frames;
+	spinlock_t ack_status_lock;
+
 	/* dummy netdev for use w/ NAPI */
 	struct net_device napi_dev;
 
net/mac80211/main.c +18 -0
@@ -597,6 +597,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(
 			WIPHY_FLAG_4ADDR_AP |
 			WIPHY_FLAG_4ADDR_STATION;
 
+	wiphy->features = NL80211_FEATURE_SK_TX_STATUS;
+
 	if (!ops->set_key)
 		wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
 
@@ -670,6 +672,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(
 	INIT_WORK(&local->sched_scan_stopped_work,
 		  ieee80211_sched_scan_stopped_work);
 
+	spin_lock_init(&local->ack_status_lock);
+	idr_init(&local->ack_status_frames);
+	/* preallocate at least one entry */
+	idr_pre_get(&local->ack_status_frames, GFP_KERNEL);
+
 	sta_info_init(local);
 
 	for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
@@ -1045,6 +1052,13 @@ void ieee80211_unregister_hw(struct ieee
 }
 EXPORT_SYMBOL(ieee80211_unregister_hw);
 
+static int ieee80211_free_ack_frame(int id, void *p, void *data)
+{
+	WARN_ONCE(1, "Have pending ack frames!\n");
+	kfree_skb(p);
+	return 0;
+}
+
 void ieee80211_free_hw(struct ieee80211_hw *hw)
 {
 	struct ieee80211_local *local = hw_to_local(hw);
@@ -1055,6 +1069,10 @@ void ieee80211_free_hw(struct ieee80211_
 	if (local->wiphy_ciphers_allocated)
 		kfree(local->hw.wiphy->cipher_suites);
 
+	idr_for_each(&local->ack_status_frames,
+		     ieee80211_free_ack_frame, NULL);
+	idr_destroy(&local->ack_status_frames);
+
 	wiphy_free(local->hw.wiphy);
 }
 EXPORT_SYMBOL(ieee80211_free_hw);
author maintainer
#13 lore raw

RFC v2 11/12 cfg80211: allow registering to beacons

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

Add the ability to register to received beacon frames to allow implementing OLBC logic in userspace. The registration is per wiphy since there's no point in receiving the same frame multiple times.

---
 include/linux/nl80211.h |    7 ++++
 include/net/cfg80211.h  |   20 +++++++++++++
 net/wireless/core.h     |    2 +
 net/wireless/nl80211.c  |   70 +++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 98 insertions(+), 1 deletion(-)
net/wireless/core.h +2 -0
@@ -54,6 +54,8 @@ struct cfg80211_registered_device {
 	int opencount; /* also protected by devlist_mtx */
 	wait_queue_head_t dev_wait;
 
+	u32 ap_beacons_nlpid;
+
 	/* BSSes/scanning */
 	spinlock_t bss_lock;
 	struct list_head bss_list;
include/linux/nl80211.h +7 -0
@@ -528,6 +528,11 @@
  *	up the event with the request. The event includes the same data and
  *	has %NL80211_ATTR_ACK set if the frame was ACKed.
  *
+ * @NL80211_CMD_REGISTER_BEACONS: Register this socket to receive beacons from
+ *	other BSSes when any interfaces are in AP mode. This helps implement
+ *	OLBC handling in hostapd. Beacons are reported in %NL80211_CMD_FRAME
+ *	messages. Note that per PHY only one application may register.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -661,6 +666,8 @@ enum nl80211_commands {
 
 	NL80211_CMD_PROBE_CLIENT,
 
+	NL80211_CMD_REGISTER_BEACONS,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
net/wireless/nl80211.c +69 -1

102 lines not on this page · raw message

include/net/cfg80211.h +20 -0
@@ -1682,6 +1682,9 @@ struct cfg80211_ops {
  *	command. When this flag is not set, @NL80211_CMD_TDLS_OPER should be
  *	used for asking the driver/firmware to perform a TDLS operation.
  * @WIPHY_FLAG_HAVE_AP_SME: device integrates AP SME
+ * @WIPHY_FLAG_REPORTS_OBSS: the device will report beacons from other BSSes
+ *	when there are virtual interfaces in AP mode by calling
+ *	cfg80211_report_obss_beacon().
  */
 enum wiphy_flags {
 	WIPHY_FLAG_CUSTOM_REGULATORY		= BIT(0),
@@ -1701,6 +1704,7 @@ enum wiphy_flags {
 	WIPHY_FLAG_SUPPORTS_TDLS		= BIT(15),
 	WIPHY_FLAG_TDLS_EXTERNAL_SETUP		= BIT(16),
 	WIPHY_FLAG_HAVE_AP_SME			= BIT(17),
+	WIPHY_FLAG_REPORTS_OBSS			= BIT(18),
 };
 
 /**
@@ -3228,6 +3232,22 @@ bool cfg80211_rx_spurious_frame(struct n
 void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
 			   u64 cookie, bool acked, gfp_t gfp);
 
+/**
+ * cfg80211_report_obss_beacon - report beacon from other APs
+ * @wiphy: The wiphy that received the beacon
+ * @frame: the frame
+ * @len: length of the frame
+ * @freq: frequency the frame was received on
+ * @gfp: allocation flags
+ *
+ * Use this function to report to userspace when a beacon was
+ * received. It is not useful to call this when there is no
+ * netdev that is in AP/GO mode.
+ */
+void cfg80211_report_obss_beacon(struct wiphy *wiphy,
+				 const u8 *frame, size_t len,
+				 int freq, gfp_t gfp);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
author maintainer
#14 lore raw

RFC v2 12/12 mac80211: report OBSS beacons

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

If there's an interface in AP mode, OBSS beacons are needed by hostapd/wpa_s to implement logic to enable/disable protection etc. Report the frames and set the capability flag.

---
 net/mac80211/ieee80211_i.h |    3 +++
 net/mac80211/main.c        |    3 ++-
 net/mac80211/rx.c          |   12 ++++++++++++
 3 files changed, 17 insertions(+), 1 deletion(-)
net/mac80211/ieee80211_i.h +3 -0
@@ -185,12 +185,15 @@ enum ieee80211_packet_rx_flags {
  * enum ieee80211_rx_flags - RX data flags
  *
  * @IEEE80211_RX_CMNTR: received on cooked monitor already
+ * @IEEE80211_RX_BEACON_REPORTED: This frame was already reported
+ *	to cfg80211_report_obss_beacon().
  *
  * These flags are used across handling multiple interfaces
  * for a single frame.
  */
 enum ieee80211_rx_flags {
 	IEEE80211_RX_CMNTR		= BIT(0),
+	IEEE80211_RX_BEACON_REPORTED	= BIT(1),
 };
 
 struct ieee80211_rx_data {
net/mac80211/main.c +2 -1
@@ -595,7 +595,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(
 
 	wiphy->flags |= WIPHY_FLAG_NETNS_OK |
 			WIPHY_FLAG_4ADDR_AP |
-			WIPHY_FLAG_4ADDR_STATION;
+			WIPHY_FLAG_4ADDR_STATION |
+			WIPHY_FLAG_REPORTS_OBSS;
 
 	wiphy->features = NL80211_FEATURE_SK_TX_STATUS;
 
net/mac80211/rx.c +12 -0
@@ -2177,6 +2177,18 @@ ieee80211_rx_h_mgmt_check(struct ieee802
 	if (!ieee80211_is_mgmt(mgmt->frame_control))
 		return RX_DROP_MONITOR;
 
+	if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
+	    ieee80211_is_beacon(mgmt->frame_control) &&
+	    !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) {
+		struct ieee80211_rx_status *status;
+
+		status = IEEE80211_SKB_RXCB(rx->skb);
+		cfg80211_report_obss_beacon(rx->local->hw.wiphy,
+					    rx->skb->data, rx->skb->len,
+					    status->freq, GFP_ATOMIC);
+		rx->flags |= IEEE80211_RX_BEACON_REPORTED;
+	}
+
 	if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
 		return RX_DROP_MONITOR;
 
author maintainer
#15 lore raw

[RFC v2 13/12] cfg80211/mac80211: allow management TX to not wait for ACK

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

For probe responses it can be useful to not wait for ACK to save airtime, so allow userspace to request not waiting with a new nl80211 flag.

Since mac80211 needs to be updated for the new function prototype anyway implement it right away -- it's just a few lines of code.

---
 drivers/net/wireless/ath/ath6kl/cfg80211.c |    3 +-
 include/linux/nl80211.h                    |    7 ++++
 include/net/cfg80211.h                     |    2 -
 net/mac80211/cfg.c                         |   11 +++++--
 net/wireless/core.h                        |    2 -
 net/wireless/mlme.c                        |    5 ++-
 net/wireless/nl80211.c                     |   43 +++++++++++++++++------------
 7 files changed, 48 insertions(+), 25 deletions(-)
include/linux/nl80211.h +7 -0
@@ -1147,6 +1147,11 @@ enum nl80211_commands {
  * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from
  *	&enum nl80211_feature_flags and is advertised in wiphy information.
  *
+ * @NL80211_ATTR_DONT_WAIT_FOR_ACK: Used with %NL80211_CMD_FRAME, this tells
+ *	the driver to not wait for an acknowledgement. Note that due to this,
+ *	it will also not give a status callback nor return a cookie. This is
+ *	mostly useful for probe responses to save airtime.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1379,6 +1384,8 @@ enum nl80211_attrs {
 
 	NL80211_ATTR_FEATURE_FLAGS,
 
+	NL80211_ATTR_DONT_WAIT_FOR_ACK,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
net/wireless/core.h +1 -1
@@ -378,7 +378,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg8021
 			  enum nl80211_channel_type channel_type,
 			  bool channel_type_valid, unsigned int wait,
 			  const u8 *buf, size_t len, bool no_cck,
-			  u64 *cookie);
+			  bool dont_wait_for_ack, u64 *cookie);
 
 /* SME */
 int __cfg80211_connect(struct cfg80211_registered_device *rdev,
net/wireless/mlme.c +3 -2
@@ -904,7 +904,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg8021
 			  enum nl80211_channel_type channel_type,
 			  bool channel_type_valid, unsigned int wait,
 			  const u8 *buf, size_t len, bool no_cck,
-			  u64 *cookie)
+			  bool dont_wait_for_ack, u64 *cookie)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	const struct ieee80211_mgmt *mgmt;
@@ -995,7 +995,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg8021
 	/* Transmit the Action frame as requested by user space */
 	return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, offchan,
 				  channel_type, channel_type_valid,
-				  wait, buf, len, no_cck, cookie);
+				  wait, buf, len, no_cck, dont_wait_for_ack,
+				  cookie);
 }
 
 bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf,
net/wireless/nl80211.c +26 -17

71 lines not on this page · raw message

include/net/cfg80211.h +1 -1
@@ -1584,7 +1584,7 @@ struct cfg80211_ops {
 			  enum nl80211_channel_type channel_type,
 			  bool channel_type_valid, unsigned int wait,
 			  const u8 *buf, size_t len, bool no_cck,
-			  u64 *cookie);
+			  bool dont_wait_for_ack, u64 *cookie);
 	int	(*mgmt_tx_cancel_wait)(struct wiphy *wiphy,
 				       struct net_device *dev,
 				       u64 cookie);
net/mac80211/cfg.c +8 -3
@@ -1936,7 +1936,7 @@ static int ieee80211_mgmt_tx(struct wiph
 			     enum nl80211_channel_type channel_type,
 			     bool channel_type_valid, unsigned int wait,
 			     const u8 *buf, size_t len, bool no_cck,
-			     u64 *cookie)
+			     bool dont_wait_for_ack, u64 *cookie)
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_local *local = sdata->local;
@@ -1944,10 +1944,15 @@ static int ieee80211_mgmt_tx(struct wiph
 	struct sta_info *sta;
 	struct ieee80211_work *wk;
 	const struct ieee80211_mgmt *mgmt = (void *)buf;
-	u32 flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
-		    IEEE80211_TX_CTL_REQ_TX_STATUS;
+	u32 flags;
 	bool is_offchan = false;
 
+	if (!dont_wait_for_ack)
+		flags = IEEE80211_TX_CTL_NO_ACK;
+	else
+		flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
+			IEEE80211_TX_CTL_REQ_TX_STATUS;
+
 	/* Check that we are on the requested channel for transmission */
 	if (chan != local->tmp_channel &&
 	    chan != local->oper_channel)
drivers/net/wireless/ath/ath6kl/cfg80211.c +2 -1
@@ -1732,7 +1732,8 @@ static int ath6kl_mgmt_tx(struct wiphy *
 			  struct ieee80211_channel *chan, bool offchan,
 			  enum nl80211_channel_type channel_type,
 			  bool channel_type_valid, unsigned int wait,
-			  const u8 *buf, size_t len, bool no_cck, u64 *cookie)
+			  const u8 *buf, size_t len, bool no_cck,
+			  bool dont_wait_for_ack, u64 *cookie)
 {
 	struct ath6kl *ar = ath6kl_priv(dev);
 	u32 id;
#16 lore raw

Re: [RFC v2 13/12] cfg80211/mac80211: allow management TX to not wait for ACK

Quoted 6 lines · Johannes Berg

From: Johannes Berg <[email protected]>

For probe responses it can be useful to not wait for ACK to save airtime, so allow userspace to request not waiting with a new nl80211 flag.

Quoted 6 lines

Since mac80211 needs to be updated for the new function prototype anyway implement it right away -- it's just a few lines of code.

---

[RFC v2 13/12] ? :)

Quoted 7 lines

       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local;

net/mac80211/cfg.c +0 -1
@@ -1944,10 +1944,15 @@ static int ieee80211_mgmt_tx(struct wiph
        struct sta_info *sta;
        struct ieee80211_work *wk;
        const struct ieee80211_mgmt *mgmt = (void *)buf;
-       u32 flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |

net/mac80211/cfg.c static int ieee80211_mgmt_tx(struct wiph · line 1955

Quoted 10 lines
net/mac80211/cfg.c +7 -1
-                   IEEE80211_TX_CTL_REQ_TX_STATUS;
+       u32 flags;
        bool is_offchan = false;
 
+       if (!dont_wait_for_ack)
+               flags = IEEE80211_TX_CTL_NO_ACK;
+       else
+               flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
+                       IEEE80211_TX_CTL_REQ_TX_STATUS;
+

shouldn't it be the other way around? (i.e. set NO_ACK if dont_wait_for_ack)

Eliad.

author maintainer
#17 lore raw

Re: [RFC v2 13/12] cfg80211/mac80211: allow management TX to not wait for ACK

Quoted 8 lines · Eliad Peller
Quoted 6 lines · Johannes Berg

From: Johannes Berg <[email protected]>

For probe responses it can be useful to not wait for ACK to save airtime, so allow userspace to request not waiting with a new nl80211 flag.

Quoted 7 lines
Quoted 5 lines

Since mac80211 needs to be updated for the new function prototype anyway implement it right away -- it's just a few lines of code.

[RFC v2 13/12] ? :)

Too lazy to send a new patchset and it really belonged with this :-)

Quoted 8 lines

net/mac80211/cfg.c static int ieee80211_mgmt_tx(struct wiph · line 1955

Quoted 6 lines
net/mac80211/cfg.c +6 -0
+       if (!dont_wait_for_ack)
+               flags = IEEE80211_TX_CTL_NO_ACK;
+       else
+               flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
+                       IEEE80211_TX_CTL_REQ_TX_STATUS;
+

shouldn't it be the other way around? (i.e. set NO_ACK if dont_wait_for_ack)

Doh, of course, thanks. I was editing this code a few times -- guess I lost track.

johannes

#18 lore raw

Re: [RFC v2 13/12] cfg80211/mac80211: allow management TX to not wait for ACK

In reply to Johannes Berg
Quoted 9 lines · Johannes Berg

From: Johannes Berg <[email protected]>

For probe responses it can be useful to not wait for ACK to save airtime, so allow userspace to request not waiting with a new nl80211 flag.

Since mac80211 needs to be updated for the new function prototype anyway implement it right away -- it's just a few lines of code.

Ah, nice!

I'll adjust my hostad patch to make use of this instead of the radiotap flag (or maybe both, need to look into this further).

Helmut

author maintainer
#19 lore raw

Re: [RFC v2 13/12] cfg80211/mac80211: allow management TX to not wait for ACK

Quoted 8 lines · Helmut Schaa
Quoted 6 lines · Johannes Berg

From: Johannes Berg <[email protected]>

For probe responses it can be useful to not wait for ACK to save airtime, so allow userspace to request not waiting with a new nl80211 flag.

Quoted 8 lines
Quoted 3 lines

Since mac80211 needs to be updated for the new function prototype anyway implement it right away -- it's just a few lines of code.

Ah, nice!

I'll adjust my hostad patch to make use of this instead of the radiotap flag (or maybe both, need to look into this further).

If you just do the radiotap part I'll add the rest with my other patchset.

johannes

#20 lore raw

RE: [RFC v2 13/12] cfg80211/mac80211: allow management TX to not wait for ACK

In reply to Johannes Berg

PiBTZW50OiBkb25kZXJkYWcgMjcgb2t0b2JlciAyMDExIDIxOjMzDQo+IEZyb206IEpvaGFubmVz IEJlcmcgPGpvaGFubmVzLmJlcmdAaW50ZWwuY29tPg0KPiANCj4gRm9yIHByb2JlIHJlc3BvbnNl cyBpdCBjYW4gYmUgdXNlZnVsIHRvIG5vdCB3YWl0IGZvciBBQ0sNCj4gdG8gc2F2ZSBhaXJ0aW1l LCBzbyBhbGxvdyB1c2Vyc3BhY2UgdG8gcmVxdWVzdCBub3Qgd2FpdGluZw0KPiB3aXRoIGEgbmV3 IG5sODAyMTEgZmxhZy4NCj4gDQo+IFNpbmNlIG1hYzgwMjExIG5lZWRzIHRvIGJlIHVwZGF0ZWQg Zm9yIHRoZSBuZXcgZnVuY3Rpb24NCj4gcHJvdG90eXBlIGFueXdheSBpbXBsZW1lbnQgaXQgcmln aHQgYXdheSAtLSBpdCdzIGp1c3QgYQ0KPiBmZXcgbGluZXMgb2YgY29kZS4NCj4gDQo+IFNpZ25l ZC1vZmYtYnk6IEpvaGFubmVzIEJlcmcgPGpvaGFubmVzLmJlcmdAaW50ZWwuY29tPg0KPiAtLS0N Cg0KSGkgSm9oYW5uZXMsDQoNCkkgd291bGQgZXhwZWN0IHRoaXMgdG8gYWZmZWN0IHRoZSBkdXJh dGlvbiBmaWVsZCBpbiB0aGUNCjgwMi4xMSBoZWFkZXIgdG8gaW5kaWNhdGUgdGhlIHNob3J0ZXIg dXNlIG9mIHRoZSBtZWRpdW0uDQpHb2luZyB0aHJvdWdoIHlvdXIgcGF0Y2ggSSBhbSBub3Qgc3Vy ZSB0aGlzIGlzIGRvbmUuDQoNCkdyLiBBdlMNCg==

#21 lore raw

Re: [RFC v2 13/12] cfg80211/mac80211: allow management TX to not wait for ACK

Quoted 3 lines · Arend Van Spriel

I would expect this to affect the duration field in the 802.11 header to indicate the shorter use of the medium. Going through your patch I am not sure this is done.

I don't think so since the frame will still be acked by the peer as it is a unicast management frame. But this will advise the hardware that it does not need to wait for the ack to happen since we're not interested in retrying it.

Helmut

#22 lore raw

RE: [RFC v2 13/12] cfg80211/mac80211: allow management TX to not wait for ACK

Quoted 9 lines

From: Helmut Schaa [mailto:[email protected]]
Sent: vrijdag 28 oktober 2011 9:52

Quoted 3 lines · Arend Van Spriel

I would expect this to affect the duration field in the 802.11 header to indicate the shorter use of the medium. Going through your patch I am not sure this is done.

Quoted 7 lines

I don't think so since the frame will still be acked by the peer as it is
a unicast management frame. But this will advise the hardware that it does not need to wait for the ack to happen since we're not interested in retrying it.

Helmut

Hi Helmut,

I understand. However, the commit message of this patch suggests we are saving airtime, which does not seem the case if the duration field is not taken into account. If the ACK is still transmitted we should not touch the duration field so I guess my comment is only on the commit message itself.

The whole duration field usage is another topic.

Gr. AvS

author maintainer
#23 lore raw

RE: [RFC v2 13/12] cfg80211/mac80211: allow management TX to not wait for ACK

Quoted 15 lines · Arend Van Spriel
Quoted 9 lines

From: Helmut Schaa [mailto:[email protected]]
Sent: vrijdag 28 oktober 2011 9:52

Quoted 3 lines · Arend Van Spriel

I would expect this to affect the duration field in the 802.11 header to indicate the shorter use of the medium. Going through your patch I am not sure this is done.

Quoted 5 lines

I don't think so since the frame will still be acked by the peer as it is
a unicast management frame. But this will advise the hardware that it does not need to wait for the ack to happen since we're not interested in retrying it.

Quoted 5 lines

I understand. However, the commit message of this patch suggests we are saving airtime, which does not seem the case if the duration field is not taken into account. If the ACK is still transmitted we should not touch the duration field so I guess my comment is only on the commit message itself.

Oh good points ...
The reason we save airtime is that often the frame will be retransmitted a lot if the station is no longer paying attention.

johannes

author maintainer
#24 lore raw

RE: [RFC v2 13/12] cfg80211/mac80211: allow management TX to not wait for ACK

In reply to Arend Van Spriel
Quoted 7 lines · Arend Van Spriel
Quoted 7 lines

Sent: donderdag 27 oktober 2011 21:33
From: Johannes Berg <[email protected]>

For probe responses it can be useful to not wait for ACK to save airtime, so allow userspace to request not waiting with a new nl80211 flag.

Quoted 7 lines
Quoted 3 lines

Since mac80211 needs to be updated for the new function prototype anyway implement it right away -- it's just a few lines of code.

I would expect this to affect the duration field in the 802.11 header to indicate the shorter use of the medium. Going through your patch I am not sure this is done.

Hmmm. You're right, but that's something we already need to fix in many cases -- as the duration field is overwritten by most hardware these days, we haven't always maintained it very well.

Your driver seems to be the exception to this -- maybe you can look into fixing up the duration calculations? Also for 11n which isn't taken into account at all today.

johannes

#25 lore raw

RE: [RFC v2 13/12] cfg80211/mac80211: allow management TX to not wait for ACK

PiBGcm9tOiBKb2hhbm5lcyBCZXJnIFttYWlsdG86am9oYW5uZXNAc2lwc29sdXRpb25zLm5ldF0N Cj4gU2VudDogdnJpamRhZyAyOCBva3RvYmVyIDIwMTEgMTA6MDENCj4gDQo+IE9uIEZyaSwgMjAx MS0xMC0yOCBhdCAwMDo0OCAtMDcwMCwgQXJlbmQgVmFuIFNwcmllbCB3cm90ZToNCj4gPiA+IFNl bnQ6IGRvbmRlcmRhZyAyNyBva3RvYmVyIDIwMTEgMjE6MzMNCj4gPiA+IEZyb206IEpvaGFubmVz IEJlcmcgPGpvaGFubmVzLmJlcmdAaW50ZWwuY29tPg0KPiA+ID4NCj4gPiA+IEZvciBwcm9iZSBy ZXNwb25zZXMgaXQgY2FuIGJlIHVzZWZ1bCB0byBub3Qgd2FpdCBmb3IgQUNLDQo+ID4gPiB0byBz YXZlIGFpcnRpbWUsIHNvIGFsbG93IHVzZXJzcGFjZSB0byByZXF1ZXN0IG5vdCB3YWl0aW5nDQo+ ID4gPiB3aXRoIGEgbmV3IG5sODAyMTEgZmxhZy4NCj4gPiA+DQo+ID4gPiBTaW5jZSBtYWM4MDIx MSBuZWVkcyB0byBiZSB1cGRhdGVkIGZvciB0aGUgbmV3IGZ1bmN0aW9uDQo+ID4gPiBwcm90b3R5 cGUgYW55d2F5IGltcGxlbWVudCBpdCByaWdodCBhd2F5IC0tIGl0J3MganVzdCBhDQo+ID4gPiBm ZXcgbGluZXMgb2YgY29kZS4NCj4gDQo+ID4gSSB3b3VsZCBleHBlY3QgdGhpcyB0byBhZmZlY3Qg dGhlIGR1cmF0aW9uIGZpZWxkIGluIHRoZQ0KPiA+IDgwMi4xMSBoZWFkZXIgdG8gaW5kaWNhdGUg dGhlIHNob3J0ZXIgdXNlIG9mIHRoZSBtZWRpdW0uDQo+ID4gR29pbmcgdGhyb3VnaCB5b3VyIHBh dGNoIEkgYW0gbm90IHN1cmUgdGhpcyBpcyBkb25lLg0KPiANCj4gSG1tbS4gWW91J3JlIHJpZ2h0 LCBidXQgdGhhdCdzIHNvbWV0aGluZyB3ZSBhbHJlYWR5IG5lZWQgdG8gZml4IGluIG1hbnkNCj4g Y2FzZXMgLS0gYXMgdGhlIGR1cmF0aW9uIGZpZWxkIGlzIG92ZXJ3cml0dGVuIGJ5IG1vc3QgaGFy ZHdhcmUgdGhlc2UNCj4gZGF5cywgd2UgaGF2ZW4ndCBhbHdheXMgbWFpbnRhaW5lZCBpdCB2ZXJ5 IHdlbGwuDQoNCklmIHRoZSBzdGF0aW9uIHN0aWxsIGRvZXMgdGhlIEFDSyB3ZSBzaG91bGQgbm90 IHRvdWNoIHRoZSBkdXJhdGlvbiBmaWVsZA0KaW4gdGhpcyBjYXNlIChzZWUgbXkgcmVwbHkgdG8g SGVsbXV0KS4NCg0KPiBZb3VyIGRyaXZlciBzZWVtcyB0byBiZSB0aGUgZXhjZXB0aW9uIHRvIHRo aXMgLS0gbWF5YmUgeW91IGNhbiBsb29rDQo+IGludG8NCj4gZml4aW5nIHVwIHRoZSBkdXJhdGlv biBjYWxjdWxhdGlvbnM/IEFsc28gZm9yIDExbiB3aGljaCBpc24ndCB0YWtlbg0KPiBpbnRvDQo+ IGFjY291bnQgYXQgYWxsIHRvZGF5Lg0KPiANCj4gam9oYW5uZXMNCj4gDQoNCkkgd2lsbCBzZWUg d2hldGhlciB3ZSBjYW4gY29udHJpYnV0ZSB0byBtYWM4MDIxMSBmb3IgdGhpcy4gQnV0IHRoZXJl DQphcmUgb25seSB0d28gb2YgdXMgd29ya2luZyBvbiB0aGlzIGFuZCB0aGVyZSBhcmUgc29tZSBt b3JlIGl0ZW1zIG9uDQpvdXIgdG9kbyBsaXN0LiBXaGVuIHdlIHdpbGwgYWRkcmVzcyBpdCB3ZSBz dXJlIHdpbGwgdGFrZSAxMW4gaW50bw0KYWNjb3VudC4NCg0KR3IuIEF2Uw0K

#26 lore raw

Re: [RFC v2 13/12] cfg80211/mac80211: allow management TX to not wait for ACK

Quoted 10 lines · Arend Van Spriel
Quoted 7 lines
Quoted 3 lines

I would expect this to affect the duration field in the 802.11 header to indicate the shorter use of the medium. Going through your patch I am not sure this is done.

Hmmm. You're right, but that's something we already need to fix in many cases -- as the duration field is overwritten by most hardware these days, we haven't always maintained it very well.

If the station still does the ACK we should not touch the duration field in this case (see my reply to Helmut).

The reason is the following: if you're running a mac80211 AP with multiple bssids, hostapd will answer to broadcast probe requests sent by STAs with one probe response per bssid (unicast of course). And since some clients stay only for a short amount of time on the scan-channel (a few ms) under some circumstances the probe responses aren't sent out yet before the scanning STA leaves the channel and thus retried till the maximum retry limit is reached. And these retries consume quite a lot of airtime. And to avoid this we just don't want to retry the probe responses in that case.

Helmut

#27 lore raw

Re: [RFC v2 13/12] cfg80211/mac80211: allow management TX to not wait for ACK

Quoted 8 lines · Helmut Schaa

The reason is the following: if you're running a mac80211 AP with multiple bssids, hostapd will answer to broadcast probe requests sent by STAs with one probe response per bssid (unicast of course). And since some clients stay only for a short amount of time on the scan-channel (a few ms) under some circumstances the probe responses aren't sent out yet before the scanning STA leaves the channel and thus retried till the maximum retry limit is reached. And these retries consume quite a lot of airtime. And to avoid this we just don't want to retry the probe responses in that case.

This is all good. But doesn't it also mean that this change increases probability that the client doesn't receive the probe response, for example due to interference where retransmission would help, and hence the AP isn't included in the client's scan results?

Signature · 1 line
Kalle Valo
#28 lore raw

Re: [RFC v2 13/12] cfg80211/mac80211: allow management TX to not wait for ACK

Quoted 11 lines · Kalle Valo
Quoted 8 lines · Helmut Schaa

The reason is the following: if you're running a mac80211 AP with multiple bssids, hostapd will answer to broadcast probe requests sent by STAs with one probe response per bssid (unicast of course). And since some clients stay only for a short amount of time on the scan-channel (a few ms) under some circumstances the probe responses aren't sent out yet before the scanning STA leaves the channel and thus retried till the maximum retry limit is reached. And these retries consume quite a lot of airtime. And to avoid this we just don't want to retry the probe responses in that case.

Quoted 4 lines

This is all good. But doesn't it also mean that this change increases probability that the client doesn't receive the probe response, for example due to interference where retransmission would help, and hence the AP isn't included in the client's scan results?

Correct. The probability to find the AP during a scan is lower then with retries. However, some commercial APs (Aruba for example) do exactly this and in some cases I noticed (on a mac80211 AP with 8 BSSIDs) one scanning client took around 50ms of airtime :)

Also in a multi BSS scenario the probability of finding the second, third etc. BSSID gets lower if probe responses are retried.

I've got a patch for hostapd to implement the don't-wait-for-ack behavior only for broadcast probe responses that contain the wildcard ssid. But maybe it makes sense to make this a configuration option? So it is up to the user to decide about the behavior.

Helmut

#29 lore raw

Re: [RFC v2 13/12] cfg80211/mac80211: allow management TX to not wait for ACK

In reply to Helmut Schaa
Quoted 21 lines · Helmut Schaa
Quoted 10 lines · Arend Van Spriel
Quoted 7 lines
Quoted 3 lines

I would expect this to affect the duration field in the 802.11 header to indicate the shorter use of the medium. Going through your patch I am not sure this is done.

Hmmm. You're right, but that's something we already need to fix in many cases -- as the duration field is overwritten by most hardware these days, we haven't always maintained it very well.

If the station still does the ACK we should not touch the duration field in this case (see my reply to Helmut).

The reason is the following: if you're running a mac80211 AP with multiple bssids, hostapd will answer to broadcast probe requests sent by STAs with one probe response per bssid (unicast of course). And since some clients stay only for a short amount of time on the scan-channel (a few ms) under some circumstances the probe responses aren't sent out yet before the scanning STA leaves the channel and thus retried till the maximum retry limit is reached. And these retries consume quite a lot of airtime. And to avoid this we just don't want to retry the probe responses in that case.

Quoted 2 lines

Helmut

Hi Helmut,

That makes perfect sense. Indeed not doing retries will obviously save airtime. Thanks for taking time to explain the scenario.

Gr. AvS

author maintainer
#30 lore raw

[RFC v3 13/12] cfg80211/mac80211: allow management TX to not wait for ACK

In reply to Johannes Berg

From: Johannes Berg <[email protected]>

For probe responses it can be useful to not wait for ACK to avoid retransmissions if the station that sent the probe is already on the next channel, so allow userspace to request not caring about the ACK with a new nl80211 flag.

Since mac80211 needs to be updated for the new function prototype anyway implement it right away -- it's just a few lines of code.

---
v2: accidentally sent as v2 instead of v1
v3: update commit log (Arend) and fix bug (Eliad)

 drivers/net/wireless/ath/ath6kl/cfg80211.c |    3 +-
 include/linux/nl80211.h                    |    7 ++++
 include/net/cfg80211.h                     |    2 -
 net/mac80211/cfg.c                         |   11 +++++--
 net/wireless/core.h                        |    2 -
 net/wireless/mlme.c                        |    5 ++-
 net/wireless/nl80211.c                     |   43 +++++++++++++++++------------
 7 files changed, 48 insertions(+), 25 deletions(-)
include/linux/nl80211.h +7 -0
@@ -1147,6 +1147,11 @@ enum nl80211_commands {
  * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from
  *	&enum nl80211_feature_flags and is advertised in wiphy information.
  *
+ * @NL80211_ATTR_DONT_WAIT_FOR_ACK: Used with %NL80211_CMD_FRAME, this tells
+ *	the driver to not wait for an acknowledgement. Note that due to this,
+ *	it will also not give a status callback nor return a cookie. This is
+ *	mostly useful for probe responses to save airtime.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1379,6 +1384,8 @@ enum nl80211_attrs {
 
 	NL80211_ATTR_FEATURE_FLAGS,
 
+	NL80211_ATTR_DONT_WAIT_FOR_ACK,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
net/wireless/core.h +1 -1
@@ -378,7 +378,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg8021
 			  enum nl80211_channel_type channel_type,
 			  bool channel_type_valid, unsigned int wait,
 			  const u8 *buf, size_t len, bool no_cck,
-			  u64 *cookie);
+			  bool dont_wait_for_ack, u64 *cookie);
 
 /* SME */
 int __cfg80211_connect(struct cfg80211_registered_device *rdev,
net/wireless/mlme.c +3 -2
@@ -904,7 +904,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg8021
 			  enum nl80211_channel_type channel_type,
 			  bool channel_type_valid, unsigned int wait,
 			  const u8 *buf, size_t len, bool no_cck,
-			  u64 *cookie)
+			  bool dont_wait_for_ack, u64 *cookie)
 {
 	struct wireless_dev *wdev = dev->ieee80211_ptr;
 	const struct ieee80211_mgmt *mgmt;
@@ -995,7 +995,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg8021
 	/* Transmit the Action frame as requested by user space */
 	return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, offchan,
 				  channel_type, channel_type_valid,
-				  wait, buf, len, no_cck, cookie);
+				  wait, buf, len, no_cck, dont_wait_for_ack,
+				  cookie);
 }
 
 bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf,
net/wireless/nl80211.c +26 -17

71 lines not on this page · raw message

include/net/cfg80211.h +1 -1
@@ -1584,7 +1584,7 @@ struct cfg80211_ops {
 			  enum nl80211_channel_type channel_type,
 			  bool channel_type_valid, unsigned int wait,
 			  const u8 *buf, size_t len, bool no_cck,
-			  u64 *cookie);
+			  bool dont_wait_for_ack, u64 *cookie);
 	int	(*mgmt_tx_cancel_wait)(struct wiphy *wiphy,
 				       struct net_device *dev,
 				       u64 cookie);
net/mac80211/cfg.c +8 -3
@@ -1936,7 +1936,7 @@ static int ieee80211_mgmt_tx(struct wiph
 			     enum nl80211_channel_type channel_type,
 			     bool channel_type_valid, unsigned int wait,
 			     const u8 *buf, size_t len, bool no_cck,
-			     u64 *cookie)
+			     bool dont_wait_for_ack, u64 *cookie)
 {
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 	struct ieee80211_local *local = sdata->local;
@@ -1944,10 +1944,15 @@ static int ieee80211_mgmt_tx(struct wiph
 	struct sta_info *sta;
 	struct ieee80211_work *wk;
 	const struct ieee80211_mgmt *mgmt = (void *)buf;
-	u32 flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
-		    IEEE80211_TX_CTL_REQ_TX_STATUS;
+	u32 flags;
 	bool is_offchan = false;
 
+	if (dont_wait_for_ack)
+		flags = IEEE80211_TX_CTL_NO_ACK;
+	else
+		flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
+			IEEE80211_TX_CTL_REQ_TX_STATUS;
+
 	/* Check that we are on the requested channel for transmission */
 	if (chan != local->tmp_channel &&
 	    chan != local->oper_channel)
drivers/net/wireless/ath/ath6kl/cfg80211.c +2 -1
@@ -1732,7 +1732,8 @@ static int ath6kl_mgmt_tx(struct wiphy *
 			  struct ieee80211_channel *chan, bool offchan,
 			  enum nl80211_channel_type channel_type,
 			  bool channel_type_valid, unsigned int wait,
-			  const u8 *buf, size_t len, bool no_cck, u64 *cookie)
+			  const u8 *buf, size_t len, bool no_cck,
+			  bool dont_wait_for_ack, u64 *cookie)
 {
 	struct ath6kl *ar = ath6kl_priv(dev);
 	u32 id;