Commit 98fc4386 authored by Johannes Berg's avatar Johannes Berg

nl80211: prohibit mixing 'any' and regular wowlan triggers

If the device supports waking up on 'any' signal - i.e. it continues
operating as usual and wakes up the host on pretty much anything that
happens, then it makes no sense to also configure the more restricted
WoWLAN mode where the device operates more autonomously but also in a
more restricted fashion.

Currently only cw2100 supports both 'any' and other triggers, but it
seems to be broken as it doesn't configure anything to the device, so
we can't currently get into a situation where both even can correctly
be configured. This is about to change (Intel devices are going to
support both and have different behaviour depending on configuration)
so make sure the conflicting modes cannot be configured.

(It seems that cw2100 advertises 'any' and 'disconnect' as a means of
saying that's what it will always do, but that isn't really the way
this API was meant to be used nor does it actually mean anything as
'any' always implies 'disconnect' already, and the driver doesn't
change device configuration in any way depending on the settings.)
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 88724a81
...@@ -3708,6 +3708,8 @@ struct nl80211_pattern_support { ...@@ -3708,6 +3708,8 @@ struct nl80211_pattern_support {
* @NL80211_WOWLAN_TRIG_ANY: wake up on any activity, do not really put * @NL80211_WOWLAN_TRIG_ANY: wake up on any activity, do not really put
* the chip into a special state -- works best with chips that have * the chip into a special state -- works best with chips that have
* support for low-power operation already (flag) * support for low-power operation already (flag)
* Note that this mode is incompatible with all of the others, if
* any others are even supported by the device.
* @NL80211_WOWLAN_TRIG_DISCONNECT: wake up on disconnect, the way disconnect * @NL80211_WOWLAN_TRIG_DISCONNECT: wake up on disconnect, the way disconnect
* is detected is implementation-specific (flag) * is detected is implementation-specific (flag)
* @NL80211_WOWLAN_TRIG_MAGIC_PKT: wake up on magic packet (6x 0xff, followed * @NL80211_WOWLAN_TRIG_MAGIC_PKT: wake up on magic packet (6x 0xff, followed
......
...@@ -9105,6 +9105,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) ...@@ -9105,6 +9105,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
const struct wiphy_wowlan_support *wowlan = rdev->wiphy.wowlan; const struct wiphy_wowlan_support *wowlan = rdev->wiphy.wowlan;
int err, i; int err, i;
bool prev_enabled = rdev->wiphy.wowlan_config; bool prev_enabled = rdev->wiphy.wowlan_config;
bool regular = false;
if (!wowlan) if (!wowlan)
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -9132,12 +9133,14 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) ...@@ -9132,12 +9133,14 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT)) if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT))
return -EINVAL; return -EINVAL;
new_triggers.disconnect = true; new_triggers.disconnect = true;
regular = true;
} }
if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) { if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) {
if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT)) if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT))
return -EINVAL; return -EINVAL;
new_triggers.magic_pkt = true; new_triggers.magic_pkt = true;
regular = true;
} }
if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED]) if (tb[NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED])
...@@ -9147,24 +9150,28 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) ...@@ -9147,24 +9150,28 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE)) if (!(wowlan->flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE))
return -EINVAL; return -EINVAL;
new_triggers.gtk_rekey_failure = true; new_triggers.gtk_rekey_failure = true;
regular = true;
} }
if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) { if (tb[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST]) {
if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ)) if (!(wowlan->flags & WIPHY_WOWLAN_EAP_IDENTITY_REQ))
return -EINVAL; return -EINVAL;
new_triggers.eap_identity_req = true; new_triggers.eap_identity_req = true;
regular = true;
} }
if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) { if (tb[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE]) {
if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE)) if (!(wowlan->flags & WIPHY_WOWLAN_4WAY_HANDSHAKE))
return -EINVAL; return -EINVAL;
new_triggers.four_way_handshake = true; new_triggers.four_way_handshake = true;
regular = true;
} }
if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) { if (tb[NL80211_WOWLAN_TRIG_RFKILL_RELEASE]) {
if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE)) if (!(wowlan->flags & WIPHY_WOWLAN_RFKILL_RELEASE))
return -EINVAL; return -EINVAL;
new_triggers.rfkill_release = true; new_triggers.rfkill_release = true;
regular = true;
} }
if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) { if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) {
...@@ -9173,6 +9180,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) ...@@ -9173,6 +9180,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
int rem, pat_len, mask_len, pkt_offset; int rem, pat_len, mask_len, pkt_offset;
struct nlattr *pat_tb[NUM_NL80211_PKTPAT]; struct nlattr *pat_tb[NUM_NL80211_PKTPAT];
regular = true;
nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN], nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
rem) rem)
n_patterns++; n_patterns++;
...@@ -9234,6 +9243,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) ...@@ -9234,6 +9243,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
} }
if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) { if (tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION]) {
regular = true;
err = nl80211_parse_wowlan_tcp( err = nl80211_parse_wowlan_tcp(
rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION], rdev, tb[NL80211_WOWLAN_TRIG_TCP_CONNECTION],
&new_triggers); &new_triggers);
...@@ -9242,6 +9252,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) ...@@ -9242,6 +9252,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
} }
if (tb[NL80211_WOWLAN_TRIG_NET_DETECT]) { if (tb[NL80211_WOWLAN_TRIG_NET_DETECT]) {
regular = true;
err = nl80211_parse_wowlan_nd( err = nl80211_parse_wowlan_nd(
rdev, wowlan, tb[NL80211_WOWLAN_TRIG_NET_DETECT], rdev, wowlan, tb[NL80211_WOWLAN_TRIG_NET_DETECT],
&new_triggers); &new_triggers);
...@@ -9249,6 +9260,17 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) ...@@ -9249,6 +9260,17 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
goto error; goto error;
} }
/* The 'any' trigger means the device continues operating more or less
* as in its normal operation mode and wakes up the host on most of the
* normal interrupts (like packet RX, ...)
* It therefore makes little sense to combine with the more constrained
* wakeup trigger modes.
*/
if (new_triggers.any && regular) {
err = -EINVAL;
goto error;
}
ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL); ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL);
if (!ntrig) { if (!ntrig) {
err = -ENOMEM; err = -ENOMEM;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment