diff options
author | Johannes Berg <johannes.berg@intel.com> | 2012-07-26 11:24:39 -0400 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2012-10-17 05:02:09 -0400 |
commit | 55de908ab292c03f1eb280f51170ddb9c6b57e31 (patch) | |
tree | bc75bb5cea581cadf6fe8b4f121cce02d07c276a /net/mac80211/chan.c | |
parent | fe57d9f5c0a2c1ef97ba8cdc42cfda5743f287b8 (diff) |
mac80211: use channel contexts
Instead of operating on a single channel only,
use the new channel context infrastructure in
all mac80211 code.
This enables drivers that want to use the new
channel context infrastructure to use multiple
channels, while nothing should change for all
the other drivers that don't support it.
Right now this disables both TX power settings
and spatial multiplexing powersave. Both need
to be re-enabled on a channel context basis.
Additionally, when channel contexts are used
drop the connection when channel switch is
received rather than trying to handle it. This
will have to be improved later.
[With fixes from Eliad and Emmanuel incorporated]
Signed-off-by: Eliad Peller <eliad@wizery.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/chan.c')
-rw-r--r-- | net/mac80211/chan.c | 152 |
1 files changed, 27 insertions, 125 deletions
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index 1a8dee42e546..41e1aa69f7aa 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c | |||
@@ -7,106 +7,6 @@ | |||
7 | #include "ieee80211_i.h" | 7 | #include "ieee80211_i.h" |
8 | #include "driver-ops.h" | 8 | #include "driver-ops.h" |
9 | 9 | ||
10 | static enum ieee80211_chan_mode | ||
11 | __ieee80211_get_channel_mode(struct ieee80211_local *local, | ||
12 | struct ieee80211_sub_if_data *ignore) | ||
13 | { | ||
14 | struct ieee80211_sub_if_data *sdata; | ||
15 | |||
16 | lockdep_assert_held(&local->iflist_mtx); | ||
17 | |||
18 | list_for_each_entry(sdata, &local->interfaces, list) { | ||
19 | if (sdata == ignore) | ||
20 | continue; | ||
21 | |||
22 | if (!ieee80211_sdata_running(sdata)) | ||
23 | continue; | ||
24 | |||
25 | switch (sdata->vif.type) { | ||
26 | case NL80211_IFTYPE_MONITOR: | ||
27 | continue; | ||
28 | case NL80211_IFTYPE_STATION: | ||
29 | if (!sdata->u.mgd.associated) | ||
30 | continue; | ||
31 | break; | ||
32 | case NL80211_IFTYPE_ADHOC: | ||
33 | if (!sdata->u.ibss.ssid_len) | ||
34 | continue; | ||
35 | if (!sdata->u.ibss.fixed_channel) | ||
36 | return CHAN_MODE_HOPPING; | ||
37 | break; | ||
38 | case NL80211_IFTYPE_AP_VLAN: | ||
39 | /* will also have _AP interface */ | ||
40 | continue; | ||
41 | case NL80211_IFTYPE_AP: | ||
42 | if (!sdata->u.ap.beacon) | ||
43 | continue; | ||
44 | break; | ||
45 | case NL80211_IFTYPE_MESH_POINT: | ||
46 | if (!sdata->wdev.mesh_id_len) | ||
47 | continue; | ||
48 | break; | ||
49 | default: | ||
50 | break; | ||
51 | } | ||
52 | |||
53 | return CHAN_MODE_FIXED; | ||
54 | } | ||
55 | |||
56 | return CHAN_MODE_UNDEFINED; | ||
57 | } | ||
58 | |||
59 | enum ieee80211_chan_mode | ||
60 | ieee80211_get_channel_mode(struct ieee80211_local *local, | ||
61 | struct ieee80211_sub_if_data *ignore) | ||
62 | { | ||
63 | enum ieee80211_chan_mode mode; | ||
64 | |||
65 | mutex_lock(&local->iflist_mtx); | ||
66 | mode = __ieee80211_get_channel_mode(local, ignore); | ||
67 | mutex_unlock(&local->iflist_mtx); | ||
68 | |||
69 | return mode; | ||
70 | } | ||
71 | |||
72 | static enum nl80211_channel_type | ||
73 | ieee80211_get_superchan(struct ieee80211_local *local, | ||
74 | struct ieee80211_sub_if_data *sdata) | ||
75 | { | ||
76 | enum nl80211_channel_type superchan = NL80211_CHAN_NO_HT; | ||
77 | struct ieee80211_sub_if_data *tmp; | ||
78 | |||
79 | mutex_lock(&local->iflist_mtx); | ||
80 | list_for_each_entry(tmp, &local->interfaces, list) { | ||
81 | if (tmp == sdata) | ||
82 | continue; | ||
83 | |||
84 | if (!ieee80211_sdata_running(tmp)) | ||
85 | continue; | ||
86 | |||
87 | switch (tmp->vif.bss_conf.channel_type) { | ||
88 | case NL80211_CHAN_NO_HT: | ||
89 | case NL80211_CHAN_HT20: | ||
90 | if (superchan > tmp->vif.bss_conf.channel_type) | ||
91 | break; | ||
92 | |||
93 | superchan = tmp->vif.bss_conf.channel_type; | ||
94 | break; | ||
95 | case NL80211_CHAN_HT40PLUS: | ||
96 | WARN_ON(superchan == NL80211_CHAN_HT40MINUS); | ||
97 | superchan = NL80211_CHAN_HT40PLUS; | ||
98 | break; | ||
99 | case NL80211_CHAN_HT40MINUS: | ||
100 | WARN_ON(superchan == NL80211_CHAN_HT40PLUS); | ||
101 | superchan = NL80211_CHAN_HT40MINUS; | ||
102 | break; | ||
103 | } | ||
104 | } | ||
105 | mutex_unlock(&local->iflist_mtx); | ||
106 | |||
107 | return superchan; | ||
108 | } | ||
109 | |||
110 | static bool | 10 | static bool |
111 | ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1, | 11 | ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1, |
112 | enum nl80211_channel_type chantype2, | 12 | enum nl80211_channel_type chantype2, |
@@ -149,26 +49,6 @@ ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1, | |||
149 | return true; | 49 | return true; |
150 | } | 50 | } |
151 | 51 | ||
152 | bool ieee80211_set_channel_type(struct ieee80211_local *local, | ||
153 | struct ieee80211_sub_if_data *sdata, | ||
154 | enum nl80211_channel_type chantype) | ||
155 | { | ||
156 | enum nl80211_channel_type superchan; | ||
157 | enum nl80211_channel_type compatchan; | ||
158 | |||
159 | superchan = ieee80211_get_superchan(local, sdata); | ||
160 | if (!ieee80211_channel_types_are_compatible(superchan, chantype, | ||
161 | &compatchan)) | ||
162 | return false; | ||
163 | |||
164 | local->_oper_channel_type = compatchan; | ||
165 | |||
166 | if (sdata) | ||
167 | sdata->vif.bss_conf.channel_type = chantype; | ||
168 | |||
169 | return true; | ||
170 | } | ||
171 | |||
172 | static void ieee80211_change_chantype(struct ieee80211_local *local, | 52 | static void ieee80211_change_chantype(struct ieee80211_local *local, |
173 | struct ieee80211_chanctx *ctx, | 53 | struct ieee80211_chanctx *ctx, |
174 | enum nl80211_channel_type chantype) | 54 | enum nl80211_channel_type chantype) |
@@ -178,6 +58,11 @@ static void ieee80211_change_chantype(struct ieee80211_local *local, | |||
178 | 58 | ||
179 | ctx->conf.channel_type = chantype; | 59 | ctx->conf.channel_type = chantype; |
180 | drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE); | 60 | drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE); |
61 | |||
62 | if (!local->use_chanctx) { | ||
63 | local->_oper_channel_type = chantype; | ||
64 | ieee80211_hw_config(local, 0); | ||
65 | } | ||
181 | } | 66 | } |
182 | 67 | ||
183 | static struct ieee80211_chanctx * | 68 | static struct ieee80211_chanctx * |
@@ -235,10 +120,16 @@ ieee80211_new_chanctx(struct ieee80211_local *local, | |||
235 | ctx->conf.channel_type = channel_type; | 120 | ctx->conf.channel_type = channel_type; |
236 | ctx->mode = mode; | 121 | ctx->mode = mode; |
237 | 122 | ||
238 | err = drv_add_chanctx(local, ctx); | 123 | if (!local->use_chanctx) { |
239 | if (err) { | 124 | local->_oper_channel_type = channel_type; |
240 | kfree(ctx); | 125 | local->_oper_channel = channel; |
241 | return ERR_PTR(err); | 126 | ieee80211_hw_config(local, 0); |
127 | } else { | ||
128 | err = drv_add_chanctx(local, ctx); | ||
129 | if (err) { | ||
130 | kfree(ctx); | ||
131 | return ERR_PTR(err); | ||
132 | } | ||
242 | } | 133 | } |
243 | 134 | ||
244 | list_add(&ctx->list, &local->chanctx_list); | 135 | list_add(&ctx->list, &local->chanctx_list); |
@@ -253,7 +144,12 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local, | |||
253 | 144 | ||
254 | WARN_ON_ONCE(ctx->refcount != 0); | 145 | WARN_ON_ONCE(ctx->refcount != 0); |
255 | 146 | ||
256 | drv_remove_chanctx(local, ctx); | 147 | if (!local->use_chanctx) { |
148 | local->_oper_channel_type = NL80211_CHAN_NO_HT; | ||
149 | ieee80211_hw_config(local, 0); | ||
150 | } else { | ||
151 | drv_remove_chanctx(local, ctx); | ||
152 | } | ||
257 | 153 | ||
258 | list_del(&ctx->list); | 154 | list_del(&ctx->list); |
259 | kfree_rcu(ctx, rcu_head); | 155 | kfree_rcu(ctx, rcu_head); |
@@ -359,6 +255,8 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
359 | struct ieee80211_chanctx *ctx; | 255 | struct ieee80211_chanctx *ctx; |
360 | int ret; | 256 | int ret; |
361 | 257 | ||
258 | WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); | ||
259 | |||
362 | mutex_lock(&local->chanctx_mtx); | 260 | mutex_lock(&local->chanctx_mtx); |
363 | __ieee80211_vif_release_channel(sdata); | 261 | __ieee80211_vif_release_channel(sdata); |
364 | 262 | ||
@@ -370,6 +268,8 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
370 | goto out; | 268 | goto out; |
371 | } | 269 | } |
372 | 270 | ||
271 | sdata->vif.bss_conf.channel_type = channel_type; | ||
272 | |||
373 | ret = ieee80211_assign_vif_chanctx(sdata, ctx); | 273 | ret = ieee80211_assign_vif_chanctx(sdata, ctx); |
374 | if (ret) { | 274 | if (ret) { |
375 | /* if assign fails refcount stays the same */ | 275 | /* if assign fails refcount stays the same */ |
@@ -385,6 +285,8 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, | |||
385 | 285 | ||
386 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) | 286 | void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) |
387 | { | 287 | { |
288 | WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); | ||
289 | |||
388 | mutex_lock(&sdata->local->chanctx_mtx); | 290 | mutex_lock(&sdata->local->chanctx_mtx); |
389 | __ieee80211_vif_release_channel(sdata); | 291 | __ieee80211_vif_release_channel(sdata); |
390 | mutex_unlock(&sdata->local->chanctx_mtx); | 292 | mutex_unlock(&sdata->local->chanctx_mtx); |