diff options
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); |