cfg80211: make WoWLAN configuration available to drivers
authorJohannes Berg <johannes.berg@intel.com>
Wed, 15 May 2013 07:30:07 +0000 (09:30 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 27 May 2013 13:10:58 +0000 (15:10 +0200)
Make the current WoWLAN configuration available to drivers
at runtime. This isn't really useful for the normal WoWLAN
behaviour and accessing it can also be racy, but drivers
may use it for testing the WoWLAN device behaviour while
the host stays up & running to observe the device.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/cfg80211.h
net/wireless/core.c
net/wireless/core.h
net/wireless/nl80211.c
net/wireless/sysfs.c

index 9f45d74ce3c227d1ad6a47efe164be5547f6bd27..b3b076a46d5074ce9d4868968d2be1455b339c6f 100644 (file)
@@ -2583,6 +2583,9 @@ struct wiphy_wowlan_support {
  *     may request, if implemented.
  *
  * @wowlan: WoWLAN support information
+ * @wowlan_config: current WoWLAN configuration; this should usually not be
+ *     used since access to it is necessarily racy, use the parameter passed
+ *     to the suspend() operation instead.
  *
  * @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features.
  * @ht_capa_mod_mask:  Specify what ht_cap values can be over-ridden.
@@ -2650,6 +2653,7 @@ struct wiphy {
 
 #ifdef CONFIG_PM
        struct wiphy_wowlan_support wowlan;
+       struct cfg80211_wowlan *wowlan_config;
 #endif
 
        u16 max_remain_on_channel_duration;
index ee422871fe9e7a1b42b7ab571a6b858bc9671171..41cec1776f4f1d63f3b629178aae025b511b01c6 100644 (file)
@@ -663,8 +663,10 @@ void wiphy_unregister(struct wiphy *wiphy)
        flush_work(&rdev->event_work);
        cancel_delayed_work_sync(&rdev->dfs_update_channels_wk);
 
-       if (rdev->wowlan && rdev->ops->set_wakeup)
+#ifdef CONFIG_PM
+       if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
                rdev_set_wakeup(rdev, false);
+#endif
        cfg80211_rdev_free_wowlan(rdev);
 }
 EXPORT_SYMBOL(wiphy_unregister);
index b4b4a566626b961f49de9500f9b5b42f4badcc17..a65eaf8a84c1eced7f773a8aaa944bd1ca760cd2 100644 (file)
@@ -74,8 +74,6 @@ struct cfg80211_registered_device {
        struct work_struct conn_work;
        struct work_struct event_work;
 
-       struct cfg80211_wowlan *wowlan;
-
        struct delayed_work dfs_update_channels_wk;
 
        /* netlink port which started critical protocol (0 means not started) */
@@ -96,17 +94,20 @@ struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy)
 static inline void
 cfg80211_rdev_free_wowlan(struct cfg80211_registered_device *rdev)
 {
+#ifdef CONFIG_PM
        int i;
 
-       if (!rdev->wowlan)
+       if (!rdev->wiphy.wowlan_config)
                return;
-       for (i = 0; i < rdev->wowlan->n_patterns; i++)
-               kfree(rdev->wowlan->patterns[i].mask);
-       kfree(rdev->wowlan->patterns);
-       if (rdev->wowlan->tcp && rdev->wowlan->tcp->sock)
-               sock_release(rdev->wowlan->tcp->sock);
-       kfree(rdev->wowlan->tcp);
-       kfree(rdev->wowlan);
+       for (i = 0; i < rdev->wiphy.wowlan_config->n_patterns; i++)
+               kfree(rdev->wiphy.wowlan_config->patterns[i].mask);
+       kfree(rdev->wiphy.wowlan_config->patterns);
+       if (rdev->wiphy.wowlan_config->tcp &&
+           rdev->wiphy.wowlan_config->tcp->sock)
+               sock_release(rdev->wiphy.wowlan_config->tcp->sock);
+       kfree(rdev->wiphy.wowlan_config->tcp);
+       kfree(rdev->wiphy.wowlan_config);
+#endif
 }
 
 extern struct workqueue_struct *cfg80211_wq;
index a09f36bb957c32977f08d52f4a3785921be1543e..fb6abcb359a148677f61a1165289814e805cdda1 100644 (file)
@@ -7489,28 +7489,29 @@ static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info)
 static int nl80211_send_wowlan_patterns(struct sk_buff *msg,
                                        struct cfg80211_registered_device *rdev)
 {
+       struct cfg80211_wowlan *wowlan = rdev->wiphy.wowlan_config;
        struct nlattr *nl_pats, *nl_pat;
        int i, pat_len;
 
-       if (!rdev->wowlan->n_patterns)
+       if (!wowlan->n_patterns)
                return 0;
 
        nl_pats = nla_nest_start(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN);
        if (!nl_pats)
                return -ENOBUFS;
 
-       for (i = 0; i < rdev->wowlan->n_patterns; i++) {
+       for (i = 0; i < wowlan->n_patterns; i++) {
                nl_pat = nla_nest_start(msg, i + 1);
                if (!nl_pat)
                        return -ENOBUFS;
-               pat_len = rdev->wowlan->patterns[i].pattern_len;
+               pat_len = wowlan->patterns[i].pattern_len;
                if (nla_put(msg, NL80211_WOWLAN_PKTPAT_MASK,
                            DIV_ROUND_UP(pat_len, 8),
-                           rdev->wowlan->patterns[i].mask) ||
+                           wowlan->patterns[i].mask) ||
                    nla_put(msg, NL80211_WOWLAN_PKTPAT_PATTERN,
-                           pat_len, rdev->wowlan->patterns[i].pattern) ||
+                           pat_len, wowlan->patterns[i].pattern) ||
                    nla_put_u32(msg, NL80211_WOWLAN_PKTPAT_OFFSET,
-                               rdev->wowlan->patterns[i].pkt_offset))
+                               wowlan->patterns[i].pkt_offset))
                        return -ENOBUFS;
                nla_nest_end(msg, nl_pat);
        }
@@ -7573,12 +7574,12 @@ static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
            !rdev->wiphy.wowlan.tcp)
                return -EOPNOTSUPP;
 
-       if (rdev->wowlan && rdev->wowlan->tcp) {
+       if (rdev->wiphy.wowlan_config && rdev->wiphy.wowlan_config->tcp) {
                /* adjust size to have room for all the data */
-               size += rdev->wowlan->tcp->tokens_size +
-                       rdev->wowlan->tcp->payload_len +
-                       rdev->wowlan->tcp->wake_len +
-                       rdev->wowlan->tcp->wake_len / 8;
+               size += rdev->wiphy.wowlan_config->tcp->tokens_size +
+                       rdev->wiphy.wowlan_config->tcp->payload_len +
+                       rdev->wiphy.wowlan_config->tcp->wake_len +
+                       rdev->wiphy.wowlan_config->tcp->wake_len / 8;
        }
 
        msg = nlmsg_new(size, GFP_KERNEL);
@@ -7590,33 +7591,34 @@ static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
        if (!hdr)
                goto nla_put_failure;
 
-       if (rdev->wowlan) {
+       if (rdev->wiphy.wowlan_config) {
                struct nlattr *nl_wowlan;
 
                nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
                if (!nl_wowlan)
                        goto nla_put_failure;
 
-               if ((rdev->wowlan->any &&
+               if ((rdev->wiphy.wowlan_config->any &&
                     nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
-                   (rdev->wowlan->disconnect &&
+                   (rdev->wiphy.wowlan_config->disconnect &&
                     nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
-                   (rdev->wowlan->magic_pkt &&
+                   (rdev->wiphy.wowlan_config->magic_pkt &&
                     nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
-                   (rdev->wowlan->gtk_rekey_failure &&
+                   (rdev->wiphy.wowlan_config->gtk_rekey_failure &&
                     nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
-                   (rdev->wowlan->eap_identity_req &&
+                   (rdev->wiphy.wowlan_config->eap_identity_req &&
                     nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
-                   (rdev->wowlan->four_way_handshake &&
+                   (rdev->wiphy.wowlan_config->four_way_handshake &&
                     nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
-                   (rdev->wowlan->rfkill_release &&
+                   (rdev->wiphy.wowlan_config->rfkill_release &&
                     nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE)))
                        goto nla_put_failure;
 
                if (nl80211_send_wowlan_patterns(msg, rdev))
                        goto nla_put_failure;
 
-               if (nl80211_send_wowlan_tcp(msg, rdev->wowlan->tcp))
+               if (nl80211_send_wowlan_tcp(msg,
+                                           rdev->wiphy.wowlan_config->tcp))
                        goto nla_put_failure;
 
                nla_nest_end(msg, nl_wowlan);
@@ -7783,7 +7785,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
        struct cfg80211_wowlan *ntrig;
        struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan;
        int err, i;
-       bool prev_enabled = rdev->wowlan;
+       bool prev_enabled = rdev->wiphy.wowlan_config;
 
        if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns &&
            !rdev->wiphy.wowlan.tcp)
@@ -7791,7 +7793,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
 
        if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) {
                cfg80211_rdev_free_wowlan(rdev);
-               rdev->wowlan = NULL;
+               rdev->wiphy.wowlan_config = NULL;
                goto set_wakeup;
        }
 
@@ -7927,11 +7929,12 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
                goto error;
        }
        cfg80211_rdev_free_wowlan(rdev);
-       rdev->wowlan = ntrig;
+       rdev->wiphy.wowlan_config = ntrig;
 
  set_wakeup:
-       if (rdev->ops->set_wakeup && prev_enabled != !!rdev->wowlan)
-               rdev_set_wakeup(rdev, rdev->wowlan);
+       if (rdev->ops->set_wakeup &&
+           prev_enabled != !!rdev->wiphy.wowlan_config)
+               rdev_set_wakeup(rdev, rdev->wiphy.wowlan_config);
 
        return 0;
  error:
index 8f28b9f798d88a48281a7b633406b99bad4b5e98..360a42c6f69494b368ebab58be31ef058be79477 100644 (file)
@@ -91,6 +91,7 @@ static void cfg80211_leave_all(struct cfg80211_registered_device *rdev)
                cfg80211_leave(rdev, wdev);
 }
 
+#ifdef CONFIG_PM
 static int wiphy_suspend(struct device *dev, pm_message_t state)
 {
        struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
@@ -100,10 +101,10 @@ static int wiphy_suspend(struct device *dev, pm_message_t state)
 
        rtnl_lock();
        if (rdev->wiphy.registered) {
-               if (!rdev->wowlan)
+               if (!rdev->wiphy.wowlan_config)
                        cfg80211_leave_all(rdev);
                if (rdev->ops->suspend)
-                       ret = rdev_suspend(rdev, rdev->wowlan);
+                       ret = rdev_suspend(rdev, rdev->wiphy.wowlan_config);
                if (ret == 1) {
                        /* Driver refuse to configure wowlan */
                        cfg80211_leave_all(rdev);
@@ -132,6 +133,7 @@ static int wiphy_resume(struct device *dev)
 
        return ret;
 }
+#endif
 
 static const void *wiphy_namespace(struct device *d)
 {
@@ -146,8 +148,10 @@ struct class ieee80211_class = {
        .dev_release = wiphy_dev_release,
        .dev_attrs = ieee80211_dev_attrs,
        .dev_uevent = wiphy_uevent,
+#ifdef CONFIG_PM
        .suspend = wiphy_suspend,
        .resume = wiphy_resume,
+#endif
        .ns_type = &net_ns_type_operations,
        .namespace = wiphy_namespace,
 };