2011-11-10 09:29:04

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH v5 1/3] nl80211: Add probe response offload attribute

Notify user-space about probe-response offloading support in the driver.

A wiphy flag is used to indicate support and a bitmap of protocols
determines which protocols are supported.

Signed-off-by: Guy Eilam <[email protected]>
Signed-off-by: Arik Nemtsov <[email protected]>
---
v4->5:
- fixed up the constant of the PROBE_RESP_OFFLOAD attribute (left over
from v3)
- rebased everything on wireless-testing

include/linux/nl80211.h | 28 ++++++++++++++++++++++++++++
include/net/cfg80211.h | 10 ++++++++++
net/wireless/nl80211.c | 4 ++++
3 files changed, 42 insertions(+), 0 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 3152ddf..be92333 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1160,6 +1160,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_PROBE_RESP_OFFLOAD: Indicates that the HW responds to probe
+ *
+ * requests while operating in AP-mode.
+ * This attribute holds a bitmap of the supported protocols for
+ * offloading (see &enum nl80211_probe_resp_offload_support_attr).
*
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -1395,6 +1400,8 @@ enum nl80211_attrs {

NL80211_ATTR_FEATURE_FLAGS,

+ NL80211_ATTR_PROBE_RESP_OFFLOAD,
+
/* add attributes here, update the policy in nl80211.c */

__NL80211_ATTR_AFTER_LAST,
@@ -2727,4 +2734,25 @@ enum nl80211_feature_flags {
NL80211_FEATURE_SK_TX_STATUS = 1 << 0,
};

+/**
+ * enum nl80211_probe_resp_offload_support_attr - optional supported
+ * protocols for probe-response offloading by the driver/FW.
+ * To be used with the %NL80211_ATTR_PROBE_RESP_OFFLOAD attribute.
+ * Each enum value represents a bit in the bitmap of supported
+ * protocols. Typically a subset of probe-requests belonging to a
+ * supported protocol will be excluded from offload and uploaded
+ * to the host.
+ *
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS: Support for WPS ver. 1
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2: Support for WPS ver. 2
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P: Support for P2P
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U: Support for 802.11u
+ */
+enum nl80211_probe_resp_offload_support_attr {
+ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS = 1<<0,
+ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 = 1<<1,
+ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P = 1<<2,
+ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U = 1<<3,
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index e1ee141..243bf23 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1689,6 +1689,8 @@ struct cfg80211_ops {
* @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().
+ * @WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD: When operating as an AP, the device
+ * responds to probe-requests in hardware.
*/
enum wiphy_flags {
WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
@@ -1709,6 +1711,7 @@ enum wiphy_flags {
WIPHY_FLAG_TDLS_EXTERNAL_SETUP = BIT(16),
WIPHY_FLAG_HAVE_AP_SME = BIT(17),
WIPHY_FLAG_REPORTS_OBSS = BIT(18),
+ WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD = BIT(19),
};

/**
@@ -1977,6 +1980,13 @@ struct wiphy {
u32 available_antennas_tx;
u32 available_antennas_rx;

+ /*
+ * Bitmap of supported protocols for probe response offloading
+ * see &enum nl80211_probe_resp_offload_support_attr. Only valid
+ * when the wiphy flag @WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD is set.
+ */
+ u32 probe_resp_offload;
+
/* If multiple wiphys are registered and you're handed e.g.
* a regular netdev with assigned ieee80211_ptr, you won't
* know whether it points to a wiphy your driver has registered
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 864fcb6..0349f48 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -759,6 +759,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
dev->wiphy.available_antennas_rx);

+ if (dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD)
+ NLA_PUT_U32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
+ dev->wiphy.probe_resp_offload);
+
if ((dev->wiphy.available_antennas_tx ||
dev->wiphy.available_antennas_rx) && dev->ops->get_antenna) {
u32 tx_ant = 0, rx_ant = 0;
--
1.7.5.4



2011-11-19 08:52:35

by Arik Nemtsov

[permalink] [raw]
Subject: Re: [PATCH v5 3/3] mac80211: Save probe response data for bss

On Fri, Nov 18, 2011 at 18:12, Johannes Berg <[email protected]> wrote:
> On Thu, 2011-11-10 at 11:28 +0200, Arik Nemtsov wrote:
>> Allow setting a probe response template for an interface operating in
>> AP mode. Low level drivers are notified about changes in the probe
>> response template and are able to retrieve a copy of the current probe
>> response. This data can, for example, be uploaded to hardware as a
>> template.
>
>> +static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? u8 *resp, size_t resp_len)
>> +{
>> + ? ? struct sk_buff *new, *old;
>> +
>> + ? ? if (!resp || !resp_len)
>> + ? ? ? ? ? ? return -EINVAL;
>> +
>> + ? ? old = sdata->u.ap.probe_resp;
>
> sparse warns here with RCU checking enabled in the kernel:
>
> cfg.c:502:13: warning: incorrect type in assignment (different address spaces)
> cfg.c:502:13: ? ?expected struct sk_buff *old
> cfg.c:502:13: ? ?got struct sk_buff [noderef] <asn:4>*probe_resp
>
>
> Please take a look, ieee80211_set_beacon() uses rtnl_dereference() to
> avoid the sparse warning and annotate that the RTNL is used to protect
> the pointer.
>

Thanks. That's indeed a handy .config option.

Arik

2011-11-10 09:29:10

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH v5 3/3] mac80211: Save probe response data for bss

Allow setting a probe response template for an interface operating in
AP mode. Low level drivers are notified about changes in the probe
response template and are able to retrieve a copy of the current probe
response. This data can, for example, be uploaded to hardware as a
template.

Signed-off-by: Guy Eilam <[email protected]>
Signed-off-by: Arik Nemtsov <[email protected]>
---
include/net/mac80211.h | 15 +++++++++++++++
net/mac80211/cfg.c | 38 +++++++++++++++++++++++++++++++++++---
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/iface.c | 6 +++++-
net/mac80211/tx.c | 31 +++++++++++++++++++++++++++++++
net/mac80211/util.c | 3 ++-
6 files changed, 89 insertions(+), 5 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 2714646..0756049 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -166,6 +166,7 @@ struct ieee80211_low_level_stats {
* that it is only ever disabled for station mode.
* @BSS_CHANGED_IDLE: Idle changed for this BSS/interface.
* @BSS_CHANGED_SSID: SSID changed for this BSS (AP mode)
+ * @BSS_CHANGED_AP_PROBE_RESP: Probe Response changed for this BSS (AP mode)
*/
enum ieee80211_bss_change {
BSS_CHANGED_ASSOC = 1<<0,
@@ -184,6 +185,7 @@ enum ieee80211_bss_change {
BSS_CHANGED_QOS = 1<<13,
BSS_CHANGED_IDLE = 1<<14,
BSS_CHANGED_SSID = 1<<15,
+ BSS_CHANGED_AP_PROBE_RESP = 1<<16,

/* when adding here, make sure to change ieee80211_reconfig */
};
@@ -2675,6 +2677,19 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
}

/**
+ * ieee80211_proberesp_get - retrieve a Probe Response template
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ *
+ * Creates a Probe Response template which can, for example, be uploaded to
+ * hardware. The destination address should be set by the caller.
+ *
+ * Can only be called in AP mode.
+ */
+struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif);
+
+/**
* ieee80211_pspoll_get - retrieve a PS Poll template
* @hw: pointer obtained from ieee80211_alloc_hw().
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 02a4323..4dc12c2 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -491,6 +491,31 @@ static void ieee80211_config_ap_ssid(struct ieee80211_sub_if_data *sdata,
(params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE);
}

+static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
+ u8 *resp, size_t resp_len)
+{
+ struct sk_buff *new, *old;
+
+ if (!resp || !resp_len)
+ return -EINVAL;
+
+ old = sdata->u.ap.probe_resp;
+
+ new = dev_alloc_skb(resp_len);
+ if (!new)
+ return -ENOMEM;
+
+ memcpy(skb_put(new, resp_len), resp, resp_len);
+
+ rcu_assign_pointer(sdata->u.ap.probe_resp, new);
+ synchronize_rcu();
+
+ if (old)
+ dev_kfree_skb(old);
+
+ return 0;
+}
+
/*
* This handles both adding a beacon and setting new beacon info
*/
@@ -501,6 +526,7 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
int new_head_len, new_tail_len;
int size;
int err = -EINVAL;
+ u32 changed = 0;

old = rtnl_dereference(sdata->u.ap.beacon);

@@ -584,11 +610,17 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,

kfree(old);

+ err = ieee80211_set_probe_resp(sdata, params->probe_resp,
+ params->probe_resp_len);
+ if (!err)
+ changed |= BSS_CHANGED_AP_PROBE_RESP;
+
ieee80211_config_ap_ssid(sdata, params);
+ changed |= BSS_CHANGED_BEACON_ENABLED |
+ BSS_CHANGED_BEACON |
+ BSS_CHANGED_SSID;

- ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
- BSS_CHANGED_BEACON |
- BSS_CHANGED_SSID);
+ ieee80211_bss_info_change_notify(sdata, changed);
return 0;
}

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 76e656b..b851981 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -232,6 +232,7 @@ struct beacon_data {

struct ieee80211_if_ap {
struct beacon_data __rcu *beacon;
+ struct sk_buff __rcu *probe_resp;

struct list_head vlans;

diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index b7bc4b7..563dbd0 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -461,15 +461,19 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data *vlan, *tmpsdata;
struct beacon_data *old_beacon =
rtnl_dereference(sdata->u.ap.beacon);
+ struct sk_buff *old_probe_resp =
+ rtnl_dereference(sdata->u.ap.probe_resp);

/* sdata_running will return false, so this will disable */
ieee80211_bss_info_change_notify(sdata,
BSS_CHANGED_BEACON_ENABLED);

- /* remove beacon */
+ /* remove beacon and probe response */
RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
+ RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL);
synchronize_rcu();
kfree(old_beacon);
+ kfree(old_probe_resp);

/* down all dependent devices, that is VLANs */
list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 83f28f9..f044963 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2416,6 +2416,37 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ieee80211_beacon_get_tim);

+struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct ieee80211_if_ap *ap = NULL;
+ struct sk_buff *presp = NULL, *skb = NULL;
+ struct ieee80211_hdr *hdr;
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+ if (sdata->vif.type != NL80211_IFTYPE_AP)
+ return NULL;
+
+ rcu_read_lock();
+
+ ap = &sdata->u.ap;
+ presp = rcu_dereference(ap->probe_resp);
+ if (!presp)
+ goto out;
+
+ skb = skb_copy(presp, GFP_ATOMIC);
+ if (!skb)
+ goto out;
+
+ hdr = (struct ieee80211_hdr *) skb->data;
+ memset(hdr->addr1, 0, sizeof(hdr->addr1));
+
+out:
+ rcu_read_unlock();
+ return skb;
+}
+EXPORT_SYMBOL(ieee80211_proberesp_get);
+
struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 68d85d2..f068c4b 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1076,7 +1076,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
changed |= BSS_CHANGED_IBSS;
/* fall through */
case NL80211_IFTYPE_AP:
- changed |= BSS_CHANGED_SSID;
+ changed |= BSS_CHANGED_SSID |
+ BSS_CHANGED_AP_PROBE_RESP;
/* fall through */
case NL80211_IFTYPE_MESH_POINT:
changed |= BSS_CHANGED_BEACON |
--
1.7.5.4


2011-11-18 16:12:12

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH v5 3/3] mac80211: Save probe response data for bss

On Thu, 2011-11-10 at 11:28 +0200, Arik Nemtsov wrote:
> Allow setting a probe response template for an interface operating in
> AP mode. Low level drivers are notified about changes in the probe
> response template and are able to retrieve a copy of the current probe
> response. This data can, for example, be uploaded to hardware as a
> template.

> +static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
> + u8 *resp, size_t resp_len)
> +{
> + struct sk_buff *new, *old;
> +
> + if (!resp || !resp_len)
> + return -EINVAL;
> +
> + old = sdata->u.ap.probe_resp;

sparse warns here with RCU checking enabled in the kernel:

cfg.c:502:13: warning: incorrect type in assignment (different address spaces)
cfg.c:502:13: expected struct sk_buff *old
cfg.c:502:13: got struct sk_buff [noderef] <asn:4>*probe_resp


Please take a look, ieee80211_set_beacon() uses rtnl_dereference() to
avoid the sparse warning and annotate that the RTNL is used to protect
the pointer.

johannes


2011-11-10 09:29:07

by Arik Nemtsov

[permalink] [raw]
Subject: [PATCH v5 2/3] nl80211: Pass probe response data to drivers

Pass probe-response data from usermode via beacon parameters.

Signed-off-by: Guy Eilam <[email protected]>
Signed-off-by: Arik Nemtsov <[email protected]>
---
include/linux/nl80211.h | 6 ++++++
include/net/cfg80211.h | 4 ++++
net/wireless/nl80211.c | 9 +++++++++
3 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index be92333..f9261c2 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -1166,6 +1166,10 @@ enum nl80211_commands {
* This attribute holds a bitmap of the supported protocols for
* offloading (see &enum nl80211_probe_resp_offload_support_attr).
*
+ * @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire
+ * probe-response frame. The DA field in the 802.11 header is zero-ed out,
+ * to be filled by the FW.
+ *
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
*/
@@ -1402,6 +1406,8 @@ enum nl80211_attrs {

NL80211_ATTR_PROBE_RESP_OFFLOAD,

+ NL80211_ATTR_PROBE_RESP,
+
/* add attributes here, update the policy in nl80211.c */

__NL80211_ATTR_AFTER_LAST,
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 243bf23..13ce855 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -391,6 +391,8 @@ struct cfg80211_crypto_settings {
* @assocresp_ies: extra information element(s) to add into (Re)Association
* Response frames or %NULL
* @assocresp_ies_len: length of assocresp_ies in octets
+ * @probe_resp_len: length of probe response template (@probe_resp)
+ * @probe_resp: probe response template (AP mode only)
*/
struct beacon_parameters {
u8 *head, *tail;
@@ -408,6 +410,8 @@ struct beacon_parameters {
size_t proberesp_ies_len;
const u8 *assocresp_ies;
size_t assocresp_ies_len;
+ int probe_resp_len;
+ u8 *probe_resp;
};

/**
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 0349f48..3ae83cb 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -197,6 +197,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
[NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG },
[NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG },
[NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG },
+ [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY,
+ .len = IEEE80211_MAX_DATA_LEN },
};

/* policy for the key attributes */
@@ -2171,6 +2173,13 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
}

+ if (info->attrs[NL80211_ATTR_PROBE_RESP]) {
+ params.probe_resp =
+ nla_data(info->attrs[NL80211_ATTR_PROBE_RESP]);
+ params.probe_resp_len =
+ nla_len(info->attrs[NL80211_ATTR_PROBE_RESP]);
+ }
+
err = call(&rdev->wiphy, dev, &params);
if (!err && params.interval)
wdev->beacon_interval = params.interval;
--
1.7.5.4