chan.c (e89a96f5cc4c39c268c771f52d675e15e3ba8123) | chan.c (55de908ab292c03f1eb280f51170ddb9c6b57e31) |
---|---|
1/* 2 * mac80211 - channel management 3 */ 4 5#include <linux/nl80211.h> 6#include <net/cfg80211.h> 7#include "ieee80211_i.h" 8#include "driver-ops.h" 9 | 1/* 2 * mac80211 - channel management 3 */ 4 5#include <linux/nl80211.h> 6#include <net/cfg80211.h> 7#include "ieee80211_i.h" 8#include "driver-ops.h" 9 |
10static 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 59enum ieee80211_chan_mode 60ieee80211_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 72static enum nl80211_channel_type 73ieee80211_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 | |
110static bool 111ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1, 112 enum nl80211_channel_type chantype2, 113 enum nl80211_channel_type *compat) 114{ 115 /* 116 * start out with chantype1 being the result, 117 * overwriting later if needed --- 26 unchanged lines hidden (view full) --- 144 if (chantype2 == chantype1) 145 break; 146 return false; 147 } 148 149 return true; 150} 151 | 10static bool 11ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1, 12 enum nl80211_channel_type chantype2, 13 enum nl80211_channel_type *compat) 14{ 15 /* 16 * start out with chantype1 being the result, 17 * overwriting later if needed --- 26 unchanged lines hidden (view full) --- 44 if (chantype2 == chantype1) 45 break; 46 return false; 47 } 48 49 return true; 50} 51 |
152bool 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 | |
172static void ieee80211_change_chantype(struct ieee80211_local *local, 173 struct ieee80211_chanctx *ctx, 174 enum nl80211_channel_type chantype) 175{ 176 if (chantype == ctx->conf.channel_type) 177 return; 178 179 ctx->conf.channel_type = chantype; 180 drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE); | 52static void ieee80211_change_chantype(struct ieee80211_local *local, 53 struct ieee80211_chanctx *ctx, 54 enum nl80211_channel_type chantype) 55{ 56 if (chantype == ctx->conf.channel_type) 57 return; 58 59 ctx->conf.channel_type = chantype; 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} 182 183static struct ieee80211_chanctx * 184ieee80211_find_chanctx(struct ieee80211_local *local, 185 struct ieee80211_channel *channel, 186 enum nl80211_channel_type channel_type, 187 enum ieee80211_chanctx_mode mode) 188{ --- 41 unchanged lines hidden (view full) --- 230 ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL); 231 if (!ctx) 232 return ERR_PTR(-ENOMEM); 233 234 ctx->conf.channel = channel; 235 ctx->conf.channel_type = channel_type; 236 ctx->mode = mode; 237 | 66} 67 68static struct ieee80211_chanctx * 69ieee80211_find_chanctx(struct ieee80211_local *local, 70 struct ieee80211_channel *channel, 71 enum nl80211_channel_type channel_type, 72 enum ieee80211_chanctx_mode mode) 73{ --- 41 unchanged lines hidden (view full) --- 115 ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL); 116 if (!ctx) 117 return ERR_PTR(-ENOMEM); 118 119 ctx->conf.channel = channel; 120 ctx->conf.channel_type = channel_type; 121 ctx->mode = mode; 122 |
238 err = drv_add_chanctx(local, ctx); 239 if (err) { 240 kfree(ctx); 241 return ERR_PTR(err); | 123 if (!local->use_chanctx) { 124 local->_oper_channel_type = channel_type; 125 local->_oper_channel = channel; 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 } 243 244 list_add(&ctx->list, &local->chanctx_list); 245 246 return ctx; 247} 248 249static void ieee80211_free_chanctx(struct ieee80211_local *local, 250 struct ieee80211_chanctx *ctx) 251{ 252 lockdep_assert_held(&local->chanctx_mtx); 253 254 WARN_ON_ONCE(ctx->refcount != 0); 255 | 133 } 134 135 list_add(&ctx->list, &local->chanctx_list); 136 137 return ctx; 138} 139 140static void ieee80211_free_chanctx(struct ieee80211_local *local, 141 struct ieee80211_chanctx *ctx) 142{ 143 lockdep_assert_held(&local->chanctx_mtx); 144 145 WARN_ON_ONCE(ctx->refcount != 0); 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 258 list_del(&ctx->list); 259 kfree_rcu(ctx, rcu_head); 260} 261 262static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, 263 struct ieee80211_chanctx *ctx) 264{ --- 89 unchanged lines hidden (view full) --- 354 struct ieee80211_channel *channel, 355 enum nl80211_channel_type channel_type, 356 enum ieee80211_chanctx_mode mode) 357{ 358 struct ieee80211_local *local = sdata->local; 359 struct ieee80211_chanctx *ctx; 360 int ret; 361 | 153 154 list_del(&ctx->list); 155 kfree_rcu(ctx, rcu_head); 156} 157 158static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, 159 struct ieee80211_chanctx *ctx) 160{ --- 89 unchanged lines hidden (view full) --- 250 struct ieee80211_channel *channel, 251 enum nl80211_channel_type channel_type, 252 enum ieee80211_chanctx_mode mode) 253{ 254 struct ieee80211_local *local = sdata->local; 255 struct ieee80211_chanctx *ctx; 256 int ret; 257 |
258 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); 259 |
|
362 mutex_lock(&local->chanctx_mtx); 363 __ieee80211_vif_release_channel(sdata); 364 365 ctx = ieee80211_find_chanctx(local, channel, channel_type, mode); 366 if (!ctx) 367 ctx = ieee80211_new_chanctx(local, channel, channel_type, mode); 368 if (IS_ERR(ctx)) { 369 ret = PTR_ERR(ctx); 370 goto out; 371 } 372 | 260 mutex_lock(&local->chanctx_mtx); 261 __ieee80211_vif_release_channel(sdata); 262 263 ctx = ieee80211_find_chanctx(local, channel, channel_type, mode); 264 if (!ctx) 265 ctx = ieee80211_new_chanctx(local, channel, channel_type, mode); 266 if (IS_ERR(ctx)) { 267 ret = PTR_ERR(ctx); 268 goto out; 269 } 270 |
271 sdata->vif.bss_conf.channel_type = channel_type; 272 |
|
373 ret = ieee80211_assign_vif_chanctx(sdata, ctx); 374 if (ret) { 375 /* if assign fails refcount stays the same */ 376 if (ctx->refcount == 0) 377 ieee80211_free_chanctx(local, ctx); 378 goto out; 379 } 380 381 out: 382 mutex_unlock(&local->chanctx_mtx); 383 return ret; 384} 385 386void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) 387{ | 273 ret = ieee80211_assign_vif_chanctx(sdata, ctx); 274 if (ret) { 275 /* if assign fails refcount stays the same */ 276 if (ctx->refcount == 0) 277 ieee80211_free_chanctx(local, ctx); 278 goto out; 279 } 280 281 out: 282 mutex_unlock(&local->chanctx_mtx); 283 return ret; 284} 285 286void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) 287{ |
288 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); 289 |
|
388 mutex_lock(&sdata->local->chanctx_mtx); 389 __ieee80211_vif_release_channel(sdata); 390 mutex_unlock(&sdata->local->chanctx_mtx); 391} | 290 mutex_lock(&sdata->local->chanctx_mtx); 291 __ieee80211_vif_release_channel(sdata); 292 mutex_unlock(&sdata->local->chanctx_mtx); 293} |