summaryrefslogtreecommitdiffstats
path: root/net/mac80211/chan.c
diff options
context:
space:
mode:
authorMichal Kazior <michal.kazior@tieto.com>2014-04-09 15:29:24 +0200
committerJohannes Berg <johannes.berg@intel.com>2014-04-25 17:08:15 +0200
commitc2b90ad8800db308cdc0db9750c7c0baa07f40d0 (patch)
treebd77ee2bd44e3de694aa2d0bb12e0822af48092d /net/mac80211/chan.c
parentmac80211: add max channel calculation utility function (diff)
downloadlinux-c2b90ad8800db308cdc0db9750c7c0baa07f40d0.tar.xz
linux-c2b90ad8800db308cdc0db9750c7c0baa07f40d0.zip
mac80211: prevent chanctx overcommit
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>
Diffstat (limited to 'net/mac80211/chan.c')
-rw-r--r--net/mac80211/chan.c24
1 files changed, 23 insertions, 1 deletions
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 57b8ab1bc5c1..fcb2cd8ffd07 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -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;
}
}