* [RFC 00/12] no more mon.wlan0
@ 2011-10-14 15:11 Johannes Berg
2011-10-14 15:11 ` [RFC 01/12] mac80211: reformat TX unauthorised check Johannes Berg
` (11 more replies)
0 siblings, 12 replies; 13+ messages in thread
From: Johannes Berg @ 2011-10-14 15:11 UTC (permalink / raw)
To: linux-wireless
Add infrastructure to get rid of the "cooked"
monitor interface in AP mode.
johannes
^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC 01/12] mac80211: reformat TX unauthorised check
2011-10-14 15:11 [RFC 00/12] no more mon.wlan0 Johannes Berg
@ 2011-10-14 15:11 ` Johannes Berg
2011-10-14 15:11 ` [RFC 02/12] mac80211: fix TID for null poll response Johannes Berg
` (10 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2011-10-14 15:11 UTC (permalink / raw)
To: linux-wireless
From: Johannes Berg <johannes.berg@intel.com>
Reformat the check, the indentation is completely strange.
Also change the last part of the condition to make the
code shorter.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/mac80211/tx.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
--- a/net/mac80211/tx.c 2011-10-12 17:11:32.000000000 +0200
+++ b/net/mac80211/tx.c 2011-10-12 17:27:00.000000000 +0200
@@ -1896,11 +1896,10 @@ netdev_tx_t ieee80211_subif_start_xmit(s
* Drop unicast frames to unauthorised stations unless they are
* EAPOL frames from the local station.
*/
- if (!ieee80211_vif_is_mesh(&sdata->vif) &&
- unlikely(!is_multicast_ether_addr(hdr.addr1) && !authorized &&
- !(cpu_to_be16(ethertype) == sdata->control_port_protocol &&
- compare_ether_addr(sdata->vif.addr,
- skb->data + ETH_ALEN) == 0))) {
+ if (unlikely(!ieee80211_vif_is_mesh(&sdata->vif) &&
+ !is_multicast_ether_addr(hdr.addr1) && !authorized &&
+ (cpu_to_be16(ethertype) != sdata->control_port_protocol ||
+ compare_ether_addr(sdata->vif.addr, skb->data + ETH_ALEN)))) {
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
if (net_ratelimit())
printk(KERN_DEBUG "%s: dropped frame to %pM"
^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC 02/12] mac80211: fix TID for null poll response
2011-10-14 15:11 [RFC 00/12] no more mon.wlan0 Johannes Berg
2011-10-14 15:11 ` [RFC 01/12] mac80211: reformat TX unauthorised check Johannes Berg
@ 2011-10-14 15:11 ` Johannes Berg
2011-10-14 15:11 ` [RFC 03/12] mac80211: add helper to free TX skb Johannes Berg
` (9 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2011-10-14 15:11 UTC (permalink / raw)
To: linux-wireless
From: Johannes Berg <johannes.berg@intel.com>
The queue mapping/TID for non-QoS null data
responses to is never set, making it default
to BK. Fix that.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/mac80211/sta_info.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
--- a/net/mac80211/sta_info.c 2011-10-07 10:43:31.000000000 +0200
+++ b/net/mac80211/sta_info.c 2011-10-13 13:16:57.000000000 +0200
@@ -1203,11 +1203,9 @@ static void ieee80211_send_null_response
memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN);
+ skb->priority = tid;
+ skb_set_queue_mapping(skb, ieee802_1d_to_ac[tid]);
if (qos) {
- skb->priority = tid;
-
- skb_set_queue_mapping(skb, ieee802_1d_to_ac[tid]);
-
nullfunc->qos_ctrl = cpu_to_le16(tid);
if (reason == IEEE80211_FRAME_RELEASE_UAPSD)
^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC 03/12] mac80211: add helper to free TX skb
2011-10-14 15:11 [RFC 00/12] no more mon.wlan0 Johannes Berg
2011-10-14 15:11 ` [RFC 01/12] mac80211: reformat TX unauthorised check Johannes Berg
2011-10-14 15:11 ` [RFC 02/12] mac80211: fix TID for null poll response Johannes Berg
@ 2011-10-14 15:11 ` Johannes Berg
2011-10-14 15:11 ` [RFC 04/12] mac80211: add support for control port protocol in AP mode Johannes Berg
` (8 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2011-10-14 15:11 UTC (permalink / raw)
To: linux-wireless
From: Johannes Berg <johannes.berg@intel.com>
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.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
include/net/mac80211.h | 10 ++++++++++
net/mac80211/status.c | 6 ++++++
2 files changed, 16 insertions(+)
--- a/include/net/mac80211.h 2011-10-11 12:08:43.000000000 +0200
+++ b/include/net/mac80211.h 2011-10-11 13:50:07.000000000 +0200
@@ -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
--- a/net/mac80211/status.c 2011-10-11 12:08:43.000000000 +0200
+++ b/net/mac80211/status.c 2011-10-11 13:50:08.000000000 +0200
@@ -544,3 +544,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);
^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC 04/12] mac80211: add support for control port protocol in AP mode
2011-10-14 15:11 [RFC 00/12] no more mon.wlan0 Johannes Berg
` (2 preceding siblings ...)
2011-10-14 15:11 ` [RFC 03/12] mac80211: add helper to free TX skb Johannes Berg
@ 2011-10-14 15:11 ` Johannes Berg
2011-10-14 15:11 ` [RFC 05/12] nl80211: allow subscribing to unexpected class3 frames Johannes Berg
` (7 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2011-10-14 15:11 UTC (permalink / raw)
To: linux-wireless
From: Johannes Berg <johannes.berg@intel.com>
This will allow us to support dynamic WEP with 802.1X
properly in mac80211 by not encrypting outgoing and
accepting unencrypted incoming frames.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/mac80211/cfg.c | 21 ++++++++++++++++++++-
net/mac80211/iface.c | 13 ++++++++++++-
2 files changed, 32 insertions(+), 2 deletions(-)
--- a/net/mac80211/cfg.c 2011-10-13 13:16:27.000000000 +0200
+++ b/net/mac80211/cfg.c 2011-10-13 21:53:56.000000000 +0200
@@ -576,6 +576,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);
@@ -583,7 +585,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,
--- a/net/mac80211/iface.c 2011-10-13 13:16:27.000000000 +0200
+++ b/net/mac80211/iface.c 2011-10-13 13:45:15.000000000 +0200
@@ -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;
^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC 05/12] nl80211: allow subscribing to unexpected class3 frames
2011-10-14 15:11 [RFC 00/12] no more mon.wlan0 Johannes Berg
` (3 preceding siblings ...)
2011-10-14 15:11 ` [RFC 04/12] mac80211: add support for control port protocol in AP mode Johannes Berg
@ 2011-10-14 15:11 ` Johannes Berg
2011-10-14 15:11 ` [RFC 06/12] mac80211: support spurious class3 event Johannes Berg
` (6 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2011-10-14 15:11 UTC (permalink / raw)
To: linux-wireless
From: Johannes Berg <johannes.berg@intel.com>
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.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
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(+)
--- a/include/linux/nl80211.h 2011-09-29 17:25:23.000000000 +0200
+++ b/include/linux/nl80211.h 2011-10-11 14:46:17.000000000 +0200
@@ -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 */
--- a/include/net/cfg80211.h 2011-10-06 21:59:47.000000000 +0200
+++ b/include/net/cfg80211.h 2011-10-11 15:22:36.000000000 +0200
@@ -2176,6 +2176,8 @@ struct wireless_dev {
int beacon_interval;
+ u32 ap_unexpected_nlpid;
+
#ifdef CONFIG_CFG80211_WEXT
/* wext data */
struct {
@@ -3182,6 +3184,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 */
--- a/net/wireless/mlme.c 2011-09-28 17:10:13.000000000 +0200
+++ b/net/wireless/mlme.c 2011-10-11 14:46:43.000000000 +0200
@@ -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);
--- a/net/wireless/nl80211.c 2011-10-04 10:49:07.000000000 +0200
+++ b/net/wireless/nl80211.c 2011-10-11 14:46:55.000000000 +0200
@@ -5823,6 +5823,23 @@ static int nl80211_set_rekey_data(struct
return err;
}
+static int nl80211_register_unexpected_frame(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+ if (wdev->iftype != NL80211_IFTYPE_AP &&
+ wdev->iftype != NL80211_IFTYPE_P2P_GO)
+ return -EINVAL;
+
+ if (wdev->ap_unexpected_nlpid)
+ return -EBUSY;
+
+ wdev->ap_unexpected_nlpid = info->snd_pid;
+ return 0;
+}
+
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -6378,6 +6395,14 @@ static struct genl_ops nl80211_ops[] = {
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL80211_CMD_UNEXPECTED_FRAME,
+ .doit = nl80211_register_unexpected_frame,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
+ },
};
static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -7198,6 +7223,47 @@ void nl80211_send_sta_del_event(struct c
nlmsg_free(msg);
}
+bool nl80211_unexpected_frame(struct net_device *dev, const u8 *addr, gfp_t gfp)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ struct sk_buff *msg;
+ void *hdr;
+ int err;
+ u32 nlpid = ACCESS_ONCE(wdev->ap_unexpected_nlpid);
+
+ if (!nlpid)
+ return false;
+
+ msg = nlmsg_new(100, gfp);
+ if (!msg)
+ return true;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_UNEXPECTED_FRAME);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return true;
+ }
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+ err = genlmsg_end(msg, hdr);
+ if (err < 0) {
+ nlmsg_free(msg);
+ return true;
+ }
+
+ genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
+ return true;
+
+ nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ nlmsg_free(msg);
+ return true;
+}
+
int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
struct net_device *netdev, u32 nlpid,
int freq, const u8 *buf, size_t len, gfp_t gfp)
--- a/net/wireless/nl80211.h 2011-09-23 10:34:28.000000000 +0200
+++ b/net/wireless/nl80211.h 2011-10-11 14:47:39.000000000 +0200
@@ -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 */
^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC 06/12] mac80211: support spurious class3 event
2011-10-14 15:11 [RFC 00/12] no more mon.wlan0 Johannes Berg
` (4 preceding siblings ...)
2011-10-14 15:11 ` [RFC 05/12] nl80211: allow subscribing to unexpected class3 frames Johannes Berg
@ 2011-10-14 15:11 ` Johannes Berg
2011-10-14 15:11 ` [RFC 07/12] nl80211: advertise device AP SME Johannes Berg
` (5 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2011-10-14 15:11 UTC (permalink / raw)
To: linux-wireless
From: Johannes Berg <johannes.berg@intel.com>
Add support for the spurious class3 frame event
to mac80211 to enable AP w/o monitor mode.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/mac80211/rx.c | 7 +++++++
1 file changed, 7 insertions(+)
--- a/net/mac80211/rx.c 2011-10-11 15:22:31.000000000 +0200
+++ b/net/mac80211/rx.c 2011-10-11 15:22:38.000000000 +0200
@@ -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;
}
^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC 07/12] nl80211: advertise device AP SME
2011-10-14 15:11 [RFC 00/12] no more mon.wlan0 Johannes Berg
` (5 preceding siblings ...)
2011-10-14 15:11 ` [RFC 06/12] mac80211: support spurious class3 event Johannes Berg
@ 2011-10-14 15:11 ` Johannes Berg
2011-10-14 15:11 ` [RFC 08/12] nl80211: add API to probe a client Johannes Berg
` (4 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2011-10-14 15:11 UTC (permalink / raw)
To: linux-wireless
From: Johannes Berg <johannes.berg@intel.com>
Add the ability to advertise that the device
contains the AP SME and what features it can
support.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
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(-)
--- a/include/linux/nl80211.h 2011-10-13 11:06:25.000000000 +0200
+++ b/include/linux/nl80211.h 2011-10-13 11:09:24.000000000 +0200
@@ -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,
@@ -2661,4 +2668,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 */
--- a/include/net/cfg80211.h 2011-10-13 11:06:25.000000000 +0200
+++ b/include/net/cfg80211.h 2011-10-13 11:10:33.000000000 +0200
@@ -1672,6 +1672,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),
@@ -1690,6 +1691,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),
};
/**
@@ -1900,6 +1902,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 */
@@ -1923,6 +1927,8 @@ struct wiphy {
u32 flags;
+ u32 ap_sme_capa;
+
enum cfg80211_signal_type signal_type;
int bss_priv_size;
--- a/net/wireless/core.c 2011-10-06 21:59:47.000000000 +0200
+++ b/net/wireless/core.c 2011-10-13 11:12:27.000000000 +0200
@@ -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;
--- a/net/wireless/nl80211.c 2011-10-13 10:21:41.000000000 +0200
+++ b/net/wireless/nl80211.c 2011-10-13 11:11:29.000000000 +0200
@@ -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:
--- a/drivers/net/wireless/ath/ath6kl/init.c 2011-10-05 09:07:16.000000000 +0200
+++ b/drivers/net/wireless/ath/ath6kl/init.c 2011-10-13 11:14:01.000000000 +0200
@@ -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)
^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC 08/12] nl80211: add API to probe a client
2011-10-14 15:11 [RFC 00/12] no more mon.wlan0 Johannes Berg
` (6 preceding siblings ...)
2011-10-14 15:11 ` [RFC 07/12] nl80211: advertise device AP SME Johannes Berg
@ 2011-10-14 15:11 ` Johannes Berg
2011-10-14 15:11 ` [RFC 09/12] mac80211: support client probe Johannes Berg
` (3 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2011-10-14 15:11 UTC (permalink / raw)
To: linux-wireless
From: Johannes Berg <johannes.berg@intel.com>
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.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
include/linux/nl80211.h | 9 ++++
include/net/cfg80211.h | 16 +++++++
net/wireless/nl80211.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 127 insertions(+)
--- a/include/linux/nl80211.h 2011-10-13 11:09:24.000000000 +0200
+++ b/include/linux/nl80211.h 2011-10-13 11:30:08.000000000 +0200
@@ -520,6 +520,13 @@
* 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.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -651,6 +658,8 @@ enum nl80211_commands {
NL80211_CMD_UNEXPECTED_FRAME,
+ NL80211_CMD_PROBE_CLIENT,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
--- a/include/net/cfg80211.h 2011-10-13 11:10:33.000000000 +0200
+++ b/include/net/cfg80211.h 2011-10-13 12:55:26.000000000 +0200
@@ -1425,6 +1425,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_acked().
*/
struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -1614,6 +1617,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);
};
/*
@@ -3207,6 +3213,16 @@ void cfg80211_pmksa_candidate_notify(str
bool cfg80211_rx_spurious_frame(struct net_device *dev,
const u8 *addr, gfp_t gfp);
+/**
+ * cfg80211_probe_acked - notify that probe was acked
+ * @dev: the device the probe was sent on
+ * @addr: the address of the peer
+ * @cookie: the cookie filled in @probe_client previously
+ * @gfp: allocation flags
+ */
+void cfg80211_probe_acked(struct net_device *dev, const u8 *addr,
+ u64 cookie, gfp_t gfp);
+
/* Logging, debugging and troubleshooting/diagnostic helpers. */
/* wiphy_printk helpers, similar to dev_printk */
--- a/net/wireless/nl80211.c 2011-10-13 11:11:29.000000000 +0200
+++ b/net/wireless/nl80211.c 2011-10-13 13:04:08.000000000 +0200
@@ -891,6 +891,7 @@ static int nl80211_send_wiphy(struct sk_
}
if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
CMD(sched_scan_start, START_SCHED_SCAN);
+ CMD(probe_client, PROBE_CLIENT);
#undef CMD
@@ -5844,6 +5845,59 @@ static int nl80211_register_unexpected_f
return 0;
}
+static int nl80211_probe_client(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct sk_buff *msg;
+ void *hdr;
+ const u8 *addr;
+ u64 cookie;
+ int err;
+
+ if (wdev->iftype != NL80211_IFTYPE_AP &&
+ wdev->iftype != NL80211_IFTYPE_P2P_GO)
+ return -EOPNOTSUPP;
+
+ if (!info->attrs[NL80211_ATTR_MAC])
+ return -EINVAL;
+
+ if (!rdev->ops->probe_client)
+ return -EOPNOTSUPP;
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
+ NL80211_CMD_PROBE_CLIENT);
+
+ if (IS_ERR(hdr)) {
+ err = PTR_ERR(hdr);
+ goto free_msg;
+ }
+
+ addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+ err = rdev->ops->probe_client(&rdev->wiphy, dev, addr, &cookie);
+ if (err)
+ goto free_msg;
+
+ NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
+
+ genlmsg_end(msg, hdr);
+
+ return genlmsg_reply(msg, info);
+
+ nla_put_failure:
+ err = -ENOBUFS;
+ free_msg:
+ nlmsg_free(msg);
+ return err;
+}
+
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -6407,6 +6461,14 @@ static struct genl_ops nl80211_ops[] = {
.internal_flags = NL80211_FLAG_NEED_NETDEV |
NL80211_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL80211_CMD_PROBE_CLIENT,
+ .doit = nl80211_probe_client,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV |
+ NL80211_FLAG_NEED_RTNL,
+ },
};
static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -7528,6 +7590,46 @@ nl80211_send_cqm_pktloss_notify(struct c
nlmsg_free(msg);
}
+void cfg80211_probe_acked(struct net_device *dev, const u8 *addr,
+ u64 cookie, gfp_t gfp)
+{
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+ struct sk_buff *msg;
+ void *hdr;
+ int err;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+ if (!msg)
+ return;
+
+ hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PROBE_CLIENT);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
+
+ err = genlmsg_end(msg, hdr);
+ if (err < 0) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_mlme_mcgrp.id, gfp);
+ return;
+
+ nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ nlmsg_free(msg);
+}
+EXPORT_SYMBOL(cfg80211_probe_acked);
+
static int nl80211_netlink_notify(struct notifier_block * nb,
unsigned long state,
void *_notify)
^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC 09/12] mac80211: support client probe
2011-10-14 15:11 [RFC 00/12] no more mon.wlan0 Johannes Berg
` (7 preceding siblings ...)
2011-10-14 15:11 ` [RFC 08/12] nl80211: add API to probe a client Johannes Berg
@ 2011-10-14 15:11 ` Johannes Berg
2011-10-14 15:11 ` [RFC 10/12] net: add wireless TX status socket option Johannes Berg
` (2 subsequent siblings)
11 siblings, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2011-10-14 15:11 UTC (permalink / raw)
To: linux-wireless
From: Johannes Berg <johannes.berg@intel.com>
Support probing clients with null data frames
in AP mode.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
net/mac80211/cfg.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++
net/mac80211/status.c | 45 +++++++++++++++++++--------------
2 files changed, 95 insertions(+), 18 deletions(-)
--- a/net/mac80211/cfg.c 2011-10-13 13:45:15.000000000 +0200
+++ b/net/mac80211/cfg.c 2011-10-13 21:52:32.000000000 +0200
@@ -2484,6 +2484,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,
@@ -2549,4 +2616,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,
};
--- a/net/mac80211/status.c 2011-10-13 13:45:14.000000000 +0200
+++ b/net/mac80211/status.c 2011-10-13 21:51:41.000000000 +0200
@@ -420,27 +420,36 @@ void ieee80211_tx_status(struct ieee8021
}
if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
- struct ieee80211_work *wk;
u64 cookie = (unsigned long)skb;
- rcu_read_lock();
- list_for_each_entry_rcu(wk, &local->work_list, list) {
- if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
- continue;
- if (wk->offchan_tx.frame != skb)
- continue;
- wk->offchan_tx.status = true;
- break;
- }
- rcu_read_unlock();
- if (local->hw_roc_skb_for_status == skb) {
- cookie = local->hw_roc_cookie ^ 2;
- local->hw_roc_skb_for_status = NULL;
- }
+ if (ieee80211_is_nullfunc(hdr->frame_control) ||
+ ieee80211_is_qos_nullfunc(hdr->frame_control)) {
+ if (info->flags & IEEE80211_TX_STAT_ACK)
+ cfg80211_probe_acked(skb->dev, hdr->addr1,
+ cookie, GFP_ATOMIC);
+ } else {
+ struct ieee80211_work *wk;
- cfg80211_mgmt_tx_status(
- skb->dev, cookie, skb->data, skb->len,
- !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC);
+ rcu_read_lock();
+ list_for_each_entry_rcu(wk, &local->work_list, list) {
+ if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
+ continue;
+ if (wk->offchan_tx.frame != skb)
+ continue;
+ wk->offchan_tx.status = true;
+ break;
+ }
+ rcu_read_unlock();
+ if (local->hw_roc_skb_for_status == skb) {
+ cookie = local->hw_roc_cookie ^ 2;
+ local->hw_roc_skb_for_status = NULL;
+ }
+
+ cfg80211_mgmt_tx_status(
+ skb->dev, cookie, skb->data, skb->len,
+ !!(info->flags & IEEE80211_TX_STAT_ACK),
+ GFP_ATOMIC);
+ }
}
/* this was a transmitted frame, but now we want to reuse it */
^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC 10/12] net: add wireless TX status socket option
2011-10-14 15:11 [RFC 00/12] no more mon.wlan0 Johannes Berg
` (8 preceding siblings ...)
2011-10-14 15:11 ` [RFC 09/12] mac80211: support client probe Johannes Berg
@ 2011-10-14 15:11 ` Johannes Berg
2011-10-14 15:11 ` [RFC 11/12] nl80211: advertise socket TX status capability Johannes Berg
2011-10-14 15:11 ` [RFC 12/12] mac80211: implement wifi TX status Johannes Berg
11 siblings, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2011-10-14 15:11 UTC (permalink / raw)
To: linux-wireless
From: Johannes Berg <johannes.berg@intel.com>
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?
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
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(-)
--- a/include/asm-generic/socket.h 2011-10-12 19:24:34.000000000 +0200
+++ b/include/asm-generic/socket.h 2011-10-13 13:45:19.000000000 +0200
@@ -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 */
--- a/net/core/sock.c 2011-10-12 19:24:40.000000000 +0200
+++ b/net/core/sock.c 2011-10-13 13:45:19.000000000 +0200
@@ -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;
}
--- a/include/net/sock.h 2011-10-12 19:24:34.000000000 +0200
+++ b/include/net/sock.h 2011-10-13 13:45:19.000000000 +0200
@@ -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,
--- a/arch/alpha/include/asm/socket.h 2011-10-12 19:24:33.000000000 +0200
+++ b/arch/alpha/include/asm/socket.h 2011-10-13 13:45:19.000000000 +0200
@@ -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.
*/
--- a/arch/arm/include/asm/socket.h 2011-10-12 19:24:33.000000000 +0200
+++ b/arch/arm/include/asm/socket.h 2011-10-13 13:45:19.000000000 +0200
@@ -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 */
--- a/arch/avr32/include/asm/socket.h 2011-10-12 19:24:32.000000000 +0200
+++ b/arch/avr32/include/asm/socket.h 2011-10-13 13:45:19.000000000 +0200
@@ -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 */
--- a/arch/cris/include/asm/socket.h 2011-10-12 19:24:33.000000000 +0200
+++ b/arch/cris/include/asm/socket.h 2011-10-13 13:45:19.000000000 +0200
@@ -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 */
--- a/arch/frv/include/asm/socket.h 2011-10-12 19:24:33.000000000 +0200
+++ b/arch/frv/include/asm/socket.h 2011-10-13 13:45:19.000000000 +0200
@@ -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 */
--- a/arch/h8300/include/asm/socket.h 2011-10-12 19:24:32.000000000 +0200
+++ b/arch/h8300/include/asm/socket.h 2011-10-13 13:45:19.000000000 +0200
@@ -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 */
--- a/arch/ia64/include/asm/socket.h 2011-10-12 19:24:33.000000000 +0200
+++ b/arch/ia64/include/asm/socket.h 2011-10-13 13:45:19.000000000 +0200
@@ -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 */
--- a/arch/m32r/include/asm/socket.h 2011-10-12 19:24:33.000000000 +0200
+++ b/arch/m32r/include/asm/socket.h 2011-10-13 13:45:19.000000000 +0200
@@ -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 */
--- a/arch/m68k/include/asm/socket.h 2011-10-12 19:24:33.000000000 +0200
+++ b/arch/m68k/include/asm/socket.h 2011-10-13 13:45:19.000000000 +0200
@@ -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 */
--- a/arch/mips/include/asm/socket.h 2011-10-12 19:24:33.000000000 +0200
+++ b/arch/mips/include/asm/socket.h 2011-10-13 13:45:19.000000000 +0200
@@ -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
--- a/arch/mn10300/include/asm/socket.h 2011-10-12 19:24:32.000000000 +0200
+++ b/arch/mn10300/include/asm/socket.h 2011-10-13 13:45:19.000000000 +0200
@@ -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 */
--- a/arch/parisc/include/asm/socket.h 2011-10-12 19:24:32.000000000 +0200
+++ b/arch/parisc/include/asm/socket.h 2011-10-13 13:45:19.000000000 +0200
@@ -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.
*/
--- a/arch/powerpc/include/asm/socket.h 2011-10-12 19:24:33.000000000 +0200
+++ b/arch/powerpc/include/asm/socket.h 2011-10-13 13:45:19.000000000 +0200
@@ -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 */
--- a/arch/s390/include/asm/socket.h 2011-10-12 19:24:32.000000000 +0200
+++ b/arch/s390/include/asm/socket.h 2011-10-13 13:45:19.000000000 +0200
@@ -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 */
--- a/arch/sparc/include/asm/socket.h 2011-10-12 19:24:32.000000000 +0200
+++ b/arch/sparc/include/asm/socket.h 2011-10-13 13:45:19.000000000 +0200
@@ -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
--- a/arch/xtensa/include/asm/socket.h 2011-10-12 19:24:32.000000000 +0200
+++ b/arch/xtensa/include/asm/socket.h 2011-10-13 13:45:19.000000000 +0200
@@ -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 */
--- a/include/linux/errqueue.h 2011-10-12 19:24:33.000000000 +0200
+++ b/include/linux/errqueue.h 2011-10-13 13:45:19.000000000 +0200
@@ -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))
--- a/include/linux/skbuff.h 2011-10-12 19:24:33.000000000 +0200
+++ b/include/linux/skbuff.h 2011-10-13 13:45:19.000000000 +0200
@@ -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);
--- a/net/core/skbuff.c 2011-10-12 19:24:34.000000000 +0200
+++ b/net/core/skbuff.c 2011-10-13 13:45:19.000000000 +0200
@@ -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
--- a/net/socket.c 2011-10-12 19:24:34.000000000 +0200
+++ b/net/socket.c 2011-10-13 13:45:19.000000000 +0200
@@ -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)
{
^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC 11/12] nl80211: advertise socket TX status capability
2011-10-14 15:11 [RFC 00/12] no more mon.wlan0 Johannes Berg
` (9 preceding siblings ...)
2011-10-14 15:11 ` [RFC 10/12] net: add wireless TX status socket option Johannes Berg
@ 2011-10-14 15:11 ` Johannes Berg
2011-10-14 15:11 ` [RFC 12/12] mac80211: implement wifi TX status Johannes Berg
11 siblings, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2011-10-14 15:11 UTC (permalink / raw)
To: linux-wireless
From: Johannes Berg <johannes.berg@intel.com>
The new wifi socket TX capability should be
supported by wifi drivers, let them advertise
whether they do or not.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
include/linux/nl80211.h | 15 +++++++++++++++
include/net/cfg80211.h | 3 ++-
net/wireless/nl80211.c | 2 ++
3 files changed, 19 insertions(+), 1 deletion(-)
--- a/include/linux/nl80211.h 2011-10-13 13:45:18.000000000 +0200
+++ b/include/linux/nl80211.h 2011-10-13 13:52:09.000000000 +0200
@@ -1136,6 +1136,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
*/
@@ -1366,6 +1369,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,
@@ -2690,4 +2695,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 */
--- a/include/net/cfg80211.h 2011-10-13 13:45:18.000000000 +0200
+++ b/include/net/cfg80211.h 2011-10-13 13:52:50.000000000 +0200
@@ -1870,6 +1870,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
@@ -1931,7 +1932,7 @@ struct wiphy {
/* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
u16 interface_modes;
- u32 flags;
+ u32 flags, features;
u32 ap_sme_capa;
--- a/net/wireless/nl80211.c 2011-10-13 13:45:18.000000000 +0200
+++ b/net/wireless/nl80211.c 2011-10-13 13:53:22.000000000 +0200
@@ -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:
^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC 12/12] mac80211: implement wifi TX status
2011-10-14 15:11 [RFC 00/12] no more mon.wlan0 Johannes Berg
` (10 preceding siblings ...)
2011-10-14 15:11 ` [RFC 11/12] nl80211: advertise socket TX status capability Johannes Berg
@ 2011-10-14 15:11 ` Johannes Berg
11 siblings, 0 replies; 13+ messages in thread
From: Johannes Berg @ 2011-10-14 15:11 UTC (permalink / raw)
To: linux-wireless
From: Johannes Berg <johannes.berg@intel.com>
Implement the socket wifi TX status error
queue reflection in mac80211.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
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(-)
--- a/net/mac80211/status.c 2011-10-13 22:02:03.000000000 +0200
+++ b/net/mac80211/status.c 2011-10-13 22:02:03.000000000 +0200
@@ -452,6 +452,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);
@@ -556,6 +574,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);
--- a/net/mac80211/tx.c 2011-10-13 22:02:02.000000000 +0200
+++ b/net/mac80211/tx.c 2011-10-13 22:02:03.000000000 +0200
@@ -1684,8 +1684,10 @@ netdev_tx_t ieee80211_subif_start_xmit(s
int nh_pos, h_pos;
struct sta_info *sta = NULL;
bool wme_sta = false, authorized = false, tdls_auth = false;
- struct sk_buff *tmp_skb;
bool tdls_direct = false;
+ bool multicast;
+ u32 info_flags = 0;
+ u16 info_id = 0;
if (unlikely(skb->len < ETH_HLEN)) {
ret = NETDEV_TX_OK;
@@ -1872,7 +1874,8 @@ netdev_tx_t ieee80211_subif_start_xmit(s
* if it is a multicast address (which can only happen
* in AP mode)
*/
- if (!is_multicast_ether_addr(hdr.addr1)) {
+ multicast = is_multicast_ether_addr(hdr.addr1);
+ if (!multicast) {
rcu_read_lock();
sta = sta_info_get(sdata, hdr.addr1);
if (sta) {
@@ -1913,11 +1916,54 @@ netdev_tx_t ieee80211_subif_start_xmit(s
goto fail;
}
+ if (unlikely(!multicast && skb->sk &&
+ skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)) {
+ struct sk_buff *orig_skb = skb;
+
+ skb = skb_clone(skb, GFP_ATOMIC);
+ if (skb) {
+ unsigned long flags;
+ int id, r;
+
+ spin_lock_irqsave(&local->ack_status_lock, flags);
+ r = idr_get_new_above(&local->ack_status_frames,
+ orig_skb, 1, &id);
+ if (r == -EAGAIN) {
+ idr_pre_get(&local->ack_status_frames,
+ GFP_ATOMIC);
+ r = idr_get_new_above(&local->ack_status_frames,
+ orig_skb, 1, &id);
+ }
+ if (WARN_ON(!id) || id > 0xffff) {
+ idr_remove(&local->ack_status_frames, id);
+ r = -ERANGE;
+ }
+ spin_unlock_irqrestore(&local->ack_status_lock, flags);
+
+ if (!r) {
+ info_id = id;
+ info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+ } else if (skb_shared(skb)) {
+ kfree_skb(orig_skb);
+ } else {
+ kfree_skb(skb);
+ skb = orig_skb;
+ }
+ } else {
+ /* couldn't clone -- lose tx status ... */
+ skb = orig_skb;
+ }
+ }
+
/*
* If the skb is shared we need to obtain our own copy.
*/
if (skb_shared(skb)) {
- tmp_skb = skb;
+ struct sk_buff *tmp_skb = skb;
+
+ /* can't happen -- skb is a clone if info_id != 0 */
+ WARN_ON(info_id);
+
skb = skb_clone(skb, GFP_ATOMIC);
kfree_skb(tmp_skb);
@@ -2018,6 +2064,10 @@ netdev_tx_t ieee80211_subif_start_xmit(s
memset(info, 0, sizeof(*info));
dev->trans_start = jiffies;
+
+ info->flags = info_flags;
+ info->ack_frame_id = info_id;
+
ieee80211_xmit(sdata, skb);
return NETDEV_TX_OK;
--- a/include/net/mac80211.h 2011-10-13 22:02:03.000000000 +0200
+++ b/include/net/mac80211.h 2011-10-13 22:02:03.000000000 +0200
@@ -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 {
--- a/net/mac80211/ieee80211_i.h 2011-10-13 22:01:52.000000000 +0200
+++ b/net/mac80211/ieee80211_i.h 2011-10-13 22:02:03.000000000 +0200
@@ -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>
@@ -1011,6 +1012,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;
--- a/net/mac80211/main.c 2011-10-13 22:01:52.000000000 +0200
+++ b/net/mac80211/main.c 2011-10-13 22:02:03.000000000 +0200
@@ -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++) {
@@ -1049,6 +1056,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);
@@ -1059,6 +1073,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);
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2011-10-14 15:13 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-10-14 15:11 [RFC 00/12] no more mon.wlan0 Johannes Berg
2011-10-14 15:11 ` [RFC 01/12] mac80211: reformat TX unauthorised check Johannes Berg
2011-10-14 15:11 ` [RFC 02/12] mac80211: fix TID for null poll response Johannes Berg
2011-10-14 15:11 ` [RFC 03/12] mac80211: add helper to free TX skb Johannes Berg
2011-10-14 15:11 ` [RFC 04/12] mac80211: add support for control port protocol in AP mode Johannes Berg
2011-10-14 15:11 ` [RFC 05/12] nl80211: allow subscribing to unexpected class3 frames Johannes Berg
2011-10-14 15:11 ` [RFC 06/12] mac80211: support spurious class3 event Johannes Berg
2011-10-14 15:11 ` [RFC 07/12] nl80211: advertise device AP SME Johannes Berg
2011-10-14 15:11 ` [RFC 08/12] nl80211: add API to probe a client Johannes Berg
2011-10-14 15:11 ` [RFC 09/12] mac80211: support client probe Johannes Berg
2011-10-14 15:11 ` [RFC 10/12] net: add wireless TX status socket option Johannes Berg
2011-10-14 15:11 ` [RFC 11/12] nl80211: advertise socket TX status capability Johannes Berg
2011-10-14 15:11 ` [RFC 12/12] mac80211: implement wifi TX status Johannes Berg
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).