mac80211: process and save VHT MU-MIMO group frame

The Group ID Management frame is an Action frame of
category VHT. It is transmitted by the AP to assign
or change the user position of a STA for one or more
group IDs.
Process and save the group membership data. Notify
underlying driver of changes.

Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Sara Sharon 2015-12-08 16:04:31 +02:00 committed by Johannes Berg
parent c799ba6eab
commit 23a1f8d44c
8 changed files with 76 additions and 0 deletions

View File

@ -843,6 +843,8 @@ enum ieee80211_vht_opmode_bits {
}; };
#define WLAN_SA_QUERY_TR_ID_LEN 2 #define WLAN_SA_QUERY_TR_ID_LEN 2
#define WLAN_MEMBERSHIP_LEN 8
#define WLAN_USER_POSITION_LEN 16
/** /**
* struct ieee80211_tpc_report_ie * struct ieee80211_tpc_report_ie
@ -989,6 +991,11 @@ struct ieee80211_mgmt {
u8 action_code; u8 action_code;
u8 operating_mode; u8 operating_mode;
} __packed vht_opmode_notif; } __packed vht_opmode_notif;
struct {
u8 action_code;
u8 membership[WLAN_MEMBERSHIP_LEN];
u8 position[WLAN_USER_POSITION_LEN];
} __packed vht_group_notif;
struct { struct {
u8 action_code; u8 action_code;
u8 dialog_token; u8 dialog_token;

View File

@ -298,6 +298,7 @@ struct ieee80211_vif_chanctx_switch {
* note that this is only called when it changes after the channel * note that this is only called when it changes after the channel
* context had been assigned. * context had been assigned.
* @BSS_CHANGED_OCB: OCB join status changed * @BSS_CHANGED_OCB: OCB join status changed
* @BSS_CHANGED_MU_GROUPS: VHT MU-MIMO group id or user position changed
*/ */
enum ieee80211_bss_change { enum ieee80211_bss_change {
BSS_CHANGED_ASSOC = 1<<0, BSS_CHANGED_ASSOC = 1<<0,
@ -323,6 +324,7 @@ enum ieee80211_bss_change {
BSS_CHANGED_BEACON_INFO = 1<<20, BSS_CHANGED_BEACON_INFO = 1<<20,
BSS_CHANGED_BANDWIDTH = 1<<21, BSS_CHANGED_BANDWIDTH = 1<<21,
BSS_CHANGED_OCB = 1<<22, BSS_CHANGED_OCB = 1<<22,
BSS_CHANGED_MU_GROUPS = 1<<23,
/* when adding here, make sure to change ieee80211_reconfig */ /* when adding here, make sure to change ieee80211_reconfig */
}; };
@ -435,6 +437,19 @@ struct ieee80211_event {
} u; } u;
}; };
/**
* struct ieee80211_mu_group_data - STA's VHT MU-MIMO group data
*
* This structure describes the group id data of VHT MU-MIMO
*
* @membership: 64 bits array - a bit is set if station is member of the group
* @position: 2 bits per group id indicating the position in the group
*/
struct ieee80211_mu_group_data {
u8 membership[WLAN_MEMBERSHIP_LEN];
u8 position[WLAN_USER_POSITION_LEN];
};
/** /**
* struct ieee80211_bss_conf - holds the BSS's changing parameters * struct ieee80211_bss_conf - holds the BSS's changing parameters
* *
@ -477,6 +492,7 @@ struct ieee80211_event {
* @enable_beacon: whether beaconing should be enabled or not * @enable_beacon: whether beaconing should be enabled or not
* @chandef: Channel definition for this BSS -- the hardware might be * @chandef: Channel definition for this BSS -- the hardware might be
* configured a higher bandwidth than this BSS uses, for example. * configured a higher bandwidth than this BSS uses, for example.
* @mu_group: VHT MU-MIMO group membership data
* @ht_operation_mode: HT operation mode like in &struct ieee80211_ht_operation. * @ht_operation_mode: HT operation mode like in &struct ieee80211_ht_operation.
* This field is only valid when the channel is a wide HT/VHT channel. * This field is only valid when the channel is a wide HT/VHT channel.
* Note that with TDLS this can be the case (channel is HT, protection must * Note that with TDLS this can be the case (channel is HT, protection must
@ -535,6 +551,7 @@ struct ieee80211_bss_conf {
s32 cqm_rssi_thold; s32 cqm_rssi_thold;
u32 cqm_rssi_hyst; u32 cqm_rssi_hyst;
struct cfg80211_chan_def chandef; struct cfg80211_chan_def chandef;
struct ieee80211_mu_group_data mu_group;
__be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN]; __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
int arp_addr_cnt; int arp_addr_cnt;
bool qos; bool qos;

View File

@ -1714,6 +1714,8 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta); enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta);
enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta); enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta);
void ieee80211_sta_set_rx_nss(struct sta_info *sta); void ieee80211_sta_set_rx_nss(struct sta_info *sta);
void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt);
u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta, u8 opmode, struct sta_info *sta, u8 opmode,
enum ieee80211_band band); enum ieee80211_band band);

View File

@ -1271,6 +1271,16 @@ static void ieee80211_iface_work(struct work_struct *work)
} }
} }
mutex_unlock(&local->sta_mtx); mutex_unlock(&local->sta_mtx);
} else if (ieee80211_is_action(mgmt->frame_control) &&
mgmt->u.action.category == WLAN_CATEGORY_VHT) {
switch (mgmt->u.action.u.vht_group_notif.action_code) {
case WLAN_VHT_ACTION_GROUPID_MGMT:
ieee80211_process_mu_groups(sdata, mgmt);
break;
default:
WARN_ON(1);
break;
}
} else if (ieee80211_is_data_qos(mgmt->frame_control)) { } else if (ieee80211_is_data_qos(mgmt->frame_control)) {
struct ieee80211_hdr *hdr = (void *)mgmt; struct ieee80211_hdr *hdr = (void *)mgmt;
/* /*

View File

@ -2079,6 +2079,13 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask));
memset(&ifmgd->vht_capa, 0, sizeof(ifmgd->vht_capa)); memset(&ifmgd->vht_capa, 0, sizeof(ifmgd->vht_capa));
memset(&ifmgd->vht_capa_mask, 0, sizeof(ifmgd->vht_capa_mask)); memset(&ifmgd->vht_capa_mask, 0, sizeof(ifmgd->vht_capa_mask));
/* reset MU-MIMO ownership and group data */
memset(sdata->vif.bss_conf.mu_group.membership, 0,
sizeof(sdata->vif.bss_conf.mu_group.membership));
memset(sdata->vif.bss_conf.mu_group.position, 0,
sizeof(sdata->vif.bss_conf.mu_group.position));
changed |= BSS_CHANGED_MU_GROUPS;
sdata->flags &= ~IEEE80211_SDATA_MU_MIMO_OWNER; sdata->flags &= ~IEEE80211_SDATA_MU_MIMO_OWNER;
sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;

View File

@ -2738,6 +2738,11 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
opmode, status->band); opmode, status->band);
goto handled; goto handled;
} }
case WLAN_VHT_ACTION_GROUPID_MGMT: {
if (len < IEEE80211_MIN_ACTION_SIZE + 25)
goto invalid;
goto queue;
}
default: default:
break; break;
} }

View File

@ -1928,6 +1928,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
BSS_CHANGED_IDLE | BSS_CHANGED_IDLE |
BSS_CHANGED_TXPOWER; BSS_CHANGED_TXPOWER;
if (sdata->flags & IEEE80211_SDATA_MU_MIMO_OWNER)
changed |= BSS_CHANGED_MU_GROUPS;
switch (sdata->vif.type) { switch (sdata->vif.type) {
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
changed |= BSS_CHANGED_ASSOC | changed |= BSS_CHANGED_ASSOC |

View File

@ -1,6 +1,9 @@
/* /*
* VHT handling * VHT handling
* *
* Portions of this file
* Copyright(c) 2015 Intel Deutschland GmbH
*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
@ -425,6 +428,28 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
return changed; return changed;
} }
void ieee80211_process_mu_groups(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt)
{
struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
if (!(sdata->flags & IEEE80211_SDATA_MU_MIMO_OWNER))
return;
if (!memcmp(mgmt->u.action.u.vht_group_notif.position,
bss_conf->mu_group.position, WLAN_USER_POSITION_LEN) &&
!memcmp(mgmt->u.action.u.vht_group_notif.membership,
bss_conf->mu_group.membership, WLAN_MEMBERSHIP_LEN))
return;
memcpy(mgmt->u.action.u.vht_group_notif.membership,
bss_conf->mu_group.membership, WLAN_MEMBERSHIP_LEN);
memcpy(mgmt->u.action.u.vht_group_notif.position,
bss_conf->mu_group.position, WLAN_USER_POSITION_LEN);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_MU_GROUPS);
}
void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta, u8 opmode, struct sta_info *sta, u8 opmode,
enum ieee80211_band band) enum ieee80211_band band)