diff options
author | Michal Kazior <michal.kazior@tieto.com> | 2012-06-29 06:47:07 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2012-06-29 07:39:19 -0400 |
commit | d4e50c5917e110451ced8f8de594cea858791f37 (patch) | |
tree | 078ac36d0642114f90b57e50ef9b585e2f8a5be9 /net/wireless/util.c | |
parent | 2e165b818456ecc1024dd0387eeac64745526377 (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/wireless/util.c')
-rw-r--r-- | net/wireless/util.c | 59 |
1 files changed, 54 insertions, 5 deletions
diff --git a/net/wireless/util.c b/net/wireless/util.c index 9b92ec57d07..4713cea9a2f 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 | ||
941 | int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | 941 | int 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)) |