mac80211: fix ieee80211_change_chandef name
[linux-2.6-block.git] / net / mac80211 / vht.c
CommitLineData
818255ea
MP
1/*
2 * VHT handling
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <linux/ieee80211.h>
10#include <linux/export.h>
11#include <net/mac80211.h>
12#include "ieee80211_i.h"
0af83d3d 13#include "rate.h"
818255ea
MP
14
15
16void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
17 struct ieee80211_supported_band *sband,
18 struct ieee80211_vht_cap *vht_cap_ie,
4a34215e 19 struct sta_info *sta)
818255ea 20{
4a34215e 21 struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap;
818255ea
MP
22
23 memset(vht_cap, 0, sizeof(*vht_cap));
24
4a34215e
JB
25 if (!sta->sta.ht_cap.ht_supported)
26 return;
27
818255ea
MP
28 if (!vht_cap_ie || !sband->vht_cap.vht_supported)
29 return;
30
e1a0c6b3
JB
31 /* A VHT STA must support 40 MHz */
32 if (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40))
33 return;
34
818255ea
MP
35 vht_cap->vht_supported = true;
36
37 vht_cap->cap = le32_to_cpu(vht_cap_ie->vht_cap_info);
38
39 /* Copy peer MCS info, the driver might need them. */
40 memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs,
41 sizeof(struct ieee80211_vht_mcs_info));
e1a0c6b3 42
0af83d3d
JB
43 switch (vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
44 case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
45 case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
46 sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160;
47 break;
48 default:
49 sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80;
50 }
51
e1a0c6b3
JB
52 sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta);
53}
54
55enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta)
56{
57 struct ieee80211_sub_if_data *sdata = sta->sdata;
58 u32 cap = sta->sta.vht_cap.cap;
0af83d3d 59 enum ieee80211_sta_rx_bandwidth bw;
e1a0c6b3 60
0af83d3d
JB
61 if (!sta->sta.vht_cap.vht_supported) {
62 bw = sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
e1a0c6b3 63 IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
0af83d3d
JB
64 goto check_max;
65 }
e1a0c6b3
JB
66
67 switch (sdata->vif.bss_conf.chandef.width) {
68 default:
69 WARN_ON_ONCE(1);
70 /* fall through */
71 case NL80211_CHAN_WIDTH_20_NOHT:
72 case NL80211_CHAN_WIDTH_20:
73 case NL80211_CHAN_WIDTH_40:
0af83d3d 74 bw = sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ?
e1a0c6b3 75 IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
0af83d3d 76 break;
e1a0c6b3 77 case NL80211_CHAN_WIDTH_160:
0af83d3d
JB
78 if ((cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) ==
79 IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ) {
80 bw = IEEE80211_STA_RX_BW_160;
81 break;
82 }
e1a0c6b3
JB
83 /* fall through */
84 case NL80211_CHAN_WIDTH_80P80:
0af83d3d
JB
85 if ((cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) ==
86 IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) {
87 bw = IEEE80211_STA_RX_BW_160;
88 break;
89 }
e1a0c6b3
JB
90 /* fall through */
91 case NL80211_CHAN_WIDTH_80:
0af83d3d 92 bw = IEEE80211_STA_RX_BW_80;
e1a0c6b3 93 }
0af83d3d
JB
94
95 check_max:
96 if (bw > sta->cur_max_bandwidth)
97 bw = sta->cur_max_bandwidth;
98 return bw;
818255ea 99}
8921d04e
JB
100
101void ieee80211_sta_set_rx_nss(struct sta_info *sta)
102{
103 u8 ht_rx_nss = 0, vht_rx_nss = 0;
104
105 /* if we received a notification already don't overwrite it */
106 if (sta->sta.rx_nss)
107 return;
108
109 if (sta->sta.ht_cap.ht_supported) {
110 if (sta->sta.ht_cap.mcs.rx_mask[0])
111 ht_rx_nss++;
112 if (sta->sta.ht_cap.mcs.rx_mask[1])
113 ht_rx_nss++;
114 if (sta->sta.ht_cap.mcs.rx_mask[2])
115 ht_rx_nss++;
116 if (sta->sta.ht_cap.mcs.rx_mask[3])
117 ht_rx_nss++;
118 /* FIXME: consider rx_highest? */
119 }
120
121 if (sta->sta.vht_cap.vht_supported) {
122 int i;
123 u16 rx_mcs_map;
124
125 rx_mcs_map = le16_to_cpu(sta->sta.vht_cap.vht_mcs.rx_mcs_map);
126
127 for (i = 7; i >= 0; i--) {
128 u8 mcs = (rx_mcs_map >> (2 * i)) & 3;
129
130 if (mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED) {
131 vht_rx_nss = i + 1;
132 break;
133 }
134 }
135 /* FIXME: consider rx_highest? */
136 }
137
138 ht_rx_nss = max(ht_rx_nss, vht_rx_nss);
139 sta->sta.rx_nss = max_t(u8, 1, ht_rx_nss);
140}
0af83d3d
JB
141
142void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
143 struct sta_info *sta, u8 opmode,
144 enum ieee80211_band band)
145{
146 struct ieee80211_local *local = sdata->local;
147 struct ieee80211_supported_band *sband;
148 enum ieee80211_sta_rx_bandwidth new_bw;
149 u32 changed = 0;
150 u8 nss;
151
152 sband = local->hw.wiphy->bands[band];
153
154 /* ignore - no support for BF yet */
155 if (opmode & IEEE80211_OPMODE_NOTIF_RX_NSS_TYPE_BF)
156 return;
157
158 nss = opmode & IEEE80211_OPMODE_NOTIF_RX_NSS_MASK;
159 nss >>= IEEE80211_OPMODE_NOTIF_RX_NSS_SHIFT;
160 nss += 1;
161
162 if (sta->sta.rx_nss != nss) {
163 sta->sta.rx_nss = nss;
164 changed |= IEEE80211_RC_NSS_CHANGED;
165 }
166
167 switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) {
168 case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ:
169 sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_20;
170 break;
171 case IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ:
172 sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_40;
173 break;
174 case IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ:
175 sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80;
176 break;
177 case IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ:
178 sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160;
179 break;
180 }
181
182 new_bw = ieee80211_sta_cur_vht_bw(sta);
183 if (new_bw != sta->sta.bandwidth) {
184 sta->sta.bandwidth = new_bw;
185 changed |= IEEE80211_RC_NSS_CHANGED;
186 }
187
188 if (changed)
189 rate_control_rate_update(local, sband, sta, changed);
190}