1 /* 2 * mac80211 - channel management 3 */ 4 5 #include <linux/nl80211.h> 6 #include <linux/export.h> 7 #include <linux/rtnetlink.h> 8 #include <net/cfg80211.h> 9 #include "ieee80211_i.h" 10 #include "driver-ops.h" 11 12 static void ieee80211_change_chandef(struct ieee80211_local *local, 13 struct ieee80211_chanctx *ctx, 14 const struct cfg80211_chan_def *chandef) 15 { 16 if (cfg80211_chandef_identical(&ctx->conf.def, chandef)) 17 return; 18 19 WARN_ON(!cfg80211_chandef_compatible(&ctx->conf.def, chandef)); 20 21 ctx->conf.def = *chandef; 22 drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH); 23 24 if (!local->use_chanctx) { 25 local->_oper_channel_type = cfg80211_get_chandef_type(chandef); 26 ieee80211_hw_config(local, 0); 27 } 28 } 29 30 static struct ieee80211_chanctx * 31 ieee80211_find_chanctx(struct ieee80211_local *local, 32 const struct cfg80211_chan_def *chandef, 33 enum ieee80211_chanctx_mode mode) 34 { 35 struct ieee80211_chanctx *ctx; 36 37 lockdep_assert_held(&local->chanctx_mtx); 38 39 if (mode == IEEE80211_CHANCTX_EXCLUSIVE) 40 return NULL; 41 42 list_for_each_entry(ctx, &local->chanctx_list, list) { 43 const struct cfg80211_chan_def *compat; 44 45 if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE) 46 continue; 47 48 compat = cfg80211_chandef_compatible(&ctx->conf.def, chandef); 49 if (!compat) 50 continue; 51 52 ieee80211_change_chandef(local, ctx, compat); 53 54 return ctx; 55 } 56 57 return NULL; 58 } 59 60 static struct ieee80211_chanctx * 61 ieee80211_new_chanctx(struct ieee80211_local *local, 62 const struct cfg80211_chan_def *chandef, 63 enum ieee80211_chanctx_mode mode) 64 { 65 struct ieee80211_chanctx *ctx; 66 int err; 67 68 lockdep_assert_held(&local->chanctx_mtx); 69 70 ctx = kzalloc(sizeof(*ctx) + local->hw.chanctx_data_size, GFP_KERNEL); 71 if (!ctx) 72 return ERR_PTR(-ENOMEM); 73 74 ctx->conf.def = *chandef; 75 ctx->conf.rx_chains_static = 1; 76 ctx->conf.rx_chains_dynamic = 1; 77 ctx->mode = mode; 78 79 if (!local->use_chanctx) { 80 local->_oper_channel_type = 81 cfg80211_get_chandef_type(chandef); 82 local->_oper_channel = chandef->chan; 83 ieee80211_hw_config(local, 0); 84 } else { 85 err = drv_add_chanctx(local, ctx); 86 if (err) { 87 kfree(ctx); 88 return ERR_PTR(err); 89 } 90 } 91 92 list_add_rcu(&ctx->list, &local->chanctx_list); 93 94 return ctx; 95 } 96 97 static void ieee80211_free_chanctx(struct ieee80211_local *local, 98 struct ieee80211_chanctx *ctx) 99 { 100 lockdep_assert_held(&local->chanctx_mtx); 101 102 WARN_ON_ONCE(ctx->refcount != 0); 103 104 if (!local->use_chanctx) { 105 local->_oper_channel_type = NL80211_CHAN_NO_HT; 106 ieee80211_hw_config(local, 0); 107 } else { 108 drv_remove_chanctx(local, ctx); 109 } 110 111 list_del_rcu(&ctx->list); 112 kfree_rcu(ctx, rcu_head); 113 } 114 115 static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, 116 struct ieee80211_chanctx *ctx) 117 { 118 struct ieee80211_local *local = sdata->local; 119 int ret; 120 121 lockdep_assert_held(&local->chanctx_mtx); 122 123 ret = drv_assign_vif_chanctx(local, sdata, ctx); 124 if (ret) 125 return ret; 126 127 rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf); 128 ctx->refcount++; 129 130 ieee80211_recalc_txpower(sdata); 131 132 return 0; 133 } 134 135 static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, 136 struct ieee80211_chanctx *ctx) 137 { 138 struct ieee80211_chanctx_conf *conf = &ctx->conf; 139 struct ieee80211_sub_if_data *sdata; 140 const struct cfg80211_chan_def *compat = NULL; 141 142 lockdep_assert_held(&local->chanctx_mtx); 143 144 rcu_read_lock(); 145 list_for_each_entry_rcu(sdata, &local->interfaces, list) { 146 147 if (!ieee80211_sdata_running(sdata)) 148 continue; 149 if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf) 150 continue; 151 152 if (!compat) 153 compat = &sdata->vif.bss_conf.chandef; 154 155 compat = cfg80211_chandef_compatible( 156 &sdata->vif.bss_conf.chandef, compat); 157 if (!compat) 158 break; 159 } 160 rcu_read_unlock(); 161 162 if (WARN_ON_ONCE(!compat)) 163 return; 164 165 ieee80211_change_chandef(local, ctx, compat); 166 } 167 168 static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata, 169 struct ieee80211_chanctx *ctx) 170 { 171 struct ieee80211_local *local = sdata->local; 172 173 lockdep_assert_held(&local->chanctx_mtx); 174 175 ctx->refcount--; 176 rcu_assign_pointer(sdata->vif.chanctx_conf, NULL); 177 178 drv_unassign_vif_chanctx(local, sdata, ctx); 179 180 if (ctx->refcount > 0) { 181 ieee80211_recalc_chanctx_chantype(sdata->local, ctx); 182 ieee80211_recalc_smps_chanctx(local, ctx); 183 } 184 } 185 186 static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) 187 { 188 struct ieee80211_local *local = sdata->local; 189 struct ieee80211_chanctx_conf *conf; 190 struct ieee80211_chanctx *ctx; 191 192 lockdep_assert_held(&local->chanctx_mtx); 193 194 conf = rcu_dereference_protected(sdata->vif.chanctx_conf, 195 lockdep_is_held(&local->chanctx_mtx)); 196 if (!conf) 197 return; 198 199 ctx = container_of(conf, struct ieee80211_chanctx, conf); 200 201 if (sdata->vif.type == NL80211_IFTYPE_AP) { 202 struct ieee80211_sub_if_data *vlan; 203 204 /* for the VLAN list */ 205 ASSERT_RTNL(); 206 list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) 207 rcu_assign_pointer(vlan->vif.chanctx_conf, NULL); 208 } 209 210 ieee80211_unassign_vif_chanctx(sdata, ctx); 211 if (ctx->refcount == 0) 212 ieee80211_free_chanctx(local, ctx); 213 } 214 215 void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local, 216 struct ieee80211_chanctx *chanctx) 217 { 218 struct ieee80211_sub_if_data *sdata; 219 u8 rx_chains_static, rx_chains_dynamic; 220 221 lockdep_assert_held(&local->chanctx_mtx); 222 223 rx_chains_static = 1; 224 rx_chains_dynamic = 1; 225 226 rcu_read_lock(); 227 list_for_each_entry_rcu(sdata, &local->interfaces, list) { 228 u8 needed_static, needed_dynamic; 229 230 if (!ieee80211_sdata_running(sdata)) 231 continue; 232 233 if (rcu_access_pointer(sdata->vif.chanctx_conf) != 234 &chanctx->conf) 235 continue; 236 237 switch (sdata->vif.type) { 238 case NL80211_IFTYPE_P2P_DEVICE: 239 continue; 240 case NL80211_IFTYPE_STATION: 241 if (!sdata->u.mgd.associated) 242 continue; 243 break; 244 case NL80211_IFTYPE_AP_VLAN: 245 continue; 246 case NL80211_IFTYPE_AP: 247 case NL80211_IFTYPE_ADHOC: 248 case NL80211_IFTYPE_WDS: 249 case NL80211_IFTYPE_MESH_POINT: 250 break; 251 default: 252 WARN_ON_ONCE(1); 253 } 254 255 switch (sdata->smps_mode) { 256 default: 257 WARN_ONCE(1, "Invalid SMPS mode %d\n", 258 sdata->smps_mode); 259 /* fall through */ 260 case IEEE80211_SMPS_OFF: 261 needed_static = sdata->needed_rx_chains; 262 needed_dynamic = sdata->needed_rx_chains; 263 break; 264 case IEEE80211_SMPS_DYNAMIC: 265 needed_static = 1; 266 needed_dynamic = sdata->needed_rx_chains; 267 break; 268 case IEEE80211_SMPS_STATIC: 269 needed_static = 1; 270 needed_dynamic = 1; 271 break; 272 } 273 274 rx_chains_static = max(rx_chains_static, needed_static); 275 rx_chains_dynamic = max(rx_chains_dynamic, needed_dynamic); 276 } 277 rcu_read_unlock(); 278 279 if (!local->use_chanctx) { 280 if (rx_chains_static > 1) 281 local->smps_mode = IEEE80211_SMPS_OFF; 282 else if (rx_chains_dynamic > 1) 283 local->smps_mode = IEEE80211_SMPS_DYNAMIC; 284 else 285 local->smps_mode = IEEE80211_SMPS_STATIC; 286 ieee80211_hw_config(local, 0); 287 } 288 289 if (rx_chains_static == chanctx->conf.rx_chains_static && 290 rx_chains_dynamic == chanctx->conf.rx_chains_dynamic) 291 return; 292 293 chanctx->conf.rx_chains_static = rx_chains_static; 294 chanctx->conf.rx_chains_dynamic = rx_chains_dynamic; 295 drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RX_CHAINS); 296 } 297 298 int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata, 299 const struct cfg80211_chan_def *chandef, 300 enum ieee80211_chanctx_mode mode) 301 { 302 struct ieee80211_local *local = sdata->local; 303 struct ieee80211_chanctx *ctx; 304 int ret; 305 306 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); 307 308 mutex_lock(&local->chanctx_mtx); 309 __ieee80211_vif_release_channel(sdata); 310 311 ctx = ieee80211_find_chanctx(local, chandef, mode); 312 if (!ctx) 313 ctx = ieee80211_new_chanctx(local, chandef, mode); 314 if (IS_ERR(ctx)) { 315 ret = PTR_ERR(ctx); 316 goto out; 317 } 318 319 sdata->vif.bss_conf.chandef = *chandef; 320 321 ret = ieee80211_assign_vif_chanctx(sdata, ctx); 322 if (ret) { 323 /* if assign fails refcount stays the same */ 324 if (ctx->refcount == 0) 325 ieee80211_free_chanctx(local, ctx); 326 goto out; 327 } 328 329 if (sdata->vif.type == NL80211_IFTYPE_AP) { 330 struct ieee80211_sub_if_data *vlan; 331 332 /* for the VLAN list */ 333 ASSERT_RTNL(); 334 list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) 335 rcu_assign_pointer(vlan->vif.chanctx_conf, &ctx->conf); 336 } 337 338 ieee80211_recalc_smps_chanctx(local, ctx); 339 out: 340 mutex_unlock(&local->chanctx_mtx); 341 return ret; 342 } 343 344 void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata) 345 { 346 WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev)); 347 348 mutex_lock(&sdata->local->chanctx_mtx); 349 __ieee80211_vif_release_channel(sdata); 350 mutex_unlock(&sdata->local->chanctx_mtx); 351 } 352 353 void ieee80211_vif_vlan_copy_chanctx(struct ieee80211_sub_if_data *sdata) 354 { 355 struct ieee80211_local *local = sdata->local; 356 struct ieee80211_sub_if_data *ap; 357 struct ieee80211_chanctx_conf *conf; 358 359 if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP_VLAN || !sdata->bss)) 360 return; 361 362 ap = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap); 363 364 mutex_lock(&local->chanctx_mtx); 365 366 conf = rcu_dereference_protected(ap->vif.chanctx_conf, 367 lockdep_is_held(&local->chanctx_mtx)); 368 rcu_assign_pointer(sdata->vif.chanctx_conf, conf); 369 mutex_unlock(&local->chanctx_mtx); 370 } 371 372 void ieee80211_iter_chan_contexts_atomic( 373 struct ieee80211_hw *hw, 374 void (*iter)(struct ieee80211_hw *hw, 375 struct ieee80211_chanctx_conf *chanctx_conf, 376 void *data), 377 void *iter_data) 378 { 379 struct ieee80211_local *local = hw_to_local(hw); 380 struct ieee80211_chanctx *ctx; 381 382 rcu_read_lock(); 383 list_for_each_entry_rcu(ctx, &local->chanctx_list, list) 384 iter(hw, &ctx->conf, iter_data); 385 rcu_read_unlock(); 386 } 387 EXPORT_SYMBOL_GPL(ieee80211_iter_chan_contexts_atomic); 388