Commit 46c1dd0c authored by Felix Fietkau's avatar Felix Fietkau Committed by Johannes Berg

cfg80211: fix regression in multi-vif AP start

Commit "cfg80211: provide channel to start_ap function" assumes that the
channel is always passed to the NL80211_CMD_START_AP command, however
in case of multi-BSSID, hostapd only passes the channel for the first vif.
This makes starting beaconing on secondary vifs fail with -EINVAL.

Fix this by storing the channel provided to .start_ap in wdev->preset_chan
and picking the first AP vif's channel for secondary vifs if not provided.
Signed-off-by: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 2bd7e35d
...@@ -2335,6 +2335,33 @@ static int nl80211_parse_beacon(struct genl_info *info, ...@@ -2335,6 +2335,33 @@ static int nl80211_parse_beacon(struct genl_info *info,
return 0; return 0;
} }
static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
struct cfg80211_ap_settings *params)
{
struct wireless_dev *wdev;
bool ret = false;
mutex_lock(&rdev->devlist_mtx);
list_for_each_entry(wdev, &rdev->netdev_list, list) {
if (wdev->iftype != NL80211_IFTYPE_AP &&
wdev->iftype != NL80211_IFTYPE_P2P_GO)
continue;
if (!wdev->preset_chan)
continue;
params->channel = wdev->preset_chan;
params->channel_type = wdev->preset_chantype;
ret = true;
break;
}
mutex_unlock(&rdev->devlist_mtx);
return ret;
}
static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
{ {
struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct cfg80211_registered_device *rdev = info->user_ptr[0];
...@@ -2437,7 +2464,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) ...@@ -2437,7 +2464,7 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
} else if (wdev->preset_chan) { } else if (wdev->preset_chan) {
params.channel = wdev->preset_chan; params.channel = wdev->preset_chan;
params.channel_type = wdev->preset_chantype; params.channel_type = wdev->preset_chantype;
} else } else if (!nl80211_get_ap_channel(rdev, &params))
return -EINVAL; return -EINVAL;
if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, params.channel, if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, params.channel,
...@@ -2445,8 +2472,11 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) ...@@ -2445,8 +2472,11 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
return -EINVAL; return -EINVAL;
err = rdev->ops->start_ap(&rdev->wiphy, dev, &params); err = rdev->ops->start_ap(&rdev->wiphy, dev, &params);
if (!err) if (!err) {
wdev->preset_chan = params.channel;
wdev->preset_chantype = params.channel_type;
wdev->beacon_interval = params.beacon_interval; wdev->beacon_interval = params.beacon_interval;
}
return err; return err;
} }
......
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