diff options
Diffstat (limited to 'net/mac80211/mesh.c')
| -rw-r--r-- | net/mac80211/mesh.c | 90 |
1 files changed, 54 insertions, 36 deletions
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index ff0296c7bab8..649ad513547f 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c | |||
| @@ -76,7 +76,7 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, | |||
| 76 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | 76 | struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; |
| 77 | struct ieee80211_local *local = sdata->local; | 77 | struct ieee80211_local *local = sdata->local; |
| 78 | u32 basic_rates = 0; | 78 | u32 basic_rates = 0; |
| 79 | enum nl80211_channel_type sta_channel_type = NL80211_CHAN_NO_HT; | 79 | struct cfg80211_chan_def sta_chan_def; |
| 80 | 80 | ||
| 81 | /* | 81 | /* |
| 82 | * As support for each feature is added, check for matching | 82 | * As support for each feature is added, check for matching |
| @@ -97,23 +97,17 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, | |||
| 97 | (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth))) | 97 | (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth))) |
| 98 | goto mismatch; | 98 | goto mismatch; |
| 99 | 99 | ||
| 100 | ieee80211_sta_get_rates(local, ie, local->oper_channel->band, | 100 | ieee80211_sta_get_rates(local, ie, ieee80211_get_sdata_band(sdata), |
| 101 | &basic_rates); | 101 | &basic_rates); |
| 102 | 102 | ||
| 103 | if (sdata->vif.bss_conf.basic_rates != basic_rates) | 103 | if (sdata->vif.bss_conf.basic_rates != basic_rates) |
| 104 | goto mismatch; | 104 | goto mismatch; |
| 105 | 105 | ||
| 106 | if (ie->ht_operation) | 106 | ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan, |
| 107 | sta_channel_type = | 107 | ie->ht_operation, &sta_chan_def); |
| 108 | ieee80211_ht_oper_to_channel_type(ie->ht_operation); | 108 | |
| 109 | 109 | if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef, | |
| 110 | /* Disallow HT40+/- mismatch */ | 110 | &sta_chan_def)) |
| 111 | if (ie->ht_operation && | ||
| 112 | (sdata->vif.bss_conf.channel_type == NL80211_CHAN_HT40MINUS || | ||
| 113 | sdata->vif.bss_conf.channel_type == NL80211_CHAN_HT40PLUS) && | ||
| 114 | (sta_channel_type == NL80211_CHAN_HT40MINUS || | ||
| 115 | sta_channel_type == NL80211_CHAN_HT40PLUS) && | ||
| 116 | sdata->vif.bss_conf.channel_type != sta_channel_type) | ||
| 117 | goto mismatch; | 111 | goto mismatch; |
| 118 | 112 | ||
| 119 | return true; | 113 | return true; |
| @@ -129,7 +123,7 @@ mismatch: | |||
| 129 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) | 123 | bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie) |
| 130 | { | 124 | { |
| 131 | return (ie->mesh_config->meshconf_cap & | 125 | return (ie->mesh_config->meshconf_cap & |
| 132 | MESHCONF_CAPAB_ACCEPT_PLINKS) != 0; | 126 | IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS) != 0; |
| 133 | } | 127 | } |
| 134 | 128 | ||
| 135 | /** | 129 | /** |
| @@ -169,7 +163,7 @@ int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) | |||
| 169 | return -ENOMEM; | 163 | return -ENOMEM; |
| 170 | sdata->u.mesh.rmc->idx_mask = RMC_BUCKETS - 1; | 164 | sdata->u.mesh.rmc->idx_mask = RMC_BUCKETS - 1; |
| 171 | for (i = 0; i < RMC_BUCKETS; i++) | 165 | for (i = 0; i < RMC_BUCKETS; i++) |
| 172 | INIT_LIST_HEAD(&sdata->u.mesh.rmc->bucket[i].list); | 166 | INIT_LIST_HEAD(&sdata->u.mesh.rmc->bucket[i]); |
| 173 | return 0; | 167 | return 0; |
| 174 | } | 168 | } |
| 175 | 169 | ||
| @@ -183,7 +177,7 @@ void mesh_rmc_free(struct ieee80211_sub_if_data *sdata) | |||
| 183 | return; | 177 | return; |
| 184 | 178 | ||
| 185 | for (i = 0; i < RMC_BUCKETS; i++) | 179 | for (i = 0; i < RMC_BUCKETS; i++) |
| 186 | list_for_each_entry_safe(p, n, &rmc->bucket[i].list, list) { | 180 | list_for_each_entry_safe(p, n, &rmc->bucket[i], list) { |
| 187 | list_del(&p->list); | 181 | list_del(&p->list); |
| 188 | kmem_cache_free(rm_cache, p); | 182 | kmem_cache_free(rm_cache, p); |
| 189 | } | 183 | } |
| @@ -216,7 +210,7 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr, | |||
| 216 | /* Don't care about endianness since only match matters */ | 210 | /* Don't care about endianness since only match matters */ |
| 217 | memcpy(&seqnum, &mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum)); | 211 | memcpy(&seqnum, &mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum)); |
| 218 | idx = le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask; | 212 | idx = le32_to_cpu(mesh_hdr->seqnum) & rmc->idx_mask; |
| 219 | list_for_each_entry_safe(p, n, &rmc->bucket[idx].list, list) { | 213 | list_for_each_entry_safe(p, n, &rmc->bucket[idx], list) { |
| 220 | ++entries; | 214 | ++entries; |
| 221 | if (time_after(jiffies, p->exp_time) || | 215 | if (time_after(jiffies, p->exp_time) || |
| 222 | (entries == RMC_QUEUE_MAX_LEN)) { | 216 | (entries == RMC_QUEUE_MAX_LEN)) { |
| @@ -235,7 +229,7 @@ int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr, | |||
| 235 | p->seqnum = seqnum; | 229 | p->seqnum = seqnum; |
| 236 | p->exp_time = jiffies + RMC_TIMEOUT; | 230 | p->exp_time = jiffies + RMC_TIMEOUT; |
| 237 | memcpy(p->sa, sa, ETH_ALEN); | 231 | memcpy(p->sa, sa, ETH_ALEN); |
| 238 | list_add(&p->list, &rmc->bucket[idx].list); | 232 | list_add(&p->list, &rmc->bucket[idx]); |
| 239 | return 0; | 233 | return 0; |
| 240 | } | 234 | } |
| 241 | 235 | ||
| @@ -264,16 +258,16 @@ mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) | |||
| 264 | /* Authentication Protocol identifier */ | 258 | /* Authentication Protocol identifier */ |
| 265 | *pos++ = ifmsh->mesh_auth_id; | 259 | *pos++ = ifmsh->mesh_auth_id; |
| 266 | /* Mesh Formation Info - number of neighbors */ | 260 | /* Mesh Formation Info - number of neighbors */ |
| 267 | neighbors = atomic_read(&ifmsh->mshstats.estab_plinks); | 261 | neighbors = atomic_read(&ifmsh->estab_plinks); |
| 268 | /* Number of neighbor mesh STAs or 15 whichever is smaller */ | 262 | /* Number of neighbor mesh STAs or 15 whichever is smaller */ |
| 269 | neighbors = (neighbors > 15) ? 15 : neighbors; | 263 | neighbors = (neighbors > 15) ? 15 : neighbors; |
| 270 | *pos++ = neighbors << 1; | 264 | *pos++ = neighbors << 1; |
| 271 | /* Mesh capability */ | 265 | /* Mesh capability */ |
| 272 | *pos = MESHCONF_CAPAB_FORWARDING; | 266 | *pos = IEEE80211_MESHCONF_CAPAB_FORWARDING; |
| 273 | *pos |= ifmsh->accepting_plinks ? | 267 | *pos |= ifmsh->accepting_plinks ? |
| 274 | MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; | 268 | IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00; |
| 275 | *pos++ |= ifmsh->adjusting_tbtt ? | 269 | *pos++ |= ifmsh->adjusting_tbtt ? |
| 276 | MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00; | 270 | IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00; |
| 277 | *pos++ = 0x00; | 271 | *pos++ = 0x00; |
| 278 | 272 | ||
| 279 | return 0; | 273 | return 0; |
| @@ -355,12 +349,22 @@ int mesh_add_ds_params_ie(struct sk_buff *skb, | |||
| 355 | { | 349 | { |
| 356 | struct ieee80211_local *local = sdata->local; | 350 | struct ieee80211_local *local = sdata->local; |
| 357 | struct ieee80211_supported_band *sband; | 351 | struct ieee80211_supported_band *sband; |
| 358 | struct ieee80211_channel *chan = local->oper_channel; | 352 | struct ieee80211_chanctx_conf *chanctx_conf; |
| 353 | struct ieee80211_channel *chan; | ||
| 359 | u8 *pos; | 354 | u8 *pos; |
| 360 | 355 | ||
| 361 | if (skb_tailroom(skb) < 3) | 356 | if (skb_tailroom(skb) < 3) |
| 362 | return -ENOMEM; | 357 | return -ENOMEM; |
| 363 | 358 | ||
| 359 | rcu_read_lock(); | ||
| 360 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 361 | if (WARN_ON(!chanctx_conf)) { | ||
| 362 | rcu_read_unlock(); | ||
| 363 | return -EINVAL; | ||
| 364 | } | ||
| 365 | chan = chanctx_conf->def.chan; | ||
| 366 | rcu_read_unlock(); | ||
| 367 | |||
| 364 | sband = local->hw.wiphy->bands[chan->band]; | 368 | sband = local->hw.wiphy->bands[chan->band]; |
| 365 | if (sband->band == IEEE80211_BAND_2GHZ) { | 369 | if (sband->band == IEEE80211_BAND_2GHZ) { |
| 366 | pos = skb_put(skb, 2 + 1); | 370 | pos = skb_put(skb, 2 + 1); |
| @@ -376,12 +380,13 @@ int mesh_add_ht_cap_ie(struct sk_buff *skb, | |||
| 376 | struct ieee80211_sub_if_data *sdata) | 380 | struct ieee80211_sub_if_data *sdata) |
| 377 | { | 381 | { |
| 378 | struct ieee80211_local *local = sdata->local; | 382 | struct ieee80211_local *local = sdata->local; |
| 383 | enum ieee80211_band band = ieee80211_get_sdata_band(sdata); | ||
| 379 | struct ieee80211_supported_band *sband; | 384 | struct ieee80211_supported_band *sband; |
| 380 | u8 *pos; | 385 | u8 *pos; |
| 381 | 386 | ||
| 382 | sband = local->hw.wiphy->bands[local->oper_channel->band]; | 387 | sband = local->hw.wiphy->bands[band]; |
| 383 | if (!sband->ht_cap.ht_supported || | 388 | if (!sband->ht_cap.ht_supported || |
| 384 | sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT) | 389 | sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT) |
| 385 | return 0; | 390 | return 0; |
| 386 | 391 | ||
| 387 | if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap)) | 392 | if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap)) |
| @@ -397,14 +402,26 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb, | |||
| 397 | struct ieee80211_sub_if_data *sdata) | 402 | struct ieee80211_sub_if_data *sdata) |
| 398 | { | 403 | { |
| 399 | struct ieee80211_local *local = sdata->local; | 404 | struct ieee80211_local *local = sdata->local; |
| 400 | struct ieee80211_channel *channel = local->oper_channel; | 405 | struct ieee80211_chanctx_conf *chanctx_conf; |
| 406 | struct ieee80211_channel *channel; | ||
| 401 | enum nl80211_channel_type channel_type = | 407 | enum nl80211_channel_type channel_type = |
| 402 | sdata->vif.bss_conf.channel_type; | 408 | cfg80211_get_chandef_type(&sdata->vif.bss_conf.chandef); |
| 403 | struct ieee80211_supported_band *sband = | 409 | struct ieee80211_supported_band *sband; |
| 404 | local->hw.wiphy->bands[channel->band]; | 410 | struct ieee80211_sta_ht_cap *ht_cap; |
| 405 | struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap; | ||
| 406 | u8 *pos; | 411 | u8 *pos; |
| 407 | 412 | ||
| 413 | rcu_read_lock(); | ||
| 414 | chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | ||
| 415 | if (WARN_ON(!chanctx_conf)) { | ||
| 416 | rcu_read_unlock(); | ||
| 417 | return -EINVAL; | ||
| 418 | } | ||
| 419 | channel = chanctx_conf->def.chan; | ||
| 420 | rcu_read_unlock(); | ||
| 421 | |||
| 422 | sband = local->hw.wiphy->bands[channel->band]; | ||
| 423 | ht_cap = &sband->ht_cap; | ||
| 424 | |||
| 408 | if (!ht_cap->ht_supported || channel_type == NL80211_CHAN_NO_HT) | 425 | if (!ht_cap->ht_supported || channel_type == NL80211_CHAN_NO_HT) |
| 409 | return 0; | 426 | return 0; |
| 410 | 427 | ||
| @@ -412,7 +429,7 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb, | |||
| 412 | return -ENOMEM; | 429 | return -ENOMEM; |
| 413 | 430 | ||
| 414 | pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation)); | 431 | pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation)); |
| 415 | ieee80211_ie_build_ht_oper(pos, ht_cap, channel, channel_type, | 432 | ieee80211_ie_build_ht_oper(pos, ht_cap, &sdata->vif.bss_conf.chandef, |
| 416 | sdata->vif.bss_conf.ht_operation_mode); | 433 | sdata->vif.bss_conf.ht_operation_mode); |
| 417 | 434 | ||
| 418 | return 0; | 435 | return 0; |
| @@ -610,7 +627,7 @@ void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) | |||
| 610 | sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; | 627 | sdata->vif.bss_conf.beacon_int = MESH_DEFAULT_BEACON_INTERVAL; |
| 611 | sdata->vif.bss_conf.basic_rates = | 628 | sdata->vif.bss_conf.basic_rates = |
| 612 | ieee80211_mandatory_rates(sdata->local, | 629 | ieee80211_mandatory_rates(sdata->local, |
| 613 | sdata->local->oper_channel->band); | 630 | ieee80211_get_sdata_band(sdata)); |
| 614 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | | 631 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON | |
| 615 | BSS_CHANGED_BEACON_ENABLED | | 632 | BSS_CHANGED_BEACON_ENABLED | |
| 616 | BSS_CHANGED_HT | | 633 | BSS_CHANGED_HT | |
| @@ -680,8 +697,10 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |||
| 680 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, | 697 | ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen, |
| 681 | &elems); | 698 | &elems); |
| 682 | 699 | ||
| 683 | /* ignore beacons from secure mesh peers if our security is off */ | 700 | /* ignore non-mesh or secure / unsecure mismatch */ |
| 684 | if (elems.rsn_len && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) | 701 | if ((!elems.mesh_id || !elems.mesh_config) || |
| 702 | (elems.rsn && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) || | ||
| 703 | (!elems.rsn && sdata->u.mesh.security != IEEE80211_MESH_SEC_NONE)) | ||
| 685 | return; | 704 | return; |
| 686 | 705 | ||
| 687 | if (elems.ds_params && elems.ds_params_len == 1) | 706 | if (elems.ds_params && elems.ds_params_len == 1) |
| @@ -694,8 +713,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, | |||
| 694 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) | 713 | if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) |
| 695 | return; | 714 | return; |
| 696 | 715 | ||
| 697 | if (elems.mesh_id && elems.mesh_config && | 716 | if (mesh_matches_local(sdata, &elems)) |
| 698 | mesh_matches_local(sdata, &elems)) | ||
| 699 | mesh_neighbour_update(sdata, mgmt->sa, &elems); | 717 | mesh_neighbour_update(sdata, mgmt->sa, &elems); |
| 700 | 718 | ||
| 701 | if (ifmsh->sync_ops) | 719 | if (ifmsh->sync_ops) |
