aboutsummaryrefslogtreecommitdiffstats
path: root/net/wireless/util.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-05-13 04:58:57 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-05-16 14:10:40 -0400
commit7527a782e187d1214a5b3dc2897ce441033bb4ef (patch)
tree3310adf988e72cb91736c0638d4c17edcccebfe1 /net/wireless/util.c
parent805d7d23ef9806e47b550ad80270c4cea4ffc984 (diff)
cfg80211: advertise possible interface combinations
Add the ability to advertise interface combinations in nl80211. This allows the driver to indicate what the combinations are that it supports. "Combinations" of just a single interface are implicit, as previously. Note that cfg80211 will enforce that the restrictions are met, but not for all drivers yet (once all drivers are updated, we can remove the flag and enforce for all). When no combinations are actually supported, an empty list will be exported so that userspace can know if the kernel exported this info or not (although it isn't clear to me what tools using the info should do if the kernel didn't export it). Since some interface types are purely virtual/software and don't fit the restrictions, those are exposed in a new list of pure SW types, not subject to restrictions. This mainly exists to handle AP-VLAN and monitor interfaces in mac80211. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/wireless/util.c')
-rw-r--r--net/wireless/util.c80
1 files changed, 80 insertions, 0 deletions
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 414c9f604df6..95e4e254da0a 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -803,6 +803,11 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
803 return -EBUSY; 803 return -EBUSY;
804 804
805 if (ntype != otype) { 805 if (ntype != otype) {
806 err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr,
807 ntype);
808 if (err)
809 return err;
810
806 dev->ieee80211_ptr->use_4addr = false; 811 dev->ieee80211_ptr->use_4addr = false;
807 dev->ieee80211_ptr->mesh_id_up_len = 0; 812 dev->ieee80211_ptr->mesh_id_up_len = 0;
808 813
@@ -921,3 +926,78 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
921 926
922 return res; 927 return res;
923} 928}
929
930int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
931 struct wireless_dev *wdev,
932 enum nl80211_iftype iftype)
933{
934 struct wireless_dev *wdev_iter;
935 int num[NUM_NL80211_IFTYPES];
936 int total = 1;
937 int i, j;
938
939 ASSERT_RTNL();
940
941 /* Always allow software iftypes */
942 if (rdev->wiphy.software_iftypes & BIT(iftype))
943 return 0;
944
945 /*
946 * Drivers will gradually all set this flag, until all
947 * have it we only enforce for those that set it.
948 */
949 if (!(rdev->wiphy.flags & WIPHY_FLAG_ENFORCE_COMBINATIONS))
950 return 0;
951
952 memset(num, 0, sizeof(num));
953
954 num[iftype] = 1;
955
956 mutex_lock(&rdev->devlist_mtx);
957 list_for_each_entry(wdev_iter, &rdev->netdev_list, list) {
958 if (wdev_iter == wdev)
959 continue;
960 if (!netif_running(wdev_iter->netdev))
961 continue;
962
963 if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype))
964 continue;
965
966 num[wdev_iter->iftype]++;
967 total++;
968 }
969 mutex_unlock(&rdev->devlist_mtx);
970
971 for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) {
972 const struct ieee80211_iface_combination *c;
973 struct ieee80211_iface_limit *limits;
974
975 c = &rdev->wiphy.iface_combinations[i];
976
977 limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
978 GFP_KERNEL);
979 if (!limits)
980 return -ENOMEM;
981 if (total > c->max_interfaces)
982 goto cont;
983
984 for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
985 if (rdev->wiphy.software_iftypes & BIT(iftype))
986 continue;
987 for (j = 0; j < c->n_limits; j++) {
988 if (!(limits[j].types & iftype))
989 continue;
990 if (limits[j].max < num[iftype])
991 goto cont;
992 limits[j].max -= num[iftype];
993 }
994 }
995 /* yay, it fits */
996 kfree(limits);
997 return 0;
998 cont:
999 kfree(limits);
1000 }
1001
1002 return -EBUSY;
1003}