mac80211: prevent chanctx overcommit
authorMichal Kazior <michal.kazior@tieto.com>
Wed, 9 Apr 2014 13:29:24 +0000 (15:29 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Fri, 25 Apr 2014 15:08:15 +0000 (17:08 +0200)
Do not allocate more channel contexts than a
driver is capable for currently matching interface
combination.

This allows the ieee80211_vif_reserve_chanctx() to
act as a guard against breaking interface
combinations.

Signed-off-by: Michal Kazior <michal.kazior@tieto.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/chan.c

index 57b8ab1bc5c1a069c0693a97f787aa08b13b8df1..fcb2cd8ffd0733b3818605c6bfd532e07bb6d929 100644 (file)
@@ -9,6 +9,25 @@
 #include "ieee80211_i.h"
 #include "driver-ops.h"
 
+static int ieee80211_num_chanctx(struct ieee80211_local *local)
+{
+       struct ieee80211_chanctx *ctx;
+       int num = 0;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+
+       list_for_each_entry(ctx, &local->chanctx_list, list)
+               num++;
+
+       return num;
+}
+
+static bool ieee80211_can_create_new_chanctx(struct ieee80211_local *local)
+{
+       lockdep_assert_held(&local->chanctx_mtx);
+       return ieee80211_num_chanctx(local) < ieee80211_max_num_channels(local);
+}
+
 static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta)
 {
        switch (sta->bandwidth) {
@@ -751,13 +770,16 @@ int ieee80211_vif_reserve_chanctx(struct ieee80211_sub_if_data *sdata,
                         * context, reserve our current context
                         */
                        new_ctx = curr_ctx;
-               } else {
+               } else if (ieee80211_can_create_new_chanctx(local)) {
                        /* create a new context and reserve it */
                        new_ctx = ieee80211_new_chanctx(local, chandef, mode);
                        if (IS_ERR(new_ctx)) {
                                ret = PTR_ERR(new_ctx);
                                goto out;
                        }
+               } else {
+                       ret = -EBUSY;
+                       goto out;
                }
        }