aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mesh_plink.c
diff options
context:
space:
mode:
authorAshok Nagarajan <ashok@cozybit.com>2012-04-30 17:20:30 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-05-08 21:53:57 -0400
commit57aac7c51c07ca7a2361477f352af422259301bd (patch)
treeb7c4e8a79335d11a46e667d1d555d537faae7a7e /net/mac80211/mesh_plink.c
parent431e31542383b71bc5f2642572a1e6ef07f1bb87 (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.c83
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 */
118static 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 }
148out:
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}