aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorMichal Kazior <michal.kazior@tieto.com>2012-06-29 06:47:07 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-06-29 07:39:19 -0400
commitd4e50c5917e110451ced8f8de594cea858791f37 (patch)
tree078ac36d0642114f90b57e50ef9b585e2f8a5be9 /net
parent2e165b818456ecc1024dd0387eeac64745526377 (diff)
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>
Diffstat (limited to 'net')
-rw-r--r--net/wireless/core.c8
-rw-r--r--net/wireless/core.h29
-rw-r--r--net/wireless/util.c59
3 files changed, 88 insertions, 8 deletions
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 580551e9caba..b26695ad3e97 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -373,6 +373,14 @@ static int wiphy_verify_combinations(struct wiphy *wiphy)
373 if (WARN_ON(!c->num_different_channels)) 373 if (WARN_ON(!c->num_different_channels))
374 return -EINVAL; 374 return -EINVAL;
375 375
376 /*
377 * Put a sane limit on maximum number of different
378 * channels to simplify channel accounting code.
379 */
380 if (WARN_ON(c->num_different_channels >
381 CFG80211_MAX_NUM_DIFFERENT_CHANNELS))
382 return -EINVAL;
383
376 if (WARN_ON(!c->n_limits)) 384 if (WARN_ON(!c->n_limits))
377 return -EINVAL; 385 return -EINVAL;
378 386
diff --git a/net/wireless/core.h b/net/wireless/core.h
index d5efe1b0a8f7..81fef3ddb5a8 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -428,9 +428,20 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
428 u32 *flags, struct vif_params *params); 428 u32 *flags, struct vif_params *params);
429void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); 429void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
430 430
431int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, 431int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
432 struct wireless_dev *wdev, 432 struct wireless_dev *wdev,
433 enum nl80211_iftype iftype); 433 enum nl80211_iftype iftype,
434 struct ieee80211_channel *chan,
435 enum cfg80211_chan_mode chanmode);
436
437static inline int
438cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
439 struct wireless_dev *wdev,
440 enum nl80211_iftype iftype)
441{
442 return cfg80211_can_use_iftype_chan(rdev, wdev, iftype, NULL,
443 CHAN_MODE_UNDEFINED);
444}
434 445
435static inline int 446static inline int
436cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, 447cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
@@ -439,6 +450,16 @@ cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
439 return cfg80211_can_change_interface(rdev, NULL, iftype); 450 return cfg80211_can_change_interface(rdev, NULL, iftype);
440} 451}
441 452
453static inline int
454cfg80211_can_use_chan(struct cfg80211_registered_device *rdev,
455 struct wireless_dev *wdev,
456 struct ieee80211_channel *chan,
457 enum cfg80211_chan_mode chanmode)
458{
459 return cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
460 chan, chanmode);
461}
462
442void 463void
443cfg80211_get_chan_state(struct cfg80211_registered_device *rdev, 464cfg80211_get_chan_state(struct cfg80211_registered_device *rdev,
444 struct wireless_dev *wdev, 465 struct wireless_dev *wdev,
@@ -461,6 +482,8 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
461void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, 482void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
462 enum nl80211_iftype iftype, int num); 483 enum nl80211_iftype iftype, int num);
463 484
485#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
486
464#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS 487#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
465#define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) 488#define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond)
466#else 489#else
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 9b92ec57d07b..4713cea9a2fa 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -938,13 +938,20 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
938 return res; 938 return res;
939} 939}
940 940
941int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, 941int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
942 struct wireless_dev *wdev, 942 struct wireless_dev *wdev,
943 enum nl80211_iftype iftype) 943 enum nl80211_iftype iftype,
944 struct ieee80211_channel *chan,
945 enum cfg80211_chan_mode chanmode)
944{ 946{
945 struct wireless_dev *wdev_iter; 947 struct wireless_dev *wdev_iter;
946 u32 used_iftypes = BIT(iftype); 948 u32 used_iftypes = BIT(iftype);
947 int num[NUM_NL80211_IFTYPES]; 949 int num[NUM_NL80211_IFTYPES];
950 struct ieee80211_channel
951 *used_channels[CFG80211_MAX_NUM_DIFFERENT_CHANNELS];
952 struct ieee80211_channel *ch;
953 enum cfg80211_chan_mode chmode;
954 int num_different_channels = 0;
948 int total = 1; 955 int total = 1;
949 int i, j; 956 int i, j;
950 957
@@ -955,9 +962,23 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
955 return 0; 962 return 0;
956 963
957 memset(num, 0, sizeof(num)); 964 memset(num, 0, sizeof(num));
965 memset(used_channels, 0, sizeof(used_channels));
958 966
959 num[iftype] = 1; 967 num[iftype] = 1;
960 968
969 switch (chanmode) {
970 case CHAN_MODE_UNDEFINED:
971 break;
972 case CHAN_MODE_SHARED:
973 WARN_ON(!chan);
974 used_channels[0] = chan;
975 num_different_channels++;
976 break;
977 case CHAN_MODE_EXCLUSIVE:
978 num_different_channels++;
979 break;
980 }
981
961 mutex_lock(&rdev->devlist_mtx); 982 mutex_lock(&rdev->devlist_mtx);
962 list_for_each_entry(wdev_iter, &rdev->netdev_list, list) { 983 list_for_each_entry(wdev_iter, &rdev->netdev_list, list) {
963 if (wdev_iter == wdev) 984 if (wdev_iter == wdev)
@@ -968,6 +989,31 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
968 if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype)) 989 if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype))
969 continue; 990 continue;
970 991
992 cfg80211_get_chan_state(rdev, wdev_iter, &ch, &chmode);
993
994 switch (chmode) {
995 case CHAN_MODE_UNDEFINED:
996 break;
997 case CHAN_MODE_SHARED:
998 for (i = 0; i < CFG80211_MAX_NUM_DIFFERENT_CHANNELS; i++)
999 if (!used_channels[i] || used_channels[i] == ch)
1000 break;
1001
1002 if (i == CFG80211_MAX_NUM_DIFFERENT_CHANNELS) {
1003 mutex_unlock(&rdev->devlist_mtx);
1004 return -EBUSY;
1005 }
1006
1007 if (used_channels[i] == NULL) {
1008 used_channels[i] = ch;
1009 num_different_channels++;
1010 }
1011 break;
1012 case CHAN_MODE_EXCLUSIVE:
1013 num_different_channels++;
1014 break;
1015 }
1016
971 num[wdev_iter->iftype]++; 1017 num[wdev_iter->iftype]++;
972 total++; 1018 total++;
973 used_iftypes |= BIT(wdev_iter->iftype); 1019 used_iftypes |= BIT(wdev_iter->iftype);
@@ -984,12 +1030,15 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
984 1030
985 c = &rdev->wiphy.iface_combinations[i]; 1031 c = &rdev->wiphy.iface_combinations[i];
986 1032
1033 if (total > c->max_interfaces)
1034 continue;
1035 if (num_different_channels > c->num_different_channels)
1036 continue;
1037
987 limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, 1038 limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
988 GFP_KERNEL); 1039 GFP_KERNEL);
989 if (!limits) 1040 if (!limits)
990 return -ENOMEM; 1041 return -ENOMEM;
991 if (total > c->max_interfaces)
992 goto cont;
993 1042
994 for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { 1043 for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
995 if (rdev->wiphy.software_iftypes & BIT(iftype)) 1044 if (rdev->wiphy.software_iftypes & BIT(iftype))