2012-12-27 17:59:07

by Johannes Berg

[permalink] [raw]
Subject: [RFC 0/3] (VHT) operating mode notification

Here's an attempt to handle the new operating mode notifications.

So far, only NSS changes are supported, need to do some refactoring
to support bandwidth changes. Also, the operating mode can also be
in a beacon IE, need to add support for that.

johannes



2012-12-27 17:59:07

by Johannes Berg

[permalink] [raw]
Subject: [RFC 1/3] mac80211: track number of spatial streams

From: Johannes Berg <[email protected]>

With VHT, a station can change the number of spatial
streams it can receive on the fly, not unlike spatial
multiplexing in HT. Prepare for that by tracking the
maximum number of spatial streams it can receive when
the connection is established.

Signed-off-by: Johannes Berg <[email protected]>
---
include/net/mac80211.h | 5 +++++
net/mac80211/ieee80211_i.h | 2 ++
net/mac80211/rate.h | 2 ++
net/mac80211/vht.c | 41 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 50 insertions(+)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 0978b0f..5bc6459 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1197,6 +1197,10 @@ enum ieee80211_sta_state {
* @uapsd_queues: bitmap of queues configured for uapsd. Only valid
* if wme is supported.
* @max_sp: max Service Period. Only valid if wme is supported.
+ * @rx_nss: in HT/VHT, the maximum number of spatial streams the
+ * station can receive at the moment, changed by operating mode
+ * notifications and capabilities. The value is only valid after
+ * the station moves to associated state.
*/
struct ieee80211_sta {
u32 supp_rates[IEEE80211_NUM_BANDS];
@@ -1207,6 +1211,7 @@ struct ieee80211_sta {
bool wme;
u8 uapsd_queues;
u8 max_sp;
+ u8 rx_nss;

/* must be last */
u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *))));
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 5ab33c7..edc88e2 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1462,6 +1462,8 @@ void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
struct ieee80211_supported_band *sband,
struct ieee80211_vht_cap *vht_cap_ie,
struct ieee80211_sta_vht_cap *vht_cap);
+void ieee80211_sta_set_rx_nss(struct sta_info *sta);
+
/* Spectrum management */
void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h
index 301386d..d35a5dd 100644
--- a/net/mac80211/rate.h
+++ b/net/mac80211/rate.h
@@ -68,6 +68,8 @@ static inline void rate_control_rate_init(struct sta_info *sta)
sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band];
rcu_read_unlock();

+ ieee80211_sta_set_rx_nss(sta);
+
ref->ops->rate_init(ref->priv, sband, ista, priv_sta);
set_sta_flag(sta, WLAN_STA_RATE_CONTROL);
}
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index f311388..7751867 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -33,3 +33,44 @@ void ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs,
sizeof(struct ieee80211_vht_mcs_info));
}
+
+void ieee80211_sta_set_rx_nss(struct sta_info *sta)
+{
+ u8 ht_rx_nss = 0, vht_rx_nss = 0;
+
+ /* if we received a notification already don't overwrite it */
+ if (sta->sta.rx_nss)
+ return;
+
+ if (sta->sta.ht_cap.ht_supported) {
+ if (sta->sta.ht_cap.mcs.rx_mask[0])
+ ht_rx_nss++;
+ if (sta->sta.ht_cap.mcs.rx_mask[1])
+ ht_rx_nss++;
+ if (sta->sta.ht_cap.mcs.rx_mask[2])
+ ht_rx_nss++;
+ if (sta->sta.ht_cap.mcs.rx_mask[3])
+ ht_rx_nss++;
+ /* FIXME: consider rx_highest? */
+ }
+
+ if (sta->sta.vht_cap.vht_supported) {
+ int i;
+ u16 rx_mcs_map;
+
+ rx_mcs_map = le16_to_cpu(sta->sta.vht_cap.vht_mcs.rx_mcs_map);
+
+ for (i = 7; i >= 0; i--) {
+ u8 mcs = (rx_mcs_map >> (2 * i)) & 3;
+
+ if (mcs != IEEE80211_VHT_MCS_NOT_SUPPORTED) {
+ vht_rx_nss = i + 1;
+ break;
+ }
+ }
+ /* FIXME: consider rx_highest? */
+ }
+
+ ht_rx_nss = max(ht_rx_nss, vht_rx_nss);
+ sta->sta.rx_nss = max_t(u8, 1, ht_rx_nss);
+}
--
1.8.0


2012-12-27 17:59:07

by Johannes Berg

[permalink] [raw]
Subject: [RFC 2/3] wireless: define VHT operating mode action frame

From: Johannes Berg <[email protected]>

Define the action frame format, the VHT category
and its action types and the field format and EID
for operating mode notifications.

Signed-off-by: Johannes Berg <[email protected]>
---
include/linux/ieee80211.h | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)

diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 09879eb..a024278 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -701,6 +701,30 @@ enum ieee80211_rann_flags {
RANN_FLAG_IS_GATE = 1 << 0,
};

+/**
+ * enum ieee80211_vht_opmode_bits - VHT operating mode field bits
+ * @IEEE80211_VHT_OPMODE_CHANWIDTH_MASK: channel width mask
+ * @IEEE80211_VHT_OPMODE_CHANWIDTH_20MHZ: 20 MHz channel width
+ * @IEEE80211_VHT_OPMODE_CHANWIDTH_40MHZ: 40 MHz channel width
+ * @IEEE80211_VHT_OPMODE_CHANWIDTH_80MHZ: 80 MHz channel width
+ * @IEEE80211_VHT_OPMODE_CHANWIDTH_160MHZ: 160 MHz or 80+80 MHz channel width
+ * @IEEE80211_VHT_OPMODE_RX_NSS_MASK: number of spatial streams mask
+ * (value is NSS + 1)
+ * @IEEE80211_VHT_OPMODE_RX_NSS_SHIFT: number of spatial streams shift
+ * @IEEE80211_VHT_OPMODE_RX_NSS_TYPE_BF: indicates streams in SU-MIMO PPDU
+ * using a beamforming steering matrix
+ */
+enum ieee80211_vht_opmode_bits {
+ IEEE80211_VHT_OPMODE_CHANWIDTH_MASK = 3,
+ IEEE80211_VHT_OPMODE_CHANWIDTH_20MHZ = 0,
+ IEEE80211_VHT_OPMODE_CHANWIDTH_40MHZ = 1,
+ IEEE80211_VHT_OPMODE_CHANWIDTH_80MHZ = 2,
+ IEEE80211_VHT_OPMODE_CHANWIDTH_160MHZ = 3,
+ IEEE80211_VHT_OPMODE_RX_NSS_MASK = 0x70,
+ IEEE80211_VHT_OPMODE_RX_NSS_SHIFT = 4,
+ IEEE80211_VHT_OPMODE_RX_NSS_TYPE_BF = 0x80,
+};
+
#define WLAN_SA_QUERY_TR_ID_LEN 2

struct ieee80211_mgmt {
@@ -827,6 +851,10 @@ struct ieee80211_mgmt {
__le16 capability;
u8 variable[0];
} __packed tdls_discover_resp;
+ struct {
+ u8 action_code;
+ u8 operating_mode;
+ } __packed vht_opmode_notif;
} u;
} __attribute__ ((packed)) action;
} u;
@@ -1581,6 +1609,7 @@ enum ieee80211_eid {

WLAN_EID_VHT_CAPABILITY = 191,
WLAN_EID_VHT_OPERATION = 192,
+ WLAN_EID_VHT_OPMODE_NOTIF = 199,

/* 802.11ad */
WLAN_EID_NON_TX_BSSID_CAP = 83,
@@ -1635,6 +1664,7 @@ enum ieee80211_category {
WLAN_CATEGORY_WMM = 17,
WLAN_CATEGORY_FST = 18,
WLAN_CATEGORY_UNPROT_DMG = 20,
+ WLAN_CATEGORY_VHT = 21,
WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126,
WLAN_CATEGORY_VENDOR_SPECIFIC = 127,
};
@@ -1660,6 +1690,13 @@ enum ieee80211_ht_actioncode {
WLAN_HT_ACTION_ASEL_IDX_FEEDBACK = 7,
};

+/* VHT action codes */
+enum ieee80211_vht_actioncode {
+ WLAN_VHT_ACTION_COMPRESSED_BF = 0,
+ WLAN_VHT_ACTION_GROUPID_MGMT = 1,
+ WLAN_VHT_ACTION_OPMODE_NOTIF = 2,
+};
+
/* Self Protected Action codes */
enum ieee80211_self_protected_actioncode {
WLAN_SP_RESERVED = 0,
--
1.8.0


2012-12-27 17:59:07

by Johannes Berg

[permalink] [raw]
Subject: [RFC 3/3] mac80211: handle operating mode notification action

From: Johannes Berg <[email protected]>

Handle the operating mode notification action frame.
When the supported streams change, let the driver and
rate control algorithm know.

INCOMPLETE - need to handle bandwidth changes

Signed-off-by: Johannes Berg <[email protected]>
---
include/net/mac80211.h | 3 +++
net/mac80211/rx.c | 42 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 45 insertions(+)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 5bc6459..66a8b0a 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2072,11 +2072,14 @@ enum ieee80211_frame_release_type {
* @IEEE80211_RC_SUPP_RATES_CHANGED: The supported rate set of this peer
* changed (in IBSS mode) due to discovering more information about
* the peer.
+ * @IEEE80211_RC_NSS_CHANGED: N_SS (number of spatial streams) was changed
+ * by the peer, using an operating mode notification
*/
enum ieee80211_rate_control_changed {
IEEE80211_RC_BW_CHANGED = BIT(0),
IEEE80211_RC_SMPS_CHANGED = BIT(1),
IEEE80211_RC_SUPP_RATES_CHANGED = BIT(2),
+ IEEE80211_RC_NSS_CHANGED = BIT(3),
};

/**
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 580704e..e863190 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2397,6 +2397,48 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
}

break;
+ case WLAN_CATEGORY_VHT:
+ if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+ sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
+ sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
+ sdata->vif.type != NL80211_IFTYPE_AP &&
+ sdata->vif.type != NL80211_IFTYPE_ADHOC)
+ break;
+
+ /* verify action code and one more byte (opmode) are present */
+ if (len < IEEE80211_MIN_ACTION_SIZE + 2)
+ goto invalid;
+
+ switch (mgmt->u.action.u.vht_opmode_notif.action_code) {
+ case WLAN_VHT_ACTION_OPMODE_NOTIF: {
+ struct ieee80211_supported_band *sband;
+ u8 opmode = mgmt->u.action.u.vht_opmode_notif.operating_mode;
+ u8 nss;
+
+ /* ignore - no support for BF yet */
+ if (opmode & IEEE80211_VHT_OPMODE_RX_NSS_TYPE_BF)
+ goto handled;
+
+ nss = opmode & IEEE80211_VHT_OPMODE_RX_NSS_MASK;
+ nss >>= IEEE80211_VHT_OPMODE_RX_NSS_SHIFT;
+
+ /* if no change do nothing */
+ if (rx->sta->sta.rx_nss == nss)
+ goto handled;
+ rx->sta->sta.rx_nss = nss;
+
+ /* TODO: handle bandwidth */
+
+ sband = rx->local->hw.wiphy->bands[status->band];
+
+ rate_control_rate_update(local, sband, rx->sta,
+ IEEE80211_RC_NSS_CHANGED);
+ goto handled;
+ }
+ default:
+ goto invalid;
+ }
+ break;
case WLAN_CATEGORY_BACK:
if (sdata->vif.type != NL80211_IFTYPE_STATION &&
sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
--
1.8.0