mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-12 08:48:48 +00:00
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))
|
if (WARN_ON(!c->num_different_channels))
|
||||||
return -EINVAL;
|
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))
|
if (WARN_ON(!c->n_limits))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -428,9 +428,20 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
|
|||||||
u32 *flags, struct vif_params *params);
|
u32 *flags, struct vif_params *params);
|
||||||
void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
|
void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
|
||||||
|
|
||||||
int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
|
int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
|
||||||
struct wireless_dev *wdev,
|
struct wireless_dev *wdev,
|
||||||
enum nl80211_iftype iftype);
|
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
|
static inline int
|
||||||
cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
|
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);
|
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
|
void
|
||||||
cfg80211_get_chan_state(struct cfg80211_registered_device *rdev,
|
cfg80211_get_chan_state(struct cfg80211_registered_device *rdev,
|
||||||
struct wireless_dev *wdev,
|
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,
|
void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
|
||||||
enum nl80211_iftype iftype, int num);
|
enum nl80211_iftype iftype, int num);
|
||||||
|
|
||||||
|
#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
|
||||||
|
|
||||||
#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
|
#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
|
||||||
#define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond)
|
#define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond)
|
||||||
#else
|
#else
|
||||||
|
@ -938,13 +938,20 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
|
int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
|
||||||
struct wireless_dev *wdev,
|
struct wireless_dev *wdev,
|
||||||
enum nl80211_iftype iftype)
|
enum nl80211_iftype iftype,
|
||||||
|
struct ieee80211_channel *chan,
|
||||||
|
enum cfg80211_chan_mode chanmode)
|
||||||
{
|
{
|
||||||
struct wireless_dev *wdev_iter;
|
struct wireless_dev *wdev_iter;
|
||||||
u32 used_iftypes = BIT(iftype);
|
u32 used_iftypes = BIT(iftype);
|
||||||
int num[NUM_NL80211_IFTYPES];
|
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 total = 1;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
@ -955,9 +962,23 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
memset(num, 0, sizeof(num));
|
memset(num, 0, sizeof(num));
|
||||||
|
memset(used_channels, 0, sizeof(used_channels));
|
||||||
|
|
||||||
num[iftype] = 1;
|
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);
|
mutex_lock(&rdev->devlist_mtx);
|
||||||
list_for_each_entry(wdev_iter, &rdev->netdev_list, list) {
|
list_for_each_entry(wdev_iter, &rdev->netdev_list, list) {
|
||||||
if (wdev_iter == wdev)
|
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))
|
if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype))
|
||||||
continue;
|
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]++;
|
num[wdev_iter->iftype]++;
|
||||||
total++;
|
total++;
|
||||||
used_iftypes |= BIT(wdev_iter->iftype);
|
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];
|
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,
|
limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!limits)
|
if (!limits)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
if (total > c->max_interfaces)
|
|
||||||
goto cont;
|
|
||||||
|
|
||||||
for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
|
for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
|
||||||
if (rdev->wiphy.software_iftypes & BIT(iftype))
|
if (rdev->wiphy.software_iftypes & BIT(iftype))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user