diff options
author | Johannes Berg <johannes.berg@intel.com> | 2012-11-09 05:39:59 -0500 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2012-11-26 06:42:59 -0500 |
commit | 4bf88530be971bf95a7830ca61b4120980bf4347 (patch) | |
tree | 405d426806cb76551d09f427dafeeee79dac0dea /net/mac80211/chan.c | |
parent | 3d9d1d6656a73ea8407734cfb00b81d14ef62d4b (diff) |
mac80211: convert to channel definition struct
Convert mac80211 (and where necessary, some drivers a
little bit) to the new channel definition struct.
This will allow extending mac80211 for VHT, which is
currently restricted to channel contexts since there
are no drivers using that which makes it easier. As
I also don't care about VHT for drivers not using the
channel context API, I won't convert the previous API
to VHT support.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/chan.c')
-rw-r--r-- | net/mac80211/chan.c | 128 |
1 files changed, 38 insertions, 90 deletions
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index a2b06d40aebf..53f03120db55 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -8,93 +8,47 @@ | |||
8 | #include "ieee80211_i.h" | 8 | #include "ieee80211_i.h" |
9 | #include "driver-ops.h" | 9 | #include "driver-ops.h" |
10 | 10 | ||
11 | static bool | 11 | static void ieee80211_change_chandef(struct ieee80211_local *local, |
12 | ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1, | 12 | struct ieee80211_chanctx *ctx, |
13 | enum nl80211_channel_type chantype2, | 13 | const struct cfg80211_chan_def *chandef) |
14 | enum nl80211_channel_type *compat) | ||
15 | { | 14 | { |
16 | /* | 15 | if (cfg80211_chandef_identical(&ctx->conf.def, chandef)) |
17 | * start out with chantype1 being the result, | ||
18 | * overwriting later if needed | ||
19 | */ | ||
20 | if (compat) | ||
21 | *compat = chantype1; | ||
22 | |||
23 | switch (chantype1) { | ||
24 | case NL80211_CHAN_NO_HT: | ||
25 | if (compat) | ||
26 | *compat = chantype2; | ||
27 | break; | ||
28 | case NL80211_CHAN_HT20: | ||
29 | /* | ||
30 | * allow any change that doesn't go to no-HT | ||
31 | * (if it already is no-HT no change is needed) | ||
32 | */ | ||
33 | if (chantype2 == NL80211_CHAN_NO_HT) | ||
34 | break; | ||
35 | if (compat) | ||
36 | *compat = chantype2; | ||
37 | break; | ||
38 | case NL80211_CHAN_HT40PLUS: | ||
39 | case NL80211_CHAN_HT40MINUS: | ||
40 | /* allow smaller bandwidth and same */ | ||
41 | if (chantype2 == NL80211_CHAN_NO_HT) | ||
42 | break; | ||
43 | if (chantype2 == NL80211_CHAN_HT20) | ||
44 | break; | ||
45 | if (chantype2 == chantype1) | ||
46 | break; | ||
47 | return false; | ||
48 | } | ||
49 | |||
50 | return true; | ||
51 | } | ||
52 | |||
53 | static void ieee80211_change_chantype(struct ieee80211_local *local, | ||
54 | struct ieee80211_chanctx *ctx, | ||
55 | enum nl80211_channel_type chantype) | ||
56 | { | ||
57 | if (chantype == ctx->conf.channel_type) | ||
58 | return; | 16 | return; |
59 | 17 | ||
60 | ctx->conf.channel_type = chantype; | 18 | WARN_ON(!cfg80211_chandef_compatible(&ctx->conf.def, chandef)); |
61 | drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE); | 19 | |
20 | ctx->conf.def = *chandef; | ||
21 | drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH); | ||
62 | 22 | ||
63 | if (!local->use_chanctx) { | 23 | if (!local->use_chanctx) { |
64 | local->_oper_channel_type = chantype; | 24 | local->_oper_channel_type = cfg80211_get_chandef_type(chandef); |
65 | ieee80211_hw_config(local, 0); | 25 | ieee80211_hw_config(local, 0); |
66 | } | 26 | } |
67 | } | 27 | } |
68 | 28 | ||
69 | static struct ieee80211_chanctx * | 29 | static struct ieee80211_chanctx * |
70 | ieee80211_find_chanctx(struct ieee80211_local *local, | 30 | ieee80211_find_chanctx(struct ieee80211_local *local, |
71 | struct ieee80211_channel *channel, | 31 | const struct cfg80211_chan_def *chandef, |
72 | enum nl80211_channel_type channel_type, | ||
73 | enum ieee80211_chanctx_mode mode) | 32 | enum ieee80211_chanctx_mode mode) |
74 | { | 33 | { |
75 | struct ieee80211_chanctx *ctx; | 34 | struct ieee80211_chanctx *ctx; |
76 | enum nl80211_channel_type compat_type; | ||
77 | 35 | ||
78 | lockdep_assert_held(&local->chanctx_mtx); | 36 | lockdep_assert_held(&local->chanctx_mtx); |
79 | 37 | ||
80 | if (mode == IEEE80211_CHANCTX_EXCLUSIVE) | 38 | if (mode == IEEE80211_CHANCTX_EXCLUSIVE) |
81 | return NULL; | 39 | return NULL; |
82 | if (WARN_ON(!channel)) | ||
83 | return NULL; | ||
84 | 40 | ||
85 | list_for_each_entry(ctx, &local->chanctx_list, list) { | 41 | list_for_each_entry(ctx, &local->chanctx_list, list) { |
86 | compat_type = ctx->conf.channel_type; | 42 | const struct cfg80211_chan_def *compat; |
87 | 43 | ||
88 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) | 44 | if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) |
89 | continue; | 45 | continue; |
90 | if (ctx->conf.channel != channel) | 46 | |
91 | continue; | 47 | compat = cfg80211_chandef_compatible(&ctx->conf.def, chandef); |
92 | if (!ieee80211_channel_types_are_compatible(ctx->conf.channel_type, | 48 | if (!compat) |
93 | channel_type, | ||
94 | &compat_type)) | ||
95 | continue; | 49 | continue; |
96 | 50 | ||
97 | ieee80211_change_chantype(local, ctx, compat_type); | 51 | ieee80211_change_chandef(local, ctx, compat); |
98 | 52 | ||
99 | return ctx; | 53 | return ctx; |
100 | } | 54 | } |
@@ -104,8 +58,7 @@ ieee80211_find_chanctx(struct ieee80211_local *local, | |||
104 | 58 | ||
105 | static struct ieee80211_chanctx * | 59 | static struct ieee80211_chanctx * |
106 | ieee80211_new_chanctx(struct ieee80211_local *local, | 60 | ieee80211_new_chanctx(struct ieee80211_local *local, |
107 | struct ieee80211_channel *channel, | 61 | const struct cfg80211_chan_def *chandef, |
108 | enum nl80211_channel_type channel_type, | ||
109 | enum ieee80211_chanctx_mode mode) | 62 | enum ieee80211_chanctx_mode mode) |
110 | { | 63 | { |
111 | struct ieee80211_chanctx *ctx; | 64 | struct ieee80211_chanctx *ctx; |
@@ -117,15 +70,15 @@ ieee80211_new_chanctx(struct ieee80211_local *local, | |||
117 | if (!ctx) | 70 | if (!ctx) |
118 | return ERR_PTR(-ENOMEM); | 71 | return ERR_PTR(-ENOMEM); |
119 | 72 | ||
120 | ctx->conf.channel = channel; | 73 | ctx->conf.def = *chandef; |
121 | ctx->conf.channel_type = channel_type; | ||
122 | ctx->conf.rx_chains_static = 1; | 74 | ctx->conf.rx_chains_static = 1; |
123 | ctx->conf.rx_chains_dynamic = 1; | 75 | ctx->conf.rx_chains_dynamic = 1; |
124 | ctx->mode = mode; | 76 | ctx->mode = mode; |
125 | 77 | ||
126 | if (!local->use_chanctx) { | 78 | if (!local->use_chanctx) { |
127 | local->_oper_channel_type = channel_type; | 79 | local->_oper_channel_type = |
128 | local->_oper_channel = channel; | 80 | cfg80211_get_chandef_type(chandef); |
81 | local->_oper_channel = chandef->chan; | ||
129 | ieee80211_hw_config(local, 0); | 82 | ieee80211_hw_config(local, 0); |
130 | } else { | 83 | } else { |
131 | err = drv_add_chanctx(local, ctx); | 84 | err = drv_add_chanctx(local, ctx); |
@@ -178,41 +131,37 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | |||
178 | return 0; | 131 | return 0; |
179 | } | 132 | } |
180 | 133 | ||
181 | static enum nl80211_channel_type | 134 | static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, |
182 | ieee80211_calc_chantype(struct ieee80211_local *local, | 135 | struct ieee80211_chanctx *ctx) |
183 | struct ieee80211_chanctx *ctx) | ||
184 | { | 136 | { |
185 | struct ieee80211_chanctx_conf *conf = &ctx->conf; | 137 | struct ieee80211_chanctx_conf *conf = &ctx->conf; |
186 | struct ieee80211_sub_if_data *sdata; | 138 | struct ieee80211_sub_if_data *sdata; |
187 | enum nl80211_channel_type result = NL80211_CHAN_NO_HT; | 139 | const struct cfg80211_chan_def *compat = NULL; |
188 | 140 | ||
189 | lockdep_assert_held(&local->chanctx_mtx); | 141 | lockdep_assert_held(&local->chanctx_mtx); |
190 | 142 | ||
191 | rcu_read_lock(); | 143 | rcu_read_lock(); |
192 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { | 144 | list_for_each_entry_rcu(sdata, &local->interfaces, list) { |
145 | |||
193 | if (!ieee80211_sdata_running(sdata)) | 146 | if (!ieee80211_sdata_running(sdata)) |
194 | continue; | 147 | continue; |
195 | if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) | 148 | if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) |
196 | continue; | 149 | continue; |
197 | 150 | ||
198 | WARN_ON_ONCE(!ieee80211_channel_types_are_compatible( | 151 | if (!compat) |
199 | sdata->vif.bss_conf.channel_type, | 152 | compat = &sdata->vif.bss_conf.chandef; |
200 | result, &result)); | 153 | |
154 | compat = cfg80211_chandef_compatible( | ||
155 | &sdata->vif.bss_conf.chandef, compat); | ||
156 | if (!compat) | ||
157 | break; | ||
201 | } | 158 | } |
202 | rcu_read_unlock(); | 159 | rcu_read_unlock(); |
203 | 160 | ||
204 | return result; | 161 | if (WARN_ON_ONCE(!compat)) |
205 | } | 162 | return; |
206 | |||
207 | static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, | ||
208 | struct ieee80211_chanctx *ctx) | ||
209 | { | ||
210 | enum nl80211_channel_type chantype; | ||
211 | |||
212 | lockdep_assert_held(&local->chanctx_mtx); | ||
213 | 163 | ||
214 | chantype = ieee80211_calc_chantype(local, ctx); | 164 | ieee80211_change_chandef(local, ctx, compat); |
215 | ieee80211_change_chantype(local, ctx, chantype); | ||
216 | } | 165 | } |
217 | 166 | ||
218 | static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, | 167 | static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, |
@@ -337,8 +286,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, | |||
337 | } | 286 | } |
338 | 287 | ||
339 | int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | 288 | int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, |
340 | struct ieee80211_channel *channel, | 289 | const struct cfg80211_chan_def *chandef, |
341 | enum nl80211_channel_type channel_type, | ||
342 | enum ieee80211_chanctx_mode mode) | 290 | enum ieee80211_chanctx_mode mode) |
343 | { | 291 | { |
344 | struct ieee80211_local *local = sdata->local; | 292 | struct ieee80211_local *local = sdata->local; |
@@ -350,15 +298,15 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
350 | mutex_lock(&local->chanctx_mtx); | 298 | mutex_lock(&local->chanctx_mtx); |
351 | __ieee80211_vif_release_channel(sdata); | 299 | __ieee80211_vif_release_channel(sdata); |
352 | 300 | ||
353 | ctx = ieee80211_find_chanctx(local, channel, channel_type, mode); | 301 | ctx = ieee80211_find_chanctx(local, chandef, mode); |
354 | if (!ctx) | 302 | if (!ctx) |
355 | ctx = ieee80211_new_chanctx(local, channel, channel_type, mode); | 303 | ctx = ieee80211_new_chanctx(local, chandef, mode); |
356 | if (IS_ERR(ctx)) { | 304 | if (IS_ERR(ctx)) { |
357 | ret = PTR_ERR(ctx); | 305 | ret = PTR_ERR(ctx); |
358 | goto out; | 306 | goto out; |
359 | } | 307 | } |
360 | 308 | ||
361 | sdata->vif.bss_conf.channel_type = channel_type; | 309 | sdata->vif.bss_conf.chandef = *chandef; |
362 | 310 | ||
363 | ret = ieee80211_assign_vif_chanctx(sdata, ctx); | 311 | ret = ieee80211_assign_vif_chanctx(sdata, ctx); |
364 | if (ret) { | 312 | if (ret) { |