Here's another round of updates for -next:
* big A-MSDU RX performance improvement (avoid linearize of paged RX) * rfkill changes: cleanups, documentation, platform properties * basic PBSS support in cfg80211 * MU-MIMO action frame processing support * BlockAck reordering & duplicate detection offload support * various cleanups & little fixes -----BEGIN PGP SIGNATURE----- iQIcBAABCgAGBQJW0LZ0AAoJEGt7eEactAAdde0P/2meIOehuHBuAtL7REVoNhri bz9eSHMTg+ozCspL7F6vW1ifDI9AaJEaqJccmriueE/UQVC3VXRPGRJ4SFCwZGo9 Zrtys2v9wOq0+XhxyN65Ucf41O9F/5FFabR5OFbf/pZhW5b2cubEjD1P4BB76Iya 8O6wf9oDDjt3zJgYK+sygm3k9wtDVrH3qEbj8IDnCy22P7010qCsfok9swfaq8OB DBgb6BVfDOFTNXvJGH5fRuUKZdtovzzxorXnoG+zjmKmFdMVdgIYj9+2QfnMjW03 B4/W85svcLLH8V3lHZc4G8oKM4J4XtjH1PskKIMF7ThJsKGMf8tL2vpt9rr8iscd Y9SwTEGc9JmhL7n2FaQFlY6ScLcp4ML+2rXxDOMpBmgF3Ne3yfBsJhLKZEl8vSfI mKhzGXpUKjJxJWIxkR0ylJy4/zHeIXkgRlUEhb8t+jgAqvOBTwiVY+vljHCDUERa sH40r1OqnGJtOHkSRqXSpxwXW+eKgyDd7fnnRX/tyttp2Fuew27/fN63SjpsfN6O 3lfSM5bl3FcCKx7vqTLuqzsoqGvDDYkSq6GDfKDqeZIk0vaXA3SJNEOKgymFWQfR rzsaXvTbBT34GYRg3xS2NCxlmcBPemei/q0x6ZOffxhF41Qpqjs1dPB1Yq3AW4jD HGF+NdRbWEqEFVIjQa8w =JHOe -----END PGP SIGNATURE----- Merge tag 'mac80211-next-for-davem-2016-02-26' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211-next Johannes Berg says: ==================== Here's another round of updates for -next: * big A-MSDU RX performance improvement (avoid linearize of paged RX) * rfkill changes: cleanups, documentation, platform properties * basic PBSS support in cfg80211 * MU-MIMO action frame processing support * BlockAck reordering & duplicate detection offload support * various cleanups & little fixes ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
d67703fced
|
@ -1,29 +0,0 @@
|
||||||
rfkill - radio frequency (RF) connector kill switch support
|
|
||||||
|
|
||||||
For details to this subsystem look at Documentation/rfkill.txt.
|
|
||||||
|
|
||||||
What: /sys/class/rfkill/rfkill[0-9]+/state
|
|
||||||
Date: 09-Jul-2007
|
|
||||||
KernelVersion v2.6.22
|
|
||||||
Contact: linux-wireless@vger.kernel.org
|
|
||||||
Description: Current state of the transmitter.
|
|
||||||
This file is deprecated and scheduled to be removed in 2014,
|
|
||||||
because its not possible to express the 'soft and hard block'
|
|
||||||
state of the rfkill driver.
|
|
||||||
Values: A numeric value.
|
|
||||||
0: RFKILL_STATE_SOFT_BLOCKED
|
|
||||||
transmitter is turned off by software
|
|
||||||
1: RFKILL_STATE_UNBLOCKED
|
|
||||||
transmitter is (potentially) active
|
|
||||||
2: RFKILL_STATE_HARD_BLOCKED
|
|
||||||
transmitter is forced off by something outside of
|
|
||||||
the driver's control.
|
|
||||||
|
|
||||||
What: /sys/class/rfkill/rfkill[0-9]+/claim
|
|
||||||
Date: 09-Jul-2007
|
|
||||||
KernelVersion v2.6.22
|
|
||||||
Contact: linux-wireless@vger.kernel.org
|
|
||||||
Description: This file is deprecated because there no longer is a way to
|
|
||||||
claim just control over a single rfkill instance.
|
|
||||||
This file is scheduled to be removed in 2012.
|
|
||||||
Values: 0: Kernel handles events
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
rfkill - radio frequency (RF) connector kill switch support
|
||||||
|
|
||||||
|
For details to this subsystem look at Documentation/rfkill.txt.
|
||||||
|
|
||||||
|
What: /sys/class/rfkill/rfkill[0-9]+/claim
|
||||||
|
Date: 09-Jul-2007
|
||||||
|
KernelVersion v2.6.22
|
||||||
|
Contact: linux-wireless@vger.kernel.org
|
||||||
|
Description: This file was deprecated because there no longer was a way to
|
||||||
|
claim just control over a single rfkill instance.
|
||||||
|
This file was scheduled to be removed in 2012, and was removed
|
||||||
|
in 2016.
|
||||||
|
Values: 0: Kernel handles events
|
|
@ -2,9 +2,8 @@ rfkill - radio frequency (RF) connector kill switch support
|
||||||
|
|
||||||
For details to this subsystem look at Documentation/rfkill.txt.
|
For details to this subsystem look at Documentation/rfkill.txt.
|
||||||
|
|
||||||
For the deprecated /sys/class/rfkill/*/state and
|
For the deprecated /sys/class/rfkill/*/claim knobs of this interface look in
|
||||||
/sys/class/rfkill/*/claim knobs of this interface look in
|
Documentation/ABI/removed/sysfs-class-rfkill.
|
||||||
Documentation/ABI/obsolete/sysfs-class-rfkill.
|
|
||||||
|
|
||||||
What: /sys/class/rfkill
|
What: /sys/class/rfkill
|
||||||
Date: 09-Jul-2007
|
Date: 09-Jul-2007
|
||||||
|
@ -42,6 +41,28 @@ Values: A numeric value.
|
||||||
1: true
|
1: true
|
||||||
|
|
||||||
|
|
||||||
|
What: /sys/class/rfkill/rfkill[0-9]+/state
|
||||||
|
Date: 09-Jul-2007
|
||||||
|
KernelVersion v2.6.22
|
||||||
|
Contact: linux-wireless@vger.kernel.org
|
||||||
|
Description: Current state of the transmitter.
|
||||||
|
This file was scheduled to be removed in 2014, but due to its
|
||||||
|
large number of users it will be sticking around for a bit
|
||||||
|
longer. Despite it being marked as stabe, the newer "hard" and
|
||||||
|
"soft" interfaces should be preffered, since it is not possible
|
||||||
|
to express the 'soft and hard block' state of the rfkill driver
|
||||||
|
through this interface. There will likely be another attempt to
|
||||||
|
remove it in the future.
|
||||||
|
Values: A numeric value.
|
||||||
|
0: RFKILL_STATE_SOFT_BLOCKED
|
||||||
|
transmitter is turned off by software
|
||||||
|
1: RFKILL_STATE_UNBLOCKED
|
||||||
|
transmitter is (potentially) active
|
||||||
|
2: RFKILL_STATE_HARD_BLOCKED
|
||||||
|
transmitter is forced off by something outside of
|
||||||
|
the driver's control.
|
||||||
|
|
||||||
|
|
||||||
What: /sys/class/rfkill/rfkill[0-9]+/hard
|
What: /sys/class/rfkill/rfkill[0-9]+/hard
|
||||||
Date: 12-March-2010
|
Date: 12-March-2010
|
||||||
KernelVersion v2.6.34
|
KernelVersion v2.6.34
|
||||||
|
|
|
@ -28,6 +28,23 @@ radiotap headers and used to control injection:
|
||||||
IEEE80211_RADIOTAP_F_TX_NOACK: frame should be sent without waiting for
|
IEEE80211_RADIOTAP_F_TX_NOACK: frame should be sent without waiting for
|
||||||
an ACK even if it is a unicast frame
|
an ACK even if it is a unicast frame
|
||||||
|
|
||||||
|
* IEEE80211_RADIOTAP_RATE
|
||||||
|
|
||||||
|
legacy rate for the transmission (only for devices without own rate control)
|
||||||
|
|
||||||
|
* IEEE80211_RADIOTAP_MCS
|
||||||
|
|
||||||
|
HT rate for the transmission (only for devices without own rate control).
|
||||||
|
Also some flags are parsed
|
||||||
|
|
||||||
|
IEEE80211_TX_RC_SHORT_GI: use short guard interval
|
||||||
|
IEEE80211_TX_RC_40_MHZ_WIDTH: send in HT40 mode
|
||||||
|
|
||||||
|
* IEEE80211_RADIOTAP_DATA_RETRIES
|
||||||
|
|
||||||
|
number of retries when either IEEE80211_RADIOTAP_RATE or
|
||||||
|
IEEE80211_RADIOTAP_MCS was used
|
||||||
|
|
||||||
The injection code can also skip all other currently defined radiotap fields
|
The injection code can also skip all other currently defined radiotap fields
|
||||||
facilitating replay of captured radiotap headers directly.
|
facilitating replay of captured radiotap headers directly.
|
||||||
|
|
||||||
|
|
|
@ -83,6 +83,8 @@ rfkill drivers that control devices that can be hard-blocked unless they also
|
||||||
assign the poll_hw_block() callback (then the rfkill core will poll the
|
assign the poll_hw_block() callback (then the rfkill core will poll the
|
||||||
device). Don't do this unless you cannot get the event in any other way.
|
device). Don't do this unless you cannot get the event in any other way.
|
||||||
|
|
||||||
|
RFKill provides per-switch LED triggers, which can be used to drive LEDs
|
||||||
|
according to the switch state (LED_FULL when blocked, LED_OFF otherwise).
|
||||||
|
|
||||||
|
|
||||||
5. Userspace support
|
5. Userspace support
|
||||||
|
|
|
@ -17,23 +17,25 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/property.h>
|
||||||
#include <linux/gpio/machine.h>
|
#include <linux/gpio/machine.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/rfkill-gpio.h>
|
|
||||||
|
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
|
|
||||||
static struct rfkill_gpio_platform_data wifi_rfkill_platform_data = {
|
static struct property_entry __initdata wifi_rfkill_prop[] = {
|
||||||
.name = "wifi_rfkill",
|
PROPERTY_ENTRY_STRING("name", "wifi_rfkill"),
|
||||||
.type = RFKILL_TYPE_WLAN,
|
PROPERTY_ENTRY_STRING("type", "wlan"),
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct property_set __initdata wifi_rfkill_pset = {
|
||||||
|
.properties = wifi_rfkill_prop,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct platform_device wifi_rfkill_device = {
|
static struct platform_device wifi_rfkill_device = {
|
||||||
.name = "rfkill_gpio",
|
.name = "rfkill_gpio",
|
||||||
.id = -1,
|
.id = -1,
|
||||||
.dev = {
|
|
||||||
.platform_data = &wifi_rfkill_platform_data,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct gpiod_lookup_table wifi_gpio_lookup = {
|
static struct gpiod_lookup_table wifi_gpio_lookup = {
|
||||||
|
@ -47,6 +49,7 @@ static struct gpiod_lookup_table wifi_gpio_lookup = {
|
||||||
|
|
||||||
void __init tegra_paz00_wifikill_init(void)
|
void __init tegra_paz00_wifikill_init(void)
|
||||||
{
|
{
|
||||||
|
platform_device_add_properties(&wifi_rfkill_device, &wifi_rfkill_pset);
|
||||||
gpiod_add_lookup_table(&wifi_gpio_lookup);
|
gpiod_add_lookup_table(&wifi_gpio_lookup);
|
||||||
platform_device_register(&wifi_rfkill_device);
|
platform_device_register(&wifi_rfkill_device);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6366,12 +6366,13 @@ static u64 ath10k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
||||||
|
|
||||||
static int ath10k_ampdu_action(struct ieee80211_hw *hw,
|
static int ath10k_ampdu_action(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif,
|
struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params)
|
||||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
|
||||||
u8 buf_size, bool amsdu)
|
|
||||||
{
|
{
|
||||||
struct ath10k *ar = hw->priv;
|
struct ath10k *ar = hw->priv;
|
||||||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||||
|
struct ieee80211_sta *sta = params->sta;
|
||||||
|
enum ieee80211_ampdu_mlme_action action = params->action;
|
||||||
|
u16 tid = params->tid;
|
||||||
|
|
||||||
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ampdu vdev_id %i sta %pM tid %hu action %d\n",
|
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac ampdu vdev_id %i sta %pM tid %hu action %d\n",
|
||||||
arvif->vdev_id, sta->addr, tid, action);
|
arvif->vdev_id, sta->addr, tid, action);
|
||||||
|
|
|
@ -1657,13 +1657,14 @@ static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw,
|
||||||
|
|
||||||
static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
|
static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif,
|
struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params)
|
||||||
struct ieee80211_sta *sta,
|
|
||||||
u16 tid, u16 *ssn, u8 buf_size, bool amsdu)
|
|
||||||
{
|
{
|
||||||
struct ath9k_htc_priv *priv = hw->priv;
|
struct ath9k_htc_priv *priv = hw->priv;
|
||||||
struct ath9k_htc_sta *ista;
|
struct ath9k_htc_sta *ista;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
struct ieee80211_sta *sta = params->sta;
|
||||||
|
enum ieee80211_ampdu_mlme_action action = params->action;
|
||||||
|
u16 tid = params->tid;
|
||||||
|
|
||||||
mutex_lock(&priv->mutex);
|
mutex_lock(&priv->mutex);
|
||||||
ath9k_htc_ps_wakeup(priv);
|
ath9k_htc_ps_wakeup(priv);
|
||||||
|
|
|
@ -1864,14 +1864,16 @@ static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
||||||
|
|
||||||
static int ath9k_ampdu_action(struct ieee80211_hw *hw,
|
static int ath9k_ampdu_action(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif,
|
struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params)
|
||||||
struct ieee80211_sta *sta,
|
|
||||||
u16 tid, u16 *ssn, u8 buf_size, bool amsdu)
|
|
||||||
{
|
{
|
||||||
struct ath_softc *sc = hw->priv;
|
struct ath_softc *sc = hw->priv;
|
||||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||||
bool flush = false;
|
bool flush = false;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
struct ieee80211_sta *sta = params->sta;
|
||||||
|
enum ieee80211_ampdu_mlme_action action = params->action;
|
||||||
|
u16 tid = params->tid;
|
||||||
|
u16 *ssn = ¶ms->ssn;
|
||||||
|
|
||||||
mutex_lock(&sc->mutex);
|
mutex_lock(&sc->mutex);
|
||||||
|
|
||||||
|
|
|
@ -1413,10 +1413,12 @@ static void carl9170_ampdu_work(struct work_struct *work)
|
||||||
|
|
||||||
static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
|
static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif,
|
struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params)
|
||||||
struct ieee80211_sta *sta,
|
|
||||||
u16 tid, u16 *ssn, u8 buf_size, bool amsdu)
|
|
||||||
{
|
{
|
||||||
|
struct ieee80211_sta *sta = params->sta;
|
||||||
|
enum ieee80211_ampdu_mlme_action action = params->action;
|
||||||
|
u16 tid = params->tid;
|
||||||
|
u16 *ssn = ¶ms->ssn;
|
||||||
struct ar9170 *ar = hw->priv;
|
struct ar9170 *ar = hw->priv;
|
||||||
struct carl9170_sta_info *sta_info = (void *) sta->drv_priv;
|
struct carl9170_sta_info *sta_info = (void *) sta->drv_priv;
|
||||||
struct carl9170_sta_tid *tid_info;
|
struct carl9170_sta_tid *tid_info;
|
||||||
|
|
|
@ -857,12 +857,14 @@ static int wcn36xx_resume(struct ieee80211_hw *hw)
|
||||||
|
|
||||||
static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
|
static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif,
|
struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params)
|
||||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
|
||||||
u8 buf_size, bool amsdu)
|
|
||||||
{
|
{
|
||||||
struct wcn36xx *wcn = hw->priv;
|
struct wcn36xx *wcn = hw->priv;
|
||||||
struct wcn36xx_sta *sta_priv = NULL;
|
struct wcn36xx_sta *sta_priv = NULL;
|
||||||
|
struct ieee80211_sta *sta = params->sta;
|
||||||
|
enum ieee80211_ampdu_mlme_action action = params->action;
|
||||||
|
u16 tid = params->tid;
|
||||||
|
u16 *ssn = ¶ms->ssn;
|
||||||
|
|
||||||
wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n",
|
wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n",
|
||||||
action, tid);
|
action, tid);
|
||||||
|
|
|
@ -422,6 +422,11 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
|
||||||
if (sme->privacy && !rsn_eid)
|
if (sme->privacy && !rsn_eid)
|
||||||
wil_info(wil, "WSC connection\n");
|
wil_info(wil, "WSC connection\n");
|
||||||
|
|
||||||
|
if (sme->pbss) {
|
||||||
|
wil_err(wil, "connect - PBSS not yet supported\n");
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
|
bss = cfg80211_get_bss(wiphy, sme->channel, sme->bssid,
|
||||||
sme->ssid, sme->ssid_len,
|
sme->ssid, sme->ssid_len,
|
||||||
IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY);
|
IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY);
|
||||||
|
@ -870,6 +875,11 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (info->pbss) {
|
||||||
|
wil_err(wil, "AP: PBSS not yet supported\n");
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
switch (info->hidden_ssid) {
|
switch (info->hidden_ssid) {
|
||||||
case NL80211_HIDDEN_SSID_NOT_IN_USE:
|
case NL80211_HIDDEN_SSID_NOT_IN_USE:
|
||||||
hidden_ssid = WMI_HIDDEN_SSID_DISABLED;
|
hidden_ssid = WMI_HIDDEN_SSID_DISABLED;
|
||||||
|
|
|
@ -818,13 +818,15 @@ brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||||
static int
|
static int
|
||||||
brcms_ops_ampdu_action(struct ieee80211_hw *hw,
|
brcms_ops_ampdu_action(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif,
|
struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params)
|
||||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
|
||||||
u8 buf_size, bool amsdu)
|
|
||||||
{
|
{
|
||||||
struct brcms_info *wl = hw->priv;
|
struct brcms_info *wl = hw->priv;
|
||||||
struct scb *scb = &wl->wlc->pri_scb;
|
struct scb *scb = &wl->wlc->pri_scb;
|
||||||
int status;
|
int status;
|
||||||
|
struct ieee80211_sta *sta = params->sta;
|
||||||
|
enum ieee80211_ampdu_mlme_action action = params->action;
|
||||||
|
u16 tid = params->tid;
|
||||||
|
u8 buf_size = params->buf_size;
|
||||||
|
|
||||||
if (WARN_ON(scb->magic != SCB_MAGIC))
|
if (WARN_ON(scb->magic != SCB_MAGIC))
|
||||||
return -EIDRM;
|
return -EIDRM;
|
||||||
|
|
|
@ -5982,12 +5982,14 @@ il4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||||
|
|
||||||
int
|
int
|
||||||
il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params)
|
||||||
struct ieee80211_sta *sta, u16 tid, u16 * ssn,
|
|
||||||
u8 buf_size, bool amsdu)
|
|
||||||
{
|
{
|
||||||
struct il_priv *il = hw->priv;
|
struct il_priv *il = hw->priv;
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
struct ieee80211_sta *sta = params->sta;
|
||||||
|
enum ieee80211_ampdu_mlme_action action = params->action;
|
||||||
|
u16 tid = params->tid;
|
||||||
|
u16 *ssn = ¶ms->ssn;
|
||||||
|
|
||||||
D_HT("A-MPDU action on addr %pM tid %d\n", sta->addr, tid);
|
D_HT("A-MPDU action on addr %pM tid %d\n", sta->addr, tid);
|
||||||
|
|
||||||
|
|
|
@ -182,9 +182,7 @@ void il4965_mac_update_tkip_key(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_sta *sta, u32 iv32,
|
struct ieee80211_sta *sta, u32 iv32,
|
||||||
u16 *phase1key);
|
u16 *phase1key);
|
||||||
int il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
int il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params);
|
||||||
struct ieee80211_sta *sta, u16 tid, u16 * ssn,
|
|
||||||
u8 buf_size, bool amsdu);
|
|
||||||
int il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
int il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||||
struct ieee80211_sta *sta);
|
struct ieee80211_sta *sta);
|
||||||
void
|
void
|
||||||
|
|
|
@ -943,14 +943,16 @@ static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
|
||||||
switch (key->cipher) {
|
switch (key->cipher) {
|
||||||
case WLAN_CIPHER_SUITE_TKIP:
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
if (sta) {
|
if (sta) {
|
||||||
|
u64 pn64;
|
||||||
|
|
||||||
tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
|
tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
|
||||||
tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
|
tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
|
||||||
|
|
||||||
rx_p1ks = data->tkip->rx_uni;
|
rx_p1ks = data->tkip->rx_uni;
|
||||||
|
|
||||||
ieee80211_get_key_tx_seq(key, &seq);
|
pn64 = atomic64_read(&key->tx_pn);
|
||||||
tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16);
|
tkip_tx_sc->iv16 = cpu_to_le16(TKIP_PN_TO_IV16(pn64));
|
||||||
tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32);
|
tkip_tx_sc->iv32 = cpu_to_le32(TKIP_PN_TO_IV32(pn64));
|
||||||
|
|
||||||
ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k);
|
ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k);
|
||||||
iwlagn_convert_p1k(p1k, data->tkip->tx.p1k);
|
iwlagn_convert_p1k(p1k, data->tkip->tx.p1k);
|
||||||
|
@ -996,19 +998,13 @@ static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
|
||||||
break;
|
break;
|
||||||
case WLAN_CIPHER_SUITE_CCMP:
|
case WLAN_CIPHER_SUITE_CCMP:
|
||||||
if (sta) {
|
if (sta) {
|
||||||
u8 *pn = seq.ccmp.pn;
|
u64 pn64;
|
||||||
|
|
||||||
aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc;
|
aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc;
|
||||||
aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc;
|
aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc;
|
||||||
|
|
||||||
ieee80211_get_key_tx_seq(key, &seq);
|
pn64 = atomic64_read(&key->tx_pn);
|
||||||
aes_tx_sc->pn = cpu_to_le64(
|
aes_tx_sc->pn = cpu_to_le64(pn64);
|
||||||
(u64)pn[5] |
|
|
||||||
((u64)pn[4] << 8) |
|
|
||||||
((u64)pn[3] << 16) |
|
|
||||||
((u64)pn[2] << 24) |
|
|
||||||
((u64)pn[1] << 32) |
|
|
||||||
((u64)pn[0] << 40));
|
|
||||||
} else
|
} else
|
||||||
aes_sc = data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc;
|
aes_sc = data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc;
|
||||||
|
|
||||||
|
|
|
@ -732,12 +732,15 @@ static inline bool iwl_enable_tx_ampdu(const struct iwl_cfg *cfg)
|
||||||
|
|
||||||
static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
|
static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif,
|
struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params)
|
||||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
|
||||||
u8 buf_size, bool amsdu)
|
|
||||||
{
|
{
|
||||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
struct ieee80211_sta *sta = params->sta;
|
||||||
|
enum ieee80211_ampdu_mlme_action action = params->action;
|
||||||
|
u16 tid = params->tid;
|
||||||
|
u16 *ssn = ¶ms->ssn;
|
||||||
|
u8 buf_size = params->buf_size;
|
||||||
struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
|
struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
|
||||||
|
|
||||||
IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",
|
IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",
|
||||||
|
|
|
@ -251,16 +251,19 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
|
||||||
return;
|
return;
|
||||||
case WLAN_CIPHER_SUITE_TKIP:
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
if (sta) {
|
if (sta) {
|
||||||
|
u64 pn64;
|
||||||
|
|
||||||
tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
|
tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
|
||||||
tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
|
tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
|
||||||
|
|
||||||
rx_p1ks = data->tkip->rx_uni;
|
rx_p1ks = data->tkip->rx_uni;
|
||||||
|
|
||||||
ieee80211_get_key_tx_seq(key, &seq);
|
pn64 = atomic64_read(&key->tx_pn);
|
||||||
tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16);
|
tkip_tx_sc->iv16 = cpu_to_le16(TKIP_PN_TO_IV16(pn64));
|
||||||
tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32);
|
tkip_tx_sc->iv32 = cpu_to_le32(TKIP_PN_TO_IV32(pn64));
|
||||||
|
|
||||||
ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k);
|
ieee80211_get_tkip_p1k_iv(key, TKIP_PN_TO_IV32(pn64),
|
||||||
|
p1k);
|
||||||
iwl_mvm_convert_p1k(p1k, data->tkip->tx.p1k);
|
iwl_mvm_convert_p1k(p1k, data->tkip->tx.p1k);
|
||||||
|
|
||||||
memcpy(data->tkip->mic_keys.tx,
|
memcpy(data->tkip->mic_keys.tx,
|
||||||
|
@ -1614,7 +1617,9 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
|
||||||
case WLAN_CIPHER_SUITE_TKIP:
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
iwl_mvm_tkip_sc_to_seq(&sc->tkip.tsc, &seq);
|
iwl_mvm_tkip_sc_to_seq(&sc->tkip.tsc, &seq);
|
||||||
iwl_mvm_set_tkip_rx_seq(sc->tkip.unicast_rsc, key);
|
iwl_mvm_set_tkip_rx_seq(sc->tkip.unicast_rsc, key);
|
||||||
ieee80211_set_key_tx_seq(key, &seq);
|
atomic64_set(&key->tx_pn,
|
||||||
|
(u64)seq.tkip.iv16 |
|
||||||
|
((u64)seq.tkip.iv32 << 16));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -837,13 +837,16 @@ iwl_mvm_ampdu_check_trigger(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||||
|
|
||||||
static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
|
static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif,
|
struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params)
|
||||||
struct ieee80211_sta *sta, u16 tid,
|
|
||||||
u16 *ssn, u8 buf_size, bool amsdu)
|
|
||||||
{
|
{
|
||||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||||
int ret;
|
int ret;
|
||||||
bool tx_agg_ref = false;
|
bool tx_agg_ref = false;
|
||||||
|
struct ieee80211_sta *sta = params->sta;
|
||||||
|
enum ieee80211_ampdu_mlme_action action = params->action;
|
||||||
|
u16 tid = params->tid;
|
||||||
|
u16 *ssn = ¶ms->ssn;
|
||||||
|
u8 buf_size = params->buf_size;
|
||||||
|
|
||||||
IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n",
|
IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n",
|
||||||
sta->addr, tid, action);
|
sta->addr, tid, action);
|
||||||
|
@ -2582,7 +2585,7 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
|
||||||
switch (key->cipher) {
|
switch (key->cipher) {
|
||||||
case WLAN_CIPHER_SUITE_TKIP:
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
|
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
|
||||||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
|
||||||
break;
|
break;
|
||||||
case WLAN_CIPHER_SUITE_CCMP:
|
case WLAN_CIPHER_SUITE_CCMP:
|
||||||
key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
|
key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
|
||||||
|
|
|
@ -299,6 +299,8 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm,
|
||||||
|
|
||||||
case WLAN_CIPHER_SUITE_TKIP:
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
|
tx_cmd->sec_ctl = TX_CMD_SEC_TKIP;
|
||||||
|
pn = atomic64_inc_return(&keyconf->tx_pn);
|
||||||
|
ieee80211_tkip_add_iv(crypto_hdr, keyconf, pn);
|
||||||
ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key);
|
ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -1334,10 +1334,8 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
|
||||||
data->tx_bytes += skb->len;
|
data->tx_bytes += skb->len;
|
||||||
ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel);
|
ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel);
|
||||||
|
|
||||||
if (ack && skb->len >= 16) {
|
if (ack && skb->len >= 16)
|
||||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
|
||||||
mac80211_hwsim_monitor_ack(channel, hdr->addr2);
|
mac80211_hwsim_monitor_ack(channel, hdr->addr2);
|
||||||
}
|
|
||||||
|
|
||||||
ieee80211_tx_info_clear_status(txi);
|
ieee80211_tx_info_clear_status(txi);
|
||||||
|
|
||||||
|
@ -1846,10 +1844,12 @@ static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw,
|
||||||
|
|
||||||
static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
|
static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif,
|
struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params)
|
||||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
|
||||||
u8 buf_size, bool amsdu)
|
|
||||||
{
|
{
|
||||||
|
struct ieee80211_sta *sta = params->sta;
|
||||||
|
enum ieee80211_ampdu_mlme_action action = params->action;
|
||||||
|
u16 tid = params->tid;
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case IEEE80211_AMPDU_TX_START:
|
case IEEE80211_AMPDU_TX_START:
|
||||||
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
|
||||||
|
|
|
@ -5421,11 +5421,13 @@ static int mwl8k_get_survey(struct ieee80211_hw *hw, int idx,
|
||||||
|
|
||||||
static int
|
static int
|
||||||
mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params)
|
||||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
|
||||||
u8 buf_size, bool amsdu)
|
|
||||||
{
|
{
|
||||||
|
struct ieee80211_sta *sta = params->sta;
|
||||||
|
enum ieee80211_ampdu_mlme_action action = params->action;
|
||||||
|
u16 tid = params->tid;
|
||||||
|
u16 *ssn = ¶ms->ssn;
|
||||||
|
u8 buf_size = params->buf_size;
|
||||||
int i, rc = 0;
|
int i, rc = 0;
|
||||||
struct mwl8k_priv *priv = hw->priv;
|
struct mwl8k_priv *priv = hw->priv;
|
||||||
struct mwl8k_ampdu_stream *stream;
|
struct mwl8k_ampdu_stream *stream;
|
||||||
|
|
|
@ -334,11 +334,13 @@ static int mt7601u_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params)
|
||||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size,
|
|
||||||
bool amsdu)
|
|
||||||
{
|
{
|
||||||
struct mt7601u_dev *dev = hw->priv;
|
struct mt7601u_dev *dev = hw->priv;
|
||||||
|
struct ieee80211_sta *sta = params->sta;
|
||||||
|
enum ieee80211_ampdu_mlme_action action = params->action;
|
||||||
|
u16 tid = params->tid;
|
||||||
|
u16 *ssn = ¶ms->ssn;
|
||||||
struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;
|
struct mt76_sta *msta = (struct mt76_sta *) sta->drv_priv;
|
||||||
|
|
||||||
WARN_ON(msta->wcid.idx > GROUP_WCID(0));
|
WARN_ON(msta->wcid.idx > GROUP_WCID(0));
|
||||||
|
|
|
@ -7936,10 +7936,11 @@ u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
|
||||||
EXPORT_SYMBOL_GPL(rt2800_get_tsf);
|
EXPORT_SYMBOL_GPL(rt2800_get_tsf);
|
||||||
|
|
||||||
int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params)
|
||||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
|
||||||
u8 buf_size, bool amsdu)
|
|
||||||
{
|
{
|
||||||
|
struct ieee80211_sta *sta = params->sta;
|
||||||
|
enum ieee80211_ampdu_mlme_action action = params->action;
|
||||||
|
u16 tid = params->tid;
|
||||||
struct rt2x00_sta *sta_priv = (struct rt2x00_sta *)sta->drv_priv;
|
struct rt2x00_sta *sta_priv = (struct rt2x00_sta *)sta->drv_priv;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
|
|
@ -218,9 +218,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw,
|
||||||
const struct ieee80211_tx_queue_params *params);
|
const struct ieee80211_tx_queue_params *params);
|
||||||
u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
|
u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
|
||||||
int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params);
|
||||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
|
||||||
u8 buf_size, bool amsdu);
|
|
||||||
int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
|
int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
|
||||||
struct survey_info *survey);
|
struct survey_info *survey);
|
||||||
void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev);
|
void rt2800_disable_wpdma(struct rt2x00_dev *rt2x00dev);
|
||||||
|
|
|
@ -5375,13 +5375,13 @@ static int rtl8xxxu_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||||
|
|
||||||
static int
|
static int
|
||||||
rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params)
|
||||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size,
|
|
||||||
bool amsdu)
|
|
||||||
{
|
{
|
||||||
struct rtl8xxxu_priv *priv = hw->priv;
|
struct rtl8xxxu_priv *priv = hw->priv;
|
||||||
struct device *dev = &priv->udev->dev;
|
struct device *dev = &priv->udev->dev;
|
||||||
u8 ampdu_factor, ampdu_density;
|
u8 ampdu_factor, ampdu_density;
|
||||||
|
struct ieee80211_sta *sta = params->sta;
|
||||||
|
enum ieee80211_ampdu_mlme_action action = params->action;
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case IEEE80211_AMPDU_TX_START:
|
case IEEE80211_AMPDU_TX_START:
|
||||||
|
|
|
@ -1371,11 +1371,13 @@ static void rtl_op_sta_notify(struct ieee80211_hw *hw,
|
||||||
|
|
||||||
static int rtl_op_ampdu_action(struct ieee80211_hw *hw,
|
static int rtl_op_ampdu_action(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif,
|
struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params)
|
||||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
|
||||||
u8 buf_size, bool amsdu)
|
|
||||||
{
|
{
|
||||||
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
||||||
|
struct ieee80211_sta *sta = params->sta;
|
||||||
|
enum ieee80211_ampdu_mlme_action action = params->action;
|
||||||
|
u16 tid = params->tid;
|
||||||
|
u16 *ssn = ¶ms->ssn;
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case IEEE80211_AMPDU_TX_START:
|
case IEEE80211_AMPDU_TX_START:
|
||||||
|
|
|
@ -659,29 +659,24 @@ static int rsi_mac80211_set_key(struct ieee80211_hw *hw,
|
||||||
* informs the f/w regarding this.
|
* informs the f/w regarding this.
|
||||||
* @hw: Pointer to the ieee80211_hw structure.
|
* @hw: Pointer to the ieee80211_hw structure.
|
||||||
* @vif: Pointer to the ieee80211_vif structure.
|
* @vif: Pointer to the ieee80211_vif structure.
|
||||||
* @action: ieee80211_ampdu_mlme_action enum.
|
* @params: Pointer to A-MPDU action parameters
|
||||||
* @sta: Pointer to the ieee80211_sta structure.
|
|
||||||
* @tid: Traffic identifier.
|
|
||||||
* @ssn: Pointer to ssn value.
|
|
||||||
* @buf_size: Buffer size (for kernel version > 2.6.38).
|
|
||||||
* @amsdu: is AMSDU in AMPDU allowed
|
|
||||||
*
|
*
|
||||||
* Return: status: 0 on success, negative error code on failure.
|
* Return: status: 0 on success, negative error code on failure.
|
||||||
*/
|
*/
|
||||||
static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw,
|
static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif,
|
struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params)
|
||||||
struct ieee80211_sta *sta,
|
|
||||||
unsigned short tid,
|
|
||||||
unsigned short *ssn,
|
|
||||||
unsigned char buf_size,
|
|
||||||
bool amsdu)
|
|
||||||
{
|
{
|
||||||
int status = -EOPNOTSUPP;
|
int status = -EOPNOTSUPP;
|
||||||
struct rsi_hw *adapter = hw->priv;
|
struct rsi_hw *adapter = hw->priv;
|
||||||
struct rsi_common *common = adapter->priv;
|
struct rsi_common *common = adapter->priv;
|
||||||
u16 seq_no = 0;
|
u16 seq_no = 0;
|
||||||
u8 ii = 0;
|
u8 ii = 0;
|
||||||
|
struct ieee80211_sta *sta = params->sta;
|
||||||
|
enum ieee80211_ampdu_mlme_action action = params->action;
|
||||||
|
u16 tid = params->tid;
|
||||||
|
u16 *ssn = ¶ms->ssn;
|
||||||
|
u8 buf_size = params->buf_size;
|
||||||
|
|
||||||
for (ii = 0; ii < RSI_MAX_VIFS; ii++) {
|
for (ii = 0; ii < RSI_MAX_VIFS; ii++) {
|
||||||
if (vif == adapter->vifs[ii])
|
if (vif == adapter->vifs[ii])
|
||||||
|
|
|
@ -2129,9 +2129,7 @@ void cw1200_mcast_timeout(unsigned long arg)
|
||||||
|
|
||||||
int cw1200_ampdu_action(struct ieee80211_hw *hw,
|
int cw1200_ampdu_action(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif,
|
struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params)
|
||||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
|
||||||
u8 buf_size, bool amsdu)
|
|
||||||
{
|
{
|
||||||
/* Aggregation is implemented fully in firmware,
|
/* Aggregation is implemented fully in firmware,
|
||||||
* including block ack negotiation. Do not allow
|
* including block ack negotiation. Do not allow
|
||||||
|
|
|
@ -109,9 +109,7 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev,
|
||||||
u32 changed);
|
u32 changed);
|
||||||
int cw1200_ampdu_action(struct ieee80211_hw *hw,
|
int cw1200_ampdu_action(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif,
|
struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params);
|
||||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
|
||||||
u8 buf_size, bool amsdu);
|
|
||||||
|
|
||||||
void cw1200_suspend_resume(struct cw1200_common *priv,
|
void cw1200_suspend_resume(struct cw1200_common *priv,
|
||||||
struct wsm_suspend_resume *arg);
|
struct wsm_suspend_resume *arg);
|
||||||
|
|
|
@ -5187,14 +5187,16 @@ out:
|
||||||
|
|
||||||
static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
|
static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif,
|
struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params)
|
||||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
|
||||||
u8 buf_size, bool amsdu)
|
|
||||||
{
|
{
|
||||||
struct wl1271 *wl = hw->priv;
|
struct wl1271 *wl = hw->priv;
|
||||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||||
int ret;
|
int ret;
|
||||||
u8 hlid, *ba_bitmap;
|
u8 hlid, *ba_bitmap;
|
||||||
|
struct ieee80211_sta *sta = params->sta;
|
||||||
|
enum ieee80211_ampdu_mlme_action action = params->action;
|
||||||
|
u16 tid = params->tid;
|
||||||
|
u16 *ssn = ¶ms->ssn;
|
||||||
|
|
||||||
wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
|
wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu action %d tid %d", action,
|
||||||
tid);
|
tid);
|
||||||
|
|
|
@ -1210,7 +1210,7 @@ static void vnt_fill_txkey(struct ieee80211_hdr *hdr, u8 *key_buffer,
|
||||||
struct sk_buff *skb, u16 payload_len,
|
struct sk_buff *skb, u16 payload_len,
|
||||||
struct vnt_mic_hdr *mic_hdr)
|
struct vnt_mic_hdr *mic_hdr)
|
||||||
{
|
{
|
||||||
struct ieee80211_key_seq seq;
|
u64 pn64;
|
||||||
u8 *iv = ((u8 *)hdr + ieee80211_get_hdrlen_from_skb(skb));
|
u8 *iv = ((u8 *)hdr + ieee80211_get_hdrlen_from_skb(skb));
|
||||||
|
|
||||||
/* strip header and icv len from payload */
|
/* strip header and icv len from payload */
|
||||||
|
@ -1243,9 +1243,13 @@ static void vnt_fill_txkey(struct ieee80211_hdr *hdr, u8 *key_buffer,
|
||||||
mic_hdr->payload_len = cpu_to_be16(payload_len);
|
mic_hdr->payload_len = cpu_to_be16(payload_len);
|
||||||
ether_addr_copy(mic_hdr->mic_addr2, hdr->addr2);
|
ether_addr_copy(mic_hdr->mic_addr2, hdr->addr2);
|
||||||
|
|
||||||
ieee80211_get_key_tx_seq(tx_key, &seq);
|
pn64 = atomic64_read(&tx_key->tx_pn);
|
||||||
|
mic_hdr->ccmp_pn[5] = pn64;
|
||||||
memcpy(mic_hdr->ccmp_pn, seq.ccmp.pn, IEEE80211_CCMP_PN_LEN);
|
mic_hdr->ccmp_pn[4] = pn64 >> 8;
|
||||||
|
mic_hdr->ccmp_pn[3] = pn64 >> 16;
|
||||||
|
mic_hdr->ccmp_pn[2] = pn64 >> 24;
|
||||||
|
mic_hdr->ccmp_pn[1] = pn64 >> 32;
|
||||||
|
mic_hdr->ccmp_pn[0] = pn64 >> 40;
|
||||||
|
|
||||||
if (ieee80211_has_a4(hdr->frame_control))
|
if (ieee80211_has_a4(hdr->frame_control))
|
||||||
mic_hdr->hlen = cpu_to_be16(28);
|
mic_hdr->hlen = cpu_to_be16(28);
|
||||||
|
|
|
@ -716,7 +716,7 @@ static void vnt_fill_txkey(struct vnt_usb_send_context *tx_context,
|
||||||
u16 payload_len, struct vnt_mic_hdr *mic_hdr)
|
u16 payload_len, struct vnt_mic_hdr *mic_hdr)
|
||||||
{
|
{
|
||||||
struct ieee80211_hdr *hdr = tx_context->hdr;
|
struct ieee80211_hdr *hdr = tx_context->hdr;
|
||||||
struct ieee80211_key_seq seq;
|
u64 pn64;
|
||||||
u8 *iv = ((u8 *)hdr + ieee80211_get_hdrlen_from_skb(skb));
|
u8 *iv = ((u8 *)hdr + ieee80211_get_hdrlen_from_skb(skb));
|
||||||
|
|
||||||
/* strip header and icv len from payload */
|
/* strip header and icv len from payload */
|
||||||
|
@ -749,9 +749,13 @@ static void vnt_fill_txkey(struct vnt_usb_send_context *tx_context,
|
||||||
mic_hdr->payload_len = cpu_to_be16(payload_len);
|
mic_hdr->payload_len = cpu_to_be16(payload_len);
|
||||||
ether_addr_copy(mic_hdr->mic_addr2, hdr->addr2);
|
ether_addr_copy(mic_hdr->mic_addr2, hdr->addr2);
|
||||||
|
|
||||||
ieee80211_get_key_tx_seq(tx_key, &seq);
|
pn64 = atomic64_read(&tx_key->tx_pn);
|
||||||
|
mic_hdr->ccmp_pn[5] = pn64;
|
||||||
memcpy(mic_hdr->ccmp_pn, seq.ccmp.pn, IEEE80211_CCMP_PN_LEN);
|
mic_hdr->ccmp_pn[4] = pn64 >> 8;
|
||||||
|
mic_hdr->ccmp_pn[3] = pn64 >> 16;
|
||||||
|
mic_hdr->ccmp_pn[2] = pn64 >> 24;
|
||||||
|
mic_hdr->ccmp_pn[1] = pn64 >> 32;
|
||||||
|
mic_hdr->ccmp_pn[0] = pn64 >> 40;
|
||||||
|
|
||||||
if (ieee80211_has_a4(hdr->frame_control))
|
if (ieee80211_has_a4(hdr->frame_control))
|
||||||
mic_hdr->hlen = cpu_to_be16(28);
|
mic_hdr->hlen = cpu_to_be16(28);
|
||||||
|
|
|
@ -163,6 +163,14 @@ static inline u16 ieee80211_sn_sub(u16 sn1, u16 sn2)
|
||||||
/* 30 byte 4 addr hdr, 2 byte QoS, 2304 byte MSDU, 12 byte crypt, 4 byte FCS */
|
/* 30 byte 4 addr hdr, 2 byte QoS, 2304 byte MSDU, 12 byte crypt, 4 byte FCS */
|
||||||
#define IEEE80211_MAX_FRAME_LEN 2352
|
#define IEEE80211_MAX_FRAME_LEN 2352
|
||||||
|
|
||||||
|
/* Maximal size of an A-MSDU */
|
||||||
|
#define IEEE80211_MAX_MPDU_LEN_HT_3839 3839
|
||||||
|
#define IEEE80211_MAX_MPDU_LEN_HT_7935 7935
|
||||||
|
|
||||||
|
#define IEEE80211_MAX_MPDU_LEN_VHT_3895 3895
|
||||||
|
#define IEEE80211_MAX_MPDU_LEN_VHT_7991 7991
|
||||||
|
#define IEEE80211_MAX_MPDU_LEN_VHT_11454 11454
|
||||||
|
|
||||||
#define IEEE80211_MAX_SSID_LEN 32
|
#define IEEE80211_MAX_SSID_LEN 32
|
||||||
|
|
||||||
#define IEEE80211_MAX_MESH_ID_LEN 32
|
#define IEEE80211_MAX_MESH_ID_LEN 32
|
||||||
|
@ -843,6 +851,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 +999,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;
|
||||||
|
@ -1498,6 +1513,7 @@ struct ieee80211_vht_operation {
|
||||||
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 0x00000000
|
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 0x00000000
|
||||||
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 0x00000001
|
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 0x00000001
|
||||||
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 0x00000002
|
#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 0x00000002
|
||||||
|
#define IEEE80211_VHT_CAP_MAX_MPDU_MASK 0x00000003
|
||||||
#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ 0x00000004
|
#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ 0x00000004
|
||||||
#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ 0x00000008
|
#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ 0x00000008
|
||||||
#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK 0x0000000C
|
#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK 0x0000000C
|
||||||
|
@ -2079,6 +2095,16 @@ enum ieee80211_tdls_actioncode {
|
||||||
#define WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED BIT(5)
|
#define WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED BIT(5)
|
||||||
#define WLAN_EXT_CAPA8_OPMODE_NOTIF BIT(6)
|
#define WLAN_EXT_CAPA8_OPMODE_NOTIF BIT(6)
|
||||||
|
|
||||||
|
/* Defines the maximal number of MSDUs in an A-MSDU. */
|
||||||
|
#define WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB BIT(7)
|
||||||
|
#define WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB BIT(0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fine Timing Measurement Initiator - bit 71 of @WLAN_EID_EXT_CAPABILITY
|
||||||
|
* information element
|
||||||
|
*/
|
||||||
|
#define WLAN_EXT_CAPA9_FTM_INITIATOR BIT(7)
|
||||||
|
|
||||||
/* TDLS specific payload type in the LLC/SNAP header */
|
/* TDLS specific payload type in the LLC/SNAP header */
|
||||||
#define WLAN_TDLS_SNAP_RFTYPE 0x2
|
#define WLAN_TDLS_SNAP_RFTYPE 0x2
|
||||||
|
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2011, NVIDIA Corporation.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
||||||
* more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef __RFKILL_GPIO_H
|
|
||||||
#define __RFKILL_GPIO_H
|
|
||||||
|
|
||||||
#include <linux/types.h>
|
|
||||||
#include <linux/rfkill.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* struct rfkill_gpio_platform_data - platform data for rfkill gpio device.
|
|
||||||
* for unused gpio's, the expected value is -1.
|
|
||||||
* @name: name for the gpio rf kill instance
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct rfkill_gpio_platform_data {
|
|
||||||
char *name;
|
|
||||||
enum rfkill_type type;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* __RFKILL_GPIO_H */
|
|
|
@ -104,7 +104,8 @@ int __must_check rfkill_register(struct rfkill *rfkill);
|
||||||
*
|
*
|
||||||
* Pause polling -- say transmitter is off for other reasons.
|
* Pause polling -- say transmitter is off for other reasons.
|
||||||
* NOTE: not necessary for suspend/resume -- in that case the
|
* NOTE: not necessary for suspend/resume -- in that case the
|
||||||
* core stops polling anyway
|
* core stops polling anyway (but will also correctly handle
|
||||||
|
* the case of polling having been paused before suspend.)
|
||||||
*/
|
*/
|
||||||
void rfkill_pause_polling(struct rfkill *rfkill);
|
void rfkill_pause_polling(struct rfkill *rfkill);
|
||||||
|
|
||||||
|
@ -212,6 +213,15 @@ void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw);
|
||||||
* @rfkill: rfkill struct to query
|
* @rfkill: rfkill struct to query
|
||||||
*/
|
*/
|
||||||
bool rfkill_blocked(struct rfkill *rfkill);
|
bool rfkill_blocked(struct rfkill *rfkill);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rfkill_find_type - Helpper for finding rfkill type by name
|
||||||
|
* @name: the name of the type
|
||||||
|
*
|
||||||
|
* Returns enum rfkill_type that conrresponds the name.
|
||||||
|
*/
|
||||||
|
enum rfkill_type rfkill_find_type(const char *name);
|
||||||
|
|
||||||
#else /* !RFKILL */
|
#else /* !RFKILL */
|
||||||
static inline struct rfkill * __must_check
|
static inline struct rfkill * __must_check
|
||||||
rfkill_alloc(const char *name,
|
rfkill_alloc(const char *name,
|
||||||
|
@ -268,6 +278,12 @@ static inline bool rfkill_blocked(struct rfkill *rfkill)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline enum rfkill_type rfkill_find_type(const char *name)
|
||||||
|
{
|
||||||
|
return RFKILL_TYPE_ALL;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* RFKILL || RFKILL_MODULE */
|
#endif /* RFKILL || RFKILL_MODULE */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -712,6 +712,8 @@ struct cfg80211_acl_data {
|
||||||
* @p2p_opp_ps: P2P opportunistic PS
|
* @p2p_opp_ps: P2P opportunistic PS
|
||||||
* @acl: ACL configuration used by the drivers which has support for
|
* @acl: ACL configuration used by the drivers which has support for
|
||||||
* MAC address based access control
|
* MAC address based access control
|
||||||
|
* @pbss: If set, start as a PCP instead of AP. Relevant for DMG
|
||||||
|
* networks.
|
||||||
*/
|
*/
|
||||||
struct cfg80211_ap_settings {
|
struct cfg80211_ap_settings {
|
||||||
struct cfg80211_chan_def chandef;
|
struct cfg80211_chan_def chandef;
|
||||||
|
@ -730,6 +732,7 @@ struct cfg80211_ap_settings {
|
||||||
u8 p2p_ctwindow;
|
u8 p2p_ctwindow;
|
||||||
bool p2p_opp_ps;
|
bool p2p_opp_ps;
|
||||||
const struct cfg80211_acl_data *acl;
|
const struct cfg80211_acl_data *acl;
|
||||||
|
bool pbss;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1888,6 +1891,8 @@ struct cfg80211_ibss_params {
|
||||||
* @ht_capa_mask: The bits of ht_capa which are to be used.
|
* @ht_capa_mask: The bits of ht_capa which are to be used.
|
||||||
* @vht_capa: VHT Capability overrides
|
* @vht_capa: VHT Capability overrides
|
||||||
* @vht_capa_mask: The bits of vht_capa which are to be used.
|
* @vht_capa_mask: The bits of vht_capa which are to be used.
|
||||||
|
* @pbss: if set, connect to a PCP instead of AP. Valid for DMG
|
||||||
|
* networks.
|
||||||
*/
|
*/
|
||||||
struct cfg80211_connect_params {
|
struct cfg80211_connect_params {
|
||||||
struct ieee80211_channel *channel;
|
struct ieee80211_channel *channel;
|
||||||
|
@ -1910,6 +1915,7 @@ struct cfg80211_connect_params {
|
||||||
struct ieee80211_ht_cap ht_capa_mask;
|
struct ieee80211_ht_cap ht_capa_mask;
|
||||||
struct ieee80211_vht_cap vht_capa;
|
struct ieee80211_vht_cap vht_capa;
|
||||||
struct ieee80211_vht_cap vht_capa_mask;
|
struct ieee80211_vht_cap vht_capa_mask;
|
||||||
|
bool pbss;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3489,6 +3495,7 @@ struct cfg80211_cached_keys;
|
||||||
* registered for unexpected class 3 frames (AP mode)
|
* registered for unexpected class 3 frames (AP mode)
|
||||||
* @conn: (private) cfg80211 software SME connection state machine data
|
* @conn: (private) cfg80211 software SME connection state machine data
|
||||||
* @connect_keys: (private) keys to set after connection is established
|
* @connect_keys: (private) keys to set after connection is established
|
||||||
|
* @conn_bss_type: connecting/connected BSS type
|
||||||
* @ibss_fixed: (private) IBSS is using fixed BSSID
|
* @ibss_fixed: (private) IBSS is using fixed BSSID
|
||||||
* @ibss_dfs_possible: (private) IBSS may change to a DFS channel
|
* @ibss_dfs_possible: (private) IBSS may change to a DFS channel
|
||||||
* @event_list: (private) list for internal event processing
|
* @event_list: (private) list for internal event processing
|
||||||
|
@ -3519,6 +3526,7 @@ struct wireless_dev {
|
||||||
u8 ssid_len, mesh_id_len, mesh_id_up_len;
|
u8 ssid_len, mesh_id_len, mesh_id_up_len;
|
||||||
struct cfg80211_conn *conn;
|
struct cfg80211_conn *conn;
|
||||||
struct cfg80211_cached_keys *connect_keys;
|
struct cfg80211_cached_keys *connect_keys;
|
||||||
|
enum ieee80211_bss_type conn_bss_type;
|
||||||
|
|
||||||
struct list_head event_list;
|
struct list_head event_list;
|
||||||
spinlock_t event_lock;
|
spinlock_t event_lock;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||||
* Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
|
* Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||||
* Copyright (C) 2015 Intel Deutschland GmbH
|
* Copyright (C) 2015 - 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
|
||||||
|
@ -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;
|
||||||
|
@ -691,12 +708,14 @@ enum mac80211_tx_info_flags {
|
||||||
* protocol frame (e.g. EAP)
|
* protocol frame (e.g. EAP)
|
||||||
* @IEEE80211_TX_CTRL_PS_RESPONSE: This frame is a response to a poll
|
* @IEEE80211_TX_CTRL_PS_RESPONSE: This frame is a response to a poll
|
||||||
* frame (PS-Poll or uAPSD).
|
* frame (PS-Poll or uAPSD).
|
||||||
|
* @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information
|
||||||
*
|
*
|
||||||
* These flags are used in tx_info->control.flags.
|
* These flags are used in tx_info->control.flags.
|
||||||
*/
|
*/
|
||||||
enum mac80211_tx_control_flags {
|
enum mac80211_tx_control_flags {
|
||||||
IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0),
|
IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0),
|
||||||
IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1),
|
IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1),
|
||||||
|
IEEE80211_TX_CTRL_RATE_INJECT = BIT(2),
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -993,6 +1012,8 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
|
||||||
* @RX_FLAG_MACTIME_END: The timestamp passed in the RX status (@mactime
|
* @RX_FLAG_MACTIME_END: The timestamp passed in the RX status (@mactime
|
||||||
* field) is valid and contains the time the last symbol of the MPDU
|
* field) is valid and contains the time the last symbol of the MPDU
|
||||||
* (including FCS) was received.
|
* (including FCS) was received.
|
||||||
|
* @RX_FLAG_MACTIME_PLCP_START: The timestamp passed in the RX status (@mactime
|
||||||
|
* field) is valid and contains the time the SYNC preamble was received.
|
||||||
* @RX_FLAG_SHORTPRE: Short preamble was used for this frame
|
* @RX_FLAG_SHORTPRE: Short preamble was used for this frame
|
||||||
* @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index
|
* @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index
|
||||||
* @RX_FLAG_VHT: VHT MCS was used and rate_index is MCS index
|
* @RX_FLAG_VHT: VHT MCS was used and rate_index is MCS index
|
||||||
|
@ -1014,6 +1035,14 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
|
||||||
* @RX_FLAG_AMPDU_DELIM_CRC_KNOWN: The delimiter CRC field is known (the CRC
|
* @RX_FLAG_AMPDU_DELIM_CRC_KNOWN: The delimiter CRC field is known (the CRC
|
||||||
* is stored in the @ampdu_delimiter_crc field)
|
* is stored in the @ampdu_delimiter_crc field)
|
||||||
* @RX_FLAG_LDPC: LDPC was used
|
* @RX_FLAG_LDPC: LDPC was used
|
||||||
|
* @RX_FLAG_ONLY_MONITOR: Report frame only to monitor interfaces without
|
||||||
|
* processing it in any regular way.
|
||||||
|
* This is useful if drivers offload some frames but still want to report
|
||||||
|
* them for sniffing purposes.
|
||||||
|
* @RX_FLAG_SKIP_MONITOR: Process and report frame to all interfaces except
|
||||||
|
* monitor interfaces.
|
||||||
|
* This is useful if drivers offload some frames but still want to report
|
||||||
|
* them for sniffing purposes.
|
||||||
* @RX_FLAG_STBC_MASK: STBC 2 bit bitmask. 1 - Nss=1, 2 - Nss=2, 3 - Nss=3
|
* @RX_FLAG_STBC_MASK: STBC 2 bit bitmask. 1 - Nss=1, 2 - Nss=2, 3 - Nss=3
|
||||||
* @RX_FLAG_10MHZ: 10 MHz (half channel) was used
|
* @RX_FLAG_10MHZ: 10 MHz (half channel) was used
|
||||||
* @RX_FLAG_5MHZ: 5 MHz (quarter channel) was used
|
* @RX_FLAG_5MHZ: 5 MHz (quarter channel) was used
|
||||||
|
@ -1033,6 +1062,7 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
|
||||||
enum mac80211_rx_flags {
|
enum mac80211_rx_flags {
|
||||||
RX_FLAG_MMIC_ERROR = BIT(0),
|
RX_FLAG_MMIC_ERROR = BIT(0),
|
||||||
RX_FLAG_DECRYPTED = BIT(1),
|
RX_FLAG_DECRYPTED = BIT(1),
|
||||||
|
RX_FLAG_MACTIME_PLCP_START = BIT(2),
|
||||||
RX_FLAG_MMIC_STRIPPED = BIT(3),
|
RX_FLAG_MMIC_STRIPPED = BIT(3),
|
||||||
RX_FLAG_IV_STRIPPED = BIT(4),
|
RX_FLAG_IV_STRIPPED = BIT(4),
|
||||||
RX_FLAG_FAILED_FCS_CRC = BIT(5),
|
RX_FLAG_FAILED_FCS_CRC = BIT(5),
|
||||||
|
@ -1046,7 +1076,7 @@ enum mac80211_rx_flags {
|
||||||
RX_FLAG_HT_GF = BIT(13),
|
RX_FLAG_HT_GF = BIT(13),
|
||||||
RX_FLAG_AMPDU_DETAILS = BIT(14),
|
RX_FLAG_AMPDU_DETAILS = BIT(14),
|
||||||
RX_FLAG_PN_VALIDATED = BIT(15),
|
RX_FLAG_PN_VALIDATED = BIT(15),
|
||||||
/* bit 16 free */
|
RX_FLAG_DUP_VALIDATED = BIT(16),
|
||||||
RX_FLAG_AMPDU_LAST_KNOWN = BIT(17),
|
RX_FLAG_AMPDU_LAST_KNOWN = BIT(17),
|
||||||
RX_FLAG_AMPDU_IS_LAST = BIT(18),
|
RX_FLAG_AMPDU_IS_LAST = BIT(18),
|
||||||
RX_FLAG_AMPDU_DELIM_CRC_ERROR = BIT(19),
|
RX_FLAG_AMPDU_DELIM_CRC_ERROR = BIT(19),
|
||||||
|
@ -1054,6 +1084,8 @@ enum mac80211_rx_flags {
|
||||||
RX_FLAG_MACTIME_END = BIT(21),
|
RX_FLAG_MACTIME_END = BIT(21),
|
||||||
RX_FLAG_VHT = BIT(22),
|
RX_FLAG_VHT = BIT(22),
|
||||||
RX_FLAG_LDPC = BIT(23),
|
RX_FLAG_LDPC = BIT(23),
|
||||||
|
RX_FLAG_ONLY_MONITOR = BIT(24),
|
||||||
|
RX_FLAG_SKIP_MONITOR = BIT(25),
|
||||||
RX_FLAG_STBC_MASK = BIT(26) | BIT(27),
|
RX_FLAG_STBC_MASK = BIT(26) | BIT(27),
|
||||||
RX_FLAG_10MHZ = BIT(28),
|
RX_FLAG_10MHZ = BIT(28),
|
||||||
RX_FLAG_5MHZ = BIT(29),
|
RX_FLAG_5MHZ = BIT(29),
|
||||||
|
@ -1072,6 +1104,7 @@ enum mac80211_rx_flags {
|
||||||
* @RX_VHT_FLAG_160MHZ: 160 MHz was used
|
* @RX_VHT_FLAG_160MHZ: 160 MHz was used
|
||||||
* @RX_VHT_FLAG_BF: packet was beamformed
|
* @RX_VHT_FLAG_BF: packet was beamformed
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum mac80211_rx_vht_flags {
|
enum mac80211_rx_vht_flags {
|
||||||
RX_VHT_FLAG_80MHZ = BIT(0),
|
RX_VHT_FLAG_80MHZ = BIT(0),
|
||||||
RX_VHT_FLAG_160MHZ = BIT(1),
|
RX_VHT_FLAG_160MHZ = BIT(1),
|
||||||
|
@ -1091,6 +1124,8 @@ enum mac80211_rx_vht_flags {
|
||||||
* it but can store it and pass it back to the driver for synchronisation
|
* it but can store it and pass it back to the driver for synchronisation
|
||||||
* @band: the active band when this frame was received
|
* @band: the active band when this frame was received
|
||||||
* @freq: frequency the radio was tuned to when receiving this frame, in MHz
|
* @freq: frequency the radio was tuned to when receiving this frame, in MHz
|
||||||
|
* This field must be set for management frames, but isn't strictly needed
|
||||||
|
* for data (other) frames - for those it only affects radiotap reporting.
|
||||||
* @signal: signal strength when receiving this frame, either in dBm, in dB or
|
* @signal: signal strength when receiving this frame, either in dBm, in dB or
|
||||||
* unspecified depending on the hardware capabilities flags
|
* unspecified depending on the hardware capabilities flags
|
||||||
* @IEEE80211_HW_SIGNAL_*
|
* @IEEE80211_HW_SIGNAL_*
|
||||||
|
@ -1347,6 +1382,7 @@ enum ieee80211_vif_flags {
|
||||||
* @csa_active: marks whether a channel switch is going on. Internally it is
|
* @csa_active: marks whether a channel switch is going on. Internally it is
|
||||||
* write-protected by sdata_lock and local->mtx so holding either is fine
|
* write-protected by sdata_lock and local->mtx so holding either is fine
|
||||||
* for read access.
|
* for read access.
|
||||||
|
* @mu_mimo_owner: indicates interface owns MU-MIMO capability
|
||||||
* @driver_flags: flags/capabilities the driver has for this interface,
|
* @driver_flags: flags/capabilities the driver has for this interface,
|
||||||
* these need to be set (or cleared) when the interface is added
|
* these need to be set (or cleared) when the interface is added
|
||||||
* or, if supported by the driver, the interface type is changed
|
* or, if supported by the driver, the interface type is changed
|
||||||
|
@ -1373,6 +1409,7 @@ struct ieee80211_vif {
|
||||||
u8 addr[ETH_ALEN];
|
u8 addr[ETH_ALEN];
|
||||||
bool p2p;
|
bool p2p;
|
||||||
bool csa_active;
|
bool csa_active;
|
||||||
|
bool mu_mimo_owner;
|
||||||
|
|
||||||
u8 cab_queue;
|
u8 cab_queue;
|
||||||
u8 hw_queue[IEEE80211_NUM_ACS];
|
u8 hw_queue[IEEE80211_NUM_ACS];
|
||||||
|
@ -1486,9 +1523,8 @@ enum ieee80211_key_flags {
|
||||||
* wants to be given when a frame is transmitted and needs to be
|
* wants to be given when a frame is transmitted and needs to be
|
||||||
* encrypted in hardware.
|
* encrypted in hardware.
|
||||||
* @cipher: The key's cipher suite selector.
|
* @cipher: The key's cipher suite selector.
|
||||||
* @tx_pn: PN used for TX on non-TKIP keys, may be used by the driver
|
* @tx_pn: PN used for TX keys, may be used by the driver as well if it
|
||||||
* as well if it needs to do software PN assignment by itself
|
* needs to do software PN assignment by itself (e.g. due to TSO)
|
||||||
* (e.g. due to TSO)
|
|
||||||
* @flags: key flags, see &enum ieee80211_key_flags.
|
* @flags: key flags, see &enum ieee80211_key_flags.
|
||||||
* @keyidx: the key index (0-3)
|
* @keyidx: the key index (0-3)
|
||||||
* @keylen: key material length
|
* @keylen: key material length
|
||||||
|
@ -1514,6 +1550,9 @@ struct ieee80211_key_conf {
|
||||||
|
|
||||||
#define IEEE80211_MAX_PN_LEN 16
|
#define IEEE80211_MAX_PN_LEN 16
|
||||||
|
|
||||||
|
#define TKIP_PN_TO_IV16(pn) ((u16)(pn & 0xffff))
|
||||||
|
#define TKIP_PN_TO_IV32(pn) ((u32)((pn >> 16) & 0xffffffff))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct ieee80211_key_seq - key sequence counter
|
* struct ieee80211_key_seq - key sequence counter
|
||||||
*
|
*
|
||||||
|
@ -1684,6 +1723,18 @@ struct ieee80211_sta_rates {
|
||||||
* @tdls_initiator: indicates the STA is an initiator of the TDLS link. Only
|
* @tdls_initiator: indicates the STA is an initiator of the TDLS link. Only
|
||||||
* valid if the STA is a TDLS peer in the first place.
|
* valid if the STA is a TDLS peer in the first place.
|
||||||
* @mfp: indicates whether the STA uses management frame protection or not.
|
* @mfp: indicates whether the STA uses management frame protection or not.
|
||||||
|
* @max_amsdu_subframes: indicates the maximal number of MSDUs in a single
|
||||||
|
* A-MSDU. Taken from the Extended Capabilities element. 0 means
|
||||||
|
* unlimited.
|
||||||
|
* @max_amsdu_len: indicates the maximal length of an A-MSDU in bytes. This
|
||||||
|
* field is always valid for packets with a VHT preamble. For packets
|
||||||
|
* with a HT preamble, additional limits apply:
|
||||||
|
* + If the skb is transmitted as part of a BA agreement, the
|
||||||
|
* A-MSDU maximal size is min(max_amsdu_len, 4065) bytes.
|
||||||
|
* + If the skb is not part of a BA aggreement, the A-MSDU maximal
|
||||||
|
* size is min(max_amsdu_len, 7935) bytes.
|
||||||
|
* Both additional HT limits must be enforced by the low level driver.
|
||||||
|
* This is defined by the spec (IEEE 802.11-2012 section 8.3.2.2 NOTE 2).
|
||||||
* @txq: per-TID data TX queues (if driver uses the TXQ abstraction)
|
* @txq: per-TID data TX queues (if driver uses the TXQ abstraction)
|
||||||
*/
|
*/
|
||||||
struct ieee80211_sta {
|
struct ieee80211_sta {
|
||||||
|
@ -1702,6 +1753,8 @@ struct ieee80211_sta {
|
||||||
bool tdls;
|
bool tdls;
|
||||||
bool tdls_initiator;
|
bool tdls_initiator;
|
||||||
bool mfp;
|
bool mfp;
|
||||||
|
u8 max_amsdu_subframes;
|
||||||
|
u16 max_amsdu_len;
|
||||||
|
|
||||||
struct ieee80211_txq *txq[IEEE80211_NUM_TIDS];
|
struct ieee80211_txq *txq[IEEE80211_NUM_TIDS];
|
||||||
|
|
||||||
|
@ -1910,6 +1963,11 @@ struct ieee80211_txq {
|
||||||
* by just its MAC address; this prevents, for example, the same station
|
* by just its MAC address; this prevents, for example, the same station
|
||||||
* from connecting to two virtual AP interfaces at the same time.
|
* from connecting to two virtual AP interfaces at the same time.
|
||||||
*
|
*
|
||||||
|
* @IEEE80211_HW_SUPPORTS_REORDERING_BUFFER: Hardware (or driver) manages the
|
||||||
|
* reordering buffer internally, guaranteeing mac80211 receives frames in
|
||||||
|
* order and does not need to manage its own reorder buffer or BA session
|
||||||
|
* timeout.
|
||||||
|
*
|
||||||
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
|
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
|
||||||
*/
|
*/
|
||||||
enum ieee80211_hw_flags {
|
enum ieee80211_hw_flags {
|
||||||
|
@ -1946,6 +2004,7 @@ enum ieee80211_hw_flags {
|
||||||
IEEE80211_HW_SUPPORTS_AMSDU_IN_AMPDU,
|
IEEE80211_HW_SUPPORTS_AMSDU_IN_AMPDU,
|
||||||
IEEE80211_HW_BEACON_TX_STATUS,
|
IEEE80211_HW_BEACON_TX_STATUS,
|
||||||
IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR,
|
IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR,
|
||||||
|
IEEE80211_HW_SUPPORTS_REORDERING_BUFFER,
|
||||||
|
|
||||||
/* keep last, obviously */
|
/* keep last, obviously */
|
||||||
NUM_IEEE80211_HW_FLAGS
|
NUM_IEEE80211_HW_FLAGS
|
||||||
|
@ -2167,7 +2226,7 @@ static inline void SET_IEEE80211_DEV(struct ieee80211_hw *hw, struct device *dev
|
||||||
* @hw: the &struct ieee80211_hw to set the MAC address for
|
* @hw: the &struct ieee80211_hw to set the MAC address for
|
||||||
* @addr: the address to set
|
* @addr: the address to set
|
||||||
*/
|
*/
|
||||||
static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr)
|
static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, const u8 *addr)
|
||||||
{
|
{
|
||||||
memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN);
|
memcpy(hw->wiphy->perm_addr, addr, ETH_ALEN);
|
||||||
}
|
}
|
||||||
|
@ -2683,6 +2742,33 @@ enum ieee80211_ampdu_mlme_action {
|
||||||
IEEE80211_AMPDU_TX_OPERATIONAL,
|
IEEE80211_AMPDU_TX_OPERATIONAL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct ieee80211_ampdu_params - AMPDU action parameters
|
||||||
|
*
|
||||||
|
* @action: the ampdu action, value from %ieee80211_ampdu_mlme_action.
|
||||||
|
* @sta: peer of this AMPDU session
|
||||||
|
* @tid: tid of the BA session
|
||||||
|
* @ssn: start sequence number of the session. TX/RX_STOP can pass 0. When
|
||||||
|
* action is set to %IEEE80211_AMPDU_RX_START the driver passes back the
|
||||||
|
* actual ssn value used to start the session and writes the value here.
|
||||||
|
* @buf_size: reorder buffer size (number of subframes). Valid only when the
|
||||||
|
* action is set to %IEEE80211_AMPDU_RX_START or
|
||||||
|
* %IEEE80211_AMPDU_TX_OPERATIONAL
|
||||||
|
* @amsdu: indicates the peer's ability to receive A-MSDU within A-MPDU.
|
||||||
|
* valid when the action is set to %IEEE80211_AMPDU_TX_OPERATIONAL
|
||||||
|
* @timeout: BA session timeout. Valid only when the action is set to
|
||||||
|
* %IEEE80211_AMPDU_RX_START
|
||||||
|
*/
|
||||||
|
struct ieee80211_ampdu_params {
|
||||||
|
enum ieee80211_ampdu_mlme_action action;
|
||||||
|
struct ieee80211_sta *sta;
|
||||||
|
u16 tid;
|
||||||
|
u16 ssn;
|
||||||
|
u8 buf_size;
|
||||||
|
bool amsdu;
|
||||||
|
u16 timeout;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enum ieee80211_frame_release_type - frame release reason
|
* enum ieee80211_frame_release_type - frame release reason
|
||||||
* @IEEE80211_FRAME_RELEASE_PSPOLL: frame released for PS-Poll
|
* @IEEE80211_FRAME_RELEASE_PSPOLL: frame released for PS-Poll
|
||||||
|
@ -3027,13 +3113,9 @@ enum ieee80211_reconfig_type {
|
||||||
* @ampdu_action: Perform a certain A-MPDU action
|
* @ampdu_action: Perform a certain A-MPDU action
|
||||||
* The RA/TID combination determines the destination and TID we want
|
* The RA/TID combination determines the destination and TID we want
|
||||||
* the ampdu action to be performed for. The action is defined through
|
* the ampdu action to be performed for. The action is defined through
|
||||||
* ieee80211_ampdu_mlme_action. Starting sequence number (@ssn)
|
* ieee80211_ampdu_mlme_action.
|
||||||
* is the first frame we expect to perform the action on. Notice
|
* When the action is set to %IEEE80211_AMPDU_TX_OPERATIONAL the driver
|
||||||
* that TX/RX_STOP can pass NULL for this parameter.
|
* may neither send aggregates containing more subframes than @buf_size
|
||||||
* The @buf_size parameter is only valid when the action is set to
|
|
||||||
* %IEEE80211_AMPDU_TX_OPERATIONAL and indicates the peer's reorder
|
|
||||||
* buffer size (number of subframes) for this session -- the driver
|
|
||||||
* may neither send aggregates containing more subframes than this
|
|
||||||
* nor send aggregates in a way that lost frames would exceed the
|
* nor send aggregates in a way that lost frames would exceed the
|
||||||
* buffer size. If just limiting the aggregate size, this would be
|
* buffer size. If just limiting the aggregate size, this would be
|
||||||
* possible with a buf_size of 8:
|
* possible with a buf_size of 8:
|
||||||
|
@ -3044,9 +3126,6 @@ enum ieee80211_reconfig_type {
|
||||||
* buffer size of 8. Correct ways to retransmit #1 would be:
|
* buffer size of 8. Correct ways to retransmit #1 would be:
|
||||||
* - TX: 1 or 18 or 81
|
* - TX: 1 or 18 or 81
|
||||||
* Even "189" would be wrong since 1 could be lost again.
|
* Even "189" would be wrong since 1 could be lost again.
|
||||||
* The @amsdu parameter is valid when the action is set to
|
|
||||||
* %IEEE80211_AMPDU_TX_OPERATIONAL and indicates the peer's ability
|
|
||||||
* to receive A-MSDU within A-MPDU.
|
|
||||||
*
|
*
|
||||||
* Returns a negative error code on failure.
|
* Returns a negative error code on failure.
|
||||||
* The callback can sleep.
|
* The callback can sleep.
|
||||||
|
@ -3388,9 +3467,7 @@ struct ieee80211_ops {
|
||||||
int (*tx_last_beacon)(struct ieee80211_hw *hw);
|
int (*tx_last_beacon)(struct ieee80211_hw *hw);
|
||||||
int (*ampdu_action)(struct ieee80211_hw *hw,
|
int (*ampdu_action)(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_vif *vif,
|
struct ieee80211_vif *vif,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params);
|
||||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
|
||||||
u8 buf_size, bool amsdu);
|
|
||||||
int (*get_survey)(struct ieee80211_hw *hw, int idx,
|
int (*get_survey)(struct ieee80211_hw *hw, int idx,
|
||||||
struct survey_info *survey);
|
struct survey_info *survey);
|
||||||
void (*rfkill_poll)(struct ieee80211_hw *hw);
|
void (*rfkill_poll)(struct ieee80211_hw *hw);
|
||||||
|
@ -4374,21 +4451,19 @@ void ieee80211_get_tkip_p2k(struct ieee80211_key_conf *keyconf,
|
||||||
struct sk_buff *skb, u8 *p2k);
|
struct sk_buff *skb, u8 *p2k);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ieee80211_get_key_tx_seq - get key TX sequence counter
|
* ieee80211_tkip_add_iv - write TKIP IV and Ext. IV to pos
|
||||||
*
|
*
|
||||||
|
* @pos: start of crypto header
|
||||||
* @keyconf: the parameter passed with the set key
|
* @keyconf: the parameter passed with the set key
|
||||||
* @seq: buffer to receive the sequence data
|
* @pn: PN to add
|
||||||
*
|
*
|
||||||
* This function allows a driver to retrieve the current TX IV/PN
|
* Returns: pointer to the octet following IVs (i.e. beginning of
|
||||||
* for the given key. It must not be called if IV generation is
|
* the packet payload)
|
||||||
* offloaded to the device.
|
|
||||||
*
|
*
|
||||||
* Note that this function may only be called when no TX processing
|
* This function writes the tkip IV value to pos (which should
|
||||||
* can be done concurrently, for example when queues are stopped
|
* point to the crypto header)
|
||||||
* and the stop has been synchronized.
|
|
||||||
*/
|
*/
|
||||||
void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf,
|
u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key_conf *keyconf, u64 pn);
|
||||||
struct ieee80211_key_seq *seq);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ieee80211_get_key_rx_seq - get key RX sequence counter
|
* ieee80211_get_key_rx_seq - get key RX sequence counter
|
||||||
|
@ -4409,23 +4484,6 @@ void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf,
|
||||||
void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf,
|
void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf,
|
||||||
int tid, struct ieee80211_key_seq *seq);
|
int tid, struct ieee80211_key_seq *seq);
|
||||||
|
|
||||||
/**
|
|
||||||
* ieee80211_set_key_tx_seq - set key TX sequence counter
|
|
||||||
*
|
|
||||||
* @keyconf: the parameter passed with the set key
|
|
||||||
* @seq: new sequence data
|
|
||||||
*
|
|
||||||
* This function allows a driver to set the current TX IV/PNs for the
|
|
||||||
* given key. This is useful when resuming from WoWLAN sleep and the
|
|
||||||
* device may have transmitted frames using the PTK, e.g. replies to
|
|
||||||
* ARP requests.
|
|
||||||
*
|
|
||||||
* Note that this function may only be called when no TX processing
|
|
||||||
* can be done concurrently.
|
|
||||||
*/
|
|
||||||
void ieee80211_set_key_tx_seq(struct ieee80211_key_conf *keyconf,
|
|
||||||
struct ieee80211_key_seq *seq);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ieee80211_set_key_rx_seq - set key RX sequence counter
|
* ieee80211_set_key_rx_seq - set key RX sequence counter
|
||||||
*
|
*
|
||||||
|
@ -5120,6 +5178,24 @@ void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw);
|
||||||
void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap,
|
void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap,
|
||||||
const u8 *addr);
|
const u8 *addr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee80211_mark_rx_ba_filtered_frames - move RX BA window and mark filtered
|
||||||
|
* @pubsta: station struct
|
||||||
|
* @tid: the session's TID
|
||||||
|
* @ssn: starting sequence number of the bitmap, all frames before this are
|
||||||
|
* assumed to be out of the window after the call
|
||||||
|
* @filtered: bitmap of filtered frames, BIT(0) is the @ssn entry etc.
|
||||||
|
* @received_mpdus: number of received mpdus in firmware
|
||||||
|
*
|
||||||
|
* This function moves the BA window and releases all frames before @ssn, and
|
||||||
|
* marks frames marked in the bitmap as having been filtered. Afterwards, it
|
||||||
|
* checks if any frames in the window starting from @ssn can now be released
|
||||||
|
* (in case they were only waiting for frames that were filtered.)
|
||||||
|
*/
|
||||||
|
void ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid,
|
||||||
|
u16 ssn, u64 filtered,
|
||||||
|
u16 received_mpdus);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ieee80211_send_bar - send a BlockAckReq frame
|
* ieee80211_send_bar - send a BlockAckReq frame
|
||||||
*
|
*
|
||||||
|
@ -5371,6 +5447,21 @@ ieee80211_vif_type_p2p(struct ieee80211_vif *vif)
|
||||||
return ieee80211_iftype_p2p(vif->type, vif->p2p);
|
return ieee80211_iftype_p2p(vif->type, vif->p2p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee80211_update_mu_groups - set the VHT MU-MIMO groud data
|
||||||
|
*
|
||||||
|
* @vif: the specified virtual interface
|
||||||
|
* @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
|
||||||
|
*
|
||||||
|
* Note: This function assumes that the given vif is valid and the position and
|
||||||
|
* membership data is of the correct size and are in the same byte order as the
|
||||||
|
* matching GroupId management frame.
|
||||||
|
* Calls to this function need to be serialized with RX path.
|
||||||
|
*/
|
||||||
|
void ieee80211_update_mu_groups(struct ieee80211_vif *vif,
|
||||||
|
const u8 *membership, const u8 *position);
|
||||||
|
|
||||||
void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif,
|
void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif,
|
||||||
int rssi_min_thold,
|
int rssi_min_thold,
|
||||||
int rssi_max_thold);
|
int rssi_max_thold);
|
||||||
|
@ -5523,4 +5614,19 @@ void ieee80211_unreserve_tid(struct ieee80211_sta *sta, u8 tid);
|
||||||
*/
|
*/
|
||||||
struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
|
struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_txq *txq);
|
struct ieee80211_txq *txq);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ieee80211_txq_get_depth - get pending frame/byte count of given txq
|
||||||
|
*
|
||||||
|
* The values are not guaranteed to be coherent with regard to each other, i.e.
|
||||||
|
* txq state can change half-way of this function and the caller may end up
|
||||||
|
* with "new" frame_cnt and "old" byte_cnt or vice-versa.
|
||||||
|
*
|
||||||
|
* @txq: pointer obtained from station or virtual interface
|
||||||
|
* @frame_cnt: pointer to store frame count
|
||||||
|
* @byte_cnt: pointer to store byte count
|
||||||
|
*/
|
||||||
|
void ieee80211_txq_get_depth(struct ieee80211_txq *txq,
|
||||||
|
unsigned long *frame_cnt,
|
||||||
|
unsigned long *byte_cnt);
|
||||||
#endif /* MAC80211_H */
|
#endif /* MAC80211_H */
|
||||||
|
|
|
@ -1727,6 +1727,8 @@ enum nl80211_commands {
|
||||||
* underlying device supports these minimal RRM features:
|
* underlying device supports these minimal RRM features:
|
||||||
* %NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES,
|
* %NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES,
|
||||||
* %NL80211_FEATURE_QUIET,
|
* %NL80211_FEATURE_QUIET,
|
||||||
|
* Or, if global RRM is supported, see:
|
||||||
|
* %NL80211_EXT_FEATURE_RRM
|
||||||
* If this flag is used, driver must add the Power Capabilities IE to the
|
* If this flag is used, driver must add the Power Capabilities IE to the
|
||||||
* association request. In addition, it must also set the RRM capability
|
* association request. In addition, it must also set the RRM capability
|
||||||
* flag in the association request's Capability Info field.
|
* flag in the association request's Capability Info field.
|
||||||
|
@ -1789,6 +1791,10 @@ enum nl80211_commands {
|
||||||
* thus it must not specify the number of iterations, only the interval
|
* thus it must not specify the number of iterations, only the interval
|
||||||
* between scans. The scan plans are executed sequentially.
|
* between scans. The scan plans are executed sequentially.
|
||||||
* Each scan plan is a nested attribute of &enum nl80211_sched_scan_plan.
|
* Each scan plan is a nested attribute of &enum nl80211_sched_scan_plan.
|
||||||
|
* @NL80211_ATTR_PBSS: flag attribute. If set it means operate
|
||||||
|
* in a PBSS. Specified in %NL80211_CMD_CONNECT to request
|
||||||
|
* connecting to a PCP, and in %NL80211_CMD_START_AP to start
|
||||||
|
* a PCP instead of AP. Relevant for DMG networks only.
|
||||||
*
|
*
|
||||||
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||||
|
@ -2164,6 +2170,8 @@ enum nl80211_attrs {
|
||||||
NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
|
NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
|
||||||
NL80211_ATTR_SCHED_SCAN_PLANS,
|
NL80211_ATTR_SCHED_SCAN_PLANS,
|
||||||
|
|
||||||
|
NL80211_ATTR_PBSS,
|
||||||
|
|
||||||
/* add attributes here, update the policy in nl80211.c */
|
/* add attributes here, update the policy in nl80211.c */
|
||||||
|
|
||||||
__NL80211_ATTR_AFTER_LAST,
|
__NL80211_ATTR_AFTER_LAST,
|
||||||
|
@ -4396,12 +4404,18 @@ enum nl80211_feature_flags {
|
||||||
/**
|
/**
|
||||||
* enum nl80211_ext_feature_index - bit index of extended features.
|
* enum nl80211_ext_feature_index - bit index of extended features.
|
||||||
* @NL80211_EXT_FEATURE_VHT_IBSS: This driver supports IBSS with VHT datarates.
|
* @NL80211_EXT_FEATURE_VHT_IBSS: This driver supports IBSS with VHT datarates.
|
||||||
|
* @NL80211_EXT_FEATURE_RRM: This driver supports RRM. When featured, user can
|
||||||
|
* can request to use RRM (see %NL80211_ATTR_USE_RRM) with
|
||||||
|
* %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests, which will set
|
||||||
|
* the ASSOC_REQ_USE_RRM flag in the association request even if
|
||||||
|
* NL80211_FEATURE_QUIET is not advertized.
|
||||||
*
|
*
|
||||||
* @NUM_NL80211_EXT_FEATURES: number of extended features.
|
* @NUM_NL80211_EXT_FEATURES: number of extended features.
|
||||||
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
|
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
|
||||||
*/
|
*/
|
||||||
enum nl80211_ext_feature_index {
|
enum nl80211_ext_feature_index {
|
||||||
NL80211_EXT_FEATURE_VHT_IBSS,
|
NL80211_EXT_FEATURE_VHT_IBSS,
|
||||||
|
NL80211_EXT_FEATURE_RRM,
|
||||||
|
|
||||||
/* add new features before the definition below */
|
/* add new features before the definition below */
|
||||||
NUM_NL80211_EXT_FEATURES,
|
NUM_NL80211_EXT_FEATURES,
|
||||||
|
|
|
@ -59,6 +59,8 @@ enum rfkill_type {
|
||||||
* @RFKILL_OP_DEL: a device was removed
|
* @RFKILL_OP_DEL: a device was removed
|
||||||
* @RFKILL_OP_CHANGE: a device's state changed -- userspace changes one device
|
* @RFKILL_OP_CHANGE: a device's state changed -- userspace changes one device
|
||||||
* @RFKILL_OP_CHANGE_ALL: userspace changes all devices (of a type, or all)
|
* @RFKILL_OP_CHANGE_ALL: userspace changes all devices (of a type, or all)
|
||||||
|
* into a state, also updating the default state used for devices that
|
||||||
|
* are hot-plugged later.
|
||||||
*/
|
*/
|
||||||
enum rfkill_operation {
|
enum rfkill_operation {
|
||||||
RFKILL_OP_ADD = 0,
|
RFKILL_OP_ADD = 0,
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||||
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
||||||
* Copyright 2007-2010, Intel Corporation
|
* Copyright 2007-2010, Intel Corporation
|
||||||
|
* 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
|
||||||
|
@ -61,16 +62,25 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
||||||
{
|
{
|
||||||
struct ieee80211_local *local = sta->local;
|
struct ieee80211_local *local = sta->local;
|
||||||
struct tid_ampdu_rx *tid_rx;
|
struct tid_ampdu_rx *tid_rx;
|
||||||
|
struct ieee80211_ampdu_params params = {
|
||||||
|
.sta = &sta->sta,
|
||||||
|
.action = IEEE80211_AMPDU_RX_STOP,
|
||||||
|
.tid = tid,
|
||||||
|
.amsdu = false,
|
||||||
|
.timeout = 0,
|
||||||
|
.ssn = 0,
|
||||||
|
};
|
||||||
|
|
||||||
lockdep_assert_held(&sta->ampdu_mlme.mtx);
|
lockdep_assert_held(&sta->ampdu_mlme.mtx);
|
||||||
|
|
||||||
tid_rx = rcu_dereference_protected(sta->ampdu_mlme.tid_rx[tid],
|
tid_rx = rcu_dereference_protected(sta->ampdu_mlme.tid_rx[tid],
|
||||||
lockdep_is_held(&sta->ampdu_mlme.mtx));
|
lockdep_is_held(&sta->ampdu_mlme.mtx));
|
||||||
|
|
||||||
if (!tid_rx)
|
if (!test_bit(tid, sta->ampdu_mlme.agg_session_valid))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL);
|
RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL);
|
||||||
|
__clear_bit(tid, sta->ampdu_mlme.agg_session_valid);
|
||||||
|
|
||||||
ht_dbg(sta->sdata,
|
ht_dbg(sta->sdata,
|
||||||
"Rx BA session stop requested for %pM tid %u %s reason: %d\n",
|
"Rx BA session stop requested for %pM tid %u %s reason: %d\n",
|
||||||
|
@ -78,8 +88,7 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
||||||
initiator == WLAN_BACK_RECIPIENT ? "recipient" : "inititator",
|
initiator == WLAN_BACK_RECIPIENT ? "recipient" : "inititator",
|
||||||
(int)reason);
|
(int)reason);
|
||||||
|
|
||||||
if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP,
|
if (drv_ampdu_action(local, sta->sdata, ¶ms))
|
||||||
&sta->sta, tid, NULL, 0, false))
|
|
||||||
sdata_info(sta->sdata,
|
sdata_info(sta->sdata,
|
||||||
"HW problem - can not stop rx aggregation for %pM tid %d\n",
|
"HW problem - can not stop rx aggregation for %pM tid %d\n",
|
||||||
sta->sta.addr, tid);
|
sta->sta.addr, tid);
|
||||||
|
@ -89,6 +98,13 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
||||||
ieee80211_send_delba(sta->sdata, sta->sta.addr,
|
ieee80211_send_delba(sta->sdata, sta->sta.addr,
|
||||||
tid, WLAN_BACK_RECIPIENT, reason);
|
tid, WLAN_BACK_RECIPIENT, reason);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return here in case tid_rx is not assigned - which will happen if
|
||||||
|
* IEEE80211_HW_SUPPORTS_REORDERING_BUFFER is set.
|
||||||
|
*/
|
||||||
|
if (!tid_rx)
|
||||||
|
return;
|
||||||
|
|
||||||
del_timer_sync(&tid_rx->session_timer);
|
del_timer_sync(&tid_rx->session_timer);
|
||||||
|
|
||||||
/* make sure ieee80211_sta_reorder_release() doesn't re-arm the timer */
|
/* make sure ieee80211_sta_reorder_release() doesn't re-arm the timer */
|
||||||
|
@ -237,6 +253,15 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||||
{
|
{
|
||||||
struct ieee80211_local *local = sta->sdata->local;
|
struct ieee80211_local *local = sta->sdata->local;
|
||||||
struct tid_ampdu_rx *tid_agg_rx;
|
struct tid_ampdu_rx *tid_agg_rx;
|
||||||
|
struct ieee80211_ampdu_params params = {
|
||||||
|
.sta = &sta->sta,
|
||||||
|
.action = IEEE80211_AMPDU_RX_START,
|
||||||
|
.tid = tid,
|
||||||
|
.amsdu = false,
|
||||||
|
.timeout = timeout,
|
||||||
|
.ssn = start_seq_num,
|
||||||
|
};
|
||||||
|
|
||||||
int i, ret = -EOPNOTSUPP;
|
int i, ret = -EOPNOTSUPP;
|
||||||
u16 status = WLAN_STATUS_REQUEST_DECLINED;
|
u16 status = WLAN_STATUS_REQUEST_DECLINED;
|
||||||
|
|
||||||
|
@ -275,11 +300,12 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||||
/* make sure the size doesn't exceed the maximum supported by the hw */
|
/* make sure the size doesn't exceed the maximum supported by the hw */
|
||||||
if (buf_size > local->hw.max_rx_aggregation_subframes)
|
if (buf_size > local->hw.max_rx_aggregation_subframes)
|
||||||
buf_size = local->hw.max_rx_aggregation_subframes;
|
buf_size = local->hw.max_rx_aggregation_subframes;
|
||||||
|
params.buf_size = buf_size;
|
||||||
|
|
||||||
/* examine state machine */
|
/* examine state machine */
|
||||||
mutex_lock(&sta->ampdu_mlme.mtx);
|
mutex_lock(&sta->ampdu_mlme.mtx);
|
||||||
|
|
||||||
if (sta->ampdu_mlme.tid_rx[tid]) {
|
if (test_bit(tid, sta->ampdu_mlme.agg_session_valid)) {
|
||||||
ht_dbg_ratelimited(sta->sdata,
|
ht_dbg_ratelimited(sta->sdata,
|
||||||
"unexpected AddBA Req from %pM on tid %u\n",
|
"unexpected AddBA Req from %pM on tid %u\n",
|
||||||
sta->sta.addr, tid);
|
sta->sta.addr, tid);
|
||||||
|
@ -290,6 +316,16 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ieee80211_hw_check(&local->hw, SUPPORTS_REORDERING_BUFFER)) {
|
||||||
|
ret = drv_ampdu_action(local, sta->sdata, ¶ms);
|
||||||
|
ht_dbg(sta->sdata,
|
||||||
|
"Rx A-MPDU request on %pM tid %d result %d\n",
|
||||||
|
sta->sta.addr, tid, ret);
|
||||||
|
if (!ret)
|
||||||
|
status = WLAN_STATUS_SUCCESS;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
/* prepare A-MPDU MLME for Rx aggregation */
|
/* prepare A-MPDU MLME for Rx aggregation */
|
||||||
tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL);
|
tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL);
|
||||||
if (!tid_agg_rx)
|
if (!tid_agg_rx)
|
||||||
|
@ -322,8 +358,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||||
for (i = 0; i < buf_size; i++)
|
for (i = 0; i < buf_size; i++)
|
||||||
__skb_queue_head_init(&tid_agg_rx->reorder_buf[i]);
|
__skb_queue_head_init(&tid_agg_rx->reorder_buf[i]);
|
||||||
|
|
||||||
ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START,
|
ret = drv_ampdu_action(local, sta->sdata, ¶ms);
|
||||||
&sta->sta, tid, &start_seq_num, 0, false);
|
|
||||||
ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n",
|
ht_dbg(sta->sdata, "Rx A-MPDU request on %pM tid %d result %d\n",
|
||||||
sta->sta.addr, tid, ret);
|
sta->sta.addr, tid, ret);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -341,6 +376,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||||
tid_agg_rx->timeout = timeout;
|
tid_agg_rx->timeout = timeout;
|
||||||
tid_agg_rx->stored_mpdu_num = 0;
|
tid_agg_rx->stored_mpdu_num = 0;
|
||||||
tid_agg_rx->auto_seq = auto_seq;
|
tid_agg_rx->auto_seq = auto_seq;
|
||||||
|
tid_agg_rx->reorder_buf_filtered = 0;
|
||||||
status = WLAN_STATUS_SUCCESS;
|
status = WLAN_STATUS_SUCCESS;
|
||||||
|
|
||||||
/* activate it for RX */
|
/* activate it for RX */
|
||||||
|
@ -352,6 +388,8 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
|
if (status == WLAN_STATUS_SUCCESS)
|
||||||
|
__set_bit(tid, sta->ampdu_mlme.agg_session_valid);
|
||||||
mutex_unlock(&sta->ampdu_mlme.mtx);
|
mutex_unlock(&sta->ampdu_mlme.mtx);
|
||||||
|
|
||||||
end_no_lock:
|
end_no_lock:
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||||
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
||||||
* Copyright 2007-2010, Intel Corporation
|
* Copyright 2007-2010, Intel Corporation
|
||||||
|
* 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
|
||||||
|
@ -295,7 +296,14 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
||||||
{
|
{
|
||||||
struct ieee80211_local *local = sta->local;
|
struct ieee80211_local *local = sta->local;
|
||||||
struct tid_ampdu_tx *tid_tx;
|
struct tid_ampdu_tx *tid_tx;
|
||||||
enum ieee80211_ampdu_mlme_action action;
|
struct ieee80211_ampdu_params params = {
|
||||||
|
.sta = &sta->sta,
|
||||||
|
.tid = tid,
|
||||||
|
.buf_size = 0,
|
||||||
|
.amsdu = false,
|
||||||
|
.timeout = 0,
|
||||||
|
.ssn = 0,
|
||||||
|
};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
lockdep_assert_held(&sta->ampdu_mlme.mtx);
|
lockdep_assert_held(&sta->ampdu_mlme.mtx);
|
||||||
|
@ -304,10 +312,10 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
||||||
case AGG_STOP_DECLINED:
|
case AGG_STOP_DECLINED:
|
||||||
case AGG_STOP_LOCAL_REQUEST:
|
case AGG_STOP_LOCAL_REQUEST:
|
||||||
case AGG_STOP_PEER_REQUEST:
|
case AGG_STOP_PEER_REQUEST:
|
||||||
action = IEEE80211_AMPDU_TX_STOP_CONT;
|
params.action = IEEE80211_AMPDU_TX_STOP_CONT;
|
||||||
break;
|
break;
|
||||||
case AGG_STOP_DESTROY_STA:
|
case AGG_STOP_DESTROY_STA:
|
||||||
action = IEEE80211_AMPDU_TX_STOP_FLUSH;
|
params.action = IEEE80211_AMPDU_TX_STOP_FLUSH;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
WARN_ON_ONCE(1);
|
WARN_ON_ONCE(1);
|
||||||
|
@ -330,9 +338,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
||||||
spin_unlock_bh(&sta->lock);
|
spin_unlock_bh(&sta->lock);
|
||||||
if (reason != AGG_STOP_DESTROY_STA)
|
if (reason != AGG_STOP_DESTROY_STA)
|
||||||
return -EALREADY;
|
return -EALREADY;
|
||||||
ret = drv_ampdu_action(local, sta->sdata,
|
params.action = IEEE80211_AMPDU_TX_STOP_FLUSH_CONT;
|
||||||
IEEE80211_AMPDU_TX_STOP_FLUSH_CONT,
|
ret = drv_ampdu_action(local, sta->sdata, ¶ms);
|
||||||
&sta->sta, tid, NULL, 0, false);
|
|
||||||
WARN_ON_ONCE(ret);
|
WARN_ON_ONCE(ret);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -381,8 +388,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
||||||
WLAN_BACK_INITIATOR;
|
WLAN_BACK_INITIATOR;
|
||||||
tid_tx->tx_stop = reason == AGG_STOP_LOCAL_REQUEST;
|
tid_tx->tx_stop = reason == AGG_STOP_LOCAL_REQUEST;
|
||||||
|
|
||||||
ret = drv_ampdu_action(local, sta->sdata, action,
|
ret = drv_ampdu_action(local, sta->sdata, ¶ms);
|
||||||
&sta->sta, tid, NULL, 0, false);
|
|
||||||
|
|
||||||
/* HW shall not deny going back to legacy */
|
/* HW shall not deny going back to legacy */
|
||||||
if (WARN_ON(ret)) {
|
if (WARN_ON(ret)) {
|
||||||
|
@ -445,7 +451,14 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
|
||||||
struct tid_ampdu_tx *tid_tx;
|
struct tid_ampdu_tx *tid_tx;
|
||||||
struct ieee80211_local *local = sta->local;
|
struct ieee80211_local *local = sta->local;
|
||||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||||
u16 start_seq_num;
|
struct ieee80211_ampdu_params params = {
|
||||||
|
.sta = &sta->sta,
|
||||||
|
.action = IEEE80211_AMPDU_TX_START,
|
||||||
|
.tid = tid,
|
||||||
|
.buf_size = 0,
|
||||||
|
.amsdu = false,
|
||||||
|
.timeout = 0,
|
||||||
|
};
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
|
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
|
||||||
|
@ -467,10 +480,8 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
|
||||||
*/
|
*/
|
||||||
synchronize_net();
|
synchronize_net();
|
||||||
|
|
||||||
start_seq_num = sta->tid_seq[tid] >> 4;
|
params.ssn = sta->tid_seq[tid] >> 4;
|
||||||
|
ret = drv_ampdu_action(local, sdata, ¶ms);
|
||||||
ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
|
|
||||||
&sta->sta, tid, &start_seq_num, 0, false);
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ht_dbg(sdata,
|
ht_dbg(sdata,
|
||||||
"BA request denied - HW unavailable for %pM tid %d\n",
|
"BA request denied - HW unavailable for %pM tid %d\n",
|
||||||
|
@ -499,7 +510,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
|
||||||
|
|
||||||
/* send AddBA request */
|
/* send AddBA request */
|
||||||
ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
|
ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
|
||||||
tid_tx->dialog_token, start_seq_num,
|
tid_tx->dialog_token, params.ssn,
|
||||||
IEEE80211_MAX_AMPDU_BUF,
|
IEEE80211_MAX_AMPDU_BUF,
|
||||||
tid_tx->timeout);
|
tid_tx->timeout);
|
||||||
}
|
}
|
||||||
|
@ -684,18 +695,24 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
|
||||||
struct sta_info *sta, u16 tid)
|
struct sta_info *sta, u16 tid)
|
||||||
{
|
{
|
||||||
struct tid_ampdu_tx *tid_tx;
|
struct tid_ampdu_tx *tid_tx;
|
||||||
|
struct ieee80211_ampdu_params params = {
|
||||||
|
.sta = &sta->sta,
|
||||||
|
.action = IEEE80211_AMPDU_TX_OPERATIONAL,
|
||||||
|
.tid = tid,
|
||||||
|
.timeout = 0,
|
||||||
|
.ssn = 0,
|
||||||
|
};
|
||||||
|
|
||||||
lockdep_assert_held(&sta->ampdu_mlme.mtx);
|
lockdep_assert_held(&sta->ampdu_mlme.mtx);
|
||||||
|
|
||||||
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
|
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
|
||||||
|
params.buf_size = tid_tx->buf_size;
|
||||||
|
params.amsdu = tid_tx->amsdu;
|
||||||
|
|
||||||
ht_dbg(sta->sdata, "Aggregation is on for %pM tid %d\n",
|
ht_dbg(sta->sdata, "Aggregation is on for %pM tid %d\n",
|
||||||
sta->sta.addr, tid);
|
sta->sta.addr, tid);
|
||||||
|
|
||||||
drv_ampdu_action(local, sta->sdata,
|
drv_ampdu_action(local, sta->sdata, ¶ms);
|
||||||
IEEE80211_AMPDU_TX_OPERATIONAL,
|
|
||||||
&sta->sta, tid, NULL, tid_tx->buf_size,
|
|
||||||
tid_tx->amsdu);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* synchronize with TX path, while splicing the TX path
|
* synchronize with TX path, while splicing the TX path
|
||||||
|
|
|
@ -339,8 +339,9 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev,
|
||||||
|
|
||||||
switch (key->conf.cipher) {
|
switch (key->conf.cipher) {
|
||||||
case WLAN_CIPHER_SUITE_TKIP:
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
iv32 = key->u.tkip.tx.iv32;
|
pn64 = atomic64_read(&key->conf.tx_pn);
|
||||||
iv16 = key->u.tkip.tx.iv16;
|
iv32 = TKIP_PN_TO_IV32(pn64);
|
||||||
|
iv16 = TKIP_PN_TO_IV16(pn64);
|
||||||
|
|
||||||
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
|
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
|
||||||
!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
|
!(key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
|
||||||
|
@ -1131,6 +1132,34 @@ static int sta_apply_parameters(struct ieee80211_local *local,
|
||||||
sta->sta.max_sp = params->max_sp;
|
sta->sta.max_sp = params->max_sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The sender might not have sent the last bit, consider it to be 0 */
|
||||||
|
if (params->ext_capab_len >= 8) {
|
||||||
|
u8 val = (params->ext_capab[7] &
|
||||||
|
WLAN_EXT_CAPA8_MAX_MSDU_IN_AMSDU_LSB) >> 7;
|
||||||
|
|
||||||
|
/* we did get all the bits, take the MSB as well */
|
||||||
|
if (params->ext_capab_len >= 9) {
|
||||||
|
u8 val_msb = params->ext_capab[8] &
|
||||||
|
WLAN_EXT_CAPA9_MAX_MSDU_IN_AMSDU_MSB;
|
||||||
|
val_msb <<= 1;
|
||||||
|
val |= val_msb;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (val) {
|
||||||
|
case 1:
|
||||||
|
sta->sta.max_amsdu_subframes = 32;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
sta->sta.max_amsdu_subframes = 16;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
sta->sta.max_amsdu_subframes = 8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sta->sta.max_amsdu_subframes = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* cfg80211 validates this (1-2007) and allows setting the AID
|
* cfg80211 validates this (1-2007) and allows setting the AID
|
||||||
* only when creating a new station entry
|
* only when creating a new station entry
|
||||||
|
@ -1160,6 +1189,7 @@ static int sta_apply_parameters(struct ieee80211_local *local,
|
||||||
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
|
ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
|
||||||
params->ht_capa, sta);
|
params->ht_capa, sta);
|
||||||
|
|
||||||
|
/* VHT can override some HT caps such as the A-MSDU max length */
|
||||||
if (params->vht_capa)
|
if (params->vht_capa)
|
||||||
ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
|
ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
|
||||||
params->vht_capa, sta);
|
params->vht_capa, sta);
|
||||||
|
|
|
@ -231,7 +231,7 @@ 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)
|
if (!sta->uploaded || !test_sta_flag(sta, WLAN_STA_ASSOC))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
max_bw = max(max_bw, ieee80211_get_sta_bw(&sta->sta));
|
max_bw = max(max_bw, ieee80211_get_sta_bw(&sta->sta));
|
||||||
|
|
|
@ -126,6 +126,7 @@ static const char *hw_flag_names[] = {
|
||||||
FLAG(SUPPORTS_AMSDU_IN_AMPDU),
|
FLAG(SUPPORTS_AMSDU_IN_AMPDU),
|
||||||
FLAG(BEACON_TX_STATUS),
|
FLAG(BEACON_TX_STATUS),
|
||||||
FLAG(NEEDS_UNIQUE_STA_ADDR),
|
FLAG(NEEDS_UNIQUE_STA_ADDR),
|
||||||
|
FLAG(SUPPORTS_REORDERING_BUFFER),
|
||||||
#undef FLAG
|
#undef FLAG
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -132,9 +132,10 @@ static ssize_t key_tx_spec_read(struct file *file, char __user *userbuf,
|
||||||
len = scnprintf(buf, sizeof(buf), "\n");
|
len = scnprintf(buf, sizeof(buf), "\n");
|
||||||
break;
|
break;
|
||||||
case WLAN_CIPHER_SUITE_TKIP:
|
case WLAN_CIPHER_SUITE_TKIP:
|
||||||
|
pn = atomic64_read(&key->conf.tx_pn);
|
||||||
len = scnprintf(buf, sizeof(buf), "%08x %04x\n",
|
len = scnprintf(buf, sizeof(buf), "%08x %04x\n",
|
||||||
key->u.tkip.tx.iv32,
|
TKIP_PN_TO_IV32(pn),
|
||||||
key->u.tkip.tx.iv16);
|
TKIP_PN_TO_IV16(pn));
|
||||||
break;
|
break;
|
||||||
case WLAN_CIPHER_SUITE_CCMP:
|
case WLAN_CIPHER_SUITE_CCMP:
|
||||||
case WLAN_CIPHER_SUITE_CCMP_256:
|
case WLAN_CIPHER_SUITE_CCMP_256:
|
||||||
|
|
|
@ -284,9 +284,7 @@ int drv_switch_vif_chanctx(struct ieee80211_local *local,
|
||||||
|
|
||||||
int drv_ampdu_action(struct ieee80211_local *local,
|
int drv_ampdu_action(struct ieee80211_local *local,
|
||||||
struct ieee80211_sub_if_data *sdata,
|
struct ieee80211_sub_if_data *sdata,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params)
|
||||||
struct ieee80211_sta *sta, u16 tid,
|
|
||||||
u16 *ssn, u8 buf_size, bool amsdu)
|
|
||||||
{
|
{
|
||||||
int ret = -EOPNOTSUPP;
|
int ret = -EOPNOTSUPP;
|
||||||
|
|
||||||
|
@ -296,12 +294,10 @@ int drv_ampdu_action(struct ieee80211_local *local,
|
||||||
if (!check_sdata_in_driver(sdata))
|
if (!check_sdata_in_driver(sdata))
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
trace_drv_ampdu_action(local, sdata, action, sta, tid,
|
trace_drv_ampdu_action(local, sdata, params);
|
||||||
ssn, buf_size, amsdu);
|
|
||||||
|
|
||||||
if (local->ops->ampdu_action)
|
if (local->ops->ampdu_action)
|
||||||
ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action,
|
ret = local->ops->ampdu_action(&local->hw, &sdata->vif, params);
|
||||||
sta, tid, ssn, buf_size, amsdu);
|
|
||||||
|
|
||||||
trace_drv_return_int(local, ret);
|
trace_drv_return_int(local, ret);
|
||||||
|
|
||||||
|
|
|
@ -585,9 +585,7 @@ static inline int drv_tx_last_beacon(struct ieee80211_local *local)
|
||||||
|
|
||||||
int drv_ampdu_action(struct ieee80211_local *local,
|
int drv_ampdu_action(struct ieee80211_local *local,
|
||||||
struct ieee80211_sub_if_data *sdata,
|
struct ieee80211_sub_if_data *sdata,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params);
|
||||||
struct ieee80211_sta *sta, u16 tid,
|
|
||||||
u16 *ssn, u8 buf_size, bool amsdu);
|
|
||||||
|
|
||||||
static inline int drv_get_survey(struct ieee80211_local *local, int idx,
|
static inline int drv_get_survey(struct ieee80211_local *local, int idx,
|
||||||
struct survey_info *survey)
|
struct survey_info *survey)
|
||||||
|
|
|
@ -230,6 +230,11 @@ bool ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_sub_if_data *sdata,
|
||||||
/* set Rx highest rate */
|
/* set Rx highest rate */
|
||||||
ht_cap.mcs.rx_highest = ht_cap_ie->mcs.rx_highest;
|
ht_cap.mcs.rx_highest = ht_cap_ie->mcs.rx_highest;
|
||||||
|
|
||||||
|
if (ht_cap.cap & IEEE80211_HT_CAP_MAX_AMSDU)
|
||||||
|
sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_7935;
|
||||||
|
else
|
||||||
|
sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_HT_3839;
|
||||||
|
|
||||||
apply:
|
apply:
|
||||||
changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));
|
changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
||||||
* Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
|
* Copyright 2009, 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
|
||||||
|
@ -1050,9 +1051,8 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata,
|
||||||
struct cfg80211_chan_def chandef;
|
struct cfg80211_chan_def chandef;
|
||||||
enum ieee80211_sta_rx_bandwidth bw = sta->sta.bandwidth;
|
enum ieee80211_sta_rx_bandwidth bw = sta->sta.bandwidth;
|
||||||
|
|
||||||
ieee80211_ht_oper_to_chandef(channel,
|
cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT);
|
||||||
elems->ht_operation,
|
ieee80211_chandef_ht_oper(elems->ht_operation, &chandef);
|
||||||
&chandef);
|
|
||||||
|
|
||||||
memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie));
|
memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie));
|
||||||
rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
|
rates_updated |= ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
|
||||||
|
@ -1066,9 +1066,8 @@ static void ieee80211_update_sta_info(struct ieee80211_sub_if_data *sdata,
|
||||||
struct ieee80211_vht_cap cap_ie;
|
struct ieee80211_vht_cap cap_ie;
|
||||||
struct ieee80211_sta_vht_cap cap = sta->sta.vht_cap;
|
struct ieee80211_sta_vht_cap cap = sta->sta.vht_cap;
|
||||||
|
|
||||||
ieee80211_vht_oper_to_chandef(channel,
|
ieee80211_chandef_vht_oper(elems->vht_operation,
|
||||||
elems->vht_operation,
|
&chandef);
|
||||||
&chandef);
|
|
||||||
memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie));
|
memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie));
|
||||||
ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
|
ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
|
||||||
&cap_ie, sta);
|
&cap_ie, sta);
|
||||||
|
@ -1485,14 +1484,21 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
|
||||||
|
|
||||||
sdata_info(sdata, "Trigger new scan to find an IBSS to join\n");
|
sdata_info(sdata, "Trigger new scan to find an IBSS to join\n");
|
||||||
|
|
||||||
num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy,
|
|
||||||
&ifibss->chandef,
|
|
||||||
channels,
|
|
||||||
ARRAY_SIZE(channels));
|
|
||||||
scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef);
|
scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef);
|
||||||
ieee80211_request_ibss_scan(sdata, ifibss->ssid,
|
|
||||||
ifibss->ssid_len, channels, num,
|
if (ifibss->fixed_channel) {
|
||||||
scan_width);
|
num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy,
|
||||||
|
&ifibss->chandef,
|
||||||
|
channels,
|
||||||
|
ARRAY_SIZE(channels));
|
||||||
|
ieee80211_request_ibss_scan(sdata, ifibss->ssid,
|
||||||
|
ifibss->ssid_len, channels,
|
||||||
|
num, scan_width);
|
||||||
|
} else {
|
||||||
|
ieee80211_request_ibss_scan(sdata, ifibss->ssid,
|
||||||
|
ifibss->ssid_len, NULL,
|
||||||
|
0, scan_width);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
int interval = IEEE80211_SCAN_INTERVAL;
|
int interval = IEEE80211_SCAN_INTERVAL;
|
||||||
|
|
||||||
|
|
|
@ -716,7 +716,6 @@ struct ieee80211_if_mesh {
|
||||||
* back to wireless media and to the local net stack.
|
* back to wireless media and to the local net stack.
|
||||||
* @IEEE80211_SDATA_DISCONNECT_RESUME: Disconnect after resume.
|
* @IEEE80211_SDATA_DISCONNECT_RESUME: Disconnect after resume.
|
||||||
* @IEEE80211_SDATA_IN_DRIVER: indicates interface was added to driver
|
* @IEEE80211_SDATA_IN_DRIVER: indicates interface was added to driver
|
||||||
* @IEEE80211_SDATA_MU_MIMO_OWNER: indicates interface owns MU-MIMO capability
|
|
||||||
*/
|
*/
|
||||||
enum ieee80211_sub_if_data_flags {
|
enum ieee80211_sub_if_data_flags {
|
||||||
IEEE80211_SDATA_ALLMULTI = BIT(0),
|
IEEE80211_SDATA_ALLMULTI = BIT(0),
|
||||||
|
@ -724,7 +723,6 @@ enum ieee80211_sub_if_data_flags {
|
||||||
IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3),
|
IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3),
|
||||||
IEEE80211_SDATA_DISCONNECT_RESUME = BIT(4),
|
IEEE80211_SDATA_DISCONNECT_RESUME = BIT(4),
|
||||||
IEEE80211_SDATA_IN_DRIVER = BIT(5),
|
IEEE80211_SDATA_IN_DRIVER = BIT(5),
|
||||||
IEEE80211_SDATA_MU_MIMO_OWNER = BIT(6),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -804,6 +802,7 @@ enum txq_info_flags {
|
||||||
struct txq_info {
|
struct txq_info {
|
||||||
struct sk_buff_head queue;
|
struct sk_buff_head queue;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
unsigned long byte_cnt;
|
||||||
|
|
||||||
/* keep last! */
|
/* keep last! */
|
||||||
struct ieee80211_txq txq;
|
struct ieee80211_txq txq;
|
||||||
|
@ -1466,7 +1465,13 @@ ieee80211_have_rx_timestamp(struct ieee80211_rx_status *status)
|
||||||
{
|
{
|
||||||
WARN_ON_ONCE(status->flag & RX_FLAG_MACTIME_START &&
|
WARN_ON_ONCE(status->flag & RX_FLAG_MACTIME_START &&
|
||||||
status->flag & RX_FLAG_MACTIME_END);
|
status->flag & RX_FLAG_MACTIME_END);
|
||||||
return status->flag & (RX_FLAG_MACTIME_START | RX_FLAG_MACTIME_END);
|
if (status->flag & (RX_FLAG_MACTIME_START | RX_FLAG_MACTIME_END))
|
||||||
|
return true;
|
||||||
|
/* can't handle HT/VHT preamble yet */
|
||||||
|
if (status->flag & RX_FLAG_MACTIME_PLCP_START &&
|
||||||
|
!(status->flag & (RX_FLAG_HT | RX_FLAG_VHT)))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
|
u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
|
||||||
|
@ -1714,6 +1719,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);
|
||||||
|
@ -1829,20 +1836,6 @@ static inline void ieee802_11_parse_elems(const u8 *start, size_t len,
|
||||||
ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0);
|
ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool ieee80211_rx_reorder_ready(struct sk_buff_head *frames)
|
|
||||||
{
|
|
||||||
struct sk_buff *tail = skb_peek_tail(frames);
|
|
||||||
struct ieee80211_rx_status *status;
|
|
||||||
|
|
||||||
if (!tail)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
status = IEEE80211_SKB_RXCB(tail);
|
|
||||||
if (status->flag & RX_FLAG_AMSDU_MORE)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern const int ieee802_1d_to_ac[8];
|
extern const int ieee802_1d_to_ac[8];
|
||||||
|
|
||||||
|
@ -1986,12 +1979,10 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
|
||||||
u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo);
|
u8 *ieee80211_add_wmm_info_ie(u8 *buf, u8 qosinfo);
|
||||||
|
|
||||||
/* channel management */
|
/* channel management */
|
||||||
void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
|
bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
|
||||||
const struct ieee80211_ht_operation *ht_oper,
|
struct cfg80211_chan_def *chandef);
|
||||||
struct cfg80211_chan_def *chandef);
|
bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper,
|
||||||
void ieee80211_vht_oper_to_chandef(struct ieee80211_channel *control_chan,
|
struct cfg80211_chan_def *chandef);
|
||||||
const struct ieee80211_vht_operation *oper,
|
|
||||||
struct cfg80211_chan_def *chandef);
|
|
||||||
u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c);
|
u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c);
|
||||||
|
|
||||||
int __must_check
|
int __must_check
|
||||||
|
|
|
@ -977,7 +977,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||||
if (sdata->vif.txq) {
|
if (sdata->vif.txq) {
|
||||||
struct txq_info *txqi = to_txq_info(sdata->vif.txq);
|
struct txq_info *txqi = to_txq_info(sdata->vif.txq);
|
||||||
|
|
||||||
|
spin_lock_bh(&txqi->queue.lock);
|
||||||
ieee80211_purge_tx_queue(&local->hw, &txqi->queue);
|
ieee80211_purge_tx_queue(&local->hw, &txqi->queue);
|
||||||
|
txqi->byte_cnt = 0;
|
||||||
|
spin_unlock_bh(&txqi->queue.lock);
|
||||||
|
|
||||||
atomic_set(&sdata->txqs_len[txqi->txq.ac], 0);
|
atomic_set(&sdata->txqs_len[txqi->txq.ac], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1271,6 +1275,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;
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -932,50 +932,6 @@ void ieee80211_gtk_rekey_notify(struct ieee80211_vif *vif, const u8 *bssid,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_notify);
|
EXPORT_SYMBOL_GPL(ieee80211_gtk_rekey_notify);
|
||||||
|
|
||||||
void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf,
|
|
||||||
struct ieee80211_key_seq *seq)
|
|
||||||
{
|
|
||||||
struct ieee80211_key *key;
|
|
||||||
u64 pn64;
|
|
||||||
|
|
||||||
if (WARN_ON(!(keyconf->flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
|
|
||||||
return;
|
|
||||||
|
|
||||||
key = container_of(keyconf, struct ieee80211_key, conf);
|
|
||||||
|
|
||||||
switch (key->conf.cipher) {
|
|
||||||
case WLAN_CIPHER_SUITE_TKIP:
|
|
||||||
seq->tkip.iv32 = key->u.tkip.tx.iv32;
|
|
||||||
seq->tkip.iv16 = key->u.tkip.tx.iv16;
|
|
||||||
break;
|
|
||||||
case WLAN_CIPHER_SUITE_CCMP:
|
|
||||||
case WLAN_CIPHER_SUITE_CCMP_256:
|
|
||||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
|
||||||
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
|
|
||||||
BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) !=
|
|
||||||
offsetof(typeof(*seq), aes_cmac));
|
|
||||||
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
|
|
||||||
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
|
|
||||||
BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) !=
|
|
||||||
offsetof(typeof(*seq), aes_gmac));
|
|
||||||
case WLAN_CIPHER_SUITE_GCMP:
|
|
||||||
case WLAN_CIPHER_SUITE_GCMP_256:
|
|
||||||
BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) !=
|
|
||||||
offsetof(typeof(*seq), gcmp));
|
|
||||||
pn64 = atomic64_read(&key->conf.tx_pn);
|
|
||||||
seq->ccmp.pn[5] = pn64;
|
|
||||||
seq->ccmp.pn[4] = pn64 >> 8;
|
|
||||||
seq->ccmp.pn[3] = pn64 >> 16;
|
|
||||||
seq->ccmp.pn[2] = pn64 >> 24;
|
|
||||||
seq->ccmp.pn[1] = pn64 >> 32;
|
|
||||||
seq->ccmp.pn[0] = pn64 >> 40;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
WARN_ON(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(ieee80211_get_key_tx_seq);
|
|
||||||
|
|
||||||
void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf,
|
void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf,
|
||||||
int tid, struct ieee80211_key_seq *seq)
|
int tid, struct ieee80211_key_seq *seq)
|
||||||
{
|
{
|
||||||
|
@ -1029,48 +985,6 @@ void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ieee80211_get_key_rx_seq);
|
EXPORT_SYMBOL(ieee80211_get_key_rx_seq);
|
||||||
|
|
||||||
void ieee80211_set_key_tx_seq(struct ieee80211_key_conf *keyconf,
|
|
||||||
struct ieee80211_key_seq *seq)
|
|
||||||
{
|
|
||||||
struct ieee80211_key *key;
|
|
||||||
u64 pn64;
|
|
||||||
|
|
||||||
key = container_of(keyconf, struct ieee80211_key, conf);
|
|
||||||
|
|
||||||
switch (key->conf.cipher) {
|
|
||||||
case WLAN_CIPHER_SUITE_TKIP:
|
|
||||||
key->u.tkip.tx.iv32 = seq->tkip.iv32;
|
|
||||||
key->u.tkip.tx.iv16 = seq->tkip.iv16;
|
|
||||||
break;
|
|
||||||
case WLAN_CIPHER_SUITE_CCMP:
|
|
||||||
case WLAN_CIPHER_SUITE_CCMP_256:
|
|
||||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
|
||||||
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
|
|
||||||
BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) !=
|
|
||||||
offsetof(typeof(*seq), aes_cmac));
|
|
||||||
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
|
|
||||||
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
|
|
||||||
BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) !=
|
|
||||||
offsetof(typeof(*seq), aes_gmac));
|
|
||||||
case WLAN_CIPHER_SUITE_GCMP:
|
|
||||||
case WLAN_CIPHER_SUITE_GCMP_256:
|
|
||||||
BUILD_BUG_ON(offsetof(typeof(*seq), ccmp) !=
|
|
||||||
offsetof(typeof(*seq), gcmp));
|
|
||||||
pn64 = (u64)seq->ccmp.pn[5] |
|
|
||||||
((u64)seq->ccmp.pn[4] << 8) |
|
|
||||||
((u64)seq->ccmp.pn[3] << 16) |
|
|
||||||
((u64)seq->ccmp.pn[2] << 24) |
|
|
||||||
((u64)seq->ccmp.pn[1] << 32) |
|
|
||||||
((u64)seq->ccmp.pn[0] << 40);
|
|
||||||
atomic64_set(&key->conf.tx_pn, pn64);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
WARN_ON(1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(ieee80211_set_key_tx_seq);
|
|
||||||
|
|
||||||
void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf,
|
void ieee80211_set_key_rx_seq(struct ieee80211_key_conf *keyconf,
|
||||||
int tid, struct ieee80211_key_seq *seq)
|
int tid, struct ieee80211_key_seq *seq)
|
||||||
{
|
{
|
||||||
|
|
|
@ -44,13 +44,17 @@ enum ieee80211_internal_tkip_state {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tkip_ctx {
|
struct tkip_ctx {
|
||||||
u32 iv32; /* current iv32 */
|
|
||||||
u16 iv16; /* current iv16 */
|
|
||||||
u16 p1k[5]; /* p1k cache */
|
u16 p1k[5]; /* p1k cache */
|
||||||
u32 p1k_iv32; /* iv32 for which p1k computed */
|
u32 p1k_iv32; /* iv32 for which p1k computed */
|
||||||
enum ieee80211_internal_tkip_state state;
|
enum ieee80211_internal_tkip_state state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct tkip_ctx_rx {
|
||||||
|
struct tkip_ctx ctx;
|
||||||
|
u32 iv32; /* current iv32 */
|
||||||
|
u16 iv16; /* current iv16 */
|
||||||
|
};
|
||||||
|
|
||||||
struct ieee80211_key {
|
struct ieee80211_key {
|
||||||
struct ieee80211_local *local;
|
struct ieee80211_local *local;
|
||||||
struct ieee80211_sub_if_data *sdata;
|
struct ieee80211_sub_if_data *sdata;
|
||||||
|
@ -71,7 +75,7 @@ struct ieee80211_key {
|
||||||
struct tkip_ctx tx;
|
struct tkip_ctx tx;
|
||||||
|
|
||||||
/* last received RSC */
|
/* last received RSC */
|
||||||
struct tkip_ctx rx[IEEE80211_NUM_TIDS];
|
struct tkip_ctx_rx rx[IEEE80211_NUM_TIDS];
|
||||||
|
|
||||||
/* number of mic failures */
|
/* number of mic failures */
|
||||||
u32 mic_failures;
|
u32 mic_failures;
|
||||||
|
|
|
@ -91,11 +91,10 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
|
||||||
if (sdata->vif.bss_conf.basic_rates != basic_rates)
|
if (sdata->vif.bss_conf.basic_rates != basic_rates)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
|
cfg80211_chandef_create(&sta_chan_def, sdata->vif.bss_conf.chandef.chan,
|
||||||
ie->ht_operation, &sta_chan_def);
|
NL80211_CHAN_NO_HT);
|
||||||
|
ieee80211_chandef_ht_oper(ie->ht_operation, &sta_chan_def);
|
||||||
ieee80211_vht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
|
ieee80211_chandef_vht_oper(ie->vht_operation, &sta_chan_def);
|
||||||
ie->vht_operation, &sta_chan_def);
|
|
||||||
|
|
||||||
if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef,
|
if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef,
|
||||||
&sta_chan_def))
|
&sta_chan_def))
|
||||||
|
|
|
@ -137,8 +137,6 @@ struct mesh_path {
|
||||||
* @copy_node: function to copy nodes of the table
|
* @copy_node: function to copy nodes of the table
|
||||||
* @size_order: determines size of the table, there will be 2^size_order hash
|
* @size_order: determines size of the table, there will be 2^size_order hash
|
||||||
* buckets
|
* buckets
|
||||||
* @mean_chain_len: maximum average length for the hash buckets' list, if it is
|
|
||||||
* reached, the table will grow
|
|
||||||
* @known_gates: list of known mesh gates and their mpaths by the station. The
|
* @known_gates: list of known mesh gates and their mpaths by the station. The
|
||||||
* gate's mpath may or may not be resolved and active.
|
* gate's mpath may or may not be resolved and active.
|
||||||
*
|
*
|
||||||
|
@ -154,7 +152,6 @@ struct mesh_table {
|
||||||
void (*free_node) (struct hlist_node *p, bool free_leafs);
|
void (*free_node) (struct hlist_node *p, bool free_leafs);
|
||||||
int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
|
int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
|
||||||
int size_order;
|
int size_order;
|
||||||
int mean_chain_len;
|
|
||||||
struct hlist_head *known_gates;
|
struct hlist_head *known_gates;
|
||||||
spinlock_t gates_lock;
|
spinlock_t gates_lock;
|
||||||
|
|
||||||
|
|
|
@ -55,16 +55,21 @@ int mpp_paths_generation;
|
||||||
static DEFINE_RWLOCK(pathtbl_resize_lock);
|
static DEFINE_RWLOCK(pathtbl_resize_lock);
|
||||||
|
|
||||||
|
|
||||||
|
static inline struct mesh_table *resize_dereference_paths(
|
||||||
|
struct mesh_table __rcu *table)
|
||||||
|
{
|
||||||
|
return rcu_dereference_protected(table,
|
||||||
|
lockdep_is_held(&pathtbl_resize_lock));
|
||||||
|
}
|
||||||
|
|
||||||
static inline struct mesh_table *resize_dereference_mesh_paths(void)
|
static inline struct mesh_table *resize_dereference_mesh_paths(void)
|
||||||
{
|
{
|
||||||
return rcu_dereference_protected(mesh_paths,
|
return resize_dereference_paths(mesh_paths);
|
||||||
lockdep_is_held(&pathtbl_resize_lock));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct mesh_table *resize_dereference_mpp_paths(void)
|
static inline struct mesh_table *resize_dereference_mpp_paths(void)
|
||||||
{
|
{
|
||||||
return rcu_dereference_protected(mpp_paths,
|
return resize_dereference_paths(mpp_paths);
|
||||||
lockdep_is_held(&pathtbl_resize_lock));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -160,11 +165,10 @@ static int mesh_table_grow(struct mesh_table *oldtbl,
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (atomic_read(&oldtbl->entries)
|
if (atomic_read(&oldtbl->entries)
|
||||||
< oldtbl->mean_chain_len * (oldtbl->hash_mask + 1))
|
< MEAN_CHAIN_LEN * (oldtbl->hash_mask + 1))
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
|
|
||||||
newtbl->free_node = oldtbl->free_node;
|
newtbl->free_node = oldtbl->free_node;
|
||||||
newtbl->mean_chain_len = oldtbl->mean_chain_len;
|
|
||||||
newtbl->copy_node = oldtbl->copy_node;
|
newtbl->copy_node = oldtbl->copy_node;
|
||||||
newtbl->known_gates = oldtbl->known_gates;
|
newtbl->known_gates = oldtbl->known_gates;
|
||||||
atomic_set(&newtbl->entries, atomic_read(&oldtbl->entries));
|
atomic_set(&newtbl->entries, atomic_read(&oldtbl->entries));
|
||||||
|
@ -585,7 +589,7 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata,
|
||||||
|
|
||||||
hlist_add_head_rcu(&new_node->list, bucket);
|
hlist_add_head_rcu(&new_node->list, bucket);
|
||||||
if (atomic_inc_return(&tbl->entries) >=
|
if (atomic_inc_return(&tbl->entries) >=
|
||||||
tbl->mean_chain_len * (tbl->hash_mask + 1))
|
MEAN_CHAIN_LEN * (tbl->hash_mask + 1))
|
||||||
grow = 1;
|
grow = 1;
|
||||||
|
|
||||||
mesh_paths_generation++;
|
mesh_paths_generation++;
|
||||||
|
@ -714,7 +718,7 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
|
||||||
|
|
||||||
hlist_add_head_rcu(&new_node->list, bucket);
|
hlist_add_head_rcu(&new_node->list, bucket);
|
||||||
if (atomic_inc_return(&tbl->entries) >=
|
if (atomic_inc_return(&tbl->entries) >=
|
||||||
tbl->mean_chain_len * (tbl->hash_mask + 1))
|
MEAN_CHAIN_LEN * (tbl->hash_mask + 1))
|
||||||
grow = 1;
|
grow = 1;
|
||||||
|
|
||||||
spin_unlock(&tbl->hashwlock[hash_idx]);
|
spin_unlock(&tbl->hashwlock[hash_idx]);
|
||||||
|
@ -835,6 +839,29 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta)
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata,
|
||||||
|
const u8 *proxy)
|
||||||
|
{
|
||||||
|
struct mesh_table *tbl;
|
||||||
|
struct mesh_path *mpp;
|
||||||
|
struct mpath_node *node;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
read_lock_bh(&pathtbl_resize_lock);
|
||||||
|
tbl = resize_dereference_mpp_paths();
|
||||||
|
for_each_mesh_entry(tbl, node, i) {
|
||||||
|
mpp = node->mpath;
|
||||||
|
if (ether_addr_equal(mpp->mpp, proxy)) {
|
||||||
|
spin_lock(&tbl->hashwlock[i]);
|
||||||
|
__mesh_path_del(tbl, node);
|
||||||
|
spin_unlock(&tbl->hashwlock[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
read_unlock_bh(&pathtbl_resize_lock);
|
||||||
|
rcu_read_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
static void table_flush_by_iface(struct mesh_table *tbl,
|
static void table_flush_by_iface(struct mesh_table *tbl,
|
||||||
struct ieee80211_sub_if_data *sdata)
|
struct ieee80211_sub_if_data *sdata)
|
||||||
{
|
{
|
||||||
|
@ -876,14 +903,17 @@ void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mesh_path_del - delete a mesh path from the table
|
* table_path_del - delete a path from the mesh or mpp table
|
||||||
*
|
*
|
||||||
* @addr: dst address (ETH_ALEN length)
|
* @tbl: mesh or mpp path table
|
||||||
* @sdata: local subif
|
* @sdata: local subif
|
||||||
|
* @addr: dst address (ETH_ALEN length)
|
||||||
*
|
*
|
||||||
* Returns: 0 if successful
|
* Returns: 0 if successful
|
||||||
*/
|
*/
|
||||||
int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
|
static int table_path_del(struct mesh_table __rcu *rcu_tbl,
|
||||||
|
struct ieee80211_sub_if_data *sdata,
|
||||||
|
const u8 *addr)
|
||||||
{
|
{
|
||||||
struct mesh_table *tbl;
|
struct mesh_table *tbl;
|
||||||
struct mesh_path *mpath;
|
struct mesh_path *mpath;
|
||||||
|
@ -892,8 +922,7 @@ int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
|
||||||
int hash_idx;
|
int hash_idx;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
read_lock_bh(&pathtbl_resize_lock);
|
tbl = resize_dereference_paths(rcu_tbl);
|
||||||
tbl = resize_dereference_mesh_paths();
|
|
||||||
hash_idx = mesh_table_hash(addr, sdata, tbl);
|
hash_idx = mesh_table_hash(addr, sdata, tbl);
|
||||||
bucket = &tbl->hash_buckets[hash_idx];
|
bucket = &tbl->hash_buckets[hash_idx];
|
||||||
|
|
||||||
|
@ -909,9 +938,50 @@ int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
|
||||||
|
|
||||||
err = -ENXIO;
|
err = -ENXIO;
|
||||||
enddel:
|
enddel:
|
||||||
mesh_paths_generation++;
|
|
||||||
spin_unlock(&tbl->hashwlock[hash_idx]);
|
spin_unlock(&tbl->hashwlock[hash_idx]);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mesh_path_del - delete a mesh path from the table
|
||||||
|
*
|
||||||
|
* @addr: dst address (ETH_ALEN length)
|
||||||
|
* @sdata: local subif
|
||||||
|
*
|
||||||
|
* Returns: 0 if successful
|
||||||
|
*/
|
||||||
|
int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
/* flush relevant mpp entries first */
|
||||||
|
mpp_flush_by_proxy(sdata, addr);
|
||||||
|
|
||||||
|
read_lock_bh(&pathtbl_resize_lock);
|
||||||
|
err = table_path_del(mesh_paths, sdata, addr);
|
||||||
|
mesh_paths_generation++;
|
||||||
read_unlock_bh(&pathtbl_resize_lock);
|
read_unlock_bh(&pathtbl_resize_lock);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mpp_path_del - delete a mesh proxy path from the table
|
||||||
|
*
|
||||||
|
* @addr: addr address (ETH_ALEN length)
|
||||||
|
* @sdata: local subif
|
||||||
|
*
|
||||||
|
* Returns: 0 if successful
|
||||||
|
*/
|
||||||
|
static int mpp_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
read_lock_bh(&pathtbl_resize_lock);
|
||||||
|
err = table_path_del(mpp_paths, sdata, addr);
|
||||||
|
mpp_paths_generation++;
|
||||||
|
read_unlock_bh(&pathtbl_resize_lock);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1076,7 +1146,6 @@ int mesh_pathtbl_init(void)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
tbl_path->free_node = &mesh_path_node_free;
|
tbl_path->free_node = &mesh_path_node_free;
|
||||||
tbl_path->copy_node = &mesh_path_node_copy;
|
tbl_path->copy_node = &mesh_path_node_copy;
|
||||||
tbl_path->mean_chain_len = MEAN_CHAIN_LEN;
|
|
||||||
tbl_path->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC);
|
tbl_path->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC);
|
||||||
if (!tbl_path->known_gates) {
|
if (!tbl_path->known_gates) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
@ -1092,7 +1161,6 @@ int mesh_pathtbl_init(void)
|
||||||
}
|
}
|
||||||
tbl_mpp->free_node = &mesh_path_node_free;
|
tbl_mpp->free_node = &mesh_path_node_free;
|
||||||
tbl_mpp->copy_node = &mesh_path_node_copy;
|
tbl_mpp->copy_node = &mesh_path_node_copy;
|
||||||
tbl_mpp->mean_chain_len = MEAN_CHAIN_LEN;
|
|
||||||
tbl_mpp->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC);
|
tbl_mpp->known_gates = kzalloc(sizeof(struct hlist_head), GFP_ATOMIC);
|
||||||
if (!tbl_mpp->known_gates) {
|
if (!tbl_mpp->known_gates) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
@ -1131,6 +1199,17 @@ void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
|
||||||
time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE))
|
time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE))
|
||||||
mesh_path_del(mpath->sdata, mpath->dst);
|
mesh_path_del(mpath->sdata, mpath->dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tbl = rcu_dereference(mpp_paths);
|
||||||
|
for_each_mesh_entry(tbl, node, i) {
|
||||||
|
if (node->mpath->sdata != sdata)
|
||||||
|
continue;
|
||||||
|
mpath = node->mpath;
|
||||||
|
if ((!(mpath->flags & MESH_PATH_FIXED)) &&
|
||||||
|
time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE))
|
||||||
|
mpp_path_del(mpath->sdata, mpath->dst);
|
||||||
|
}
|
||||||
|
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -976,6 +976,10 @@ mesh_plink_get_event(struct ieee80211_sub_if_data *sdata,
|
||||||
mpl_dbg(sdata, "Mesh plink error: no more free plinks\n");
|
mpl_dbg(sdata, "Mesh plink error: no more free plinks\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* new matching peer */
|
||||||
|
event = OPN_ACPT;
|
||||||
|
goto out;
|
||||||
} else {
|
} else {
|
||||||
if (!test_sta_flag(sta, WLAN_STA_AUTH)) {
|
if (!test_sta_flag(sta, WLAN_STA_AUTH)) {
|
||||||
mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n");
|
mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n");
|
||||||
|
@ -985,12 +989,6 @@ mesh_plink_get_event(struct ieee80211_sub_if_data *sdata,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* new matching peer */
|
|
||||||
if (!sta) {
|
|
||||||
event = OPN_ACPT;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (ftype) {
|
switch (ftype) {
|
||||||
case WLAN_SP_MESH_PEERING_OPEN:
|
case WLAN_SP_MESH_PEERING_OPEN:
|
||||||
if (!matches_local)
|
if (!matches_local)
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||||
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
||||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||||
* Copyright (C) 2015 Intel Deutschland GmbH
|
* Copyright (C) 2015 - 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
|
||||||
|
@ -196,16 +196,7 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
|
||||||
|
|
||||||
/* check 40 MHz support, if we have it */
|
/* check 40 MHz support, if we have it */
|
||||||
if (sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
|
if (sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
|
||||||
switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
|
ieee80211_chandef_ht_oper(ht_oper, chandef);
|
||||||
case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
|
|
||||||
chandef->width = NL80211_CHAN_WIDTH_40;
|
|
||||||
chandef->center_freq1 += 10;
|
|
||||||
break;
|
|
||||||
case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
|
|
||||||
chandef->width = NL80211_CHAN_WIDTH_40;
|
|
||||||
chandef->center_freq1 -= 10;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
/* 40 MHz (and 80 MHz) must be supported for VHT */
|
/* 40 MHz (and 80 MHz) must be supported for VHT */
|
||||||
ret = IEEE80211_STA_DISABLE_VHT;
|
ret = IEEE80211_STA_DISABLE_VHT;
|
||||||
|
@ -219,35 +210,11 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
vht_chandef.chan = channel;
|
vht_chandef = *chandef;
|
||||||
vht_chandef.center_freq1 =
|
if (!ieee80211_chandef_vht_oper(vht_oper, &vht_chandef)) {
|
||||||
ieee80211_channel_to_frequency(vht_oper->center_freq_seg1_idx,
|
|
||||||
channel->band);
|
|
||||||
vht_chandef.center_freq2 = 0;
|
|
||||||
|
|
||||||
switch (vht_oper->chan_width) {
|
|
||||||
case IEEE80211_VHT_CHANWIDTH_USE_HT:
|
|
||||||
vht_chandef.width = chandef->width;
|
|
||||||
vht_chandef.center_freq1 = chandef->center_freq1;
|
|
||||||
break;
|
|
||||||
case IEEE80211_VHT_CHANWIDTH_80MHZ:
|
|
||||||
vht_chandef.width = NL80211_CHAN_WIDTH_80;
|
|
||||||
break;
|
|
||||||
case IEEE80211_VHT_CHANWIDTH_160MHZ:
|
|
||||||
vht_chandef.width = NL80211_CHAN_WIDTH_160;
|
|
||||||
break;
|
|
||||||
case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
|
|
||||||
vht_chandef.width = NL80211_CHAN_WIDTH_80P80;
|
|
||||||
vht_chandef.center_freq2 =
|
|
||||||
ieee80211_channel_to_frequency(
|
|
||||||
vht_oper->center_freq_seg2_idx,
|
|
||||||
channel->band);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
|
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
|
||||||
sdata_info(sdata,
|
sdata_info(sdata,
|
||||||
"AP VHT operation IE has invalid channel width (%d), disable VHT\n",
|
"AP VHT information is invalid, disable VHT\n");
|
||||||
vht_oper->chan_width);
|
|
||||||
ret = IEEE80211_STA_DISABLE_VHT;
|
ret = IEEE80211_STA_DISABLE_VHT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -592,7 +559,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
|
||||||
struct ieee80211_sub_if_data *other;
|
struct ieee80211_sub_if_data *other;
|
||||||
|
|
||||||
list_for_each_entry_rcu(other, &local->interfaces, list) {
|
list_for_each_entry_rcu(other, &local->interfaces, list) {
|
||||||
if (other->flags & IEEE80211_SDATA_MU_MIMO_OWNER) {
|
if (other->vif.mu_mimo_owner) {
|
||||||
disable_mu_mimo = true;
|
disable_mu_mimo = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -600,7 +567,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
|
||||||
if (disable_mu_mimo)
|
if (disable_mu_mimo)
|
||||||
cap &= ~IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
|
cap &= ~IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
|
||||||
else
|
else
|
||||||
sdata->flags |= IEEE80211_SDATA_MU_MIMO_OWNER;
|
sdata->vif.mu_mimo_owner = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
mask = IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
|
mask = IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK;
|
||||||
|
@ -1638,8 +1605,7 @@ void ieee80211_dynamic_ps_timer(unsigned long data)
|
||||||
|
|
||||||
void ieee80211_dfs_cac_timer_work(struct work_struct *work)
|
void ieee80211_dfs_cac_timer_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct delayed_work *delayed_work =
|
struct delayed_work *delayed_work = to_delayed_work(work);
|
||||||
container_of(work, struct delayed_work, work);
|
|
||||||
struct ieee80211_sub_if_data *sdata =
|
struct ieee80211_sub_if_data *sdata =
|
||||||
container_of(delayed_work, struct ieee80211_sub_if_data,
|
container_of(delayed_work, struct ieee80211_sub_if_data,
|
||||||
dfs_cac_timer_work);
|
dfs_cac_timer_work);
|
||||||
|
@ -2079,7 +2045,14 @@ 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));
|
||||||
sdata->flags &= ~IEEE80211_SDATA_MU_MIMO_OWNER;
|
|
||||||
|
/* 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->vif.mu_mimo_owner = false;
|
||||||
|
|
||||||
sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
|
sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
|
||||||
|
|
||||||
|
@ -2536,7 +2509,8 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
|
||||||
eth_zero_addr(sdata->u.mgd.bssid);
|
eth_zero_addr(sdata->u.mgd.bssid);
|
||||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
|
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
|
||||||
sdata->u.mgd.flags = 0;
|
sdata->u.mgd.flags = 0;
|
||||||
sdata->flags &= ~IEEE80211_SDATA_MU_MIMO_OWNER;
|
sdata->vif.mu_mimo_owner = false;
|
||||||
|
|
||||||
mutex_lock(&sdata->local->mtx);
|
mutex_lock(&sdata->local->mtx);
|
||||||
ieee80211_vif_release_channel(sdata);
|
ieee80211_vif_release_channel(sdata);
|
||||||
mutex_unlock(&sdata->local->mtx);
|
mutex_unlock(&sdata->local->mtx);
|
||||||
|
@ -3571,6 +3545,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
|
||||||
elems.ht_cap_elem, elems.ht_operation,
|
elems.ht_cap_elem, elems.ht_operation,
|
||||||
elems.vht_operation, bssid, &changed)) {
|
elems.vht_operation, bssid, &changed)) {
|
||||||
mutex_unlock(&local->sta_mtx);
|
mutex_unlock(&local->sta_mtx);
|
||||||
|
sdata_info(sdata,
|
||||||
|
"failed to follow AP %pM bandwidth change, disconnect\n",
|
||||||
|
bssid);
|
||||||
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
|
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
|
||||||
WLAN_REASON_DEAUTH_LEAVING,
|
WLAN_REASON_DEAUTH_LEAVING,
|
||||||
true, deauth_buf);
|
true, deauth_buf);
|
||||||
|
@ -3946,11 +3923,9 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
|
||||||
* We actually lost the connection ... or did we?
|
* We actually lost the connection ... or did we?
|
||||||
* Let's make sure!
|
* Let's make sure!
|
||||||
*/
|
*/
|
||||||
wiphy_debug(local->hw.wiphy,
|
mlme_dbg(sdata,
|
||||||
"%s: No probe response from AP %pM"
|
"No probe response from AP %pM after %dms, disconnecting.\n",
|
||||||
" after %dms, disconnecting.\n",
|
bssid, probe_wait_ms);
|
||||||
sdata->name,
|
|
||||||
bssid, probe_wait_ms);
|
|
||||||
|
|
||||||
ieee80211_sta_connection_lost(sdata, bssid,
|
ieee80211_sta_connection_lost(sdata, bssid,
|
||||||
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, false);
|
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, false);
|
||||||
|
@ -4536,6 +4511,9 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
|
||||||
if (ifmgd->associated) {
|
if (ifmgd->associated) {
|
||||||
u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
|
u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
|
||||||
|
|
||||||
|
sdata_info(sdata,
|
||||||
|
"disconnect from AP %pM for new auth to %pM\n",
|
||||||
|
ifmgd->associated->bssid, req->bss->bssid);
|
||||||
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
|
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
|
||||||
WLAN_REASON_UNSPECIFIED,
|
WLAN_REASON_UNSPECIFIED,
|
||||||
false, frame_buf);
|
false, frame_buf);
|
||||||
|
@ -4604,6 +4582,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
||||||
if (ifmgd->associated) {
|
if (ifmgd->associated) {
|
||||||
u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
|
u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
|
||||||
|
|
||||||
|
sdata_info(sdata,
|
||||||
|
"disconnect from AP %pM for new assoc to %pM\n",
|
||||||
|
ifmgd->associated->bssid, req->bss->bssid);
|
||||||
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
|
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
|
||||||
WLAN_REASON_UNSPECIFIED,
|
WLAN_REASON_UNSPECIFIED,
|
||||||
false, frame_buf);
|
false, frame_buf);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||||
* Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
|
* Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||||
|
* Copyright(c) 2015 - 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
|
||||||
|
@ -18,6 +19,7 @@
|
||||||
#include <linux/etherdevice.h>
|
#include <linux/etherdevice.h>
|
||||||
#include <linux/rcupdate.h>
|
#include <linux/rcupdate.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
#include <net/mac80211.h>
|
#include <net/mac80211.h>
|
||||||
#include <net/ieee80211_radiotap.h>
|
#include <net/ieee80211_radiotap.h>
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
|
@ -122,7 +124,8 @@ static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len,
|
||||||
hdr = (void *)(skb->data + rtap_vendor_space);
|
hdr = (void *)(skb->data + rtap_vendor_space);
|
||||||
|
|
||||||
if (status->flag & (RX_FLAG_FAILED_FCS_CRC |
|
if (status->flag & (RX_FLAG_FAILED_FCS_CRC |
|
||||||
RX_FLAG_FAILED_PLCP_CRC))
|
RX_FLAG_FAILED_PLCP_CRC |
|
||||||
|
RX_FLAG_ONLY_MONITOR))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (unlikely(skb->len < 16 + present_fcs_len + rtap_vendor_space))
|
if (unlikely(skb->len < 16 + present_fcs_len + rtap_vendor_space))
|
||||||
|
@ -507,7 +510,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!local->monitors) {
|
if (!local->monitors || (status->flag & RX_FLAG_SKIP_MONITOR)) {
|
||||||
if (should_drop_frame(origskb, present_fcs_len,
|
if (should_drop_frame(origskb, present_fcs_len,
|
||||||
rtap_vendor_space)) {
|
rtap_vendor_space)) {
|
||||||
dev_kfree_skb(origskb);
|
dev_kfree_skb(origskb);
|
||||||
|
@ -797,6 +800,26 @@ static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
|
||||||
return RX_CONTINUE;
|
return RX_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool ieee80211_rx_reorder_ready(struct tid_ampdu_rx *tid_agg_rx,
|
||||||
|
int index)
|
||||||
|
{
|
||||||
|
struct sk_buff_head *frames = &tid_agg_rx->reorder_buf[index];
|
||||||
|
struct sk_buff *tail = skb_peek_tail(frames);
|
||||||
|
struct ieee80211_rx_status *status;
|
||||||
|
|
||||||
|
if (tid_agg_rx->reorder_buf_filtered & BIT_ULL(index))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!tail)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
status = IEEE80211_SKB_RXCB(tail);
|
||||||
|
if (status->flag & RX_FLAG_AMSDU_MORE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
|
static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
|
||||||
struct tid_ampdu_rx *tid_agg_rx,
|
struct tid_ampdu_rx *tid_agg_rx,
|
||||||
int index,
|
int index,
|
||||||
|
@ -811,7 +834,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
|
||||||
if (skb_queue_empty(skb_list))
|
if (skb_queue_empty(skb_list))
|
||||||
goto no_frame;
|
goto no_frame;
|
||||||
|
|
||||||
if (!ieee80211_rx_reorder_ready(skb_list)) {
|
if (!ieee80211_rx_reorder_ready(tid_agg_rx, index)) {
|
||||||
__skb_queue_purge(skb_list);
|
__skb_queue_purge(skb_list);
|
||||||
goto no_frame;
|
goto no_frame;
|
||||||
}
|
}
|
||||||
|
@ -825,6 +848,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
|
||||||
}
|
}
|
||||||
|
|
||||||
no_frame:
|
no_frame:
|
||||||
|
tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index);
|
||||||
tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num);
|
tid_agg_rx->head_seq_num = ieee80211_sn_inc(tid_agg_rx->head_seq_num);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -865,7 +889,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
|
||||||
|
|
||||||
/* release the buffer until next missing frame */
|
/* release the buffer until next missing frame */
|
||||||
index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
|
index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
|
||||||
if (!ieee80211_rx_reorder_ready(&tid_agg_rx->reorder_buf[index]) &&
|
if (!ieee80211_rx_reorder_ready(tid_agg_rx, index) &&
|
||||||
tid_agg_rx->stored_mpdu_num) {
|
tid_agg_rx->stored_mpdu_num) {
|
||||||
/*
|
/*
|
||||||
* No buffers ready to be released, but check whether any
|
* No buffers ready to be released, but check whether any
|
||||||
|
@ -874,8 +898,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
|
||||||
int skipped = 1;
|
int skipped = 1;
|
||||||
for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
|
for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
|
||||||
j = (j + 1) % tid_agg_rx->buf_size) {
|
j = (j + 1) % tid_agg_rx->buf_size) {
|
||||||
if (!ieee80211_rx_reorder_ready(
|
if (!ieee80211_rx_reorder_ready(tid_agg_rx, j)) {
|
||||||
&tid_agg_rx->reorder_buf[j])) {
|
|
||||||
skipped++;
|
skipped++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -902,8 +925,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
|
||||||
skipped) & IEEE80211_SN_MASK;
|
skipped) & IEEE80211_SN_MASK;
|
||||||
skipped = 0;
|
skipped = 0;
|
||||||
}
|
}
|
||||||
} else while (ieee80211_rx_reorder_ready(
|
} else while (ieee80211_rx_reorder_ready(tid_agg_rx, index)) {
|
||||||
&tid_agg_rx->reorder_buf[index])) {
|
|
||||||
ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
|
ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
|
||||||
frames);
|
frames);
|
||||||
index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
|
index = tid_agg_rx->head_seq_num % tid_agg_rx->buf_size;
|
||||||
|
@ -914,8 +936,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
|
||||||
|
|
||||||
for (; j != (index - 1) % tid_agg_rx->buf_size;
|
for (; j != (index - 1) % tid_agg_rx->buf_size;
|
||||||
j = (j + 1) % tid_agg_rx->buf_size) {
|
j = (j + 1) % tid_agg_rx->buf_size) {
|
||||||
if (ieee80211_rx_reorder_ready(
|
if (ieee80211_rx_reorder_ready(tid_agg_rx, j))
|
||||||
&tid_agg_rx->reorder_buf[j]))
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -986,7 +1007,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata
|
||||||
index = mpdu_seq_num % tid_agg_rx->buf_size;
|
index = mpdu_seq_num % tid_agg_rx->buf_size;
|
||||||
|
|
||||||
/* check if we already stored this frame */
|
/* check if we already stored this frame */
|
||||||
if (ieee80211_rx_reorder_ready(&tid_agg_rx->reorder_buf[index])) {
|
if (ieee80211_rx_reorder_ready(tid_agg_rx, index)) {
|
||||||
dev_kfree_skb(skb);
|
dev_kfree_skb(skb);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -1099,6 +1120,9 @@ ieee80211_rx_h_check_dup(struct ieee80211_rx_data *rx)
|
||||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
|
||||||
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
||||||
|
|
||||||
|
if (status->flag & RX_FLAG_DUP_VALIDATED)
|
||||||
|
return RX_CONTINUE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Drop duplicate 802.11 retransmissions
|
* Drop duplicate 802.11 retransmissions
|
||||||
* (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery")
|
* (IEEE 802.11-2012: 9.3.2.10 "Duplicate detection and recovery")
|
||||||
|
@ -2199,9 +2223,6 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx)
|
||||||
skb->dev = dev;
|
skb->dev = dev;
|
||||||
__skb_queue_head_init(&frame_list);
|
__skb_queue_head_init(&frame_list);
|
||||||
|
|
||||||
if (skb_linearize(skb))
|
|
||||||
return RX_DROP_UNUSABLE;
|
|
||||||
|
|
||||||
ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
|
ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
|
||||||
rx->sdata->vif.type,
|
rx->sdata->vif.type,
|
||||||
rx->local->hw.extra_tx_headroom, true);
|
rx->local->hw.extra_tx_headroom, true);
|
||||||
|
@ -2231,7 +2252,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
|
||||||
struct ieee80211_local *local = rx->local;
|
struct ieee80211_local *local = rx->local;
|
||||||
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
||||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||||
u16 q, hdrlen;
|
u16 ac, q, hdrlen;
|
||||||
|
|
||||||
hdr = (struct ieee80211_hdr *) skb->data;
|
hdr = (struct ieee80211_hdr *) skb->data;
|
||||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||||
|
@ -2290,6 +2311,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
|
||||||
spin_lock_bh(&mppath->state_lock);
|
spin_lock_bh(&mppath->state_lock);
|
||||||
if (!ether_addr_equal(mppath->mpp, mpp_addr))
|
if (!ether_addr_equal(mppath->mpp, mpp_addr))
|
||||||
memcpy(mppath->mpp, mpp_addr, ETH_ALEN);
|
memcpy(mppath->mpp, mpp_addr, ETH_ALEN);
|
||||||
|
mppath->exp_time = jiffies;
|
||||||
spin_unlock_bh(&mppath->state_lock);
|
spin_unlock_bh(&mppath->state_lock);
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
@ -2300,7 +2322,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
|
||||||
ether_addr_equal(sdata->vif.addr, hdr->addr3))
|
ether_addr_equal(sdata->vif.addr, hdr->addr3))
|
||||||
return RX_CONTINUE;
|
return RX_CONTINUE;
|
||||||
|
|
||||||
q = ieee80211_select_queue_80211(sdata, skb, hdr);
|
ac = ieee80211_select_queue_80211(sdata, skb, hdr);
|
||||||
|
q = sdata->vif.hw_queue[ac];
|
||||||
if (ieee80211_queue_stopped(&local->hw, q)) {
|
if (ieee80211_queue_stopped(&local->hw, q)) {
|
||||||
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion);
|
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion);
|
||||||
return RX_DROP_MONITOR;
|
return RX_DROP_MONITOR;
|
||||||
|
@ -2738,6 +2761,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;
|
||||||
}
|
}
|
||||||
|
@ -3275,6 +3303,85 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
|
||||||
ieee80211_rx_handlers(&rx, &frames);
|
ieee80211_rx_handlers(&rx, &frames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ieee80211_mark_rx_ba_filtered_frames(struct ieee80211_sta *pubsta, u8 tid,
|
||||||
|
u16 ssn, u64 filtered,
|
||||||
|
u16 received_mpdus)
|
||||||
|
{
|
||||||
|
struct sta_info *sta;
|
||||||
|
struct tid_ampdu_rx *tid_agg_rx;
|
||||||
|
struct sk_buff_head frames;
|
||||||
|
struct ieee80211_rx_data rx = {
|
||||||
|
/* This is OK -- must be QoS data frame */
|
||||||
|
.security_idx = tid,
|
||||||
|
.seqno_idx = tid,
|
||||||
|
};
|
||||||
|
int i, diff;
|
||||||
|
|
||||||
|
if (WARN_ON(!pubsta || tid >= IEEE80211_NUM_TIDS))
|
||||||
|
return;
|
||||||
|
|
||||||
|
__skb_queue_head_init(&frames);
|
||||||
|
|
||||||
|
sta = container_of(pubsta, struct sta_info, sta);
|
||||||
|
|
||||||
|
rx.sta = sta;
|
||||||
|
rx.sdata = sta->sdata;
|
||||||
|
rx.local = sta->local;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
|
||||||
|
if (!tid_agg_rx)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
spin_lock_bh(&tid_agg_rx->reorder_lock);
|
||||||
|
|
||||||
|
if (received_mpdus >= IEEE80211_SN_MODULO >> 1) {
|
||||||
|
int release;
|
||||||
|
|
||||||
|
/* release all frames in the reorder buffer */
|
||||||
|
release = (tid_agg_rx->head_seq_num + tid_agg_rx->buf_size) %
|
||||||
|
IEEE80211_SN_MODULO;
|
||||||
|
ieee80211_release_reorder_frames(sta->sdata, tid_agg_rx,
|
||||||
|
release, &frames);
|
||||||
|
/* update ssn to match received ssn */
|
||||||
|
tid_agg_rx->head_seq_num = ssn;
|
||||||
|
} else {
|
||||||
|
ieee80211_release_reorder_frames(sta->sdata, tid_agg_rx, ssn,
|
||||||
|
&frames);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* handle the case that received ssn is behind the mac ssn.
|
||||||
|
* it can be tid_agg_rx->buf_size behind and still be valid */
|
||||||
|
diff = (tid_agg_rx->head_seq_num - ssn) & IEEE80211_SN_MASK;
|
||||||
|
if (diff >= tid_agg_rx->buf_size) {
|
||||||
|
tid_agg_rx->reorder_buf_filtered = 0;
|
||||||
|
goto release;
|
||||||
|
}
|
||||||
|
filtered = filtered >> diff;
|
||||||
|
ssn += diff;
|
||||||
|
|
||||||
|
/* update bitmap */
|
||||||
|
for (i = 0; i < tid_agg_rx->buf_size; i++) {
|
||||||
|
int index = (ssn + i) % tid_agg_rx->buf_size;
|
||||||
|
|
||||||
|
tid_agg_rx->reorder_buf_filtered &= ~BIT_ULL(index);
|
||||||
|
if (filtered & BIT_ULL(i))
|
||||||
|
tid_agg_rx->reorder_buf_filtered |= BIT_ULL(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now process also frames that the filter marking released */
|
||||||
|
ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx, &frames);
|
||||||
|
|
||||||
|
release:
|
||||||
|
spin_unlock_bh(&tid_agg_rx->reorder_lock);
|
||||||
|
|
||||||
|
ieee80211_rx_handlers(&rx, &frames);
|
||||||
|
|
||||||
|
out:
|
||||||
|
rcu_read_unlock();
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(ieee80211_mark_rx_ba_filtered_frames);
|
||||||
|
|
||||||
/* main receive path */
|
/* main receive path */
|
||||||
|
|
||||||
static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
|
static bool ieee80211_accept_frame(struct ieee80211_rx_data *rx)
|
||||||
|
|
|
@ -116,6 +116,7 @@ static void __cleanup_single_sta(struct sta_info *sta)
|
||||||
|
|
||||||
ieee80211_purge_tx_queue(&local->hw, &txqi->queue);
|
ieee80211_purge_tx_queue(&local->hw, &txqi->queue);
|
||||||
atomic_sub(n, &sdata->txqs_len[txqi->txq.ac]);
|
atomic_sub(n, &sdata->txqs_len[txqi->txq.ac]);
|
||||||
|
txqi->byte_cnt = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -498,11 +499,17 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
|
||||||
{
|
{
|
||||||
struct ieee80211_local *local = sta->local;
|
struct ieee80211_local *local = sta->local;
|
||||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||||
struct station_info sinfo;
|
struct station_info *sinfo;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
lockdep_assert_held(&local->sta_mtx);
|
lockdep_assert_held(&local->sta_mtx);
|
||||||
|
|
||||||
|
sinfo = kzalloc(sizeof(struct station_info), GFP_KERNEL);
|
||||||
|
if (!sinfo) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto out_err;
|
||||||
|
}
|
||||||
|
|
||||||
/* check if STA exists already */
|
/* check if STA exists already */
|
||||||
if (sta_info_get_bss(sdata, sta->sta.addr)) {
|
if (sta_info_get_bss(sdata, sta->sta.addr)) {
|
||||||
err = -EEXIST;
|
err = -EEXIST;
|
||||||
|
@ -530,14 +537,12 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
|
||||||
/* accept BA sessions now */
|
/* accept BA sessions now */
|
||||||
clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
|
clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
|
||||||
|
|
||||||
ieee80211_recalc_min_chandef(sdata);
|
|
||||||
ieee80211_sta_debugfs_add(sta);
|
ieee80211_sta_debugfs_add(sta);
|
||||||
rate_control_add_sta_debugfs(sta);
|
rate_control_add_sta_debugfs(sta);
|
||||||
|
|
||||||
memset(&sinfo, 0, sizeof(sinfo));
|
sinfo->generation = local->sta_generation;
|
||||||
sinfo.filled = 0;
|
cfg80211_new_sta(sdata->dev, sta->sta.addr, sinfo, GFP_KERNEL);
|
||||||
sinfo.generation = local->sta_generation;
|
kfree(sinfo);
|
||||||
cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
|
|
||||||
|
|
||||||
sta_dbg(sdata, "Inserted STA %pM\n", sta->sta.addr);
|
sta_dbg(sdata, "Inserted STA %pM\n", sta->sta.addr);
|
||||||
|
|
||||||
|
@ -557,6 +562,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
|
||||||
__cleanup_single_sta(sta);
|
__cleanup_single_sta(sta);
|
||||||
out_err:
|
out_err:
|
||||||
mutex_unlock(&local->sta_mtx);
|
mutex_unlock(&local->sta_mtx);
|
||||||
|
kfree(sinfo);
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -898,7 +904,7 @@ static void __sta_info_destroy_part2(struct sta_info *sta)
|
||||||
{
|
{
|
||||||
struct ieee80211_local *local = sta->local;
|
struct ieee80211_local *local = sta->local;
|
||||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||||
struct station_info sinfo = {};
|
struct station_info *sinfo;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -936,12 +942,14 @@ static void __sta_info_destroy_part2(struct sta_info *sta)
|
||||||
|
|
||||||
sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr);
|
sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr);
|
||||||
|
|
||||||
sta_set_sinfo(sta, &sinfo);
|
sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL);
|
||||||
cfg80211_del_sta_sinfo(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
|
if (sinfo)
|
||||||
|
sta_set_sinfo(sta, sinfo);
|
||||||
|
cfg80211_del_sta_sinfo(sdata->dev, sta->sta.addr, sinfo, GFP_KERNEL);
|
||||||
|
kfree(sinfo);
|
||||||
|
|
||||||
rate_control_remove_sta_debugfs(sta);
|
rate_control_remove_sta_debugfs(sta);
|
||||||
ieee80211_sta_debugfs_remove(sta);
|
ieee80211_sta_debugfs_remove(sta);
|
||||||
ieee80211_recalc_min_chandef(sdata);
|
|
||||||
|
|
||||||
cleanup_single_sta(sta);
|
cleanup_single_sta(sta);
|
||||||
}
|
}
|
||||||
|
@ -1808,14 +1816,17 @@ int sta_info_move_state(struct sta_info *sta,
|
||||||
clear_bit(WLAN_STA_AUTH, &sta->_flags);
|
clear_bit(WLAN_STA_AUTH, &sta->_flags);
|
||||||
break;
|
break;
|
||||||
case IEEE80211_STA_AUTH:
|
case IEEE80211_STA_AUTH:
|
||||||
if (sta->sta_state == IEEE80211_STA_NONE)
|
if (sta->sta_state == IEEE80211_STA_NONE) {
|
||||||
set_bit(WLAN_STA_AUTH, &sta->_flags);
|
set_bit(WLAN_STA_AUTH, &sta->_flags);
|
||||||
else if (sta->sta_state == IEEE80211_STA_ASSOC)
|
} else if (sta->sta_state == IEEE80211_STA_ASSOC) {
|
||||||
clear_bit(WLAN_STA_ASSOC, &sta->_flags);
|
clear_bit(WLAN_STA_ASSOC, &sta->_flags);
|
||||||
|
ieee80211_recalc_min_chandef(sta->sdata);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case IEEE80211_STA_ASSOC:
|
case IEEE80211_STA_ASSOC:
|
||||||
if (sta->sta_state == IEEE80211_STA_AUTH) {
|
if (sta->sta_state == IEEE80211_STA_AUTH) {
|
||||||
set_bit(WLAN_STA_ASSOC, &sta->_flags);
|
set_bit(WLAN_STA_ASSOC, &sta->_flags);
|
||||||
|
ieee80211_recalc_min_chandef(sta->sdata);
|
||||||
} else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) {
|
} else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) {
|
||||||
if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
|
if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||||
(sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
|
(sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2005, Devicescape Software, Inc.
|
* Copyright 2002-2005, Devicescape Software, Inc.
|
||||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||||
|
* 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
|
||||||
|
@ -167,6 +168,8 @@ struct tid_ampdu_tx {
|
||||||
*
|
*
|
||||||
* @reorder_buf: buffer to reorder incoming aggregated MPDUs. An MPDU may be an
|
* @reorder_buf: buffer to reorder incoming aggregated MPDUs. An MPDU may be an
|
||||||
* A-MSDU with individually reported subframes.
|
* A-MSDU with individually reported subframes.
|
||||||
|
* @reorder_buf_filtered: bitmap indicating where there are filtered frames in
|
||||||
|
* the reorder buffer that should be ignored when releasing frames
|
||||||
* @reorder_time: jiffies when skb was added
|
* @reorder_time: jiffies when skb was added
|
||||||
* @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
|
* @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
|
||||||
* @reorder_timer: releases expired frames from the reorder buffer.
|
* @reorder_timer: releases expired frames from the reorder buffer.
|
||||||
|
@ -194,6 +197,7 @@ struct tid_ampdu_tx {
|
||||||
struct tid_ampdu_rx {
|
struct tid_ampdu_rx {
|
||||||
struct rcu_head rcu_head;
|
struct rcu_head rcu_head;
|
||||||
spinlock_t reorder_lock;
|
spinlock_t reorder_lock;
|
||||||
|
u64 reorder_buf_filtered;
|
||||||
struct sk_buff_head *reorder_buf;
|
struct sk_buff_head *reorder_buf;
|
||||||
unsigned long *reorder_time;
|
unsigned long *reorder_time;
|
||||||
struct timer_list session_timer;
|
struct timer_list session_timer;
|
||||||
|
@ -212,20 +216,21 @@ struct tid_ampdu_rx {
|
||||||
/**
|
/**
|
||||||
* struct sta_ampdu_mlme - STA aggregation information.
|
* struct sta_ampdu_mlme - STA aggregation information.
|
||||||
*
|
*
|
||||||
|
* @mtx: mutex to protect all TX data (except non-NULL assignments
|
||||||
|
* to tid_tx[idx], which are protected by the sta spinlock)
|
||||||
|
* tid_start_tx is also protected by sta->lock.
|
||||||
* @tid_rx: aggregation info for Rx per TID -- RCU protected
|
* @tid_rx: aggregation info for Rx per TID -- RCU protected
|
||||||
* @tid_tx: aggregation info for Tx per TID
|
|
||||||
* @tid_start_tx: sessions where start was requested
|
|
||||||
* @addba_req_num: number of times addBA request has been sent.
|
|
||||||
* @last_addba_req_time: timestamp of the last addBA request.
|
|
||||||
* @dialog_token_allocator: dialog token enumerator for each new session;
|
|
||||||
* @work: work struct for starting/stopping aggregation
|
|
||||||
* @tid_rx_timer_expired: bitmap indicating on which TIDs the
|
* @tid_rx_timer_expired: bitmap indicating on which TIDs the
|
||||||
* RX timer expired until the work for it runs
|
* RX timer expired until the work for it runs
|
||||||
* @tid_rx_stop_requested: bitmap indicating which BA sessions per TID the
|
* @tid_rx_stop_requested: bitmap indicating which BA sessions per TID the
|
||||||
* driver requested to close until the work for it runs
|
* driver requested to close until the work for it runs
|
||||||
* @mtx: mutex to protect all TX data (except non-NULL assignments
|
* @agg_session_valid: bitmap indicating which TID has a rx BA session open on
|
||||||
* to tid_tx[idx], which are protected by the sta spinlock)
|
* @work: work struct for starting/stopping aggregation
|
||||||
* tid_start_tx is also protected by sta->lock.
|
* @tid_tx: aggregation info for Tx per TID
|
||||||
|
* @tid_start_tx: sessions where start was requested
|
||||||
|
* @last_addba_req_time: timestamp of the last addBA request.
|
||||||
|
* @addba_req_num: number of times addBA request has been sent.
|
||||||
|
* @dialog_token_allocator: dialog token enumerator for each new session;
|
||||||
*/
|
*/
|
||||||
struct sta_ampdu_mlme {
|
struct sta_ampdu_mlme {
|
||||||
struct mutex mtx;
|
struct mutex mtx;
|
||||||
|
@ -233,6 +238,7 @@ struct sta_ampdu_mlme {
|
||||||
struct tid_ampdu_rx __rcu *tid_rx[IEEE80211_NUM_TIDS];
|
struct tid_ampdu_rx __rcu *tid_rx[IEEE80211_NUM_TIDS];
|
||||||
unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
|
unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
|
||||||
unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
|
unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
|
||||||
|
unsigned long agg_session_valid[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
|
||||||
/* tx */
|
/* tx */
|
||||||
struct work_struct work;
|
struct work_struct work;
|
||||||
struct tid_ampdu_tx __rcu *tid_tx[IEEE80211_NUM_TIDS];
|
struct tid_ampdu_tx __rcu *tid_tx[IEEE80211_NUM_TIDS];
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2004, Instant802 Networks, Inc.
|
* Copyright 2002-2004, Instant802 Networks, Inc.
|
||||||
* Copyright 2005, Devicescape Software, Inc.
|
* Copyright 2005, Devicescape Software, Inc.
|
||||||
|
* 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
|
||||||
|
@ -142,15 +143,14 @@ static void tkip_mixing_phase2(const u8 *tk, struct tkip_ctx *ctx,
|
||||||
/* Add TKIP IV and Ext. IV at @pos. @iv0, @iv1, and @iv2 are the first octets
|
/* Add TKIP IV and Ext. IV at @pos. @iv0, @iv1, and @iv2 are the first octets
|
||||||
* of the IV. Returns pointer to the octet following IVs (i.e., beginning of
|
* of the IV. Returns pointer to the octet following IVs (i.e., beginning of
|
||||||
* the packet payload). */
|
* the packet payload). */
|
||||||
u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key)
|
u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key_conf *keyconf, u64 pn)
|
||||||
{
|
{
|
||||||
lockdep_assert_held(&key->u.tkip.txlock);
|
pos = write_tkip_iv(pos, TKIP_PN_TO_IV16(pn));
|
||||||
|
*pos++ = (keyconf->keyidx << 6) | (1 << 5) /* Ext IV */;
|
||||||
pos = write_tkip_iv(pos, key->u.tkip.tx.iv16);
|
put_unaligned_le32(TKIP_PN_TO_IV32(pn), pos);
|
||||||
*pos++ = (key->conf.keyidx << 6) | (1 << 5) /* Ext IV */;
|
|
||||||
put_unaligned_le32(key->u.tkip.tx.iv32, pos);
|
|
||||||
return pos + 4;
|
return pos + 4;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(ieee80211_tkip_add_iv);
|
||||||
|
|
||||||
static void ieee80211_compute_tkip_p1k(struct ieee80211_key *key, u32 iv32)
|
static void ieee80211_compute_tkip_p1k(struct ieee80211_key *key, u32 iv32)
|
||||||
{
|
{
|
||||||
|
@ -250,6 +250,7 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
|
||||||
u8 rc4key[16], keyid, *pos = payload;
|
u8 rc4key[16], keyid, *pos = payload;
|
||||||
int res;
|
int res;
|
||||||
const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
|
const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
|
||||||
|
struct tkip_ctx_rx *rx_ctx = &key->u.tkip.rx[queue];
|
||||||
|
|
||||||
if (payload_len < 12)
|
if (payload_len < 12)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -265,37 +266,36 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
|
||||||
if ((keyid >> 6) != key->conf.keyidx)
|
if ((keyid >> 6) != key->conf.keyidx)
|
||||||
return TKIP_DECRYPT_INVALID_KEYIDX;
|
return TKIP_DECRYPT_INVALID_KEYIDX;
|
||||||
|
|
||||||
if (key->u.tkip.rx[queue].state != TKIP_STATE_NOT_INIT &&
|
if (rx_ctx->ctx.state != TKIP_STATE_NOT_INIT &&
|
||||||
(iv32 < key->u.tkip.rx[queue].iv32 ||
|
(iv32 < rx_ctx->iv32 ||
|
||||||
(iv32 == key->u.tkip.rx[queue].iv32 &&
|
(iv32 == rx_ctx->iv32 && iv16 <= rx_ctx->iv16)))
|
||||||
iv16 <= key->u.tkip.rx[queue].iv16)))
|
|
||||||
return TKIP_DECRYPT_REPLAY;
|
return TKIP_DECRYPT_REPLAY;
|
||||||
|
|
||||||
if (only_iv) {
|
if (only_iv) {
|
||||||
res = TKIP_DECRYPT_OK;
|
res = TKIP_DECRYPT_OK;
|
||||||
key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED;
|
rx_ctx->ctx.state = TKIP_STATE_PHASE1_HW_UPLOADED;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key->u.tkip.rx[queue].state == TKIP_STATE_NOT_INIT ||
|
if (rx_ctx->ctx.state == TKIP_STATE_NOT_INIT ||
|
||||||
key->u.tkip.rx[queue].iv32 != iv32) {
|
rx_ctx->iv32 != iv32) {
|
||||||
/* IV16 wrapped around - perform TKIP phase 1 */
|
/* IV16 wrapped around - perform TKIP phase 1 */
|
||||||
tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32);
|
tkip_mixing_phase1(tk, &rx_ctx->ctx, ta, iv32);
|
||||||
}
|
}
|
||||||
if (key->local->ops->update_tkip_key &&
|
if (key->local->ops->update_tkip_key &&
|
||||||
key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
|
key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
|
||||||
key->u.tkip.rx[queue].state != TKIP_STATE_PHASE1_HW_UPLOADED) {
|
rx_ctx->ctx.state != TKIP_STATE_PHASE1_HW_UPLOADED) {
|
||||||
struct ieee80211_sub_if_data *sdata = key->sdata;
|
struct ieee80211_sub_if_data *sdata = key->sdata;
|
||||||
|
|
||||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||||
sdata = container_of(key->sdata->bss,
|
sdata = container_of(key->sdata->bss,
|
||||||
struct ieee80211_sub_if_data, u.ap);
|
struct ieee80211_sub_if_data, u.ap);
|
||||||
drv_update_tkip_key(key->local, sdata, &key->conf, key->sta,
|
drv_update_tkip_key(key->local, sdata, &key->conf, key->sta,
|
||||||
iv32, key->u.tkip.rx[queue].p1k);
|
iv32, rx_ctx->ctx.p1k);
|
||||||
key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED;
|
rx_ctx->ctx.state = TKIP_STATE_PHASE1_HW_UPLOADED;
|
||||||
}
|
}
|
||||||
|
|
||||||
tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key);
|
tkip_mixing_phase2(tk, &rx_ctx->ctx, iv16, rc4key);
|
||||||
|
|
||||||
res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12);
|
res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12);
|
||||||
done:
|
done:
|
||||||
|
|
|
@ -13,8 +13,6 @@
|
||||||
#include <linux/crypto.h>
|
#include <linux/crypto.h>
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
|
|
||||||
u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key);
|
|
||||||
|
|
||||||
int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm,
|
int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm,
|
||||||
struct ieee80211_key *key,
|
struct ieee80211_key *key,
|
||||||
struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
|
|
|
@ -80,7 +80,23 @@
|
||||||
#define KEY_PR_FMT " cipher:0x%x, flags=%#x, keyidx=%d, hw_key_idx=%d"
|
#define KEY_PR_FMT " cipher:0x%x, flags=%#x, keyidx=%d, hw_key_idx=%d"
|
||||||
#define KEY_PR_ARG __entry->cipher, __entry->flags, __entry->keyidx, __entry->hw_key_idx
|
#define KEY_PR_ARG __entry->cipher, __entry->flags, __entry->keyidx, __entry->hw_key_idx
|
||||||
|
|
||||||
|
#define AMPDU_ACTION_ENTRY __field(enum ieee80211_ampdu_mlme_action, \
|
||||||
|
ieee80211_ampdu_mlme_action) \
|
||||||
|
STA_ENTRY \
|
||||||
|
__field(u16, tid) \
|
||||||
|
__field(u16, ssn) \
|
||||||
|
__field(u8, buf_size) \
|
||||||
|
__field(bool, amsdu) \
|
||||||
|
__field(u16, timeout)
|
||||||
|
#define AMPDU_ACTION_ASSIGN STA_NAMED_ASSIGN(params->sta); \
|
||||||
|
__entry->tid = params->tid; \
|
||||||
|
__entry->ssn = params->ssn; \
|
||||||
|
__entry->buf_size = params->buf_size; \
|
||||||
|
__entry->amsdu = params->amsdu; \
|
||||||
|
__entry->timeout = params->timeout;
|
||||||
|
#define AMPDU_ACTION_PR_FMT STA_PR_FMT " tid %d, ssn %d, buf_size %u, amsdu %d, timeout %d"
|
||||||
|
#define AMPDU_ACTION_PR_ARG STA_PR_ARG, __entry->tid, __entry->ssn, \
|
||||||
|
__entry->buf_size, __entry->amsdu, __entry->timeout
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tracing for driver callbacks.
|
* Tracing for driver callbacks.
|
||||||
|
@ -970,38 +986,25 @@ DEFINE_EVENT(local_only_evt, drv_tx_last_beacon,
|
||||||
TRACE_EVENT(drv_ampdu_action,
|
TRACE_EVENT(drv_ampdu_action,
|
||||||
TP_PROTO(struct ieee80211_local *local,
|
TP_PROTO(struct ieee80211_local *local,
|
||||||
struct ieee80211_sub_if_data *sdata,
|
struct ieee80211_sub_if_data *sdata,
|
||||||
enum ieee80211_ampdu_mlme_action action,
|
struct ieee80211_ampdu_params *params),
|
||||||
struct ieee80211_sta *sta, u16 tid,
|
|
||||||
u16 *ssn, u8 buf_size, bool amsdu),
|
|
||||||
|
|
||||||
TP_ARGS(local, sdata, action, sta, tid, ssn, buf_size, amsdu),
|
TP_ARGS(local, sdata, params),
|
||||||
|
|
||||||
TP_STRUCT__entry(
|
TP_STRUCT__entry(
|
||||||
LOCAL_ENTRY
|
LOCAL_ENTRY
|
||||||
STA_ENTRY
|
|
||||||
__field(u32, action)
|
|
||||||
__field(u16, tid)
|
|
||||||
__field(u16, ssn)
|
|
||||||
__field(u8, buf_size)
|
|
||||||
__field(bool, amsdu)
|
|
||||||
VIF_ENTRY
|
VIF_ENTRY
|
||||||
|
AMPDU_ACTION_ENTRY
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_fast_assign(
|
TP_fast_assign(
|
||||||
LOCAL_ASSIGN;
|
LOCAL_ASSIGN;
|
||||||
VIF_ASSIGN;
|
VIF_ASSIGN;
|
||||||
STA_ASSIGN;
|
AMPDU_ACTION_ASSIGN;
|
||||||
__entry->action = action;
|
|
||||||
__entry->tid = tid;
|
|
||||||
__entry->ssn = ssn ? *ssn : 0;
|
|
||||||
__entry->buf_size = buf_size;
|
|
||||||
__entry->amsdu = amsdu;
|
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_printk(
|
TP_printk(
|
||||||
LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d buf:%d amsdu:%d",
|
LOCAL_PR_FMT VIF_PR_FMT AMPDU_ACTION_PR_FMT,
|
||||||
LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action,
|
LOCAL_PR_ARG, VIF_PR_ARG, AMPDU_ACTION_PR_ARG
|
||||||
__entry->tid, __entry->buf_size, __entry->amsdu
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -710,6 +710,10 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
|
||||||
|
|
||||||
info->control.short_preamble = txrc.short_preamble;
|
info->control.short_preamble = txrc.short_preamble;
|
||||||
|
|
||||||
|
/* don't ask rate control when rate already injected via radiotap */
|
||||||
|
if (info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT)
|
||||||
|
return TX_CONTINUE;
|
||||||
|
|
||||||
if (tx->sta)
|
if (tx->sta)
|
||||||
assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC);
|
assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC);
|
||||||
|
|
||||||
|
@ -1266,7 +1270,11 @@ static void ieee80211_drv_tx(struct ieee80211_local *local,
|
||||||
if (atomic_read(&sdata->txqs_len[ac]) >= local->hw.txq_ac_max_pending)
|
if (atomic_read(&sdata->txqs_len[ac]) >= local->hw.txq_ac_max_pending)
|
||||||
netif_stop_subqueue(sdata->dev, ac);
|
netif_stop_subqueue(sdata->dev, ac);
|
||||||
|
|
||||||
skb_queue_tail(&txqi->queue, skb);
|
spin_lock_bh(&txqi->queue.lock);
|
||||||
|
txqi->byte_cnt += skb->len;
|
||||||
|
__skb_queue_tail(&txqi->queue, skb);
|
||||||
|
spin_unlock_bh(&txqi->queue.lock);
|
||||||
|
|
||||||
drv_wake_tx_queue(local, txqi);
|
drv_wake_tx_queue(local, txqi);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -1294,6 +1302,8 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
|
||||||
if (!skb)
|
if (!skb)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
txqi->byte_cnt -= skb->len;
|
||||||
|
|
||||||
atomic_dec(&sdata->txqs_len[ac]);
|
atomic_dec(&sdata->txqs_len[ac]);
|
||||||
if (__netif_subqueue_stopped(sdata->dev, ac))
|
if (__netif_subqueue_stopped(sdata->dev, ac))
|
||||||
ieee80211_propagate_queue_wake(local, sdata->vif.hw_queue[ac]);
|
ieee80211_propagate_queue_wake(local, sdata->vif.hw_queue[ac]);
|
||||||
|
@ -1665,15 +1675,24 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
|
||||||
ieee80211_tx(sdata, sta, skb, false);
|
ieee80211_tx(sdata, sta, skb, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
|
static bool ieee80211_parse_tx_radiotap(struct ieee80211_local *local,
|
||||||
|
struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct ieee80211_radiotap_iterator iterator;
|
struct ieee80211_radiotap_iterator iterator;
|
||||||
struct ieee80211_radiotap_header *rthdr =
|
struct ieee80211_radiotap_header *rthdr =
|
||||||
(struct ieee80211_radiotap_header *) skb->data;
|
(struct ieee80211_radiotap_header *) skb->data;
|
||||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||||
|
struct ieee80211_supported_band *sband =
|
||||||
|
local->hw.wiphy->bands[info->band];
|
||||||
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
|
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
|
||||||
NULL);
|
NULL);
|
||||||
u16 txflags;
|
u16 txflags;
|
||||||
|
u16 rate = 0;
|
||||||
|
bool rate_found = false;
|
||||||
|
u8 rate_retries = 0;
|
||||||
|
u16 rate_flags = 0;
|
||||||
|
u8 mcs_known, mcs_flags;
|
||||||
|
int i;
|
||||||
|
|
||||||
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
|
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
|
||||||
IEEE80211_TX_CTL_DONTFRAG;
|
IEEE80211_TX_CTL_DONTFRAG;
|
||||||
|
@ -1724,6 +1743,35 @@ static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
|
||||||
info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
info->flags |= IEEE80211_TX_CTL_NO_ACK;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IEEE80211_RADIOTAP_RATE:
|
||||||
|
rate = *iterator.this_arg;
|
||||||
|
rate_flags = 0;
|
||||||
|
rate_found = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IEEE80211_RADIOTAP_DATA_RETRIES:
|
||||||
|
rate_retries = *iterator.this_arg;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IEEE80211_RADIOTAP_MCS:
|
||||||
|
mcs_known = iterator.this_arg[0];
|
||||||
|
mcs_flags = iterator.this_arg[1];
|
||||||
|
if (!(mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_MCS))
|
||||||
|
break;
|
||||||
|
|
||||||
|
rate_found = true;
|
||||||
|
rate = iterator.this_arg[2];
|
||||||
|
rate_flags = IEEE80211_TX_RC_MCS;
|
||||||
|
|
||||||
|
if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_GI &&
|
||||||
|
mcs_flags & IEEE80211_RADIOTAP_MCS_SGI)
|
||||||
|
rate_flags |= IEEE80211_TX_RC_SHORT_GI;
|
||||||
|
|
||||||
|
if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_BW &&
|
||||||
|
mcs_flags & IEEE80211_RADIOTAP_MCS_BW_40)
|
||||||
|
rate_flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
|
||||||
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Please update the file
|
* Please update the file
|
||||||
* Documentation/networking/mac80211-injection.txt
|
* Documentation/networking/mac80211-injection.txt
|
||||||
|
@ -1738,6 +1786,32 @@ static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb)
|
||||||
if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
|
if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (rate_found) {
|
||||||
|
info->control.flags |= IEEE80211_TX_CTRL_RATE_INJECT;
|
||||||
|
|
||||||
|
for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
|
||||||
|
info->control.rates[i].idx = -1;
|
||||||
|
info->control.rates[i].flags = 0;
|
||||||
|
info->control.rates[i].count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rate_flags & IEEE80211_TX_RC_MCS) {
|
||||||
|
info->control.rates[0].idx = rate;
|
||||||
|
} else {
|
||||||
|
for (i = 0; i < sband->n_bitrates; i++) {
|
||||||
|
if (rate * 5 != sband->bitrates[i].bitrate)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
info->control.rates[0].idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info->control.rates[0].flags = rate_flags;
|
||||||
|
info->control.rates[0].count = min_t(u8, rate_retries + 1,
|
||||||
|
local->hw.max_rate_tries);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* remove the radiotap header
|
* remove the radiotap header
|
||||||
* iterator->_max_length was sanity-checked against
|
* iterator->_max_length was sanity-checked against
|
||||||
|
@ -1818,10 +1892,6 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
|
||||||
info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
|
info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS |
|
||||||
IEEE80211_TX_CTL_INJECTED;
|
IEEE80211_TX_CTL_INJECTED;
|
||||||
|
|
||||||
/* process and remove the injection radiotap header */
|
|
||||||
if (!ieee80211_parse_tx_radiotap(skb))
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1883,6 +1953,11 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
|
||||||
goto fail_rcu;
|
goto fail_rcu;
|
||||||
|
|
||||||
info->band = chandef->chan->band;
|
info->band = chandef->chan->band;
|
||||||
|
|
||||||
|
/* process and remove the injection radiotap header */
|
||||||
|
if (!ieee80211_parse_tx_radiotap(local, skb))
|
||||||
|
goto fail_rcu;
|
||||||
|
|
||||||
ieee80211_xmit(sdata, NULL, skb);
|
ieee80211_xmit(sdata, NULL, skb);
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
@ -2099,8 +2174,11 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
||||||
mpp_lookup = true;
|
mpp_lookup = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mpp_lookup)
|
if (mpp_lookup) {
|
||||||
mppath = mpp_path_lookup(sdata, skb->data);
|
mppath = mpp_path_lookup(sdata, skb->data);
|
||||||
|
if (mppath)
|
||||||
|
mppath->exp_time = jiffies;
|
||||||
|
}
|
||||||
|
|
||||||
if (mppath && mpath)
|
if (mppath && mpath)
|
||||||
mesh_path_del(mpath->sdata, mpath->dst);
|
mesh_path_del(mpath->sdata, mpath->dst);
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||||
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
|
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
|
||||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||||
* Copyright (C) 2015 Intel Deutschland GmbH
|
* Copyright (C) 2015-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
|
||||||
|
@ -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->vif.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 |
|
||||||
|
@ -2371,10 +2374,23 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
|
||||||
|
|
||||||
switch (chandef->width) {
|
switch (chandef->width) {
|
||||||
case NL80211_CHAN_WIDTH_160:
|
case NL80211_CHAN_WIDTH_160:
|
||||||
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_160MHZ;
|
/*
|
||||||
|
* Convert 160 MHz channel width to new style as interop
|
||||||
|
* workaround.
|
||||||
|
*/
|
||||||
|
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
|
||||||
|
vht_oper->center_freq_seg2_idx = vht_oper->center_freq_seg1_idx;
|
||||||
|
if (chandef->chan->center_freq < chandef->center_freq1)
|
||||||
|
vht_oper->center_freq_seg1_idx -= 8;
|
||||||
|
else
|
||||||
|
vht_oper->center_freq_seg1_idx += 8;
|
||||||
break;
|
break;
|
||||||
case NL80211_CHAN_WIDTH_80P80:
|
case NL80211_CHAN_WIDTH_80P80:
|
||||||
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80P80MHZ;
|
/*
|
||||||
|
* Convert 80+80 MHz channel width to new style as interop
|
||||||
|
* workaround.
|
||||||
|
*/
|
||||||
|
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
|
||||||
break;
|
break;
|
||||||
case NL80211_CHAN_WIDTH_80:
|
case NL80211_CHAN_WIDTH_80:
|
||||||
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
|
vht_oper->chan_width = IEEE80211_VHT_CHANWIDTH_80MHZ;
|
||||||
|
@ -2390,17 +2406,13 @@ u8 *ieee80211_ie_build_vht_oper(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
|
||||||
return pos + sizeof(struct ieee80211_vht_operation);
|
return pos + sizeof(struct ieee80211_vht_operation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
|
bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
|
||||||
const struct ieee80211_ht_operation *ht_oper,
|
struct cfg80211_chan_def *chandef)
|
||||||
struct cfg80211_chan_def *chandef)
|
|
||||||
{
|
{
|
||||||
enum nl80211_channel_type channel_type;
|
enum nl80211_channel_type channel_type;
|
||||||
|
|
||||||
if (!ht_oper) {
|
if (!ht_oper)
|
||||||
cfg80211_chandef_create(chandef, control_chan,
|
return false;
|
||||||
NL80211_CHAN_NO_HT);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
|
switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
|
||||||
case IEEE80211_HT_PARAM_CHA_SEC_NONE:
|
case IEEE80211_HT_PARAM_CHA_SEC_NONE:
|
||||||
|
@ -2414,42 +2426,66 @@ void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
channel_type = NL80211_CHAN_NO_HT;
|
channel_type = NL80211_CHAN_NO_HT;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg80211_chandef_create(chandef, control_chan, channel_type);
|
cfg80211_chandef_create(chandef, chandef->chan, channel_type);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ieee80211_vht_oper_to_chandef(struct ieee80211_channel *control_chan,
|
bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper,
|
||||||
const struct ieee80211_vht_operation *oper,
|
struct cfg80211_chan_def *chandef)
|
||||||
struct cfg80211_chan_def *chandef)
|
|
||||||
{
|
{
|
||||||
if (!oper)
|
struct cfg80211_chan_def new = *chandef;
|
||||||
return;
|
int cf1, cf2;
|
||||||
|
|
||||||
chandef->chan = control_chan;
|
if (!oper)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
cf1 = ieee80211_channel_to_frequency(oper->center_freq_seg1_idx,
|
||||||
|
chandef->chan->band);
|
||||||
|
cf2 = ieee80211_channel_to_frequency(oper->center_freq_seg2_idx,
|
||||||
|
chandef->chan->band);
|
||||||
|
|
||||||
switch (oper->chan_width) {
|
switch (oper->chan_width) {
|
||||||
case IEEE80211_VHT_CHANWIDTH_USE_HT:
|
case IEEE80211_VHT_CHANWIDTH_USE_HT:
|
||||||
break;
|
break;
|
||||||
case IEEE80211_VHT_CHANWIDTH_80MHZ:
|
case IEEE80211_VHT_CHANWIDTH_80MHZ:
|
||||||
chandef->width = NL80211_CHAN_WIDTH_80;
|
new.width = NL80211_CHAN_WIDTH_80;
|
||||||
|
new.center_freq1 = cf1;
|
||||||
|
/* If needed, adjust based on the newer interop workaround. */
|
||||||
|
if (oper->center_freq_seg2_idx) {
|
||||||
|
unsigned int diff;
|
||||||
|
|
||||||
|
diff = abs(oper->center_freq_seg2_idx -
|
||||||
|
oper->center_freq_seg1_idx);
|
||||||
|
if (diff == 8) {
|
||||||
|
new.width = NL80211_CHAN_WIDTH_160;
|
||||||
|
new.center_freq1 = cf2;
|
||||||
|
} else if (diff > 8) {
|
||||||
|
new.width = NL80211_CHAN_WIDTH_80P80;
|
||||||
|
new.center_freq2 = cf2;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case IEEE80211_VHT_CHANWIDTH_160MHZ:
|
case IEEE80211_VHT_CHANWIDTH_160MHZ:
|
||||||
chandef->width = NL80211_CHAN_WIDTH_160;
|
new.width = NL80211_CHAN_WIDTH_160;
|
||||||
|
new.center_freq1 = cf1;
|
||||||
break;
|
break;
|
||||||
case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
|
case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
|
||||||
chandef->width = NL80211_CHAN_WIDTH_80P80;
|
new.width = NL80211_CHAN_WIDTH_80P80;
|
||||||
|
new.center_freq1 = cf1;
|
||||||
|
new.center_freq2 = cf2;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
chandef->center_freq1 =
|
if (!cfg80211_chandef_valid(&new))
|
||||||
ieee80211_channel_to_frequency(oper->center_freq_seg1_idx,
|
return false;
|
||||||
control_chan->band);
|
|
||||||
chandef->center_freq2 =
|
*chandef = new;
|
||||||
ieee80211_channel_to_frequency(oper->center_freq_seg2_idx,
|
return true;
|
||||||
control_chan->band);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
|
int ieee80211_parse_bitrates(struct cfg80211_chan_def *chandef,
|
||||||
|
@ -2672,6 +2708,18 @@ u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
|
||||||
sband = local->hw.wiphy->bands[status->band];
|
sband = local->hw.wiphy->bands[status->band];
|
||||||
bitrate = sband->bitrates[status->rate_idx].bitrate;
|
bitrate = sband->bitrates[status->rate_idx].bitrate;
|
||||||
ri.legacy = DIV_ROUND_UP(bitrate, (1 << shift));
|
ri.legacy = DIV_ROUND_UP(bitrate, (1 << shift));
|
||||||
|
|
||||||
|
if (status->flag & RX_FLAG_MACTIME_PLCP_START) {
|
||||||
|
/* TODO: handle HT/VHT preambles */
|
||||||
|
if (status->band == IEEE80211_BAND_5GHZ) {
|
||||||
|
ts += 20 << shift;
|
||||||
|
mpdu_offset += 2;
|
||||||
|
} else if (status->flag & RX_FLAG_SHORTPRE) {
|
||||||
|
ts += 96;
|
||||||
|
} else {
|
||||||
|
ts += 192;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rate = cfg80211_calculate_bitrate(&ri);
|
rate = cfg80211_calculate_bitrate(&ri);
|
||||||
|
@ -3357,3 +3405,17 @@ void ieee80211_init_tx_queue(struct ieee80211_sub_if_data *sdata,
|
||||||
txqi->txq.ac = IEEE80211_AC_BE;
|
txqi->txq.ac = IEEE80211_AC_BE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ieee80211_txq_get_depth(struct ieee80211_txq *txq,
|
||||||
|
unsigned long *frame_cnt,
|
||||||
|
unsigned long *byte_cnt)
|
||||||
|
{
|
||||||
|
struct txq_info *txqi = to_txq_info(txq);
|
||||||
|
|
||||||
|
if (frame_cnt)
|
||||||
|
*frame_cnt = txqi->queue.qlen;
|
||||||
|
|
||||||
|
if (byte_cnt)
|
||||||
|
*byte_cnt = txqi->byte_cnt;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(ieee80211_txq_get_depth);
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
/*
|
/*
|
||||||
* VHT handling
|
* VHT handling
|
||||||
*
|
*
|
||||||
|
* Portions of this file
|
||||||
|
* Copyright(c) 2015 - 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
|
||||||
* published by the Free Software Foundation.
|
* published by the Free Software Foundation.
|
||||||
|
@ -278,6 +281,23 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
|
||||||
}
|
}
|
||||||
|
|
||||||
sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta);
|
sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta);
|
||||||
|
|
||||||
|
/* If HT IE reported 3839 bytes only, stay with that size. */
|
||||||
|
if (sta->sta.max_amsdu_len == IEEE80211_MAX_MPDU_LEN_HT_3839)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) {
|
||||||
|
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
|
||||||
|
sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_11454;
|
||||||
|
break;
|
||||||
|
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991:
|
||||||
|
sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_7991;
|
||||||
|
break;
|
||||||
|
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895:
|
||||||
|
default:
|
||||||
|
sta->sta.max_amsdu_len = IEEE80211_MAX_MPDU_LEN_VHT_3895;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
@ -425,6 +445,43 @@ 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->vif.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(bss_conf->mu_group.membership,
|
||||||
|
mgmt->u.action.u.vht_group_notif.membership,
|
||||||
|
WLAN_MEMBERSHIP_LEN);
|
||||||
|
memcpy(bss_conf->mu_group.position,
|
||||||
|
mgmt->u.action.u.vht_group_notif.position,
|
||||||
|
WLAN_USER_POSITION_LEN);
|
||||||
|
|
||||||
|
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_MU_GROUPS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ieee80211_update_mu_groups(struct ieee80211_vif *vif,
|
||||||
|
const u8 *membership, const u8 *position)
|
||||||
|
{
|
||||||
|
struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
|
||||||
|
|
||||||
|
if (WARN_ON_ONCE(!vif->mu_mimo_owner))
|
||||||
|
return;
|
||||||
|
|
||||||
|
memcpy(bss_conf->mu_group.membership, membership, WLAN_MEMBERSHIP_LEN);
|
||||||
|
memcpy(bss_conf->mu_group.position, position, WLAN_USER_POSITION_LEN);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(ieee80211_update_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)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2004, Instant802 Networks, Inc.
|
* Copyright 2002-2004, Instant802 Networks, Inc.
|
||||||
* Copyright 2008, Jouni Malinen <j@w1.fi>
|
* Copyright 2008, Jouni Malinen <j@w1.fi>
|
||||||
|
* 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
|
||||||
|
@ -183,7 +184,6 @@ mic_fail_no_key:
|
||||||
return RX_DROP_UNUSABLE;
|
return RX_DROP_UNUSABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
|
static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||||
|
@ -191,6 +191,7 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
|
||||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||||
unsigned int hdrlen;
|
unsigned int hdrlen;
|
||||||
int len, tail;
|
int len, tail;
|
||||||
|
u64 pn;
|
||||||
u8 *pos;
|
u8 *pos;
|
||||||
|
|
||||||
if (info->control.hw_key &&
|
if (info->control.hw_key &&
|
||||||
|
@ -222,12 +223,8 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Increase IV for the frame */
|
/* Increase IV for the frame */
|
||||||
spin_lock(&key->u.tkip.txlock);
|
pn = atomic64_inc_return(&key->conf.tx_pn);
|
||||||
key->u.tkip.tx.iv16++;
|
pos = ieee80211_tkip_add_iv(pos, &key->conf, pn);
|
||||||
if (key->u.tkip.tx.iv16 == 0)
|
|
||||||
key->u.tkip.tx.iv32++;
|
|
||||||
pos = ieee80211_tkip_add_iv(pos, key);
|
|
||||||
spin_unlock(&key->u.tkip.txlock);
|
|
||||||
|
|
||||||
/* hwaccel - with software IV */
|
/* hwaccel - with software IV */
|
||||||
if (info->control.hw_key)
|
if (info->control.hw_key)
|
||||||
|
|
|
@ -41,5 +41,4 @@ config RFKILL_GPIO
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
If you say yes here you get support of a generic gpio RFKILL
|
If you say yes here you get support of a generic gpio RFKILL
|
||||||
driver. The platform should fill in the appropriate fields in the
|
driver.
|
||||||
rfkill_gpio_platform_data structure and pass that to the driver.
|
|
||||||
|
|
|
@ -57,6 +57,8 @@ struct rfkill {
|
||||||
|
|
||||||
bool registered;
|
bool registered;
|
||||||
bool persistent;
|
bool persistent;
|
||||||
|
bool polling_paused;
|
||||||
|
bool suspended;
|
||||||
|
|
||||||
const struct rfkill_ops *ops;
|
const struct rfkill_ops *ops;
|
||||||
void *data;
|
void *data;
|
||||||
|
@ -233,29 +235,6 @@ static void rfkill_event(struct rfkill *rfkill)
|
||||||
rfkill_send_events(rfkill, RFKILL_OP_CHANGE);
|
rfkill_send_events(rfkill, RFKILL_OP_CHANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool __rfkill_set_hw_state(struct rfkill *rfkill,
|
|
||||||
bool blocked, bool *change)
|
|
||||||
{
|
|
||||||
unsigned long flags;
|
|
||||||
bool prev, any;
|
|
||||||
|
|
||||||
BUG_ON(!rfkill);
|
|
||||||
|
|
||||||
spin_lock_irqsave(&rfkill->lock, flags);
|
|
||||||
prev = !!(rfkill->state & RFKILL_BLOCK_HW);
|
|
||||||
if (blocked)
|
|
||||||
rfkill->state |= RFKILL_BLOCK_HW;
|
|
||||||
else
|
|
||||||
rfkill->state &= ~RFKILL_BLOCK_HW;
|
|
||||||
*change = prev != blocked;
|
|
||||||
any = !!(rfkill->state & RFKILL_BLOCK_ANY);
|
|
||||||
spin_unlock_irqrestore(&rfkill->lock, flags);
|
|
||||||
|
|
||||||
rfkill_led_trigger_event(rfkill);
|
|
||||||
|
|
||||||
return any;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rfkill_set_block - wrapper for set_block method
|
* rfkill_set_block - wrapper for set_block method
|
||||||
*
|
*
|
||||||
|
@ -285,7 +264,7 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked)
|
||||||
spin_lock_irqsave(&rfkill->lock, flags);
|
spin_lock_irqsave(&rfkill->lock, flags);
|
||||||
prev = rfkill->state & RFKILL_BLOCK_SW;
|
prev = rfkill->state & RFKILL_BLOCK_SW;
|
||||||
|
|
||||||
if (rfkill->state & RFKILL_BLOCK_SW)
|
if (prev)
|
||||||
rfkill->state |= RFKILL_BLOCK_SW_PREV;
|
rfkill->state |= RFKILL_BLOCK_SW_PREV;
|
||||||
else
|
else
|
||||||
rfkill->state &= ~RFKILL_BLOCK_SW_PREV;
|
rfkill->state &= ~RFKILL_BLOCK_SW_PREV;
|
||||||
|
@ -303,8 +282,8 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked)
|
||||||
spin_lock_irqsave(&rfkill->lock, flags);
|
spin_lock_irqsave(&rfkill->lock, flags);
|
||||||
if (err) {
|
if (err) {
|
||||||
/*
|
/*
|
||||||
* Failed -- reset status to _prev, this may be different
|
* Failed -- reset status to _PREV, which may be different
|
||||||
* from what set set _PREV to earlier in this function
|
* from what we have set _PREV to earlier in this function
|
||||||
* if rfkill_set_sw_state was invoked.
|
* if rfkill_set_sw_state was invoked.
|
||||||
*/
|
*/
|
||||||
if (rfkill->state & RFKILL_BLOCK_SW_PREV)
|
if (rfkill->state & RFKILL_BLOCK_SW_PREV)
|
||||||
|
@ -323,6 +302,19 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked)
|
||||||
rfkill_event(rfkill);
|
rfkill_event(rfkill);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rfkill_update_global_state(enum rfkill_type type, bool blocked)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (type != RFKILL_TYPE_ALL) {
|
||||||
|
rfkill_global_states[type].cur = blocked;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_RFKILL_TYPES; i++)
|
||||||
|
rfkill_global_states[i].cur = blocked;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_RFKILL_INPUT
|
#ifdef CONFIG_RFKILL_INPUT
|
||||||
static atomic_t rfkill_input_disabled = ATOMIC_INIT(0);
|
static atomic_t rfkill_input_disabled = ATOMIC_INIT(0);
|
||||||
|
|
||||||
|
@ -332,8 +324,7 @@ static atomic_t rfkill_input_disabled = ATOMIC_INIT(0);
|
||||||
* @blocked: the new state
|
* @blocked: the new state
|
||||||
*
|
*
|
||||||
* This function sets the state of all switches of given type,
|
* This function sets the state of all switches of given type,
|
||||||
* unless a specific switch is claimed by userspace (in which case,
|
* unless a specific switch is suspended.
|
||||||
* that switch is left alone) or suspended.
|
|
||||||
*
|
*
|
||||||
* Caller must have acquired rfkill_global_mutex.
|
* Caller must have acquired rfkill_global_mutex.
|
||||||
*/
|
*/
|
||||||
|
@ -341,15 +332,7 @@ static void __rfkill_switch_all(const enum rfkill_type type, bool blocked)
|
||||||
{
|
{
|
||||||
struct rfkill *rfkill;
|
struct rfkill *rfkill;
|
||||||
|
|
||||||
if (type == RFKILL_TYPE_ALL) {
|
rfkill_update_global_state(type, blocked);
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < NUM_RFKILL_TYPES; i++)
|
|
||||||
rfkill_global_states[i].cur = blocked;
|
|
||||||
} else {
|
|
||||||
rfkill_global_states[type].cur = blocked;
|
|
||||||
}
|
|
||||||
|
|
||||||
list_for_each_entry(rfkill, &rfkill_list, node) {
|
list_for_each_entry(rfkill, &rfkill_list, node) {
|
||||||
if (rfkill->type != type && type != RFKILL_TYPE_ALL)
|
if (rfkill->type != type && type != RFKILL_TYPE_ALL)
|
||||||
continue;
|
continue;
|
||||||
|
@ -477,17 +460,28 @@ bool rfkill_get_global_sw_state(const enum rfkill_type type)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked)
|
bool rfkill_set_hw_state(struct rfkill *rfkill, bool blocked)
|
||||||
{
|
{
|
||||||
bool ret, change;
|
unsigned long flags;
|
||||||
|
bool ret, prev;
|
||||||
|
|
||||||
ret = __rfkill_set_hw_state(rfkill, blocked, &change);
|
BUG_ON(!rfkill);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&rfkill->lock, flags);
|
||||||
|
prev = !!(rfkill->state & RFKILL_BLOCK_HW);
|
||||||
|
if (blocked)
|
||||||
|
rfkill->state |= RFKILL_BLOCK_HW;
|
||||||
|
else
|
||||||
|
rfkill->state &= ~RFKILL_BLOCK_HW;
|
||||||
|
ret = !!(rfkill->state & RFKILL_BLOCK_ANY);
|
||||||
|
spin_unlock_irqrestore(&rfkill->lock, flags);
|
||||||
|
|
||||||
|
rfkill_led_trigger_event(rfkill);
|
||||||
|
|
||||||
if (!rfkill->registered)
|
if (!rfkill->registered)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (change)
|
if (prev != blocked)
|
||||||
schedule_work(&rfkill->uevent_work);
|
schedule_work(&rfkill->uevent_work);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -582,6 +576,34 @@ void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(rfkill_set_states);
|
EXPORT_SYMBOL(rfkill_set_states);
|
||||||
|
|
||||||
|
static const char * const rfkill_types[] = {
|
||||||
|
NULL, /* RFKILL_TYPE_ALL */
|
||||||
|
"wlan",
|
||||||
|
"bluetooth",
|
||||||
|
"ultrawideband",
|
||||||
|
"wimax",
|
||||||
|
"wwan",
|
||||||
|
"gps",
|
||||||
|
"fm",
|
||||||
|
"nfc",
|
||||||
|
};
|
||||||
|
|
||||||
|
enum rfkill_type rfkill_find_type(const char *name)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
BUILD_BUG_ON(ARRAY_SIZE(rfkill_types) != NUM_RFKILL_TYPES);
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
return RFKILL_TYPE_ALL;
|
||||||
|
|
||||||
|
for (i = 1; i < NUM_RFKILL_TYPES; i++)
|
||||||
|
if (!strcmp(name, rfkill_types[i]))
|
||||||
|
return i;
|
||||||
|
return RFKILL_TYPE_ALL;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(rfkill_find_type);
|
||||||
|
|
||||||
static ssize_t name_show(struct device *dev, struct device_attribute *attr,
|
static ssize_t name_show(struct device *dev, struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
|
@ -591,38 +613,12 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr,
|
||||||
}
|
}
|
||||||
static DEVICE_ATTR_RO(name);
|
static DEVICE_ATTR_RO(name);
|
||||||
|
|
||||||
static const char *rfkill_get_type_str(enum rfkill_type type)
|
|
||||||
{
|
|
||||||
BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_NFC + 1);
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case RFKILL_TYPE_WLAN:
|
|
||||||
return "wlan";
|
|
||||||
case RFKILL_TYPE_BLUETOOTH:
|
|
||||||
return "bluetooth";
|
|
||||||
case RFKILL_TYPE_UWB:
|
|
||||||
return "ultrawideband";
|
|
||||||
case RFKILL_TYPE_WIMAX:
|
|
||||||
return "wimax";
|
|
||||||
case RFKILL_TYPE_WWAN:
|
|
||||||
return "wwan";
|
|
||||||
case RFKILL_TYPE_GPS:
|
|
||||||
return "gps";
|
|
||||||
case RFKILL_TYPE_FM:
|
|
||||||
return "fm";
|
|
||||||
case RFKILL_TYPE_NFC:
|
|
||||||
return "nfc";
|
|
||||||
default:
|
|
||||||
BUG();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t type_show(struct device *dev, struct device_attribute *attr,
|
static ssize_t type_show(struct device *dev, struct device_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
struct rfkill *rfkill = to_rfkill(dev);
|
struct rfkill *rfkill = to_rfkill(dev);
|
||||||
|
|
||||||
return sprintf(buf, "%s\n", rfkill_get_type_str(rfkill->type));
|
return sprintf(buf, "%s\n", rfkill_types[rfkill->type]);
|
||||||
}
|
}
|
||||||
static DEVICE_ATTR_RO(type);
|
static DEVICE_ATTR_RO(type);
|
||||||
|
|
||||||
|
@ -730,20 +726,12 @@ static ssize_t state_store(struct device *dev, struct device_attribute *attr,
|
||||||
}
|
}
|
||||||
static DEVICE_ATTR_RW(state);
|
static DEVICE_ATTR_RW(state);
|
||||||
|
|
||||||
static ssize_t claim_show(struct device *dev, struct device_attribute *attr,
|
|
||||||
char *buf)
|
|
||||||
{
|
|
||||||
return sprintf(buf, "%d\n", 0);
|
|
||||||
}
|
|
||||||
static DEVICE_ATTR_RO(claim);
|
|
||||||
|
|
||||||
static struct attribute *rfkill_dev_attrs[] = {
|
static struct attribute *rfkill_dev_attrs[] = {
|
||||||
&dev_attr_name.attr,
|
&dev_attr_name.attr,
|
||||||
&dev_attr_type.attr,
|
&dev_attr_type.attr,
|
||||||
&dev_attr_index.attr,
|
&dev_attr_index.attr,
|
||||||
&dev_attr_persistent.attr,
|
&dev_attr_persistent.attr,
|
||||||
&dev_attr_state.attr,
|
&dev_attr_state.attr,
|
||||||
&dev_attr_claim.attr,
|
|
||||||
&dev_attr_soft.attr,
|
&dev_attr_soft.attr,
|
||||||
&dev_attr_hard.attr,
|
&dev_attr_hard.attr,
|
||||||
NULL,
|
NULL,
|
||||||
|
@ -768,7 +756,7 @@ static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
error = add_uevent_var(env, "RFKILL_TYPE=%s",
|
error = add_uevent_var(env, "RFKILL_TYPE=%s",
|
||||||
rfkill_get_type_str(rfkill->type));
|
rfkill_types[rfkill->type]);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
spin_lock_irqsave(&rfkill->lock, flags);
|
spin_lock_irqsave(&rfkill->lock, flags);
|
||||||
|
@ -786,6 +774,7 @@ void rfkill_pause_polling(struct rfkill *rfkill)
|
||||||
if (!rfkill->ops->poll)
|
if (!rfkill->ops->poll)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
rfkill->polling_paused = true;
|
||||||
cancel_delayed_work_sync(&rfkill->poll_work);
|
cancel_delayed_work_sync(&rfkill->poll_work);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(rfkill_pause_polling);
|
EXPORT_SYMBOL(rfkill_pause_polling);
|
||||||
|
@ -797,6 +786,11 @@ void rfkill_resume_polling(struct rfkill *rfkill)
|
||||||
if (!rfkill->ops->poll)
|
if (!rfkill->ops->poll)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
rfkill->polling_paused = false;
|
||||||
|
|
||||||
|
if (rfkill->suspended)
|
||||||
|
return;
|
||||||
|
|
||||||
queue_delayed_work(system_power_efficient_wq,
|
queue_delayed_work(system_power_efficient_wq,
|
||||||
&rfkill->poll_work, 0);
|
&rfkill->poll_work, 0);
|
||||||
}
|
}
|
||||||
|
@ -807,7 +801,8 @@ static int rfkill_suspend(struct device *dev)
|
||||||
{
|
{
|
||||||
struct rfkill *rfkill = to_rfkill(dev);
|
struct rfkill *rfkill = to_rfkill(dev);
|
||||||
|
|
||||||
rfkill_pause_polling(rfkill);
|
rfkill->suspended = true;
|
||||||
|
cancel_delayed_work_sync(&rfkill->poll_work);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -817,12 +812,16 @@ static int rfkill_resume(struct device *dev)
|
||||||
struct rfkill *rfkill = to_rfkill(dev);
|
struct rfkill *rfkill = to_rfkill(dev);
|
||||||
bool cur;
|
bool cur;
|
||||||
|
|
||||||
|
rfkill->suspended = false;
|
||||||
|
|
||||||
if (!rfkill->persistent) {
|
if (!rfkill->persistent) {
|
||||||
cur = !!(rfkill->state & RFKILL_BLOCK_SW);
|
cur = !!(rfkill->state & RFKILL_BLOCK_SW);
|
||||||
rfkill_set_block(rfkill, cur);
|
rfkill_set_block(rfkill, cur);
|
||||||
}
|
}
|
||||||
|
|
||||||
rfkill_resume_polling(rfkill);
|
if (rfkill->ops->poll && !rfkill->polling_paused)
|
||||||
|
queue_delayed_work(system_power_efficient_wq,
|
||||||
|
&rfkill->poll_work, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1164,15 +1163,8 @@ static ssize_t rfkill_fop_write(struct file *file, const char __user *buf,
|
||||||
|
|
||||||
mutex_lock(&rfkill_global_mutex);
|
mutex_lock(&rfkill_global_mutex);
|
||||||
|
|
||||||
if (ev.op == RFKILL_OP_CHANGE_ALL) {
|
if (ev.op == RFKILL_OP_CHANGE_ALL)
|
||||||
if (ev.type == RFKILL_TYPE_ALL) {
|
rfkill_update_global_state(ev.type, ev.soft);
|
||||||
enum rfkill_type i;
|
|
||||||
for (i = 0; i < NUM_RFKILL_TYPES; i++)
|
|
||||||
rfkill_global_states[i].cur = ev.soft;
|
|
||||||
} else {
|
|
||||||
rfkill_global_states[ev.type].cur = ev.soft;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
list_for_each_entry(rfkill, &rfkill_list, node) {
|
list_for_each_entry(rfkill, &rfkill_list, node) {
|
||||||
if (rfkill->idx != ev.idx && ev.op != RFKILL_OP_CHANGE_ALL)
|
if (rfkill->idx != ev.idx && ev.op != RFKILL_OP_CHANGE_ALL)
|
||||||
|
@ -1261,10 +1253,8 @@ static struct miscdevice rfkill_miscdev = {
|
||||||
static int __init rfkill_init(void)
|
static int __init rfkill_init(void)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < NUM_RFKILL_TYPES; i++)
|
rfkill_update_global_state(RFKILL_TYPE_ALL, !rfkill_default_state);
|
||||||
rfkill_global_states[i].cur = !rfkill_default_state;
|
|
||||||
|
|
||||||
error = class_register(&rfkill_class);
|
error = class_register(&rfkill_class);
|
||||||
if (error)
|
if (error)
|
||||||
|
|
|
@ -27,8 +27,6 @@
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
|
|
||||||
#include <linux/rfkill-gpio.h>
|
|
||||||
|
|
||||||
struct rfkill_gpio_data {
|
struct rfkill_gpio_data {
|
||||||
const char *name;
|
const char *name;
|
||||||
enum rfkill_type type;
|
enum rfkill_type type;
|
||||||
|
@ -81,7 +79,6 @@ static int rfkill_gpio_acpi_probe(struct device *dev,
|
||||||
if (!id)
|
if (!id)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
rfkill->name = dev_name(dev);
|
|
||||||
rfkill->type = (unsigned)id->driver_data;
|
rfkill->type = (unsigned)id->driver_data;
|
||||||
|
|
||||||
return acpi_dev_add_driver_gpios(ACPI_COMPANION(dev),
|
return acpi_dev_add_driver_gpios(ACPI_COMPANION(dev),
|
||||||
|
@ -90,24 +87,27 @@ static int rfkill_gpio_acpi_probe(struct device *dev,
|
||||||
|
|
||||||
static int rfkill_gpio_probe(struct platform_device *pdev)
|
static int rfkill_gpio_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct rfkill_gpio_platform_data *pdata = pdev->dev.platform_data;
|
|
||||||
struct rfkill_gpio_data *rfkill;
|
struct rfkill_gpio_data *rfkill;
|
||||||
struct gpio_desc *gpio;
|
struct gpio_desc *gpio;
|
||||||
|
const char *type_name;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
rfkill = devm_kzalloc(&pdev->dev, sizeof(*rfkill), GFP_KERNEL);
|
rfkill = devm_kzalloc(&pdev->dev, sizeof(*rfkill), GFP_KERNEL);
|
||||||
if (!rfkill)
|
if (!rfkill)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
device_property_read_string(&pdev->dev, "name", &rfkill->name);
|
||||||
|
device_property_read_string(&pdev->dev, "type", &type_name);
|
||||||
|
|
||||||
|
if (!rfkill->name)
|
||||||
|
rfkill->name = dev_name(&pdev->dev);
|
||||||
|
|
||||||
|
rfkill->type = rfkill_find_type(type_name);
|
||||||
|
|
||||||
if (ACPI_HANDLE(&pdev->dev)) {
|
if (ACPI_HANDLE(&pdev->dev)) {
|
||||||
ret = rfkill_gpio_acpi_probe(&pdev->dev, rfkill);
|
ret = rfkill_gpio_acpi_probe(&pdev->dev, rfkill);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
} else if (pdata) {
|
|
||||||
rfkill->name = pdata->name;
|
|
||||||
rfkill->type = pdata->type;
|
|
||||||
} else {
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rfkill->clk = devm_clk_get(&pdev->dev, NULL);
|
rfkill->clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
|
@ -124,10 +124,8 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
rfkill->shutdown_gpio = gpio;
|
rfkill->shutdown_gpio = gpio;
|
||||||
|
|
||||||
/* Make sure at-least one of the GPIO is defined and that
|
/* Make sure at-least one GPIO is defined for this instance */
|
||||||
* a name is specified for this instance
|
if (!rfkill->reset_gpio && !rfkill->shutdown_gpio) {
|
||||||
*/
|
|
||||||
if ((!rfkill->reset_gpio && !rfkill->shutdown_gpio) || !rfkill->name) {
|
|
||||||
dev_err(&pdev->dev, "invalid platform data\n");
|
dev_err(&pdev->dev, "invalid platform data\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,8 +50,8 @@ config CFG80211_DEVELOPER_WARNINGS
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
This option enables some additional warnings that help
|
This option enables some additional warnings that help
|
||||||
cfg80211 developers and driver developers, but that can
|
cfg80211 developers and driver developers, but beware that
|
||||||
trigger due to races with userspace.
|
they can also trigger due to races with userspace.
|
||||||
|
|
||||||
For example, when a driver reports that it was disconnected
|
For example, when a driver reports that it was disconnected
|
||||||
from the AP, but the user disconnects manually at the same
|
from the AP, but the user disconnects manually at the same
|
||||||
|
@ -61,19 +61,6 @@ config CFG80211_DEVELOPER_WARNINGS
|
||||||
on it (or mac80211).
|
on it (or mac80211).
|
||||||
|
|
||||||
|
|
||||||
config CFG80211_REG_DEBUG
|
|
||||||
bool "cfg80211 regulatory debugging"
|
|
||||||
depends on CFG80211
|
|
||||||
default n
|
|
||||||
---help---
|
|
||||||
You can enable this if you want to debug regulatory changes.
|
|
||||||
For more information on cfg80211 regulatory refer to the wireless
|
|
||||||
wiki:
|
|
||||||
|
|
||||||
http://wireless.kernel.org/en/developers/Regulatory
|
|
||||||
|
|
||||||
If unsure, say N.
|
|
||||||
|
|
||||||
config CFG80211_CERTIFICATION_ONUS
|
config CFG80211_CERTIFICATION_ONUS
|
||||||
bool "cfg80211 certification onus"
|
bool "cfg80211 certification onus"
|
||||||
depends on CFG80211 && EXPERT
|
depends on CFG80211 && EXPERT
|
||||||
|
@ -123,7 +110,7 @@ config CFG80211_REG_RELAX_NO_IR
|
||||||
interface which associated to an AP which userspace assumes or confirms
|
interface which associated to an AP which userspace assumes or confirms
|
||||||
to be an authorized master, i.e., with radar detection support and DFS
|
to be an authorized master, i.e., with radar detection support and DFS
|
||||||
capabilities. However, note that in order to not create daisy chain
|
capabilities. However, note that in order to not create daisy chain
|
||||||
scenarios, this relaxation is not allowed in cases that the BSS client
|
scenarios, this relaxation is not allowed in cases where the BSS client
|
||||||
is associated to P2P GO and in addition the P2P GO instantiated on
|
is associated to P2P GO and in addition the P2P GO instantiated on
|
||||||
a channel due to this relaxation should not allow connection from
|
a channel due to this relaxation should not allow connection from
|
||||||
non P2P clients.
|
non P2P clients.
|
||||||
|
@ -148,7 +135,7 @@ config CFG80211_DEBUGFS
|
||||||
depends on CFG80211
|
depends on CFG80211
|
||||||
depends on DEBUG_FS
|
depends on DEBUG_FS
|
||||||
---help---
|
---help---
|
||||||
You can enable this if you want to debugfs entries for cfg80211.
|
You can enable this if you want debugfs entries for cfg80211.
|
||||||
|
|
||||||
If unsure, say N.
|
If unsure, say N.
|
||||||
|
|
||||||
|
@ -159,7 +146,7 @@ config CFG80211_INTERNAL_REGDB
|
||||||
---help---
|
---help---
|
||||||
This option generates an internal data structure representing
|
This option generates an internal data structure representing
|
||||||
the wireless regulatory rules described in net/wireless/db.txt
|
the wireless regulatory rules described in net/wireless/db.txt
|
||||||
and includes code to query that database. This is an alternative
|
and includes code to query that database. This is an alternative
|
||||||
to using CRDA for defining regulatory rules for the kernel.
|
to using CRDA for defining regulatory rules for the kernel.
|
||||||
|
|
||||||
Using this option requires some parsing of the db.txt at build time,
|
Using this option requires some parsing of the db.txt at build time,
|
||||||
|
@ -172,7 +159,7 @@ config CFG80211_INTERNAL_REGDB
|
||||||
|
|
||||||
http://wireless.kernel.org/en/developers/Regulatory
|
http://wireless.kernel.org/en/developers/Regulatory
|
||||||
|
|
||||||
Most distributions have a CRDA package. So if unsure, say N.
|
Most distributions have a CRDA package. So if unsure, say N.
|
||||||
|
|
||||||
config CFG80211_CRDA_SUPPORT
|
config CFG80211_CRDA_SUPPORT
|
||||||
bool "support CRDA" if CFG80211_INTERNAL_REGDB
|
bool "support CRDA" if CFG80211_INTERNAL_REGDB
|
||||||
|
|
|
@ -352,6 +352,16 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
|
||||||
WARN_ON(ops->add_station && !ops->del_station);
|
WARN_ON(ops->add_station && !ops->del_station);
|
||||||
WARN_ON(ops->add_mpath && !ops->del_mpath);
|
WARN_ON(ops->add_mpath && !ops->del_mpath);
|
||||||
WARN_ON(ops->join_mesh && !ops->leave_mesh);
|
WARN_ON(ops->join_mesh && !ops->leave_mesh);
|
||||||
|
WARN_ON(ops->start_p2p_device && !ops->stop_p2p_device);
|
||||||
|
WARN_ON(ops->start_ap && !ops->stop_ap);
|
||||||
|
WARN_ON(ops->join_ocb && !ops->leave_ocb);
|
||||||
|
WARN_ON(ops->suspend && !ops->resume);
|
||||||
|
WARN_ON(ops->sched_scan_start && !ops->sched_scan_stop);
|
||||||
|
WARN_ON(ops->remain_on_channel && !ops->cancel_remain_on_channel);
|
||||||
|
WARN_ON(ops->tdls_channel_switch && !ops->tdls_cancel_channel_switch);
|
||||||
|
WARN_ON(ops->add_tx_ts && !ops->del_tx_ts);
|
||||||
|
WARN_ON(ops->set_tx_power && !ops->get_tx_power);
|
||||||
|
WARN_ON(ops->set_antenna && !ops->get_antenna);
|
||||||
|
|
||||||
alloc_size = sizeof(*rdev) + sizeof_priv;
|
alloc_size = sizeof(*rdev) + sizeof_priv;
|
||||||
|
|
||||||
|
|
|
@ -711,7 +711,7 @@ EXPORT_SYMBOL(cfg80211_rx_mgmt);
|
||||||
|
|
||||||
void cfg80211_dfs_channels_update_work(struct work_struct *work)
|
void cfg80211_dfs_channels_update_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct delayed_work *delayed_work;
|
struct delayed_work *delayed_work = to_delayed_work(work);
|
||||||
struct cfg80211_registered_device *rdev;
|
struct cfg80211_registered_device *rdev;
|
||||||
struct cfg80211_chan_def chandef;
|
struct cfg80211_chan_def chandef;
|
||||||
struct ieee80211_supported_band *sband;
|
struct ieee80211_supported_band *sband;
|
||||||
|
@ -721,7 +721,6 @@ void cfg80211_dfs_channels_update_work(struct work_struct *work)
|
||||||
unsigned long timeout, next_time = 0;
|
unsigned long timeout, next_time = 0;
|
||||||
int bandid, i;
|
int bandid, i;
|
||||||
|
|
||||||
delayed_work = container_of(work, struct delayed_work, work);
|
|
||||||
rdev = container_of(delayed_work, struct cfg80211_registered_device,
|
rdev = container_of(delayed_work, struct cfg80211_registered_device,
|
||||||
dfs_update_channels_wk);
|
dfs_update_channels_wk);
|
||||||
wiphy = &rdev->wiphy;
|
wiphy = &rdev->wiphy;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
|
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||||
* Copyright 2015 Intel Deutschland GmbH
|
* Copyright 2015-2016 Intel Deutschland GmbH
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/if.h>
|
#include <linux/if.h>
|
||||||
|
@ -401,6 +401,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
|
||||||
[NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
|
[NL80211_ATTR_NETNS_FD] = { .type = NLA_U32 },
|
||||||
[NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
|
[NL80211_ATTR_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
|
||||||
[NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
|
[NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
|
||||||
|
[NL80211_ATTR_PBSS] = { .type = NLA_FLAG },
|
||||||
};
|
};
|
||||||
|
|
||||||
/* policy for the key attributes */
|
/* policy for the key attributes */
|
||||||
|
@ -3461,6 +3462,10 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
|
||||||
return PTR_ERR(params.acl);
|
return PTR_ERR(params.acl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
|
||||||
|
if (params.pbss && !rdev->wiphy.bands[IEEE80211_BAND_60GHZ])
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
wdev_lock(wdev);
|
wdev_lock(wdev);
|
||||||
err = rdev_start_ap(rdev, dev, ¶ms);
|
err = rdev_start_ap(rdev, dev, ¶ms);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
|
@ -7281,9 +7286,11 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
|
if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
|
||||||
if (!(rdev->wiphy.features &
|
if (!((rdev->wiphy.features &
|
||||||
NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) ||
|
NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
|
||||||
!(rdev->wiphy.features & NL80211_FEATURE_QUIET))
|
(rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
|
||||||
|
!wiphy_ext_feature_isset(&rdev->wiphy,
|
||||||
|
NL80211_EXT_FEATURE_RRM))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
req.flags |= ASSOC_REQ_USE_RRM;
|
req.flags |= ASSOC_REQ_USE_RRM;
|
||||||
}
|
}
|
||||||
|
@ -7971,15 +7978,23 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
|
if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
|
||||||
if (!(rdev->wiphy.features &
|
if (!((rdev->wiphy.features &
|
||||||
NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) ||
|
NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
|
||||||
!(rdev->wiphy.features & NL80211_FEATURE_QUIET)) {
|
(rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
|
||||||
|
!wiphy_ext_feature_isset(&rdev->wiphy,
|
||||||
|
NL80211_EXT_FEATURE_RRM)) {
|
||||||
kzfree(connkeys);
|
kzfree(connkeys);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
connect.flags |= ASSOC_REQ_USE_RRM;
|
connect.flags |= ASSOC_REQ_USE_RRM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connect.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
|
||||||
|
if (connect.pbss && !rdev->wiphy.bands[IEEE80211_BAND_60GHZ]) {
|
||||||
|
kzfree(connkeys);
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
wdev_lock(dev->ieee80211_ptr);
|
wdev_lock(dev->ieee80211_ptr);
|
||||||
err = cfg80211_connect(rdev, dev, &connect, connkeys, NULL);
|
err = cfg80211_connect(rdev, dev, &connect, connkeys, NULL);
|
||||||
wdev_unlock(dev->ieee80211_ptr);
|
wdev_unlock(dev->ieee80211_ptr);
|
||||||
|
|
|
@ -43,6 +43,7 @@ static const struct radiotap_align_size rtap_namespace_sizes[] = {
|
||||||
[IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, },
|
[IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, },
|
||||||
[IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, },
|
[IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, },
|
||||||
[IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, },
|
[IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, },
|
||||||
|
[IEEE80211_RADIOTAP_VHT] = { .align = 2, .size = 12, },
|
||||||
/*
|
/*
|
||||||
* add more here as they are defined in radiotap.h
|
* add more here as they are defined in radiotap.h
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -60,13 +60,6 @@
|
||||||
#include "regdb.h"
|
#include "regdb.h"
|
||||||
#include "nl80211.h"
|
#include "nl80211.h"
|
||||||
|
|
||||||
#ifdef CONFIG_CFG80211_REG_DEBUG
|
|
||||||
#define REG_DBG_PRINT(format, args...) \
|
|
||||||
printk(KERN_DEBUG pr_fmt(format), ##args)
|
|
||||||
#else
|
|
||||||
#define REG_DBG_PRINT(args...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Grace period we give before making sure all current interfaces reside on
|
* Grace period we give before making sure all current interfaces reside on
|
||||||
* channels allowed by the current regulatory domain.
|
* channels allowed by the current regulatory domain.
|
||||||
|
@ -178,12 +171,10 @@ enum nl80211_dfs_regions reg_get_dfs_region(struct wiphy *wiphy)
|
||||||
if (wiphy_regd->dfs_region == regd->dfs_region)
|
if (wiphy_regd->dfs_region == regd->dfs_region)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
REG_DBG_PRINT("%s: device specific dfs_region "
|
pr_debug("%s: device specific dfs_region (%s) disagrees with cfg80211's central dfs_region (%s)\n",
|
||||||
"(%s) disagrees with cfg80211's "
|
dev_name(&wiphy->dev),
|
||||||
"central dfs_region (%s)\n",
|
reg_dfs_region_str(wiphy_regd->dfs_region),
|
||||||
dev_name(&wiphy->dev),
|
reg_dfs_region_str(regd->dfs_region));
|
||||||
reg_dfs_region_str(wiphy_regd->dfs_region),
|
|
||||||
reg_dfs_region_str(regd->dfs_region));
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return regd->dfs_region;
|
return regd->dfs_region;
|
||||||
|
@ -543,7 +534,7 @@ static DECLARE_DELAYED_WORK(crda_timeout, crda_timeout_work);
|
||||||
|
|
||||||
static void crda_timeout_work(struct work_struct *work)
|
static void crda_timeout_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
REG_DBG_PRINT("Timeout while waiting for CRDA to reply, restoring regulatory settings\n");
|
pr_debug("Timeout while waiting for CRDA to reply, restoring regulatory settings\n");
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
reg_crda_timeouts++;
|
reg_crda_timeouts++;
|
||||||
restore_regulatory_settings(true);
|
restore_regulatory_settings(true);
|
||||||
|
@ -585,7 +576,7 @@ static int call_crda(const char *alpha2)
|
||||||
|
|
||||||
if (!is_world_regdom((char *) alpha2))
|
if (!is_world_regdom((char *) alpha2))
|
||||||
pr_debug("Calling CRDA for country: %c%c\n",
|
pr_debug("Calling CRDA for country: %c%c\n",
|
||||||
alpha2[0], alpha2[1]);
|
alpha2[0], alpha2[1]);
|
||||||
else
|
else
|
||||||
pr_debug("Calling CRDA to update world regulatory domain\n");
|
pr_debug("Calling CRDA to update world regulatory domain\n");
|
||||||
|
|
||||||
|
@ -1132,42 +1123,6 @@ const char *reg_initiator_name(enum nl80211_reg_initiator initiator)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(reg_initiator_name);
|
EXPORT_SYMBOL(reg_initiator_name);
|
||||||
|
|
||||||
static void chan_reg_rule_print_dbg(const struct ieee80211_regdomain *regd,
|
|
||||||
struct ieee80211_channel *chan,
|
|
||||||
const struct ieee80211_reg_rule *reg_rule)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_CFG80211_REG_DEBUG
|
|
||||||
const struct ieee80211_power_rule *power_rule;
|
|
||||||
const struct ieee80211_freq_range *freq_range;
|
|
||||||
char max_antenna_gain[32], bw[32];
|
|
||||||
|
|
||||||
power_rule = ®_rule->power_rule;
|
|
||||||
freq_range = ®_rule->freq_range;
|
|
||||||
|
|
||||||
if (!power_rule->max_antenna_gain)
|
|
||||||
snprintf(max_antenna_gain, sizeof(max_antenna_gain), "N/A");
|
|
||||||
else
|
|
||||||
snprintf(max_antenna_gain, sizeof(max_antenna_gain), "%d mBi",
|
|
||||||
power_rule->max_antenna_gain);
|
|
||||||
|
|
||||||
if (reg_rule->flags & NL80211_RRF_AUTO_BW)
|
|
||||||
snprintf(bw, sizeof(bw), "%d KHz, %d KHz AUTO",
|
|
||||||
freq_range->max_bandwidth_khz,
|
|
||||||
reg_get_max_bandwidth(regd, reg_rule));
|
|
||||||
else
|
|
||||||
snprintf(bw, sizeof(bw), "%d KHz",
|
|
||||||
freq_range->max_bandwidth_khz);
|
|
||||||
|
|
||||||
REG_DBG_PRINT("Updating information on frequency %d MHz with regulatory rule:\n",
|
|
||||||
chan->center_freq);
|
|
||||||
|
|
||||||
REG_DBG_PRINT("(%d KHz - %d KHz @ %s), (%s, %d mBm)\n",
|
|
||||||
freq_range->start_freq_khz, freq_range->end_freq_khz,
|
|
||||||
bw, max_antenna_gain,
|
|
||||||
power_rule->max_eirp);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t reg_rule_to_chan_bw_flags(const struct ieee80211_regdomain *regd,
|
static uint32_t reg_rule_to_chan_bw_flags(const struct ieee80211_regdomain *regd,
|
||||||
const struct ieee80211_reg_rule *reg_rule,
|
const struct ieee80211_reg_rule *reg_rule,
|
||||||
const struct ieee80211_channel *chan)
|
const struct ieee80211_channel *chan)
|
||||||
|
@ -1242,20 +1197,19 @@ static void handle_channel(struct wiphy *wiphy,
|
||||||
if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
|
if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
|
||||||
request_wiphy && request_wiphy == wiphy &&
|
request_wiphy && request_wiphy == wiphy &&
|
||||||
request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
|
request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
|
||||||
REG_DBG_PRINT("Disabling freq %d MHz for good\n",
|
pr_debug("Disabling freq %d MHz for good\n",
|
||||||
chan->center_freq);
|
chan->center_freq);
|
||||||
chan->orig_flags |= IEEE80211_CHAN_DISABLED;
|
chan->orig_flags |= IEEE80211_CHAN_DISABLED;
|
||||||
chan->flags = chan->orig_flags;
|
chan->flags = chan->orig_flags;
|
||||||
} else {
|
} else {
|
||||||
REG_DBG_PRINT("Disabling freq %d MHz\n",
|
pr_debug("Disabling freq %d MHz\n",
|
||||||
chan->center_freq);
|
chan->center_freq);
|
||||||
chan->flags |= IEEE80211_CHAN_DISABLED;
|
chan->flags |= IEEE80211_CHAN_DISABLED;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
regd = reg_get_regdomain(wiphy);
|
regd = reg_get_regdomain(wiphy);
|
||||||
chan_reg_rule_print_dbg(regd, chan, reg_rule);
|
|
||||||
|
|
||||||
power_rule = ®_rule->power_rule;
|
power_rule = ®_rule->power_rule;
|
||||||
bw_flags = reg_rule_to_chan_bw_flags(regd, reg_rule, chan);
|
bw_flags = reg_rule_to_chan_bw_flags(regd, reg_rule, chan);
|
||||||
|
@ -1393,18 +1347,15 @@ static bool ignore_reg_update(struct wiphy *wiphy,
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!lr) {
|
if (!lr) {
|
||||||
REG_DBG_PRINT("Ignoring regulatory request set by %s "
|
pr_debug("Ignoring regulatory request set by %s since last_request is not set\n",
|
||||||
"since last_request is not set\n",
|
reg_initiator_name(initiator));
|
||||||
reg_initiator_name(initiator));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initiator == NL80211_REGDOM_SET_BY_CORE &&
|
if (initiator == NL80211_REGDOM_SET_BY_CORE &&
|
||||||
wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) {
|
wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) {
|
||||||
REG_DBG_PRINT("Ignoring regulatory request set by %s "
|
pr_debug("Ignoring regulatory request set by %s since the driver uses its own custom regulatory domain\n",
|
||||||
"since the driver uses its own custom "
|
reg_initiator_name(initiator));
|
||||||
"regulatory domain\n",
|
|
||||||
reg_initiator_name(initiator));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1415,10 +1366,8 @@ static bool ignore_reg_update(struct wiphy *wiphy,
|
||||||
if (wiphy_strict_alpha2_regd(wiphy) && !wiphy->regd &&
|
if (wiphy_strict_alpha2_regd(wiphy) && !wiphy->regd &&
|
||||||
initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
|
initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
|
||||||
!is_world_regdom(lr->alpha2)) {
|
!is_world_regdom(lr->alpha2)) {
|
||||||
REG_DBG_PRINT("Ignoring regulatory request set by %s "
|
pr_debug("Ignoring regulatory request set by %s since the driver requires its own regulatory domain to be set first\n",
|
||||||
"since the driver requires its own regulatory "
|
reg_initiator_name(initiator));
|
||||||
"domain to be set first\n",
|
|
||||||
reg_initiator_name(initiator));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1699,7 +1648,7 @@ static void reg_check_chans_work(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct cfg80211_registered_device *rdev;
|
struct cfg80211_registered_device *rdev;
|
||||||
|
|
||||||
REG_DBG_PRINT("Verifying active interfaces after reg change\n");
|
pr_debug("Verifying active interfaces after reg change\n");
|
||||||
rtnl_lock();
|
rtnl_lock();
|
||||||
|
|
||||||
list_for_each_entry(rdev, &cfg80211_rdev_list, list)
|
list_for_each_entry(rdev, &cfg80211_rdev_list, list)
|
||||||
|
@ -1781,8 +1730,8 @@ static void handle_channel_custom(struct wiphy *wiphy,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_ERR(reg_rule)) {
|
if (IS_ERR(reg_rule)) {
|
||||||
REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n",
|
pr_debug("Disabling freq %d MHz as custom regd has no rule that fits it\n",
|
||||||
chan->center_freq);
|
chan->center_freq);
|
||||||
if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) {
|
if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) {
|
||||||
chan->flags |= IEEE80211_CHAN_DISABLED;
|
chan->flags |= IEEE80211_CHAN_DISABLED;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1792,8 +1741,6 @@ static void handle_channel_custom(struct wiphy *wiphy,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
chan_reg_rule_print_dbg(regd, chan, reg_rule);
|
|
||||||
|
|
||||||
power_rule = ®_rule->power_rule;
|
power_rule = ®_rule->power_rule;
|
||||||
bw_flags = reg_rule_to_chan_bw_flags(regd, reg_rule, chan);
|
bw_flags = reg_rule_to_chan_bw_flags(regd, reg_rule, chan);
|
||||||
|
|
||||||
|
@ -2524,7 +2471,7 @@ static void restore_alpha2(char *alpha2, bool reset_user)
|
||||||
if (is_user_regdom_saved()) {
|
if (is_user_regdom_saved()) {
|
||||||
/* Unless we're asked to ignore it and reset it */
|
/* Unless we're asked to ignore it and reset it */
|
||||||
if (reset_user) {
|
if (reset_user) {
|
||||||
REG_DBG_PRINT("Restoring regulatory settings including user preference\n");
|
pr_debug("Restoring regulatory settings including user preference\n");
|
||||||
user_alpha2[0] = '9';
|
user_alpha2[0] = '9';
|
||||||
user_alpha2[1] = '7';
|
user_alpha2[1] = '7';
|
||||||
|
|
||||||
|
@ -2534,24 +2481,24 @@ static void restore_alpha2(char *alpha2, bool reset_user)
|
||||||
* back as they were for a full restore.
|
* back as they were for a full restore.
|
||||||
*/
|
*/
|
||||||
if (!is_world_regdom(ieee80211_regdom)) {
|
if (!is_world_regdom(ieee80211_regdom)) {
|
||||||
REG_DBG_PRINT("Keeping preference on module parameter ieee80211_regdom: %c%c\n",
|
pr_debug("Keeping preference on module parameter ieee80211_regdom: %c%c\n",
|
||||||
ieee80211_regdom[0], ieee80211_regdom[1]);
|
ieee80211_regdom[0], ieee80211_regdom[1]);
|
||||||
alpha2[0] = ieee80211_regdom[0];
|
alpha2[0] = ieee80211_regdom[0];
|
||||||
alpha2[1] = ieee80211_regdom[1];
|
alpha2[1] = ieee80211_regdom[1];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
REG_DBG_PRINT("Restoring regulatory settings while preserving user preference for: %c%c\n",
|
pr_debug("Restoring regulatory settings while preserving user preference for: %c%c\n",
|
||||||
user_alpha2[0], user_alpha2[1]);
|
user_alpha2[0], user_alpha2[1]);
|
||||||
alpha2[0] = user_alpha2[0];
|
alpha2[0] = user_alpha2[0];
|
||||||
alpha2[1] = user_alpha2[1];
|
alpha2[1] = user_alpha2[1];
|
||||||
}
|
}
|
||||||
} else if (!is_world_regdom(ieee80211_regdom)) {
|
} else if (!is_world_regdom(ieee80211_regdom)) {
|
||||||
REG_DBG_PRINT("Keeping preference on module parameter ieee80211_regdom: %c%c\n",
|
pr_debug("Keeping preference on module parameter ieee80211_regdom: %c%c\n",
|
||||||
ieee80211_regdom[0], ieee80211_regdom[1]);
|
ieee80211_regdom[0], ieee80211_regdom[1]);
|
||||||
alpha2[0] = ieee80211_regdom[0];
|
alpha2[0] = ieee80211_regdom[0];
|
||||||
alpha2[1] = ieee80211_regdom[1];
|
alpha2[1] = ieee80211_regdom[1];
|
||||||
} else
|
} else
|
||||||
REG_DBG_PRINT("Restoring regulatory settings\n");
|
pr_debug("Restoring regulatory settings\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void restore_custom_reg_settings(struct wiphy *wiphy)
|
static void restore_custom_reg_settings(struct wiphy *wiphy)
|
||||||
|
@ -2663,14 +2610,14 @@ static void restore_regulatory_settings(bool reset_user)
|
||||||
list_splice_tail_init(&tmp_reg_req_list, ®_requests_list);
|
list_splice_tail_init(&tmp_reg_req_list, ®_requests_list);
|
||||||
spin_unlock(®_requests_lock);
|
spin_unlock(®_requests_lock);
|
||||||
|
|
||||||
REG_DBG_PRINT("Kicking the queue\n");
|
pr_debug("Kicking the queue\n");
|
||||||
|
|
||||||
schedule_work(®_work);
|
schedule_work(®_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
void regulatory_hint_disconnect(void)
|
void regulatory_hint_disconnect(void)
|
||||||
{
|
{
|
||||||
REG_DBG_PRINT("All devices are disconnected, going to restore regulatory settings\n");
|
pr_debug("All devices are disconnected, going to restore regulatory settings\n");
|
||||||
restore_regulatory_settings(false);
|
restore_regulatory_settings(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2718,10 +2665,10 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
|
||||||
if (!reg_beacon)
|
if (!reg_beacon)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
REG_DBG_PRINT("Found new beacon on frequency: %d MHz (Ch %d) on %s\n",
|
pr_debug("Found new beacon on frequency: %d MHz (Ch %d) on %s\n",
|
||||||
beacon_chan->center_freq,
|
beacon_chan->center_freq,
|
||||||
ieee80211_frequency_to_channel(beacon_chan->center_freq),
|
ieee80211_frequency_to_channel(beacon_chan->center_freq),
|
||||||
wiphy_name(wiphy));
|
wiphy_name(wiphy));
|
||||||
|
|
||||||
memcpy(®_beacon->chan, beacon_chan,
|
memcpy(®_beacon->chan, beacon_chan,
|
||||||
sizeof(struct ieee80211_channel));
|
sizeof(struct ieee80211_channel));
|
||||||
|
@ -2800,8 +2747,7 @@ bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region)
|
||||||
case NL80211_DFS_JP:
|
case NL80211_DFS_JP:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
REG_DBG_PRINT("Ignoring uknown DFS master region: %d\n",
|
pr_debug("Ignoring uknown DFS master region: %d\n", dfs_region);
|
||||||
dfs_region);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -264,7 +264,7 @@ static struct cfg80211_bss *cfg80211_get_conn_bss(struct wireless_dev *wdev)
|
||||||
wdev->conn->params.bssid,
|
wdev->conn->params.bssid,
|
||||||
wdev->conn->params.ssid,
|
wdev->conn->params.ssid,
|
||||||
wdev->conn->params.ssid_len,
|
wdev->conn->params.ssid_len,
|
||||||
IEEE80211_BSS_TYPE_ESS,
|
wdev->conn_bss_type,
|
||||||
IEEE80211_PRIVACY(wdev->conn->params.privacy));
|
IEEE80211_PRIVACY(wdev->conn->params.privacy));
|
||||||
if (!bss)
|
if (!bss)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -687,7 +687,7 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
|
||||||
WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect);
|
WARN_ON_ONCE(!wiphy_to_rdev(wdev->wiphy)->ops->connect);
|
||||||
bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
|
bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
|
||||||
wdev->ssid, wdev->ssid_len,
|
wdev->ssid, wdev->ssid_len,
|
||||||
IEEE80211_BSS_TYPE_ESS,
|
wdev->conn_bss_type,
|
||||||
IEEE80211_PRIVACY_ANY);
|
IEEE80211_PRIVACY_ANY);
|
||||||
if (bss)
|
if (bss)
|
||||||
cfg80211_hold_bss(bss_from_pub(bss));
|
cfg80211_hold_bss(bss_from_pub(bss));
|
||||||
|
@ -846,7 +846,7 @@ void cfg80211_roamed(struct net_device *dev,
|
||||||
|
|
||||||
bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid,
|
bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, wdev->ssid,
|
||||||
wdev->ssid_len,
|
wdev->ssid_len,
|
||||||
IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY);
|
wdev->conn_bss_type, IEEE80211_PRIVACY_ANY);
|
||||||
if (WARN_ON(!bss))
|
if (WARN_ON(!bss))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1017,6 +1017,9 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
|
||||||
memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
|
memcpy(wdev->ssid, connect->ssid, connect->ssid_len);
|
||||||
wdev->ssid_len = connect->ssid_len;
|
wdev->ssid_len = connect->ssid_len;
|
||||||
|
|
||||||
|
wdev->conn_bss_type = connect->pbss ? IEEE80211_BSS_TYPE_PBSS :
|
||||||
|
IEEE80211_BSS_TYPE_ESS;
|
||||||
|
|
||||||
if (!rdev->ops->connect)
|
if (!rdev->ops->connect)
|
||||||
err = cfg80211_sme_connect(wdev, connect, prev_bssid);
|
err = cfg80211_sme_connect(wdev, connect, prev_bssid);
|
||||||
else
|
else
|
||||||
|
|
|
@ -393,9 +393,9 @@ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
|
EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
|
||||||
|
|
||||||
unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
|
static unsigned int __ieee80211_get_mesh_hdrlen(u8 flags)
|
||||||
{
|
{
|
||||||
int ae = meshhdr->flags & MESH_FLAGS_AE;
|
int ae = flags & MESH_FLAGS_AE;
|
||||||
/* 802.11-2012, 8.2.4.7.3 */
|
/* 802.11-2012, 8.2.4.7.3 */
|
||||||
switch (ae) {
|
switch (ae) {
|
||||||
default:
|
default:
|
||||||
|
@ -407,21 +407,31 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
|
||||||
return 18;
|
return 18;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
|
||||||
|
{
|
||||||
|
return __ieee80211_get_mesh_hdrlen(meshhdr->flags);
|
||||||
|
}
|
||||||
EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
|
EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen);
|
||||||
|
|
||||||
int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
|
static int __ieee80211_data_to_8023(struct sk_buff *skb, struct ethhdr *ehdr,
|
||||||
enum nl80211_iftype iftype)
|
const u8 *addr, enum nl80211_iftype iftype)
|
||||||
{
|
{
|
||||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||||
u16 hdrlen, ethertype;
|
struct {
|
||||||
u8 *payload;
|
u8 hdr[ETH_ALEN] __aligned(2);
|
||||||
u8 dst[ETH_ALEN];
|
__be16 proto;
|
||||||
u8 src[ETH_ALEN] __aligned(2);
|
} payload;
|
||||||
|
struct ethhdr tmp;
|
||||||
|
u16 hdrlen;
|
||||||
|
u8 mesh_flags = 0;
|
||||||
|
|
||||||
if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
|
if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||||
|
if (skb->len < hdrlen + 8)
|
||||||
|
return -1;
|
||||||
|
|
||||||
/* convert IEEE 802.11 header + possible LLC headers into Ethernet
|
/* convert IEEE 802.11 header + possible LLC headers into Ethernet
|
||||||
* header
|
* header
|
||||||
|
@ -432,8 +442,11 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
|
||||||
* 1 0 BSSID SA DA n/a
|
* 1 0 BSSID SA DA n/a
|
||||||
* 1 1 RA TA DA SA
|
* 1 1 RA TA DA SA
|
||||||
*/
|
*/
|
||||||
memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN);
|
memcpy(tmp.h_dest, ieee80211_get_DA(hdr), ETH_ALEN);
|
||||||
memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN);
|
memcpy(tmp.h_source, ieee80211_get_SA(hdr), ETH_ALEN);
|
||||||
|
|
||||||
|
if (iftype == NL80211_IFTYPE_MESH_POINT)
|
||||||
|
skb_copy_bits(skb, hdrlen, &mesh_flags, 1);
|
||||||
|
|
||||||
switch (hdr->frame_control &
|
switch (hdr->frame_control &
|
||||||
cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
|
cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
|
||||||
|
@ -450,44 +463,31 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
|
||||||
iftype != NL80211_IFTYPE_STATION))
|
iftype != NL80211_IFTYPE_STATION))
|
||||||
return -1;
|
return -1;
|
||||||
if (iftype == NL80211_IFTYPE_MESH_POINT) {
|
if (iftype == NL80211_IFTYPE_MESH_POINT) {
|
||||||
struct ieee80211s_hdr *meshdr =
|
if (mesh_flags & MESH_FLAGS_AE_A4)
|
||||||
(struct ieee80211s_hdr *) (skb->data + hdrlen);
|
|
||||||
/* make sure meshdr->flags is on the linear part */
|
|
||||||
if (!pskb_may_pull(skb, hdrlen + 1))
|
|
||||||
return -1;
|
return -1;
|
||||||
if (meshdr->flags & MESH_FLAGS_AE_A4)
|
if (mesh_flags & MESH_FLAGS_AE_A5_A6) {
|
||||||
return -1;
|
|
||||||
if (meshdr->flags & MESH_FLAGS_AE_A5_A6) {
|
|
||||||
skb_copy_bits(skb, hdrlen +
|
skb_copy_bits(skb, hdrlen +
|
||||||
offsetof(struct ieee80211s_hdr, eaddr1),
|
offsetof(struct ieee80211s_hdr, eaddr1),
|
||||||
dst, ETH_ALEN);
|
tmp.h_dest, 2 * ETH_ALEN);
|
||||||
skb_copy_bits(skb, hdrlen +
|
|
||||||
offsetof(struct ieee80211s_hdr, eaddr2),
|
|
||||||
src, ETH_ALEN);
|
|
||||||
}
|
}
|
||||||
hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
|
hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case cpu_to_le16(IEEE80211_FCTL_FROMDS):
|
case cpu_to_le16(IEEE80211_FCTL_FROMDS):
|
||||||
if ((iftype != NL80211_IFTYPE_STATION &&
|
if ((iftype != NL80211_IFTYPE_STATION &&
|
||||||
iftype != NL80211_IFTYPE_P2P_CLIENT &&
|
iftype != NL80211_IFTYPE_P2P_CLIENT &&
|
||||||
iftype != NL80211_IFTYPE_MESH_POINT) ||
|
iftype != NL80211_IFTYPE_MESH_POINT) ||
|
||||||
(is_multicast_ether_addr(dst) &&
|
(is_multicast_ether_addr(tmp.h_dest) &&
|
||||||
ether_addr_equal(src, addr)))
|
ether_addr_equal(tmp.h_source, addr)))
|
||||||
return -1;
|
return -1;
|
||||||
if (iftype == NL80211_IFTYPE_MESH_POINT) {
|
if (iftype == NL80211_IFTYPE_MESH_POINT) {
|
||||||
struct ieee80211s_hdr *meshdr =
|
if (mesh_flags & MESH_FLAGS_AE_A5_A6)
|
||||||
(struct ieee80211s_hdr *) (skb->data + hdrlen);
|
|
||||||
/* make sure meshdr->flags is on the linear part */
|
|
||||||
if (!pskb_may_pull(skb, hdrlen + 1))
|
|
||||||
return -1;
|
return -1;
|
||||||
if (meshdr->flags & MESH_FLAGS_AE_A5_A6)
|
if (mesh_flags & MESH_FLAGS_AE_A4)
|
||||||
return -1;
|
|
||||||
if (meshdr->flags & MESH_FLAGS_AE_A4)
|
|
||||||
skb_copy_bits(skb, hdrlen +
|
skb_copy_bits(skb, hdrlen +
|
||||||
offsetof(struct ieee80211s_hdr, eaddr1),
|
offsetof(struct ieee80211s_hdr, eaddr1),
|
||||||
src, ETH_ALEN);
|
tmp.h_source, ETH_ALEN);
|
||||||
hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
|
hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case cpu_to_le16(0):
|
case cpu_to_le16(0):
|
||||||
|
@ -498,33 +498,33 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pskb_may_pull(skb, hdrlen + 8))
|
skb_copy_bits(skb, hdrlen, &payload, sizeof(payload));
|
||||||
return -1;
|
tmp.h_proto = payload.proto;
|
||||||
|
|
||||||
payload = skb->data + hdrlen;
|
if (likely((ether_addr_equal(payload.hdr, rfc1042_header) &&
|
||||||
ethertype = (payload[6] << 8) | payload[7];
|
tmp.h_proto != htons(ETH_P_AARP) &&
|
||||||
|
tmp.h_proto != htons(ETH_P_IPX)) ||
|
||||||
if (likely((ether_addr_equal(payload, rfc1042_header) &&
|
ether_addr_equal(payload.hdr, bridge_tunnel_header)))
|
||||||
ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
|
|
||||||
ether_addr_equal(payload, bridge_tunnel_header))) {
|
|
||||||
/* remove RFC1042 or Bridge-Tunnel encapsulation and
|
/* remove RFC1042 or Bridge-Tunnel encapsulation and
|
||||||
* replace EtherType */
|
* replace EtherType */
|
||||||
skb_pull(skb, hdrlen + 6);
|
hdrlen += ETH_ALEN + 2;
|
||||||
memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
|
else
|
||||||
memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
|
tmp.h_proto = htons(skb->len);
|
||||||
} else {
|
|
||||||
struct ethhdr *ehdr;
|
|
||||||
__be16 len;
|
|
||||||
|
|
||||||
skb_pull(skb, hdrlen);
|
pskb_pull(skb, hdrlen);
|
||||||
len = htons(skb->len);
|
|
||||||
|
if (!ehdr)
|
||||||
ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
|
ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
|
||||||
memcpy(ehdr->h_dest, dst, ETH_ALEN);
|
memcpy(ehdr, &tmp, sizeof(tmp));
|
||||||
memcpy(ehdr->h_source, src, ETH_ALEN);
|
|
||||||
ehdr->h_proto = len;
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
|
||||||
|
enum nl80211_iftype iftype)
|
||||||
|
{
|
||||||
|
return __ieee80211_data_to_8023(skb, NULL, addr, iftype);
|
||||||
|
}
|
||||||
EXPORT_SYMBOL(ieee80211_data_to_8023);
|
EXPORT_SYMBOL(ieee80211_data_to_8023);
|
||||||
|
|
||||||
int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
|
int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
|
||||||
|
@ -644,70 +644,147 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ieee80211_data_from_8023);
|
EXPORT_SYMBOL(ieee80211_data_from_8023);
|
||||||
|
|
||||||
|
static void
|
||||||
|
__frame_add_frag(struct sk_buff *skb, struct page *page,
|
||||||
|
void *ptr, int len, int size)
|
||||||
|
{
|
||||||
|
struct skb_shared_info *sh = skb_shinfo(skb);
|
||||||
|
int page_offset;
|
||||||
|
|
||||||
|
atomic_inc(&page->_count);
|
||||||
|
page_offset = ptr - page_address(page);
|
||||||
|
skb_add_rx_frag(skb, sh->nr_frags, page, page_offset, len, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
__ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame,
|
||||||
|
int offset, int len)
|
||||||
|
{
|
||||||
|
struct skb_shared_info *sh = skb_shinfo(skb);
|
||||||
|
const skb_frag_t *frag = &sh->frags[-1];
|
||||||
|
struct page *frag_page;
|
||||||
|
void *frag_ptr;
|
||||||
|
int frag_len, frag_size;
|
||||||
|
int head_size = skb->len - skb->data_len;
|
||||||
|
int cur_len;
|
||||||
|
|
||||||
|
frag_page = virt_to_head_page(skb->head);
|
||||||
|
frag_ptr = skb->data;
|
||||||
|
frag_size = head_size;
|
||||||
|
|
||||||
|
while (offset >= frag_size) {
|
||||||
|
offset -= frag_size;
|
||||||
|
frag++;
|
||||||
|
frag_page = skb_frag_page(frag);
|
||||||
|
frag_ptr = skb_frag_address(frag);
|
||||||
|
frag_size = skb_frag_size(frag);
|
||||||
|
}
|
||||||
|
|
||||||
|
frag_ptr += offset;
|
||||||
|
frag_len = frag_size - offset;
|
||||||
|
|
||||||
|
cur_len = min(len, frag_len);
|
||||||
|
|
||||||
|
__frame_add_frag(frame, frag_page, frag_ptr, cur_len, frag_size);
|
||||||
|
len -= cur_len;
|
||||||
|
|
||||||
|
while (len > 0) {
|
||||||
|
frag++;
|
||||||
|
frag_len = skb_frag_size(frag);
|
||||||
|
cur_len = min(len, frag_len);
|
||||||
|
__frame_add_frag(frame, skb_frag_page(frag),
|
||||||
|
skb_frag_address(frag), cur_len, frag_len);
|
||||||
|
len -= cur_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sk_buff *
|
||||||
|
__ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
|
||||||
|
int offset, int len, bool reuse_frag)
|
||||||
|
{
|
||||||
|
struct sk_buff *frame;
|
||||||
|
int cur_len = len;
|
||||||
|
|
||||||
|
if (skb->len - offset < len)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When reusing framents, copy some data to the head to simplify
|
||||||
|
* ethernet header handling and speed up protocol header processing
|
||||||
|
* in the stack later.
|
||||||
|
*/
|
||||||
|
if (reuse_frag)
|
||||||
|
cur_len = min_t(int, len, 32);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate and reserve two bytes more for payload
|
||||||
|
* alignment since sizeof(struct ethhdr) is 14.
|
||||||
|
*/
|
||||||
|
frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + cur_len);
|
||||||
|
|
||||||
|
skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
|
||||||
|
skb_copy_bits(skb, offset, skb_put(frame, cur_len), cur_len);
|
||||||
|
|
||||||
|
len -= cur_len;
|
||||||
|
if (!len)
|
||||||
|
return frame;
|
||||||
|
|
||||||
|
offset += cur_len;
|
||||||
|
__ieee80211_amsdu_copy_frag(skb, frame, offset, len);
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
|
void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
|
||||||
const u8 *addr, enum nl80211_iftype iftype,
|
const u8 *addr, enum nl80211_iftype iftype,
|
||||||
const unsigned int extra_headroom,
|
const unsigned int extra_headroom,
|
||||||
bool has_80211_header)
|
bool has_80211_header)
|
||||||
{
|
{
|
||||||
|
unsigned int hlen = ALIGN(extra_headroom, 4);
|
||||||
struct sk_buff *frame = NULL;
|
struct sk_buff *frame = NULL;
|
||||||
u16 ethertype;
|
u16 ethertype;
|
||||||
u8 *payload;
|
u8 *payload;
|
||||||
const struct ethhdr *eth;
|
int offset = 0, remaining, err;
|
||||||
int remaining, err;
|
struct ethhdr eth;
|
||||||
u8 dst[ETH_ALEN], src[ETH_ALEN];
|
bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb);
|
||||||
|
bool reuse_skb = false;
|
||||||
|
bool last = false;
|
||||||
|
|
||||||
if (has_80211_header) {
|
if (has_80211_header) {
|
||||||
err = ieee80211_data_to_8023(skb, addr, iftype);
|
err = __ieee80211_data_to_8023(skb, ð, addr, iftype);
|
||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* skip the wrapping header */
|
|
||||||
eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr));
|
|
||||||
if (!eth)
|
|
||||||
goto out;
|
|
||||||
} else {
|
|
||||||
eth = (struct ethhdr *) skb->data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (skb != frame) {
|
while (!last) {
|
||||||
|
unsigned int subframe_len;
|
||||||
|
int len;
|
||||||
u8 padding;
|
u8 padding;
|
||||||
__be16 len = eth->h_proto;
|
|
||||||
unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len);
|
|
||||||
|
|
||||||
remaining = skb->len;
|
|
||||||
memcpy(dst, eth->h_dest, ETH_ALEN);
|
|
||||||
memcpy(src, eth->h_source, ETH_ALEN);
|
|
||||||
|
|
||||||
|
skb_copy_bits(skb, offset, ð, sizeof(eth));
|
||||||
|
len = ntohs(eth.h_proto);
|
||||||
|
subframe_len = sizeof(struct ethhdr) + len;
|
||||||
padding = (4 - subframe_len) & 0x3;
|
padding = (4 - subframe_len) & 0x3;
|
||||||
|
|
||||||
/* the last MSDU has no padding */
|
/* the last MSDU has no padding */
|
||||||
|
remaining = skb->len - offset;
|
||||||
if (subframe_len > remaining)
|
if (subframe_len > remaining)
|
||||||
goto purge;
|
goto purge;
|
||||||
|
|
||||||
skb_pull(skb, sizeof(struct ethhdr));
|
offset += sizeof(struct ethhdr);
|
||||||
/* reuse skb for the last subframe */
|
/* reuse skb for the last subframe */
|
||||||
if (remaining <= subframe_len + padding)
|
last = remaining <= subframe_len + padding;
|
||||||
|
if (!skb_is_nonlinear(skb) && !reuse_frag && last) {
|
||||||
|
skb_pull(skb, offset);
|
||||||
frame = skb;
|
frame = skb;
|
||||||
else {
|
reuse_skb = true;
|
||||||
unsigned int hlen = ALIGN(extra_headroom, 4);
|
} else {
|
||||||
/*
|
frame = __ieee80211_amsdu_copy(skb, hlen, offset, len,
|
||||||
* Allocate and reserve two bytes more for payload
|
reuse_frag);
|
||||||
* alignment since sizeof(struct ethhdr) is 14.
|
|
||||||
*/
|
|
||||||
frame = dev_alloc_skb(hlen + subframe_len + 2);
|
|
||||||
if (!frame)
|
if (!frame)
|
||||||
goto purge;
|
goto purge;
|
||||||
|
|
||||||
skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
|
offset += len + padding;
|
||||||
memcpy(skb_put(frame, ntohs(len)), skb->data,
|
|
||||||
ntohs(len));
|
|
||||||
|
|
||||||
eth = (struct ethhdr *)skb_pull(skb, ntohs(len) +
|
|
||||||
padding);
|
|
||||||
if (!eth) {
|
|
||||||
dev_kfree_skb(frame);
|
|
||||||
goto purge;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
skb_reset_network_header(frame);
|
skb_reset_network_header(frame);
|
||||||
|
@ -716,24 +793,20 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
|
||||||
|
|
||||||
payload = frame->data;
|
payload = frame->data;
|
||||||
ethertype = (payload[6] << 8) | payload[7];
|
ethertype = (payload[6] << 8) | payload[7];
|
||||||
|
|
||||||
if (likely((ether_addr_equal(payload, rfc1042_header) &&
|
if (likely((ether_addr_equal(payload, rfc1042_header) &&
|
||||||
ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
|
ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
|
||||||
ether_addr_equal(payload, bridge_tunnel_header))) {
|
ether_addr_equal(payload, bridge_tunnel_header))) {
|
||||||
/* remove RFC1042 or Bridge-Tunnel
|
eth.h_proto = htons(ethertype);
|
||||||
* encapsulation and replace EtherType */
|
skb_pull(frame, ETH_ALEN + 2);
|
||||||
skb_pull(frame, 6);
|
|
||||||
memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
|
|
||||||
memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
|
|
||||||
} else {
|
|
||||||
memcpy(skb_push(frame, sizeof(__be16)), &len,
|
|
||||||
sizeof(__be16));
|
|
||||||
memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN);
|
|
||||||
memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memcpy(skb_push(frame, sizeof(eth)), ð, sizeof(eth));
|
||||||
__skb_queue_tail(list, frame);
|
__skb_queue_tail(list, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!reuse_skb)
|
||||||
|
dev_kfree_skb(skb);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
purge:
|
purge:
|
||||||
|
|
Loading…
Reference in New Issue