Commit 1a717fcf authored by David S. Miller's avatar David S. Miller

Merge tag 'mac80211-for-davem-2017-01-13' of...

Merge tag 'mac80211-for-davem-2017-01-13' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211

Johannes Berg says:

====================
We have a number of fixes, in part because I was late
in actually sending them out - will try to do better in
the future:
 * handle VHT opmode properly when hostapd is controlling
   full station state
 * two fixes for minimum channel width in mac80211
 * don't leave SMPS set to junk in HT capabilities
 * fix headroom when forwarding mesh packets, recently
   broken by another fix that failed to take into account
   frame encryption
 * fix the TID in null-data packets indicating EOSP (end
   of service period) in U-APSD
 * prevent attempting to use (and then failing which
   results in crashes) TXQs on stations that aren't added
   to the driver yet
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 75f01a4c dbef5362
...@@ -1772,7 +1772,9 @@ enum nl80211_commands { ...@@ -1772,7 +1772,9 @@ enum nl80211_commands {
* *
* @NL80211_ATTR_OPMODE_NOTIF: Operating mode field from Operating Mode * @NL80211_ATTR_OPMODE_NOTIF: Operating mode field from Operating Mode
* Notification Element based on association request when used with * Notification Element based on association request when used with
* %NL80211_CMD_NEW_STATION; u8 attribute. * %NL80211_CMD_NEW_STATION or %NL80211_CMD_SET_STATION (only when
* %NL80211_FEATURE_FULL_AP_CLIENT_STATE is supported, or with TDLS);
* u8 attribute.
* *
* @NL80211_ATTR_VENDOR_ID: The vendor ID, either a 24-bit OUI or, if * @NL80211_ATTR_VENDOR_ID: The vendor ID, either a 24-bit OUI or, if
* %NL80211_VENDOR_ID_IS_LINUX is set, a special Linux ID (not used yet) * %NL80211_VENDOR_ID_IS_LINUX is set, a special Linux ID (not used yet)
......
...@@ -231,9 +231,6 @@ ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata) ...@@ -231,9 +231,6 @@ ieee80211_get_max_required_bw(struct ieee80211_sub_if_data *sdata)
!(sta->sdata->bss && sta->sdata->bss == sdata->bss)) !(sta->sdata->bss && sta->sdata->bss == sdata->bss))
continue; continue;
if (!sta->uploaded || !test_sta_flag(sta, WLAN_STA_ASSOC))
continue;
max_bw = max(max_bw, ieee80211_get_sta_bw(&sta->sta)); max_bw = max(max_bw, ieee80211_get_sta_bw(&sta->sta));
} }
rcu_read_unlock(); rcu_read_unlock();
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
* Copyright (c) 2006 Jiri Benc <jbenc@suse.cz> * Copyright (c) 2006 Jiri Benc <jbenc@suse.cz>
* Copyright 2008, Johannes Berg <johannes@sipsolutions.net> * Copyright 2008, Johannes Berg <johannes@sipsolutions.net>
* Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright (c) 2016 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
...@@ -1295,6 +1296,26 @@ static void ieee80211_iface_work(struct work_struct *work) ...@@ -1295,6 +1296,26 @@ static void ieee80211_iface_work(struct work_struct *work)
} else if (ieee80211_is_action(mgmt->frame_control) && } else if (ieee80211_is_action(mgmt->frame_control) &&
mgmt->u.action.category == WLAN_CATEGORY_VHT) { mgmt->u.action.category == WLAN_CATEGORY_VHT) {
switch (mgmt->u.action.u.vht_group_notif.action_code) { switch (mgmt->u.action.u.vht_group_notif.action_code) {
case WLAN_VHT_ACTION_OPMODE_NOTIF: {
struct ieee80211_rx_status *status;
enum nl80211_band band;
u8 opmode;
status = IEEE80211_SKB_RXCB(skb);
band = status->band;
opmode = mgmt->u.action.u.vht_opmode_notif.operating_mode;
mutex_lock(&local->sta_mtx);
sta = sta_info_get_bss(sdata, mgmt->sa);
if (sta)
ieee80211_vht_handle_opmode(sdata, sta,
opmode,
band);
mutex_unlock(&local->sta_mtx);
break;
}
case WLAN_VHT_ACTION_GROUPID_MGMT: case WLAN_VHT_ACTION_GROUPID_MGMT:
ieee80211_process_mu_groups(sdata, mgmt); ieee80211_process_mu_groups(sdata, mgmt);
break; break;
......
...@@ -913,12 +913,17 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) ...@@ -913,12 +913,17 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
supp_ht = supp_ht || sband->ht_cap.ht_supported; supp_ht = supp_ht || sband->ht_cap.ht_supported;
supp_vht = supp_vht || sband->vht_cap.vht_supported; supp_vht = supp_vht || sband->vht_cap.vht_supported;
if (sband->ht_cap.ht_supported) if (!sband->ht_cap.ht_supported)
local->rx_chains = continue;
max(ieee80211_mcs_to_chains(&sband->ht_cap.mcs),
local->rx_chains);
/* TODO: consider VHT for RX chains, hopefully it's the same */ /* TODO: consider VHT for RX chains, hopefully it's the same */
local->rx_chains =
max(ieee80211_mcs_to_chains(&sband->ht_cap.mcs),
local->rx_chains);
/* no need to mask, SM_PS_DISABLED has all bits set */
sband->ht_cap.cap |= WLAN_HT_CAP_SM_PS_DISABLED <<
IEEE80211_HT_CAP_SM_PS_SHIFT;
} }
/* if low-level driver supports AP, we also support VLAN */ /* if low-level driver supports AP, we also support VLAN */
......
...@@ -40,6 +40,8 @@ void rate_control_rate_init(struct sta_info *sta) ...@@ -40,6 +40,8 @@ void rate_control_rate_init(struct sta_info *sta)
ieee80211_sta_set_rx_nss(sta); ieee80211_sta_set_rx_nss(sta);
ieee80211_recalc_min_chandef(sta->sdata);
if (!ref) if (!ref)
return; return;
......
...@@ -2472,7 +2472,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) ...@@ -2472,7 +2472,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
if (!ifmsh->mshcfg.dot11MeshForwarding) if (!ifmsh->mshcfg.dot11MeshForwarding)
goto out; goto out;
fwd_skb = skb_copy_expand(skb, local->tx_headroom, 0, GFP_ATOMIC); fwd_skb = skb_copy_expand(skb, local->tx_headroom +
sdata->encrypt_headroom, 0, GFP_ATOMIC);
if (!fwd_skb) { if (!fwd_skb) {
net_info_ratelimited("%s: failed to clone mesh frame\n", net_info_ratelimited("%s: failed to clone mesh frame\n",
sdata->name); sdata->name);
...@@ -2880,17 +2881,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) ...@@ -2880,17 +2881,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
switch (mgmt->u.action.u.vht_opmode_notif.action_code) { switch (mgmt->u.action.u.vht_opmode_notif.action_code) {
case WLAN_VHT_ACTION_OPMODE_NOTIF: { case WLAN_VHT_ACTION_OPMODE_NOTIF: {
u8 opmode;
/* verify opmode is present */ /* verify opmode is present */
if (len < IEEE80211_MIN_ACTION_SIZE + 2) if (len < IEEE80211_MIN_ACTION_SIZE + 2)
goto invalid; goto invalid;
goto queue;
opmode = mgmt->u.action.u.vht_opmode_notif.operating_mode;
ieee80211_vht_handle_opmode(rx->sdata, rx->sta,
opmode, status->band);
goto handled;
} }
case WLAN_VHT_ACTION_GROUPID_MGMT: { case WLAN_VHT_ACTION_GROUPID_MGMT: {
if (len < IEEE80211_MIN_ACTION_SIZE + 25) if (len < IEEE80211_MIN_ACTION_SIZE + 25)
...@@ -3942,21 +3936,31 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx, ...@@ -3942,21 +3936,31 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx,
u64_stats_update_end(&stats->syncp); u64_stats_update_end(&stats->syncp);
if (fast_rx->internal_forward) { if (fast_rx->internal_forward) {
struct sta_info *dsta = sta_info_get(rx->sdata, skb->data); struct sk_buff *xmit_skb = NULL;
bool multicast = is_multicast_ether_addr(skb->data);
if (multicast) {
xmit_skb = skb_copy(skb, GFP_ATOMIC);
} else if (sta_info_get(rx->sdata, skb->data)) {
xmit_skb = skb;
skb = NULL;
}
if (dsta) { if (xmit_skb) {
/* /*
* Send to wireless media and increase priority by 256 * Send to wireless media and increase priority by 256
* to keep the received priority instead of * to keep the received priority instead of
* reclassifying the frame (see cfg80211_classify8021d). * reclassifying the frame (see cfg80211_classify8021d).
*/ */
skb->priority += 256; xmit_skb->priority += 256;
skb->protocol = htons(ETH_P_802_3); xmit_skb->protocol = htons(ETH_P_802_3);
skb_reset_network_header(skb); skb_reset_network_header(xmit_skb);
skb_reset_mac_header(skb); skb_reset_mac_header(xmit_skb);
dev_queue_xmit(skb); dev_queue_xmit(xmit_skb);
return true;
} }
if (!skb)
return true;
} }
/* deliver to local stack */ /* deliver to local stack */
......
...@@ -1501,8 +1501,8 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta, ...@@ -1501,8 +1501,8 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
/* This will evaluate to 1, 3, 5 or 7. */ /* This will evaluate to 1, 3, 5 or 7. */
for (ac = IEEE80211_AC_VO; ac < IEEE80211_NUM_ACS; ac++) for (ac = IEEE80211_AC_VO; ac < IEEE80211_NUM_ACS; ac++)
if (ignored_acs & BIT(ac)) if (!(ignored_acs & ieee80211_ac_to_qos_mask[ac]))
continue; break;
tid = 7 - 2 * ac; tid = 7 - 2 * ac;
ieee80211_send_null_response(sta, tid, reason, true, false); ieee80211_send_null_response(sta, tid, reason, true, false);
......
...@@ -1243,7 +1243,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, ...@@ -1243,7 +1243,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local, static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_sta *pubsta, struct sta_info *sta,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
...@@ -1257,10 +1257,13 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local, ...@@ -1257,10 +1257,13 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
if (!ieee80211_is_data(hdr->frame_control)) if (!ieee80211_is_data(hdr->frame_control))
return NULL; return NULL;
if (pubsta) { if (sta) {
u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
txq = pubsta->txq[tid]; if (!sta->uploaded)
return NULL;
txq = sta->sta.txq[tid];
} else if (vif) { } else if (vif) {
txq = vif->txq; txq = vif->txq;
} }
...@@ -1503,23 +1506,17 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local, ...@@ -1503,23 +1506,17 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local,
struct fq *fq = &local->fq; struct fq *fq = &local->fq;
struct ieee80211_vif *vif; struct ieee80211_vif *vif;
struct txq_info *txqi; struct txq_info *txqi;
struct ieee80211_sta *pubsta;
if (!local->ops->wake_tx_queue || if (!local->ops->wake_tx_queue ||
sdata->vif.type == NL80211_IFTYPE_MONITOR) sdata->vif.type == NL80211_IFTYPE_MONITOR)
return false; return false;
if (sta && sta->uploaded)
pubsta = &sta->sta;
else
pubsta = NULL;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
sdata = container_of(sdata->bss, sdata = container_of(sdata->bss,
struct ieee80211_sub_if_data, u.ap); struct ieee80211_sub_if_data, u.ap);
vif = &sdata->vif; vif = &sdata->vif;
txqi = ieee80211_get_txq(local, vif, pubsta, skb); txqi = ieee80211_get_txq(local, vif, sta, skb);
if (!txqi) if (!txqi)
return false; return false;
......
...@@ -527,8 +527,10 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, ...@@ -527,8 +527,10 @@ void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
u32 changed = __ieee80211_vht_handle_opmode(sdata, sta, opmode, band); u32 changed = __ieee80211_vht_handle_opmode(sdata, sta, opmode, band);
if (changed > 0) if (changed > 0) {
ieee80211_recalc_min_chandef(sdata);
rate_control_rate_update(local, sband, sta, changed); rate_control_rate_update(local, sband, sta, changed);
}
} }
void ieee80211_get_vht_mask_from_cap(__le16 vht_cap, void ieee80211_get_vht_mask_from_cap(__le16 vht_cap,
......
...@@ -4615,6 +4615,15 @@ int cfg80211_check_station_change(struct wiphy *wiphy, ...@@ -4615,6 +4615,15 @@ int cfg80211_check_station_change(struct wiphy *wiphy,
break; break;
} }
/*
* Older kernel versions ignored this attribute entirely, so don't
* reject attempts to update it but mark it as unused instead so the
* driver won't look at the data.
*/
if (statype != CFG80211_STA_AP_CLIENT_UNASSOC &&
statype != CFG80211_STA_TDLS_PEER_SETUP)
params->opmode_notif_used = false;
return 0; return 0;
} }
EXPORT_SYMBOL(cfg80211_check_station_change); EXPORT_SYMBOL(cfg80211_check_station_change);
...@@ -4854,6 +4863,12 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) ...@@ -4854,6 +4863,12 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info)
params.local_pm = pm; params.local_pm = pm;
} }
if (info->attrs[NL80211_ATTR_OPMODE_NOTIF]) {
params.opmode_notif_used = true;
params.opmode_notif =
nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
}
/* Include parameters for TDLS peer (will check later) */ /* Include parameters for TDLS peer (will check later) */
err = nl80211_set_station_tdls(info, &params); err = nl80211_set_station_tdls(info, &params);
if (err) if (err)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment