2013-05-28 11:02:02

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH v2 1/3] cfg80211: support an active monitor interface flag

An active monitor interface is one that is used for communication (via
injection). It is expected to ACK incoming unicast packets. This is
useful for running various 802.11 testing utilities that associate to an
AP via injection and manage the state in user space.

Signed-off-by: Felix Fietkau <[email protected]>
---
include/net/cfg80211.h | 1 +
include/uapi/linux/nl80211.h | 4 ++++
net/wireless/nl80211.c | 10 ++++++++++
3 files changed, 15 insertions(+)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 26b5b69..489821f 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -954,6 +954,7 @@ enum monitor_flags {
MONITOR_FLAG_CONTROL = 1<<NL80211_MNTR_FLAG_CONTROL,
MONITOR_FLAG_OTHER_BSS = 1<<NL80211_MNTR_FLAG_OTHER_BSS,
MONITOR_FLAG_COOK_FRAMES = 1<<NL80211_MNTR_FLAG_COOK_FRAMES,
+ MONITOR_FLAG_ACTIVE = 1<<NL80211_MNTR_FLAG_ACTIVE,
};

/**
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index d1e48b5..7b4b101 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -2413,6 +2413,8 @@ enum nl80211_survey_info {
* @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering
* @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing.
* overrides all other flags.
+ * @NL80211_MNTR_FLAG_ACTIVE: use the configured MAC address
+ * and ACK incoming unicast packets.
*
* @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
* @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
@@ -2424,6 +2426,7 @@ enum nl80211_mntr_flags {
NL80211_MNTR_FLAG_CONTROL,
NL80211_MNTR_FLAG_OTHER_BSS,
NL80211_MNTR_FLAG_COOK_FRAMES,
+ NL80211_MNTR_FLAG_ACTIVE,

/* keep last */
__NL80211_MNTR_FLAG_AFTER_LAST,
@@ -3575,6 +3578,7 @@ enum nl80211_feature_flags {
NL80211_FEATURE_ADVERTISE_CHAN_LIMITS = 1 << 14,
NL80211_FEATURE_FULL_AP_CLIENT_STATE = 1 << 15,
NL80211_FEATURE_USERSPACE_MPM = 1 << 16,
+ NL80211_FEATURE_ACTIVE_MONITOR = 1 << 17,
};

/**
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index dfdb5e6..27c9f5c 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -2279,6 +2279,7 @@ static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = {
[NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG },
[NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG },
[NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG },
+ [NL80211_MNTR_FLAG_ACTIVE] = { .type = NLA_FLAG },
};

static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags)
@@ -2390,6 +2391,10 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info)
change = true;
}

+ if ((*flags & NL80211_MNTR_FLAG_ACTIVE) &&
+ !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
+ return -EOPNOTSUPP;
+
if (change)
err = cfg80211_change_iface(rdev, dev, ntype, flags, &params);
else
@@ -2447,6 +2452,11 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info)
err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ?
info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL,
&flags);
+
+ if (!err && (flags & NL80211_MNTR_FLAG_ACTIVE) &&
+ !(rdev->wiphy.features & NL80211_FEATURE_ACTIVE_MONITOR))
+ return -EOPNOTSUPP;
+
wdev = rdev_add_virtual_intf(rdev,
nla_data(info->attrs[NL80211_ATTR_IFNAME]),
type, err ? NULL : &flags, &params);
--
1.8.0.2



2013-05-28 11:02:01

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH v2 3/3] ath9k: advertise support for active monitor interfaces

Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/ath/ath9k/init.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index c0aa4ff..f1d028a 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -772,6 +772,8 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt)
hw->flags |= IEEE80211_HW_MFP_CAPABLE;

+ hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR;
+
hw->wiphy->interface_modes =
BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_P2P_CLIENT) |
--
1.8.0.2


2013-05-28 11:50:14

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] cfg80211: support an active monitor interface flag

On Tue, 2013-05-28 at 13:01 +0200, Felix Fietkau wrote:
> An active monitor interface is one that is used for communication (via
> injection). It is expected to ACK incoming unicast packets. This is
> useful for running various 802.11 testing utilities that associate to an
> AP via injection and manage the state in user space.

Applied 1 and 2.

Allowing MAC address duplication seems a bit strange, but I guess it
simplifies things for users?

johannes


2013-05-28 12:17:10

by Felix Fietkau

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] cfg80211: support an active monitor interface flag

On 2013-05-28 1:50 PM, Johannes Berg wrote:
> On Tue, 2013-05-28 at 13:01 +0200, Felix Fietkau wrote:
>> An active monitor interface is one that is used for communication (via
>> injection). It is expected to ACK incoming unicast packets. This is
>> useful for running various 802.11 testing utilities that associate to an
>> AP via injection and manage the state in user space.
>
> Applied 1 and 2.
>
> Allowing MAC address duplication seems a bit strange, but I guess it
> simplifies things for users?
It is allowed only for non-active monitor interfaces, which previously
did not use ieee80211_verify_mac and ignores the configured MAC address
anyway.

- Felix


2013-05-28 11:02:04

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH v2 2/3] mac80211: support active monitor interfaces

Support them only if the driver advertises support for them via
IEEE80211_HW_SUPPORTS_ACTIVE_MONITOR. Unlike normal monitor interfaces,
they are added to the driver, along with their MAC address.

Signed-off-by: Felix Fietkau <[email protected]>
---
net/mac80211/cfg.c | 11 +++++++----
net/mac80211/driver-ops.h | 3 ++-
net/mac80211/iface.c | 29 +++++++++++++++++++++++------
net/mac80211/util.c | 6 ++++++
4 files changed, 38 insertions(+), 11 deletions(-)

diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 1a89c80..7f73859 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -73,16 +73,19 @@ static int ieee80211_change_iface(struct wiphy *wiphy,
struct ieee80211_local *local = sdata->local;

if (ieee80211_sdata_running(sdata)) {
+ u32 mask = MONITOR_FLAG_COOK_FRAMES |
+ MONITOR_FLAG_ACTIVE;
+
/*
- * Prohibit MONITOR_FLAG_COOK_FRAMES to be
- * changed while the interface is up.
+ * Prohibit MONITOR_FLAG_COOK_FRAMES and
+ * MONITOR_FLAG_ACTIVE to be changed while the
+ * interface is up.
* Else we would need to add a lot of cruft
* to update everything:
* cooked_mntrs, monitor and all fif_* counters
* reconfigure hardware
*/
- if ((*flags & MONITOR_FLAG_COOK_FRAMES) !=
- (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES))
+ if ((*flags & mask) != (sdata->u.mntr_flags & mask))
return -EBUSY;

ieee80211_adjust_monitor_flags(sdata, -1);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 169664c..b931c96 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -146,7 +146,8 @@ static inline int drv_add_interface(struct ieee80211_local *local,

if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
(sdata->vif.type == NL80211_IFTYPE_MONITOR &&
- !(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF))))
+ !(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF) &&
+ !(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))))
return -EINVAL;

trace_drv_add_interface(local, sdata);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 60f1ce5..47e03e5 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -159,7 +159,8 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
return 0;
}

-static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr)
+static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr,
+ bool check_dup)
{
struct ieee80211_sub_if_data *sdata;
u64 new, mask, tmp;
@@ -179,10 +180,13 @@ static int ieee80211_verify_mac(struct ieee80211_local *local, u8 *addr)
((u64)m[2] << 3*8) | ((u64)m[3] << 2*8) |
((u64)m[4] << 1*8) | ((u64)m[5] << 0*8);

+ if (!check_dup)
+ return ret;

mutex_lock(&local->iflist_mtx);
list_for_each_entry(sdata, &local->interfaces, list) {
- if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
+ !(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
continue;

m = sdata->vif.addr;
@@ -204,12 +208,17 @@ static int ieee80211_change_mac(struct net_device *dev, void *addr)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct sockaddr *sa = addr;
+ bool check_dup = true;
int ret;

if (ieee80211_sdata_running(sdata))
return -EBUSY;

- ret = ieee80211_verify_mac(sdata->local, sa->sa_data);
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR &&
+ !(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
+ check_dup = false;
+
+ ret = ieee80211_verify_mac(sdata->local, sa->sa_data, check_dup);
if (ret)
return ret;

@@ -538,7 +547,11 @@ int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up)
break;
}

- if (local->monitors == 0 && local->open_count == 0) {
+ if (sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE) {
+ res = drv_add_interface(local, sdata);
+ if (res)
+ goto err_stop;
+ } else if (local->monitors == 0 && local->open_count == 0) {
res = ieee80211_add_virtual_monitor(local);
if (res)
goto err_stop;
@@ -912,7 +925,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
mutex_lock(&local->mtx);
ieee80211_recalc_idle(local);
mutex_unlock(&local->mtx);
- break;
+
+ if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
+ break;
+
+ /* fall through */
default:
if (going_down)
drv_remove_interface(local, sdata);
@@ -1061,7 +1078,7 @@ static const struct net_device_ops ieee80211_monitorif_ops = {
.ndo_start_xmit = ieee80211_monitor_start_xmit,
.ndo_set_rx_mode = ieee80211_set_multicast_list,
.ndo_change_mtu = ieee80211_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
+ .ndo_set_mac_address = ieee80211_change_mac,
.ndo_select_queue = ieee80211_monitor_select_queue,
};

diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 27e0715..7cbe0db 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -560,6 +560,9 @@ void ieee80211_iterate_active_interfaces(
list_for_each_entry(sdata, &local->interfaces, list) {
switch (sdata->vif.type) {
case NL80211_IFTYPE_MONITOR:
+ if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
+ continue;
+ break;
case NL80211_IFTYPE_AP_VLAN:
continue;
default:
@@ -598,6 +601,9 @@ void ieee80211_iterate_active_interfaces_atomic(
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
switch (sdata->vif.type) {
case NL80211_IFTYPE_MONITOR:
+ if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
+ continue;
+ break;
case NL80211_IFTYPE_AP_VLAN:
continue;
default:
--
1.8.0.2


2013-05-28 12:38:37

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH v2 1/3] cfg80211: support an active monitor interface flag

On Tue, 2013-05-28 at 14:17 +0200, Felix Fietkau wrote:
> On 2013-05-28 1:50 PM, Johannes Berg wrote:
> > On Tue, 2013-05-28 at 13:01 +0200, Felix Fietkau wrote:
> >> An active monitor interface is one that is used for communication (via
> >> injection). It is expected to ACK incoming unicast packets. This is
> >> useful for running various 802.11 testing utilities that associate to an
> >> AP via injection and manage the state in user space.
> >
> > Applied 1 and 2.
> >
> > Allowing MAC address duplication seems a bit strange, but I guess it
> > simplifies things for users?
> It is allowed only for non-active monitor interfaces, which previously
> did not use ieee80211_verify_mac and ignores the configured MAC address
> anyway.

Oh, that makes sense, I misread the code then.

johannes