Commit d3fe1e01 authored by David S. Miller's avatar David S. Miller

Merge tag 'mac80211-for-davem-2017-11-27' of...

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

Johannes Berg says:

====================
Four fixes:
 * CRYPTO_SHA256 is needed for regdb validation
 * mac80211: mesh path metric was wrong in some frames
 * mac80211: use QoS null-data packets on QoS connections
 * mac80211: tear down RX aggregation sessions first to
   drop fewer packets in HW restart scenarios
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 6b56b1a2 72e2c343
...@@ -1113,7 +1113,7 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp, ...@@ -1113,7 +1113,7 @@ ath_chanctx_send_vif_ps_frame(struct ath_softc *sc, struct ath_vif *avp,
if (!avp->assoc) if (!avp->assoc)
return false; return false;
skb = ieee80211_nullfunc_get(sc->hw, vif); skb = ieee80211_nullfunc_get(sc->hw, vif, false);
if (!skb) if (!skb)
return false; return false;
......
...@@ -198,7 +198,7 @@ void __cw1200_cqm_bssloss_sm(struct cw1200_common *priv, ...@@ -198,7 +198,7 @@ void __cw1200_cqm_bssloss_sm(struct cw1200_common *priv,
priv->bss_loss_state++; priv->bss_loss_state++;
skb = ieee80211_nullfunc_get(priv->hw, priv->vif); skb = ieee80211_nullfunc_get(priv->hw, priv->vif, false);
WARN_ON(!skb); WARN_ON(!skb);
if (skb) if (skb)
cw1200_tx(priv->hw, NULL, skb); cw1200_tx(priv->hw, NULL, skb);
...@@ -2265,7 +2265,7 @@ static int cw1200_upload_null(struct cw1200_common *priv) ...@@ -2265,7 +2265,7 @@ static int cw1200_upload_null(struct cw1200_common *priv)
.rate = 0xFF, .rate = 0xFF,
}; };
frame.skb = ieee80211_nullfunc_get(priv->hw, priv->vif); frame.skb = ieee80211_nullfunc_get(priv->hw, priv->vif, false);
if (!frame.skb) if (!frame.skb)
return -ENOMEM; return -ENOMEM;
......
...@@ -566,7 +566,7 @@ static int wl1251_build_null_data(struct wl1251 *wl) ...@@ -566,7 +566,7 @@ static int wl1251_build_null_data(struct wl1251 *wl)
size = sizeof(struct wl12xx_null_data_template); size = sizeof(struct wl12xx_null_data_template);
ptr = NULL; ptr = NULL;
} else { } else {
skb = ieee80211_nullfunc_get(wl->hw, wl->vif); skb = ieee80211_nullfunc_get(wl->hw, wl->vif, false);
if (!skb) if (!skb)
goto out; goto out;
size = skb->len; size = skb->len;
......
...@@ -1069,7 +1069,8 @@ int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif) ...@@ -1069,7 +1069,8 @@ int wl12xx_cmd_build_null_data(struct wl1271 *wl, struct wl12xx_vif *wlvif)
ptr = NULL; ptr = NULL;
} else { } else {
skb = ieee80211_nullfunc_get(wl->hw, skb = ieee80211_nullfunc_get(wl->hw,
wl12xx_wlvif_to_vif(wlvif)); wl12xx_wlvif_to_vif(wlvif),
false);
if (!skb) if (!skb)
goto out; goto out;
size = skb->len; size = skb->len;
...@@ -1096,7 +1097,7 @@ int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl, ...@@ -1096,7 +1097,7 @@ int wl12xx_cmd_build_klv_null_data(struct wl1271 *wl,
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
int ret = -ENOMEM; int ret = -ENOMEM;
skb = ieee80211_nullfunc_get(wl->hw, vif); skb = ieee80211_nullfunc_get(wl->hw, vif, false);
if (!skb) if (!skb)
goto out; goto out;
......
...@@ -4470,18 +4470,24 @@ struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw, ...@@ -4470,18 +4470,24 @@ struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
* ieee80211_nullfunc_get - retrieve a nullfunc template * ieee80211_nullfunc_get - retrieve a nullfunc template
* @hw: pointer obtained from ieee80211_alloc_hw(). * @hw: pointer obtained from ieee80211_alloc_hw().
* @vif: &struct ieee80211_vif pointer from the add_interface callback. * @vif: &struct ieee80211_vif pointer from the add_interface callback.
* @qos_ok: QoS NDP is acceptable to the caller, this should be set
* if at all possible
* *
* Creates a Nullfunc template which can, for example, uploaded to * Creates a Nullfunc template which can, for example, uploaded to
* hardware. The template must be updated after association so that correct * hardware. The template must be updated after association so that correct
* BSSID and address is used. * BSSID and address is used.
* *
* If @qos_ndp is set and the association is to an AP with QoS/WMM, the
* returned packet will be QoS NDP.
*
* Note: Caller (or hardware) is responsible for setting the * Note: Caller (or hardware) is responsible for setting the
* &IEEE80211_FCTL_PM bit as well as Duration and Sequence Control fields. * &IEEE80211_FCTL_PM bit as well as Duration and Sequence Control fields.
* *
* Return: The nullfunc template. %NULL on error. * Return: The nullfunc template. %NULL on error.
*/ */
struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw,
struct ieee80211_vif *vif); struct ieee80211_vif *vif,
bool qos_ok);
/** /**
* ieee80211_probereq_get - retrieve a Probe Request template * ieee80211_probereq_get - retrieve a Probe Request template
......
...@@ -292,7 +292,6 @@ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, ...@@ -292,7 +292,6 @@ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
mutex_lock(&sta->ampdu_mlme.mtx); mutex_lock(&sta->ampdu_mlme.mtx);
for (i = 0; i < IEEE80211_NUM_TIDS; i++) { for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
___ieee80211_stop_tx_ba_session(sta, i, reason);
___ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT, ___ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT,
WLAN_REASON_QSTA_LEAVE_QBSS, WLAN_REASON_QSTA_LEAVE_QBSS,
reason != AGG_STOP_DESTROY_STA && reason != AGG_STOP_DESTROY_STA &&
...@@ -300,6 +299,9 @@ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, ...@@ -300,6 +299,9 @@ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
} }
mutex_unlock(&sta->ampdu_mlme.mtx); mutex_unlock(&sta->ampdu_mlme.mtx);
for (i = 0; i < IEEE80211_NUM_TIDS; i++)
___ieee80211_stop_tx_ba_session(sta, i, reason);
/* stopping might queue the work again - so cancel only afterwards */ /* stopping might queue the work again - so cancel only afterwards */
cancel_work_sync(&sta->ampdu_mlme.work); cancel_work_sync(&sta->ampdu_mlme.work);
......
...@@ -797,7 +797,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, ...@@ -797,7 +797,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
struct mesh_path *mpath; struct mesh_path *mpath;
u8 ttl, flags, hopcount; u8 ttl, flags, hopcount;
const u8 *orig_addr; const u8 *orig_addr;
u32 orig_sn, metric, metric_txsta, interval; u32 orig_sn, new_metric, orig_metric, last_hop_metric, interval;
bool root_is_gate; bool root_is_gate;
ttl = rann->rann_ttl; ttl = rann->rann_ttl;
...@@ -808,7 +808,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, ...@@ -808,7 +808,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
interval = le32_to_cpu(rann->rann_interval); interval = le32_to_cpu(rann->rann_interval);
hopcount = rann->rann_hopcount; hopcount = rann->rann_hopcount;
hopcount++; hopcount++;
metric = le32_to_cpu(rann->rann_metric); orig_metric = le32_to_cpu(rann->rann_metric);
/* Ignore our own RANNs */ /* Ignore our own RANNs */
if (ether_addr_equal(orig_addr, sdata->vif.addr)) if (ether_addr_equal(orig_addr, sdata->vif.addr))
...@@ -825,7 +825,10 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, ...@@ -825,7 +825,10 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
return; return;
} }
metric_txsta = airtime_link_metric_get(local, sta); last_hop_metric = airtime_link_metric_get(local, sta);
new_metric = orig_metric + last_hop_metric;
if (new_metric < orig_metric)
new_metric = MAX_METRIC;
mpath = mesh_path_lookup(sdata, orig_addr); mpath = mesh_path_lookup(sdata, orig_addr);
if (!mpath) { if (!mpath) {
...@@ -838,7 +841,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, ...@@ -838,7 +841,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
} }
if (!(SN_LT(mpath->sn, orig_sn)) && if (!(SN_LT(mpath->sn, orig_sn)) &&
!(mpath->sn == orig_sn && metric < mpath->rann_metric)) { !(mpath->sn == orig_sn && new_metric < mpath->rann_metric)) {
rcu_read_unlock(); rcu_read_unlock();
return; return;
} }
...@@ -856,7 +859,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, ...@@ -856,7 +859,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
} }
mpath->sn = orig_sn; mpath->sn = orig_sn;
mpath->rann_metric = metric + metric_txsta; mpath->rann_metric = new_metric;
mpath->is_root = true; mpath->is_root = true;
/* Recording RANNs sender address to send individually /* Recording RANNs sender address to send individually
* addressed PREQs destined for root mesh STA */ * addressed PREQs destined for root mesh STA */
...@@ -876,7 +879,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, ...@@ -876,7 +879,7 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr, mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr,
orig_sn, 0, NULL, 0, broadcast_addr, orig_sn, 0, NULL, 0, broadcast_addr,
hopcount, ttl, interval, hopcount, ttl, interval,
metric + metric_txsta, 0, sdata); new_metric, 0, sdata);
} }
rcu_read_unlock(); rcu_read_unlock();
......
...@@ -895,7 +895,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local, ...@@ -895,7 +895,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
struct ieee80211_hdr_3addr *nullfunc; struct ieee80211_hdr_3addr *nullfunc;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif); skb = ieee80211_nullfunc_get(&local->hw, &sdata->vif, true);
if (!skb) if (!skb)
return; return;
......
...@@ -4438,13 +4438,15 @@ struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw, ...@@ -4438,13 +4438,15 @@ struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
EXPORT_SYMBOL(ieee80211_pspoll_get); EXPORT_SYMBOL(ieee80211_pspoll_get);
struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw,
struct ieee80211_vif *vif) struct ieee80211_vif *vif,
bool qos_ok)
{ {
struct ieee80211_hdr_3addr *nullfunc; struct ieee80211_hdr_3addr *nullfunc;
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
struct ieee80211_if_managed *ifmgd; struct ieee80211_if_managed *ifmgd;
struct ieee80211_local *local; struct ieee80211_local *local;
struct sk_buff *skb; struct sk_buff *skb;
bool qos = false;
if (WARN_ON(vif->type != NL80211_IFTYPE_STATION)) if (WARN_ON(vif->type != NL80211_IFTYPE_STATION))
return NULL; return NULL;
...@@ -4453,7 +4455,17 @@ struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, ...@@ -4453,7 +4455,17 @@ struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw,
ifmgd = &sdata->u.mgd; ifmgd = &sdata->u.mgd;
local = sdata->local; local = sdata->local;
skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*nullfunc)); if (qos_ok) {
struct sta_info *sta;
rcu_read_lock();
sta = sta_info_get(sdata, ifmgd->bssid);
qos = sta && sta->sta.wme;
rcu_read_unlock();
}
skb = dev_alloc_skb(local->hw.extra_tx_headroom +
sizeof(*nullfunc) + 2);
if (!skb) if (!skb)
return NULL; return NULL;
...@@ -4463,6 +4475,19 @@ struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw, ...@@ -4463,6 +4475,19 @@ struct sk_buff *ieee80211_nullfunc_get(struct ieee80211_hw *hw,
nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
IEEE80211_STYPE_NULLFUNC | IEEE80211_STYPE_NULLFUNC |
IEEE80211_FCTL_TODS); IEEE80211_FCTL_TODS);
if (qos) {
__le16 qos = cpu_to_le16(7);
BUILD_BUG_ON((IEEE80211_STYPE_QOS_NULLFUNC |
IEEE80211_STYPE_NULLFUNC) !=
IEEE80211_STYPE_QOS_NULLFUNC);
nullfunc->frame_control |=
cpu_to_le16(IEEE80211_STYPE_QOS_NULLFUNC);
skb->priority = 7;
skb_set_queue_mapping(skb, IEEE80211_AC_VO);
skb_put_data(skb, &qos, sizeof(qos));
}
memcpy(nullfunc->addr1, ifmgd->bssid, ETH_ALEN); memcpy(nullfunc->addr1, ifmgd->bssid, ETH_ALEN);
memcpy(nullfunc->addr2, vif->addr, ETH_ALEN); memcpy(nullfunc->addr2, vif->addr, ETH_ALEN);
memcpy(nullfunc->addr3, ifmgd->bssid, ETH_ALEN); memcpy(nullfunc->addr3, ifmgd->bssid, ETH_ALEN);
......
...@@ -20,6 +20,10 @@ config CFG80211 ...@@ -20,6 +20,10 @@ config CFG80211
tristate "cfg80211 - wireless configuration API" tristate "cfg80211 - wireless configuration API"
depends on RFKILL || !RFKILL depends on RFKILL || !RFKILL
select FW_LOADER select FW_LOADER
# may need to update this when certificates are changed and are
# using a different algorithm, though right now they shouldn't
# (this is here rather than below to allow it to be a module)
select CRYPTO_SHA256 if CFG80211_USE_KERNEL_REGDB_KEYS
---help--- ---help---
cfg80211 is the Linux wireless LAN (802.11) configuration API. cfg80211 is the Linux wireless LAN (802.11) configuration API.
Enable this if you have a wireless device. Enable this if you have a wireless device.
...@@ -113,6 +117,9 @@ config CFG80211_EXTRA_REGDB_KEYDIR ...@@ -113,6 +117,9 @@ config CFG80211_EXTRA_REGDB_KEYDIR
certificates like in the kernel sources (net/wireless/certs/) certificates like in the kernel sources (net/wireless/certs/)
that shall be accepted for a signed regulatory database. that shall be accepted for a signed regulatory database.
Note that you need to also select the correct CRYPTO_<hash> modules
for your certificates, and if cfg80211 is built-in they also must be.
config CFG80211_REG_CELLULAR_HINTS config CFG80211_REG_CELLULAR_HINTS
bool "cfg80211 regulatory support for cellular base station hints" bool "cfg80211 regulatory support for cellular base station hints"
depends on CFG80211_CERTIFICATION_ONUS depends on CFG80211_CERTIFICATION_ONUS
......
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