diff options
Diffstat (limited to 'net/wireless/util.c')
| -rw-r--r-- | net/wireless/util.c | 21 |
1 files changed, 19 insertions, 2 deletions
diff --git a/net/wireless/util.c b/net/wireless/util.c index 55d99466babb..316cfd00914f 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
| @@ -804,7 +804,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, | |||
| 804 | ntype == NL80211_IFTYPE_P2P_CLIENT)) | 804 | ntype == NL80211_IFTYPE_P2P_CLIENT)) |
| 805 | return -EBUSY; | 805 | return -EBUSY; |
| 806 | 806 | ||
| 807 | if (ntype != otype) { | 807 | if (ntype != otype && netif_running(dev)) { |
| 808 | err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, | 808 | err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, |
| 809 | ntype); | 809 | ntype); |
| 810 | if (err) | 810 | if (err) |
| @@ -935,6 +935,7 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | |||
| 935 | enum nl80211_iftype iftype) | 935 | enum nl80211_iftype iftype) |
| 936 | { | 936 | { |
| 937 | struct wireless_dev *wdev_iter; | 937 | struct wireless_dev *wdev_iter; |
| 938 | u32 used_iftypes = BIT(iftype); | ||
| 938 | int num[NUM_NL80211_IFTYPES]; | 939 | int num[NUM_NL80211_IFTYPES]; |
| 939 | int total = 1; | 940 | int total = 1; |
| 940 | int i, j; | 941 | int i, j; |
| @@ -961,6 +962,7 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | |||
| 961 | 962 | ||
| 962 | num[wdev_iter->iftype]++; | 963 | num[wdev_iter->iftype]++; |
| 963 | total++; | 964 | total++; |
| 965 | used_iftypes |= BIT(wdev_iter->iftype); | ||
| 964 | } | 966 | } |
| 965 | mutex_unlock(&rdev->devlist_mtx); | 967 | mutex_unlock(&rdev->devlist_mtx); |
| 966 | 968 | ||
| @@ -970,6 +972,7 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | |||
| 970 | for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) { | 972 | for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) { |
| 971 | const struct ieee80211_iface_combination *c; | 973 | const struct ieee80211_iface_combination *c; |
| 972 | struct ieee80211_iface_limit *limits; | 974 | struct ieee80211_iface_limit *limits; |
| 975 | u32 all_iftypes = 0; | ||
| 973 | 976 | ||
| 974 | c = &rdev->wiphy.iface_combinations[i]; | 977 | c = &rdev->wiphy.iface_combinations[i]; |
| 975 | 978 | ||
| @@ -984,6 +987,7 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | |||
| 984 | if (rdev->wiphy.software_iftypes & BIT(iftype)) | 987 | if (rdev->wiphy.software_iftypes & BIT(iftype)) |
| 985 | continue; | 988 | continue; |
| 986 | for (j = 0; j < c->n_limits; j++) { | 989 | for (j = 0; j < c->n_limits; j++) { |
| 990 | all_iftypes |= limits[j].types; | ||
| 987 | if (!(limits[j].types & BIT(iftype))) | 991 | if (!(limits[j].types & BIT(iftype))) |
| 988 | continue; | 992 | continue; |
| 989 | if (limits[j].max < num[iftype]) | 993 | if (limits[j].max < num[iftype]) |
| @@ -991,7 +995,20 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, | |||
| 991 | limits[j].max -= num[iftype]; | 995 | limits[j].max -= num[iftype]; |
| 992 | } | 996 | } |
| 993 | } | 997 | } |
| 994 | /* yay, it fits */ | 998 | |
| 999 | /* | ||
| 1000 | * Finally check that all iftypes that we're currently | ||
| 1001 | * using are actually part of this combination. If they | ||
| 1002 | * aren't then we can't use this combination and have | ||
| 1003 | * to continue to the next. | ||
| 1004 | */ | ||
| 1005 | if ((all_iftypes & used_iftypes) != used_iftypes) | ||
| 1006 | goto cont; | ||
| 1007 | |||
| 1008 | /* | ||
| 1009 | * This combination covered all interface types and | ||
| 1010 | * supported the requested numbers, so we're good. | ||
| 1011 | */ | ||
| 995 | kfree(limits); | 1012 | kfree(limits); |
| 996 | return 0; | 1013 | return 0; |
| 997 | cont: | 1014 | cont: |
