cfg80211: add channel checking for iface combinations
.connect cannot be handled since the driver scans and connects on its own. It is up to the driver then to refuse a connection (with -EBUSY for example). Non-fixed channel IBSSes always take a single channel resource. For example two non-fixed channel IBSSes always take up 2 num_different_channels, even if they operate on the same channel at a given point of time. Signed-off-by: Michal Kazior <michal.kazior@tieto.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
parent
2e165b8184
commit
d4e50c5917
|
@ -373,6 +373,14 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
|
|||
if (WARN_ON(!c->num_different_channels))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Put a sane limit on maximum number of different
|
||||
* channels to simplify channel accounting code.
|
||||
*/
|
||||
if (WARN_ON(c->num_different_channels >
|
||||
CFG80211_MAX_NUM_DIFFERENT_CHANNELS))
|
||||
return -EINVAL;
|
||||
|
||||
if (WARN_ON(!c->n_limits))
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
@ -428,9 +428,20 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
|
|||
u32 *flags, struct vif_params *params);
|
||||
void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
|
||||
|
||||
int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
enum nl80211_iftype iftype);
|
||||
int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
enum nl80211_iftype iftype,
|
||||
struct ieee80211_channel *chan,
|
||||
enum cfg80211_chan_mode chanmode);
|
||||
|
||||
static inline int
|
||||
cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
enum nl80211_iftype iftype)
|
||||
{
|
||||
return cfg80211_can_use_iftype_chan(rdev, wdev, iftype, NULL,
|
||||
CHAN_MODE_UNDEFINED);
|
||||
}
|
||||
|
||||
static inline int
|
||||
cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
|
||||
|
@ -439,6 +450,16 @@ cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
|
|||
return cfg80211_can_change_interface(rdev, NULL, iftype);
|
||||
}
|
||||
|
||||
static inline int
|
||||
cfg80211_can_use_chan(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
struct ieee80211_channel *chan,
|
||||
enum cfg80211_chan_mode chanmode)
|
||||
{
|
||||
return cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
|
||||
chan, chanmode);
|
||||
}
|
||||
|
||||
void
|
||||
cfg80211_get_chan_state(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
|
@ -461,6 +482,8 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
|
|||
void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
|
||||
enum nl80211_iftype iftype, int num);
|
||||
|
||||
#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
|
||||
|
||||
#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
|
||||
#define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond)
|
||||
#else
|
||||
|
|
|
@ -938,13 +938,20 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
|
|||
return res;
|
||||
}
|
||||
|
||||
int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
enum nl80211_iftype iftype)
|
||||
int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
|
||||
struct wireless_dev *wdev,
|
||||
enum nl80211_iftype iftype,
|
||||
struct ieee80211_channel *chan,
|
||||
enum cfg80211_chan_mode chanmode)
|
||||
{
|
||||
struct wireless_dev *wdev_iter;
|
||||
u32 used_iftypes = BIT(iftype);
|
||||
int num[NUM_NL80211_IFTYPES];
|
||||
struct ieee80211_channel
|
||||
*used_channels[CFG80211_MAX_NUM_DIFFERENT_CHANNELS];
|
||||
struct ieee80211_channel *ch;
|
||||
enum cfg80211_chan_mode chmode;
|
||||
int num_different_channels = 0;
|
||||
int total = 1;
|
||||
int i, j;
|
||||
|
||||
|
@ -955,9 +962,23 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
|
|||
return 0;
|
||||
|
||||
memset(num, 0, sizeof(num));
|
||||
memset(used_channels, 0, sizeof(used_channels));
|
||||
|
||||
num[iftype] = 1;
|
||||
|
||||
switch (chanmode) {
|
||||
case CHAN_MODE_UNDEFINED:
|
||||
break;
|
||||
case CHAN_MODE_SHARED:
|
||||
WARN_ON(!chan);
|
||||
used_channels[0] = chan;
|
||||
num_different_channels++;
|
||||
break;
|
||||
case CHAN_MODE_EXCLUSIVE:
|
||||
num_different_channels++;
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_lock(&rdev->devlist_mtx);
|
||||
list_for_each_entry(wdev_iter, &rdev->netdev_list, list) {
|
||||
if (wdev_iter == wdev)
|
||||
|
@ -968,6 +989,31 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
|
|||
if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype))
|
||||
continue;
|
||||
|
||||
cfg80211_get_chan_state(rdev, wdev_iter, &ch, &chmode);
|
||||
|
||||
switch (chmode) {
|
||||
case CHAN_MODE_UNDEFINED:
|
||||
break;
|
||||
case CHAN_MODE_SHARED:
|
||||
for (i = 0; i < CFG80211_MAX_NUM_DIFFERENT_CHANNELS; i++)
|
||||
if (!used_channels[i] || used_channels[i] == ch)
|
||||
break;
|
||||
|
||||
if (i == CFG80211_MAX_NUM_DIFFERENT_CHANNELS) {
|
||||
mutex_unlock(&rdev->devlist_mtx);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (used_channels[i] == NULL) {
|
||||
used_channels[i] = ch;
|
||||
num_different_channels++;
|
||||
}
|
||||
break;
|
||||
case CHAN_MODE_EXCLUSIVE:
|
||||
num_different_channels++;
|
||||
break;
|
||||
}
|
||||
|
||||
num[wdev_iter->iftype]++;
|
||||
total++;
|
||||
used_iftypes |= BIT(wdev_iter->iftype);
|
||||
|
@ -984,12 +1030,15 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
|
|||
|
||||
c = &rdev->wiphy.iface_combinations[i];
|
||||
|
||||
if (total > c->max_interfaces)
|
||||
continue;
|
||||
if (num_different_channels > c->num_different_channels)
|
||||
continue;
|
||||
|
||||
limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
|
||||
GFP_KERNEL);
|
||||
if (!limits)
|
||||
return -ENOMEM;
|
||||
if (total > c->max_interfaces)
|
||||
goto cont;
|
||||
|
||||
for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
|
||||
if (rdev->wiphy.software_iftypes & BIT(iftype))
|
||||
|
|
Loading…
Reference in a new issue