Skip to content

Commit

Permalink
cfg80211: restrict AP beacon intervals
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: John W. Linville <[email protected]>
  • Loading branch information
jmberg-intel authored and linvjw committed May 12, 2011
1 parent 15cb309 commit 56d1893
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 17 deletions.
4 changes: 4 additions & 0 deletions include/net/cfg80211.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -1948,6 +1950,8 @@ struct wireless_dev {
bool ps;
int ps_timeout;

int beacon_interval;

#ifdef CONFIG_CFG80211_WEXT
/* wext data */
struct {
Expand Down
1 change: 1 addition & 0 deletions net/wireless/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions net/wireless/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
40 changes: 23 additions & 17 deletions net/wireless/nl80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 */
Expand All @@ -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:
Expand All @@ -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 =
Expand All @@ -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;
Expand All @@ -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] = {
Expand Down
25 changes: 25 additions & 0 deletions net/wireless/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

0 comments on commit 56d1893

Please sign in to comment.