cfg80211: restrict AP beacon intervals
authorJohannes Berg <johannes.berg@intel.com>
Mon, 9 May 2011 16:41:15 +0000 (18:41 +0200)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 12 May 2011 18:10:47 +0000 (14:10 -0400)
Multiple virtual AP interfaces can currently try
to use different beacon intervals, but that just
leads to problems since it won't actually be done
that way by drivers. Return an error in this case
to make sure it won't be done wrong.

Also, ignore attempts to change the DTIM period
or beacon interval during the lifetime of the BSS.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
include/net/cfg80211.h
net/wireless/core.c
net/wireless/core.h
net/wireless/nl80211.c
net/wireless/util.c

index 1f1e221b6ce3f5a6e098df2e7b99efa4168e28ed..a46adb7a91b7c4ce55d350f94dece67c14ad21c9 100644 (file)
@@ -1908,6 +1908,8 @@ struct cfg80211_cached_keys;
  * @mgmt_registrations_lock: lock for the list
  * @mtx: mutex used to lock data in this struct
  * @cleanup_work: work struct used for cleanup that can't be done directly
+ * @beacon_interval: beacon interval used on this device for transmitting
+ *     beacons, 0 when not valid
  */
 struct wireless_dev {
        struct wiphy *wiphy;
@@ -1948,6 +1950,8 @@ struct wireless_dev {
        bool ps;
        int ps_timeout;
 
+       int beacon_interval;
+
 #ifdef CONFIG_CFG80211_WEXT
        /* wext data */
        struct {
index f924a49b2425eaa6f6037937d22c7065809a9410..e2ab65d7c86dd2dcee8bf67a22dabfeaabf25a6a 100644 (file)
@@ -787,6 +787,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
                default:
                        break;
                }
+               wdev->beacon_interval = 0;
                break;
        case NETDEV_DOWN:
                dev_hold(dev);
index e3f7b1d995cd0ba3f52be2cbe9a2d6bdb8844f87..fd9135f9b5be72c033d6bd04efe8d08e4241a8a0 100644 (file)
@@ -433,6 +433,9 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev,
 
 u16 cfg80211_calculate_bitrate(struct rate_info *rate);
 
+int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
+                                u32 beacon_int);
+
 #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
 #define CFG80211_DEV_WARN_ON(cond)     WARN_ON(cond)
 #else
index b5b050b62f2ad74dffabb7f9e1b6e050aab9717b..9ef8e287d61b4b5ad74e4b1b05dd2b509bec58b1 100644 (file)
@@ -1876,8 +1876,9 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
                    struct beacon_parameters *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 beacon_parameters params;
-       int haveinfo = 0;
+       int haveinfo = 0, err;
 
        if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]))
                return -EINVAL;
@@ -1886,6 +1887,8 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
            dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
                return -EOPNOTSUPP;
 
+       memset(&params, 0, sizeof(params));
+
        switch (info->genlhdr->cmd) {
        case NL80211_CMD_NEW_BEACON:
                /* these are required for NEW_BEACON */
@@ -1894,6 +1897,15 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
                    !info->attrs[NL80211_ATTR_BEACON_HEAD])
                        return -EINVAL;
 
+               params.interval =
+                       nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
+               params.dtim_period =
+                       nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
+
+               err = cfg80211_validate_beacon_int(rdev, params.interval);
+               if (err)
+                       return err;
+
                call = rdev->ops->add_beacon;
                break;
        case NL80211_CMD_SET_BEACON:
@@ -1907,20 +1919,6 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
        if (!call)
                return -EOPNOTSUPP;
 
-       memset(&params, 0, sizeof(params));
-
-       if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
-               params.interval =
-                   nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
-               haveinfo = 1;
-       }
-
-       if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
-               params.dtim_period =
-                   nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
-               haveinfo = 1;
-       }
-
        if (info->attrs[NL80211_ATTR_BEACON_HEAD]) {
                params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
                params.head_len =
@@ -1938,13 +1936,18 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
        if (!haveinfo)
                return -EINVAL;
 
-       return call(&rdev->wiphy, dev, &params);
+       err = call(&rdev->wiphy, dev, &params);
+       if (!err && params.interval)
+               wdev->beacon_interval = params.interval;
+       return err;
 }
 
 static int nl80211_del_beacon(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;
+       int err;
 
        if (!rdev->ops->del_beacon)
                return -EOPNOTSUPP;
@@ -1953,7 +1956,10 @@ static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
            dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
                return -EOPNOTSUPP;
 
-       return rdev->ops->del_beacon(&rdev->wiphy, dev);
+       err = rdev->ops->del_beacon(&rdev->wiphy, dev);
+       if (!err)
+               wdev->beacon_interval = 0;
+       return err;
 }
 
 static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
index 6a750bc6bcfe3cf3fddc82202a7d7ddeabf28720..414c9f604df634c94b40e85a2a52fd819955aa7c 100644 (file)
@@ -896,3 +896,28 @@ u16 cfg80211_calculate_bitrate(struct rate_info *rate)
        /* do NOT round down here */
        return (bitrate + 50000) / 100000;
 }
+
+int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
+                                u32 beacon_int)
+{
+       struct wireless_dev *wdev;
+       int res = 0;
+
+       if (!beacon_int)
+               return -EINVAL;
+
+       mutex_lock(&rdev->devlist_mtx);
+
+       list_for_each_entry(wdev, &rdev->netdev_list, list) {
+               if (!wdev->beacon_interval)
+                       continue;
+               if (wdev->beacon_interval != beacon_int) {
+                       res = -EINVAL;
+                       break;
+               }
+       }
+
+       mutex_unlock(&rdev->devlist_mtx);
+
+       return res;
+}