Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mac80211: implement VHT support for mesh

Implement the basics required for supporting very high throughput
with mesh: include VHT information elements in beacons, probe
responses, and peering action frames, and check for compatible VHT
configurations when peering.

Signed-off-by: Bob Copeland <me@bobcopeland.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>

authored by

Bob Copeland and committed by
Johannes Berg
c85fb53c f020ae40

+85 -4
+73 -3
net/mac80211/mesh.c
··· 94 94 ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan, 95 95 ie->ht_operation, &sta_chan_def); 96 96 97 + ieee80211_vht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan, 98 + ie->vht_operation, &sta_chan_def); 99 + 97 100 if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef, 98 101 &sta_chan_def)) 99 102 return false; ··· 439 436 struct ieee80211_local *local = sdata->local; 440 437 struct ieee80211_chanctx_conf *chanctx_conf; 441 438 struct ieee80211_channel *channel; 442 - enum nl80211_channel_type channel_type = 443 - cfg80211_get_chandef_type(&sdata->vif.bss_conf.chandef); 444 439 struct ieee80211_supported_band *sband; 445 440 struct ieee80211_sta_ht_cap *ht_cap; 446 441 u8 *pos; ··· 455 454 sband = local->hw.wiphy->bands[channel->band]; 456 455 ht_cap = &sband->ht_cap; 457 456 458 - if (!ht_cap->ht_supported || channel_type == NL80211_CHAN_NO_HT) 457 + if (!ht_cap->ht_supported || 458 + sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || 459 + sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || 460 + sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10) 459 461 return 0; 460 462 461 463 if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_operation)) ··· 467 463 pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation)); 468 464 ieee80211_ie_build_ht_oper(pos, ht_cap, &sdata->vif.bss_conf.chandef, 469 465 sdata->vif.bss_conf.ht_operation_mode); 466 + 467 + return 0; 468 + } 469 + 470 + int mesh_add_vht_cap_ie(struct ieee80211_sub_if_data *sdata, 471 + struct sk_buff *skb) 472 + { 473 + struct ieee80211_local *local = sdata->local; 474 + enum ieee80211_band band = ieee80211_get_sdata_band(sdata); 475 + struct ieee80211_supported_band *sband; 476 + u8 *pos; 477 + 478 + sband = local->hw.wiphy->bands[band]; 479 + if (!sband->vht_cap.vht_supported || 480 + sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || 481 + sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || 482 + sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10) 483 + return 0; 484 + 485 + if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_vht_cap)) 486 + return -ENOMEM; 487 + 488 + pos = skb_put(skb, 2 + sizeof(struct ieee80211_vht_cap)); 489 + ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, sband->vht_cap.cap); 490 + 491 + return 0; 492 + } 493 + 494 + int mesh_add_vht_oper_ie(struct ieee80211_sub_if_data *sdata, 495 + struct sk_buff *skb) 496 + { 497 + struct ieee80211_local *local = sdata->local; 498 + struct ieee80211_chanctx_conf *chanctx_conf; 499 + struct ieee80211_channel *channel; 500 + struct ieee80211_supported_band *sband; 501 + struct ieee80211_sta_vht_cap *vht_cap; 502 + u8 *pos; 503 + 504 + rcu_read_lock(); 505 + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); 506 + if (WARN_ON(!chanctx_conf)) { 507 + rcu_read_unlock(); 508 + return -EINVAL; 509 + } 510 + channel = chanctx_conf->def.chan; 511 + rcu_read_unlock(); 512 + 513 + sband = local->hw.wiphy->bands[channel->band]; 514 + vht_cap = &sband->vht_cap; 515 + 516 + if (!vht_cap->vht_supported || 517 + sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT || 518 + sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_5 || 519 + sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_10) 520 + return 0; 521 + 522 + if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_vht_operation)) 523 + return -ENOMEM; 524 + 525 + pos = skb_put(skb, 2 + sizeof(struct ieee80211_vht_operation)); 526 + ieee80211_ie_build_vht_oper(pos, vht_cap, 527 + &sdata->vif.bss_conf.chandef); 470 528 471 529 return 0; 472 530 } ··· 703 637 2 + ifmsh->mesh_id_len + 704 638 2 + sizeof(struct ieee80211_meshconf_ie) + 705 639 2 + sizeof(__le16) + /* awake window */ 640 + 2 + sizeof(struct ieee80211_vht_cap) + 641 + 2 + sizeof(struct ieee80211_vht_operation) + 706 642 ifmsh->ie_len; 707 643 708 644 bcn = kzalloc(sizeof(*bcn) + head_len + tail_len, GFP_KERNEL); ··· 786 718 mesh_add_meshid_ie(sdata, skb) || 787 719 mesh_add_meshconf_ie(sdata, skb) || 788 720 mesh_add_awake_window_ie(sdata, skb) || 721 + mesh_add_vht_cap_ie(sdata, skb) || 722 + mesh_add_vht_oper_ie(sdata, skb) || 789 723 mesh_add_vendor_ies(sdata, skb)) 790 724 goto out_free; 791 725
+4
net/mac80211/mesh.h
··· 227 227 struct sk_buff *skb); 228 228 int mesh_add_ht_oper_ie(struct ieee80211_sub_if_data *sdata, 229 229 struct sk_buff *skb); 230 + int mesh_add_vht_cap_ie(struct ieee80211_sub_if_data *sdata, 231 + struct sk_buff *skb); 232 + int mesh_add_vht_oper_ie(struct ieee80211_sub_if_data *sdata, 233 + struct sk_buff *skb); 230 234 void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); 231 235 int mesh_rmc_init(struct ieee80211_sub_if_data *sdata); 232 236 void ieee80211s_init(void);
+8 -1
net/mac80211/mesh_plink.c
··· 226 226 2 + sizeof(struct ieee80211_meshconf_ie) + 227 227 2 + sizeof(struct ieee80211_ht_cap) + 228 228 2 + sizeof(struct ieee80211_ht_operation) + 229 + 2 + sizeof(struct ieee80211_vht_cap) + 230 + 2 + sizeof(struct ieee80211_vht_operation) + 229 231 2 + 8 + /* peering IE */ 230 232 sdata->u.mesh.ie_len); 231 233 if (!skb) ··· 308 306 309 307 if (action != WLAN_SP_MESH_PEERING_CLOSE) { 310 308 if (mesh_add_ht_cap_ie(sdata, skb) || 311 - mesh_add_ht_oper_ie(sdata, skb)) 309 + mesh_add_ht_oper_ie(sdata, skb) || 310 + mesh_add_vht_cap_ie(sdata, skb) || 311 + mesh_add_vht_oper_ie(sdata, skb)) 312 312 goto free; 313 313 } 314 314 ··· 405 401 if (ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband, 406 402 elems->ht_cap_elem, sta)) 407 403 changed |= IEEE80211_RC_BW_CHANGED; 404 + 405 + ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband, 406 + elems->vht_cap_elem, sta); 408 407 409 408 if (bw != sta->sta.bandwidth) 410 409 changed |= IEEE80211_RC_BW_CHANGED;