From: Johannes Berg Date: Tue, 5 Jun 2012 10:16:50 +0000 (+0200) Subject: UPSTREAM: cfg80211: fix interface combinations check X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=513947718ea93ebe82f97c28cd1459509acfafe5;p=people%2Faperard%2Flinux-chromebook.git UPSTREAM: cfg80211: fix interface combinations check If a given interface combination doesn't contain a required interface type then we missed checking that and erroneously allowed it even though iface type wasn't there at all. Add a check that makes sure that all interface types are accounted for. Cc: stable@kernel.org Reported-by: Mohammed Shafi Shajakhan Signed-off-by: Johannes Berg Signed-off-by: John W. Linville Change-Id: I46925dac512f669f5431861a8e5153e24c9afb08 BUG=chrome-os-partner:16305 TEST=Boot, login as user, join an IBSS network, run suspend-resume test or close the lid for few seconds and then open the lid. Check dmesg for WARNINGS. Signed-off-by: Ashok Nagarajan Tested-by: Ashok Nagarajan Reviewed-on: https://gerrit.chromium.org/gerrit/41292 Reviewed-by: Paul Stewart --- diff --git a/net/wireless/util.c b/net/wireless/util.c index 08ff9cd67d525..2c4083db66133 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -936,6 +936,7 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, enum nl80211_iftype iftype) { struct wireless_dev *wdev_iter; + u32 used_iftypes = BIT(iftype); int num[NUM_NL80211_IFTYPES]; int total = 1; int i, j; @@ -969,12 +970,14 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, num[wdev_iter->iftype]++; total++; + used_iftypes |= BIT(wdev_iter->iftype); } mutex_unlock(&rdev->devlist_mtx); for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) { const struct ieee80211_iface_combination *c; struct ieee80211_iface_limit *limits; + u32 all_iftypes = 0; c = &rdev->wiphy.iface_combinations[i]; @@ -989,6 +992,7 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, if (rdev->wiphy.software_iftypes & BIT(iftype)) continue; for (j = 0; j < c->n_limits; j++) { + all_iftypes |= limits[j].types; if (!(limits[j].types & BIT(iftype))) continue; if (limits[j].max < num[iftype]) @@ -996,7 +1000,20 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, limits[j].max -= num[iftype]; } } - /* yay, it fits */ + + /* + * Finally check that all iftypes that we're currently + * using are actually part of this combination. If they + * aren't then we can't use this combination and have + * to continue to the next. + */ + if ((all_iftypes & used_iftypes) != used_iftypes) + goto cont; + + /* + * This combination covered all interface types and + * supported the requested numbers, so we're good. + */ kfree(limits); return 0; cont: