diff options
author | Ashok Nagarajan <ashok@cozybit.com> | 2012-04-30 17:20:30 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-05-08 21:53:57 -0400 |
commit | 57aac7c51c07ca7a2361477f352af422259301bd (patch) | |
tree | b7c4e8a79335d11a46e667d1d555d537faae7a7e /net/mac80211/mesh_plink.c | |
parent | 431e31542383b71bc5f2642572a1e6ef07f1bb87 (diff) |
mac80211: Implement HT mixed protection mode
Section 9.23.3.5 of IEEE 80211s standard describes the protection rules for
HT mesh STA in a MBSS. Three HT protection modes are supported for now:
non-HT mixed mode - is selected if any non-HT peers are present in our MBSS.
20MHz-protection mode - is selected if all peers in our 20/40MHz MBSS support
HT and atleast one HT20 peer is present.
no-protection mode - is selected otherwise.
This is a limited implementation of 9.23.3.5, which only considers mesh peers
when determining the HT protection mode. Station's channel_type needs to be
maintained.
Signed-off-by: Ashok Nagarajan <ashok@cozybit.com>
Reviewed-by: Thomas Pedersen <thomas@cozybit.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/mesh_plink.c')
-rw-r--r-- | net/mac80211/mesh_plink.c | 83 |
1 files changed, 76 insertions, 7 deletions
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 6209327840f7..2e0ae7310697 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -105,6 +105,66 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, | |||
105 | return sta; | 105 | return sta; |
106 | } | 106 | } |
107 | 107 | ||
108 | /** mesh_set_ht_prot_mode - set correct HT protection mode | ||
109 | * | ||
110 | * Section 9.23.3.5 of IEEE 80211s standard describes the protection rules for | ||
111 | * HT mesh STA in a MBSS. Three HT protection modes are supported for now, | ||
112 | * non-HT mixed mode, 20MHz-protection and no-protection mode. non-HT mixed | ||
113 | * mode is selected if any non-HT peers are present in our MBSS. | ||
114 | * 20MHz-protection mode is selected if all peers in our 20/40MHz MBSS support | ||
115 | * HT and atleast one HT20 peer is present. Otherwise no-protection mode is | ||
116 | * selected. | ||
117 | */ | ||
118 | static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) | ||
119 | { | ||
120 | struct ieee80211_local *local = sdata->local; | ||
121 | struct sta_info *sta; | ||
122 | u32 changed = 0; | ||
123 | u16 ht_opmode; | ||
124 | bool non_ht_sta = false, ht20_sta = false; | ||
125 | |||
126 | if (local->_oper_channel_type == NL80211_CHAN_NO_HT) | ||
127 | return 0; | ||
128 | |||
129 | rcu_read_lock(); | ||
130 | list_for_each_entry_rcu(sta, &local->sta_list, list) { | ||
131 | if (sdata == sta->sdata && | ||
132 | sta->plink_state == NL80211_PLINK_ESTAB) { | ||
133 | switch (sta->ch_type) { | ||
134 | case NL80211_CHAN_NO_HT: | ||
135 | mpl_dbg("mesh_plink %pM: nonHT sta (%pM) is present", | ||
136 | sdata->vif.addr, sta->sta.addr); | ||
137 | non_ht_sta = true; | ||
138 | goto out; | ||
139 | case NL80211_CHAN_HT20: | ||
140 | mpl_dbg("mesh_plink %pM: HT20 sta (%pM) is present", | ||
141 | sdata->vif.addr, sta->sta.addr); | ||
142 | ht20_sta = true; | ||
143 | default: | ||
144 | break; | ||
145 | } | ||
146 | } | ||
147 | } | ||
148 | out: | ||
149 | rcu_read_unlock(); | ||
150 | |||
151 | if (non_ht_sta) | ||
152 | ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED; | ||
153 | else if (ht20_sta && local->_oper_channel_type > NL80211_CHAN_HT20) | ||
154 | ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_20MHZ; | ||
155 | else | ||
156 | ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE; | ||
157 | |||
158 | if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) { | ||
159 | sdata->vif.bss_conf.ht_operation_mode = ht_opmode; | ||
160 | changed = BSS_CHANGED_HT; | ||
161 | mpl_dbg("mesh_plink %pM: protection mode changed to %d", | ||
162 | sdata->vif.addr, ht_opmode); | ||
163 | } | ||
164 | |||
165 | return changed; | ||
166 | } | ||
167 | |||
108 | /** | 168 | /** |
109 | * __mesh_plink_deactivate - deactivate mesh peer link | 169 | * __mesh_plink_deactivate - deactivate mesh peer link |
110 | * | 170 | * |
@@ -302,11 +362,14 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, | |||
302 | else | 362 | else |
303 | memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap)); | 363 | memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap)); |
304 | 364 | ||
305 | if (elems->ht_operation) | 365 | if (elems->ht_operation) { |
306 | if (!(elems->ht_operation->ht_param & | 366 | if (!(elems->ht_operation->ht_param & |
307 | IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) | 367 | IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) |
308 | sta->sta.ht_cap.cap &= | 368 | sta->sta.ht_cap.cap &= |
309 | ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; | 369 | ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; |
370 | sta->ch_type = | ||
371 | ieee80211_ht_oper_to_channel_type(elems->ht_operation); | ||
372 | } | ||
310 | 373 | ||
311 | rate_control_rate_init(sta); | 374 | rate_control_rate_init(sta); |
312 | spin_unlock_bh(&sta->lock); | 375 | spin_unlock_bh(&sta->lock); |
@@ -495,9 +558,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
495 | enum plink_event event; | 558 | enum plink_event event; |
496 | enum ieee80211_self_protected_actioncode ftype; | 559 | enum ieee80211_self_protected_actioncode ftype; |
497 | size_t baselen; | 560 | size_t baselen; |
498 | bool deactivated, matches_local = true; | 561 | bool matches_local = true; |
499 | u8 ie_len; | 562 | u8 ie_len; |
500 | u8 *baseaddr; | 563 | u8 *baseaddr; |
564 | u32 changed = 0; | ||
501 | __le16 plid, llid, reason; | 565 | __le16 plid, llid, reason; |
502 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG | 566 | #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG |
503 | static const char *mplstates[] = { | 567 | static const char *mplstates[] = { |
@@ -783,7 +847,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
783 | sta->plink_state = NL80211_PLINK_ESTAB; | 847 | sta->plink_state = NL80211_PLINK_ESTAB; |
784 | spin_unlock_bh(&sta->lock); | 848 | spin_unlock_bh(&sta->lock); |
785 | mesh_plink_inc_estab_count(sdata); | 849 | mesh_plink_inc_estab_count(sdata); |
786 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | 850 | changed |= mesh_set_ht_prot_mode(sdata); |
851 | changed |= BSS_CHANGED_BEACON; | ||
787 | mpl_dbg("Mesh plink with %pM ESTABLISHED\n", | 852 | mpl_dbg("Mesh plink with %pM ESTABLISHED\n", |
788 | sta->sta.addr); | 853 | sta->sta.addr); |
789 | break; | 854 | break; |
@@ -818,7 +883,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
818 | sta->plink_state = NL80211_PLINK_ESTAB; | 883 | sta->plink_state = NL80211_PLINK_ESTAB; |
819 | spin_unlock_bh(&sta->lock); | 884 | spin_unlock_bh(&sta->lock); |
820 | mesh_plink_inc_estab_count(sdata); | 885 | mesh_plink_inc_estab_count(sdata); |
821 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | 886 | changed |= mesh_set_ht_prot_mode(sdata); |
887 | changed |= BSS_CHANGED_BEACON; | ||
822 | mpl_dbg("Mesh plink with %pM ESTABLISHED\n", | 888 | mpl_dbg("Mesh plink with %pM ESTABLISHED\n", |
823 | sta->sta.addr); | 889 | sta->sta.addr); |
824 | mesh_plink_frame_tx(sdata, | 890 | mesh_plink_frame_tx(sdata, |
@@ -836,13 +902,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
836 | case CLS_ACPT: | 902 | case CLS_ACPT: |
837 | reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE); | 903 | reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE); |
838 | sta->reason = reason; | 904 | sta->reason = reason; |
839 | deactivated = __mesh_plink_deactivate(sta); | 905 | __mesh_plink_deactivate(sta); |
840 | sta->plink_state = NL80211_PLINK_HOLDING; | 906 | sta->plink_state = NL80211_PLINK_HOLDING; |
841 | llid = sta->llid; | 907 | llid = sta->llid; |
842 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); | 908 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); |
843 | spin_unlock_bh(&sta->lock); | 909 | spin_unlock_bh(&sta->lock); |
844 | if (deactivated) | 910 | changed |= mesh_set_ht_prot_mode(sdata); |
845 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | 911 | changed |= BSS_CHANGED_BEACON; |
846 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, | 912 | mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, |
847 | sta->sta.addr, llid, plid, reason); | 913 | sta->sta.addr, llid, plid, reason); |
848 | break; | 914 | break; |
@@ -889,4 +955,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
889 | } | 955 | } |
890 | 956 | ||
891 | rcu_read_unlock(); | 957 | rcu_read_unlock(); |
958 | |||
959 | if (changed) | ||
960 | ieee80211_bss_info_change_notify(sdata, changed); | ||
892 | } | 961 | } |