mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 14:11:52 +00:00
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
|
13
Documentation/ABI/removed/sysfs-class-rfkill
Normal file
13
Documentation/ABI/removed/sysfs-class-rfkill
Normal file
@ -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 the deprecated /sys/class/rfkill/*/state and
|
||||
/sys/class/rfkill/*/claim knobs of this interface look in
|
||||
Documentation/ABI/obsolete/sysfs-class-rfkill.
|
||||
For the deprecated /sys/class/rfkill/*/claim knobs of this interface look in
|
||||
Documentation/ABI/removed/sysfs-class-rfkill.
|
||||
|
||||
What: /sys/class/rfkill
|
||||
Date: 09-Jul-2007
|
||||
@ -42,6 +41,28 @@ Values: A numeric value.
|
||||
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
|
||||
Date: 12-March-2010
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
|
@ -17,23 +17,25 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/property.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rfkill-gpio.h>
|
||||
|
||||
#include "board.h"
|
||||
|
||||
static struct rfkill_gpio_platform_data wifi_rfkill_platform_data = {
|
||||
.name = "wifi_rfkill",
|
||||
.type = RFKILL_TYPE_WLAN,
|
||||
static struct property_entry __initdata wifi_rfkill_prop[] = {
|
||||
PROPERTY_ENTRY_STRING("name", "wifi_rfkill"),
|
||||
PROPERTY_ENTRY_STRING("type", "wlan"),
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct property_set __initdata wifi_rfkill_pset = {
|
||||
.properties = wifi_rfkill_prop,
|
||||
};
|
||||
|
||||
static struct platform_device wifi_rfkill_device = {
|
||||
.name = "rfkill_gpio",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.platform_data = &wifi_rfkill_platform_data,
|
||||
},
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
platform_device_add_properties(&wifi_rfkill_device, &wifi_rfkill_pset);
|
||||
gpiod_add_lookup_table(&wifi_gpio_lookup);
|
||||
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,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size, bool amsdu)
|
||||
struct ieee80211_ampdu_params *params)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
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",
|
||||
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,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta,
|
||||
u16 tid, u16 *ssn, u8 buf_size, bool amsdu)
|
||||
struct ieee80211_ampdu_params *params)
|
||||
{
|
||||
struct ath9k_htc_priv *priv = hw->priv;
|
||||
struct ath9k_htc_sta *ista;
|
||||
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);
|
||||
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,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta,
|
||||
u16 tid, u16 *ssn, u8 buf_size, bool amsdu)
|
||||
struct ieee80211_ampdu_params *params)
|
||||
{
|
||||
struct ath_softc *sc = hw->priv;
|
||||
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
|
||||
bool flush = false;
|
||||
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);
|
||||
|
||||
|
@ -1413,10 +1413,12 @@ static void carl9170_ampdu_work(struct work_struct *work)
|
||||
|
||||
static int carl9170_op_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta,
|
||||
u16 tid, u16 *ssn, u8 buf_size, bool amsdu)
|
||||
struct ieee80211_ampdu_params *params)
|
||||
{
|
||||
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 carl9170_sta_info *sta_info = (void *) sta->drv_priv;
|
||||
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,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size, bool amsdu)
|
||||
struct ieee80211_ampdu_params *params)
|
||||
{
|
||||
struct wcn36xx *wcn = hw->priv;
|
||||
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",
|
||||
action, tid);
|
||||
|
@ -422,6 +422,11 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
|
||||
if (sme->privacy && !rsn_eid)
|
||||
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,
|
||||
sme->ssid, sme->ssid_len,
|
||||
IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY);
|
||||
@ -870,6 +875,11 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (info->pbss) {
|
||||
wil_err(wil, "AP: PBSS not yet supported\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
switch (info->hidden_ssid) {
|
||||
case NL80211_HIDDEN_SSID_NOT_IN_USE:
|
||||
hidden_ssid = WMI_HIDDEN_SSID_DISABLED;
|
||||
|
@ -818,13 +818,15 @@ brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
static int
|
||||
brcms_ops_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size, bool amsdu)
|
||||
struct ieee80211_ampdu_params *params)
|
||||
{
|
||||
struct brcms_info *wl = hw->priv;
|
||||
struct scb *scb = &wl->wlc->pri_scb;
|
||||
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))
|
||||
return -EIDRM;
|
||||
|
@ -5982,12 +5982,14 @@ il4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
|
||||
|
||||
int
|
||||
il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 * ssn,
|
||||
u8 buf_size, bool amsdu)
|
||||
struct ieee80211_ampdu_params *params)
|
||||
{
|
||||
struct il_priv *il = hw->priv;
|
||||
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);
|
||||
|
||||
|
@ -182,9 +182,7 @@ void il4965_mac_update_tkip_key(struct ieee80211_hw *hw,
|
||||
struct ieee80211_sta *sta, u32 iv32,
|
||||
u16 *phase1key);
|
||||
int il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 * ssn,
|
||||
u8 buf_size, bool amsdu);
|
||||
struct ieee80211_ampdu_params *params);
|
||||
int il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta);
|
||||
void
|
||||
|
@ -943,14 +943,16 @@ static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
|
||||
switch (key->cipher) {
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
if (sta) {
|
||||
u64 pn64;
|
||||
|
||||
tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
|
||||
tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
|
||||
|
||||
rx_p1ks = data->tkip->rx_uni;
|
||||
|
||||
ieee80211_get_key_tx_seq(key, &seq);
|
||||
tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16);
|
||||
tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32);
|
||||
pn64 = atomic64_read(&key->tx_pn);
|
||||
tkip_tx_sc->iv16 = cpu_to_le16(TKIP_PN_TO_IV16(pn64));
|
||||
tkip_tx_sc->iv32 = cpu_to_le32(TKIP_PN_TO_IV32(pn64));
|
||||
|
||||
ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k);
|
||||
iwlagn_convert_p1k(p1k, data->tkip->tx.p1k);
|
||||
@ -996,19 +998,13 @@ static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
if (sta) {
|
||||
u8 *pn = seq.ccmp.pn;
|
||||
u64 pn64;
|
||||
|
||||
aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc;
|
||||
aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc;
|
||||
|
||||
ieee80211_get_key_tx_seq(key, &seq);
|
||||
aes_tx_sc->pn = cpu_to_le64(
|
||||
(u64)pn[5] |
|
||||
((u64)pn[4] << 8) |
|
||||
((u64)pn[3] << 16) |
|
||||
((u64)pn[2] << 24) |
|
||||
((u64)pn[1] << 32) |
|
||||
((u64)pn[0] << 40));
|
||||
pn64 = atomic64_read(&key->tx_pn);
|
||||
aes_tx_sc->pn = cpu_to_le64(pn64);
|
||||
} else
|
||||
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,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size, bool amsdu)
|
||||
struct ieee80211_ampdu_params *params)
|
||||
{
|
||||
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||
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;
|
||||
|
||||
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;
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
if (sta) {
|
||||
u64 pn64;
|
||||
|
||||
tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
|
||||
tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
|
||||
|
||||
rx_p1ks = data->tkip->rx_uni;
|
||||
|
||||
ieee80211_get_key_tx_seq(key, &seq);
|
||||
tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16);
|
||||
tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32);
|
||||
pn64 = atomic64_read(&key->tx_pn);
|
||||
tkip_tx_sc->iv16 = cpu_to_le16(TKIP_PN_TO_IV16(pn64));
|
||||
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);
|
||||
|
||||
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:
|
||||
iwl_mvm_tkip_sc_to_seq(&sc->tkip.tsc, &seq);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid,
|
||||
u16 *ssn, u8 buf_size, bool amsdu)
|
||||
struct ieee80211_ampdu_params *params)
|
||||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
int ret;
|
||||
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",
|
||||
sta->addr, tid, action);
|
||||
@ -2582,7 +2585,7 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
|
||||
switch (key->cipher) {
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC;
|
||||
key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
|
||||
key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
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:
|
||||
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);
|
||||
break;
|
||||
|
||||
|
@ -1334,10 +1334,8 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
|
||||
data->tx_bytes += skb->len;
|
||||
ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel);
|
||||
|
||||
if (ack && skb->len >= 16) {
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
if (ack && skb->len >= 16)
|
||||
mac80211_hwsim_monitor_ack(channel, hdr->addr2);
|
||||
}
|
||||
|
||||
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,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size, bool amsdu)
|
||||
struct ieee80211_ampdu_params *params)
|
||||
{
|
||||
struct ieee80211_sta *sta = params->sta;
|
||||
enum ieee80211_ampdu_mlme_action action = params->action;
|
||||
u16 tid = params->tid;
|
||||
|
||||
switch (action) {
|
||||
case IEEE80211_AMPDU_TX_START:
|
||||
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
|
||||
mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size, bool amsdu)
|
||||
struct ieee80211_ampdu_params *params)
|
||||
{
|
||||
|
||||
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;
|
||||
struct mwl8k_priv *priv = hw->priv;
|
||||
struct mwl8k_ampdu_stream *stream;
|
||||
|
@ -334,11 +334,13 @@ static int mt7601u_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
|
||||
|
||||
static int
|
||||
mt76_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size,
|
||||
bool amsdu)
|
||||
struct ieee80211_ampdu_params *params)
|
||||
{
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size, bool amsdu)
|
||||
struct ieee80211_ampdu_params *params)
|
||||
{
|
||||
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;
|
||||
int ret = 0;
|
||||
|
||||
|
@ -218,9 +218,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw,
|
||||
const struct ieee80211_tx_queue_params *params);
|
||||
u64 rt2800_get_tsf(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_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size, bool amsdu);
|
||||
struct ieee80211_ampdu_params *params);
|
||||
int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
|
||||
struct survey_info *survey);
|
||||
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
|
||||
rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn, u8 buf_size,
|
||||
bool amsdu)
|
||||
struct ieee80211_ampdu_params *params)
|
||||
{
|
||||
struct rtl8xxxu_priv *priv = hw->priv;
|
||||
struct device *dev = &priv->udev->dev;
|
||||
u8 ampdu_factor, ampdu_density;
|
||||
struct ieee80211_sta *sta = params->sta;
|
||||
enum ieee80211_ampdu_mlme_action action = params->action;
|
||||
|
||||
switch (action) {
|
||||
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,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size, bool amsdu)
|
||||
struct ieee80211_ampdu_params *params)
|
||||
{
|
||||
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) {
|
||||
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.
|
||||
* @hw: Pointer to the ieee80211_hw structure.
|
||||
* @vif: Pointer to the ieee80211_vif structure.
|
||||
* @action: ieee80211_ampdu_mlme_action enum.
|
||||
* @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
|
||||
* @params: Pointer to A-MPDU action parameters
|
||||
*
|
||||
* Return: status: 0 on success, negative error code on failure.
|
||||
*/
|
||||
static int rsi_mac80211_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta,
|
||||
unsigned short tid,
|
||||
unsigned short *ssn,
|
||||
unsigned char buf_size,
|
||||
bool amsdu)
|
||||
struct ieee80211_ampdu_params *params)
|
||||
{
|
||||
int status = -EOPNOTSUPP;
|
||||
struct rsi_hw *adapter = hw->priv;
|
||||
struct rsi_common *common = adapter->priv;
|
||||
u16 seq_no = 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++) {
|
||||
if (vif == adapter->vifs[ii])
|
||||
|
@ -2129,9 +2129,7 @@ void cw1200_mcast_timeout(unsigned long arg)
|
||||
|
||||
int cw1200_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size, bool amsdu)
|
||||
struct ieee80211_ampdu_params *params)
|
||||
{
|
||||
/* Aggregation is implemented fully in firmware,
|
||||
* including block ack negotiation. Do not allow
|
||||
|
@ -109,9 +109,7 @@ void cw1200_bss_info_changed(struct ieee80211_hw *dev,
|
||||
u32 changed);
|
||||
int cw1200_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size, bool amsdu);
|
||||
struct ieee80211_ampdu_params *params);
|
||||
|
||||
void cw1200_suspend_resume(struct cw1200_common *priv,
|
||||
struct wsm_suspend_resume *arg);
|
||||
|
@ -5187,14 +5187,16 @@ out:
|
||||
|
||||
static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size, bool amsdu)
|
||||
struct ieee80211_ampdu_params *params)
|
||||
{
|
||||
struct wl1271 *wl = hw->priv;
|
||||
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
|
||||
int ret;
|
||||
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,
|
||||
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 vnt_mic_hdr *mic_hdr)
|
||||
{
|
||||
struct ieee80211_key_seq seq;
|
||||
u64 pn64;
|
||||
u8 *iv = ((u8 *)hdr + ieee80211_get_hdrlen_from_skb(skb));
|
||||
|
||||
/* 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);
|
||||
ether_addr_copy(mic_hdr->mic_addr2, hdr->addr2);
|
||||
|
||||
ieee80211_get_key_tx_seq(tx_key, &seq);
|
||||
|
||||
memcpy(mic_hdr->ccmp_pn, seq.ccmp.pn, IEEE80211_CCMP_PN_LEN);
|
||||
pn64 = atomic64_read(&tx_key->tx_pn);
|
||||
mic_hdr->ccmp_pn[5] = pn64;
|
||||
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))
|
||||
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)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = tx_context->hdr;
|
||||
struct ieee80211_key_seq seq;
|
||||
u64 pn64;
|
||||
u8 *iv = ((u8 *)hdr + ieee80211_get_hdrlen_from_skb(skb));
|
||||
|
||||
/* 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);
|
||||
ether_addr_copy(mic_hdr->mic_addr2, hdr->addr2);
|
||||
|
||||
ieee80211_get_key_tx_seq(tx_key, &seq);
|
||||
|
||||
memcpy(mic_hdr->ccmp_pn, seq.ccmp.pn, IEEE80211_CCMP_PN_LEN);
|
||||
pn64 = atomic64_read(&tx_key->tx_pn);
|
||||
mic_hdr->ccmp_pn[5] = pn64;
|
||||
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))
|
||||
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 */
|
||||
#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_MESH_ID_LEN 32
|
||||
@ -843,6 +851,8 @@ enum ieee80211_vht_opmode_bits {
|
||||
};
|
||||
|
||||
#define WLAN_SA_QUERY_TR_ID_LEN 2
|
||||
#define WLAN_MEMBERSHIP_LEN 8
|
||||
#define WLAN_USER_POSITION_LEN 16
|
||||
|
||||
/**
|
||||
* struct ieee80211_tpc_report_ie
|
||||
@ -989,6 +999,11 @@ struct ieee80211_mgmt {
|
||||
u8 action_code;
|
||||
u8 operating_mode;
|
||||
} __packed vht_opmode_notif;
|
||||
struct {
|
||||
u8 action_code;
|
||||
u8 membership[WLAN_MEMBERSHIP_LEN];
|
||||
u8 position[WLAN_USER_POSITION_LEN];
|
||||
} __packed vht_group_notif;
|
||||
struct {
|
||||
u8 action_code;
|
||||
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_7991 0x00000001
|
||||
#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_160_80PLUS80MHZ 0x00000008
|
||||
#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_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 */
|
||||
#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.
|
||||
* 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);
|
||||
|
||||
@ -212,6 +213,15 @@ void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw);
|
||||
* @rfkill: rfkill struct to query
|
||||
*/
|
||||
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 */
|
||||
static inline struct rfkill * __must_check
|
||||
rfkill_alloc(const char *name,
|
||||
@ -268,6 +278,12 @@ static inline bool rfkill_blocked(struct rfkill *rfkill)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline enum rfkill_type rfkill_find_type(const char *name)
|
||||
{
|
||||
return RFKILL_TYPE_ALL;
|
||||
}
|
||||
|
||||
#endif /* RFKILL || RFKILL_MODULE */
|
||||
|
||||
|
||||
|
@ -712,6 +712,8 @@ struct cfg80211_acl_data {
|
||||
* @p2p_opp_ps: P2P opportunistic PS
|
||||
* @acl: ACL configuration used by the drivers which has support for
|
||||
* 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_chan_def chandef;
|
||||
@ -730,6 +732,7 @@ struct cfg80211_ap_settings {
|
||||
u8 p2p_ctwindow;
|
||||
bool p2p_opp_ps;
|
||||
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.
|
||||
* @vht_capa: VHT Capability overrides
|
||||
* @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 ieee80211_channel *channel;
|
||||
@ -1910,6 +1915,7 @@ struct cfg80211_connect_params {
|
||||
struct ieee80211_ht_cap ht_capa_mask;
|
||||
struct ieee80211_vht_cap vht_capa;
|
||||
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)
|
||||
* @conn: (private) cfg80211 software SME connection state machine data
|
||||
* @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_dfs_possible: (private) IBSS may change to a DFS channel
|
||||
* @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;
|
||||
struct cfg80211_conn *conn;
|
||||
struct cfg80211_cached_keys *connect_keys;
|
||||
enum ieee80211_bss_type conn_bss_type;
|
||||
|
||||
struct list_head event_list;
|
||||
spinlock_t event_lock;
|
||||
|
@ -5,7 +5,7 @@
|
||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* 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
|
||||
* 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
|
||||
* context had been assigned.
|
||||
* @BSS_CHANGED_OCB: OCB join status changed
|
||||
* @BSS_CHANGED_MU_GROUPS: VHT MU-MIMO group id or user position changed
|
||||
*/
|
||||
enum ieee80211_bss_change {
|
||||
BSS_CHANGED_ASSOC = 1<<0,
|
||||
@ -323,6 +324,7 @@ enum ieee80211_bss_change {
|
||||
BSS_CHANGED_BEACON_INFO = 1<<20,
|
||||
BSS_CHANGED_BANDWIDTH = 1<<21,
|
||||
BSS_CHANGED_OCB = 1<<22,
|
||||
BSS_CHANGED_MU_GROUPS = 1<<23,
|
||||
|
||||
/* when adding here, make sure to change ieee80211_reconfig */
|
||||
};
|
||||
@ -435,6 +437,19 @@ struct ieee80211_event {
|
||||
} 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
|
||||
*
|
||||
@ -477,6 +492,7 @@ struct ieee80211_event {
|
||||
* @enable_beacon: whether beaconing should be enabled or not
|
||||
* @chandef: Channel definition for this BSS -- the hardware might be
|
||||
* 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.
|
||||
* 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
|
||||
@ -535,6 +551,7 @@ struct ieee80211_bss_conf {
|
||||
s32 cqm_rssi_thold;
|
||||
u32 cqm_rssi_hyst;
|
||||
struct cfg80211_chan_def chandef;
|
||||
struct ieee80211_mu_group_data mu_group;
|
||||
__be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
|
||||
int arp_addr_cnt;
|
||||
bool qos;
|
||||
@ -691,12 +708,14 @@ enum mac80211_tx_info_flags {
|
||||
* protocol frame (e.g. EAP)
|
||||
* @IEEE80211_TX_CTRL_PS_RESPONSE: This frame is a response to a poll
|
||||
* 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.
|
||||
*/
|
||||
enum mac80211_tx_control_flags {
|
||||
IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0),
|
||||
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
|
||||
* field) is valid and contains the time the last symbol of the MPDU
|
||||
* (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_HT: HT MCS was used and rate_idx 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
|
||||
* is stored in the @ampdu_delimiter_crc field)
|
||||
* @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_10MHZ: 10 MHz (half 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 {
|
||||
RX_FLAG_MMIC_ERROR = BIT(0),
|
||||
RX_FLAG_DECRYPTED = BIT(1),
|
||||
RX_FLAG_MACTIME_PLCP_START = BIT(2),
|
||||
RX_FLAG_MMIC_STRIPPED = BIT(3),
|
||||
RX_FLAG_IV_STRIPPED = BIT(4),
|
||||
RX_FLAG_FAILED_FCS_CRC = BIT(5),
|
||||
@ -1046,7 +1076,7 @@ enum mac80211_rx_flags {
|
||||
RX_FLAG_HT_GF = BIT(13),
|
||||
RX_FLAG_AMPDU_DETAILS = BIT(14),
|
||||
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_IS_LAST = BIT(18),
|
||||
RX_FLAG_AMPDU_DELIM_CRC_ERROR = BIT(19),
|
||||
@ -1054,6 +1084,8 @@ enum mac80211_rx_flags {
|
||||
RX_FLAG_MACTIME_END = BIT(21),
|
||||
RX_FLAG_VHT = BIT(22),
|
||||
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_10MHZ = BIT(28),
|
||||
RX_FLAG_5MHZ = BIT(29),
|
||||
@ -1072,6 +1104,7 @@ enum mac80211_rx_flags {
|
||||
* @RX_VHT_FLAG_160MHZ: 160 MHz was used
|
||||
* @RX_VHT_FLAG_BF: packet was beamformed
|
||||
*/
|
||||
|
||||
enum mac80211_rx_vht_flags {
|
||||
RX_VHT_FLAG_80MHZ = BIT(0),
|
||||
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
|
||||
* @band: the active band when this frame was received
|
||||
* @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
|
||||
* unspecified depending on the hardware capabilities flags
|
||||
* @IEEE80211_HW_SIGNAL_*
|
||||
@ -1347,6 +1382,7 @@ enum ieee80211_vif_flags {
|
||||
* @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
|
||||
* for read access.
|
||||
* @mu_mimo_owner: indicates interface owns MU-MIMO capability
|
||||
* @driver_flags: flags/capabilities the driver has for this interface,
|
||||
* these need to be set (or cleared) when the interface is added
|
||||
* or, if supported by the driver, the interface type is changed
|
||||
@ -1373,6 +1409,7 @@ struct ieee80211_vif {
|
||||
u8 addr[ETH_ALEN];
|
||||
bool p2p;
|
||||
bool csa_active;
|
||||
bool mu_mimo_owner;
|
||||
|
||||
u8 cab_queue;
|
||||
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
|
||||
* encrypted in hardware.
|
||||
* @cipher: The key's cipher suite selector.
|
||||
* @tx_pn: PN used for TX on non-TKIP keys, may be used by the driver
|
||||
* as well if it needs to do software PN assignment by itself
|
||||
* (e.g. due to TSO)
|
||||
* @tx_pn: PN used for TX keys, may be used by the driver as well if it
|
||||
* needs to do software PN assignment by itself (e.g. due to TSO)
|
||||
* @flags: key flags, see &enum ieee80211_key_flags.
|
||||
* @keyidx: the key index (0-3)
|
||||
* @keylen: key material length
|
||||
@ -1514,6 +1550,9 @@ struct ieee80211_key_conf {
|
||||
|
||||
#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
|
||||
*
|
||||
@ -1684,6 +1723,18 @@ struct ieee80211_sta_rates {
|
||||
* @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.
|
||||
* @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)
|
||||
*/
|
||||
struct ieee80211_sta {
|
||||
@ -1702,6 +1753,8 @@ struct ieee80211_sta {
|
||||
bool tdls;
|
||||
bool tdls_initiator;
|
||||
bool mfp;
|
||||
u8 max_amsdu_subframes;
|
||||
u16 max_amsdu_len;
|
||||
|
||||
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
|
||||
* 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
|
||||
*/
|
||||
enum ieee80211_hw_flags {
|
||||
@ -1946,6 +2004,7 @@ enum ieee80211_hw_flags {
|
||||
IEEE80211_HW_SUPPORTS_AMSDU_IN_AMPDU,
|
||||
IEEE80211_HW_BEACON_TX_STATUS,
|
||||
IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR,
|
||||
IEEE80211_HW_SUPPORTS_REORDERING_BUFFER,
|
||||
|
||||
/* keep last, obviously */
|
||||
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
|
||||
* @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);
|
||||
}
|
||||
@ -2683,6 +2742,33 @@ enum ieee80211_ampdu_mlme_action {
|
||||
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
|
||||
* @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
|
||||
* The RA/TID combination determines the destination and TID we want
|
||||
* the ampdu action to be performed for. The action is defined through
|
||||
* ieee80211_ampdu_mlme_action. Starting sequence number (@ssn)
|
||||
* is the first frame we expect to perform the action on. Notice
|
||||
* that TX/RX_STOP can pass NULL for this parameter.
|
||||
* 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
|
||||
* ieee80211_ampdu_mlme_action.
|
||||
* When the action is set to %IEEE80211_AMPDU_TX_OPERATIONAL the driver
|
||||
* may neither send aggregates containing more subframes than @buf_size
|
||||
* nor send aggregates in a way that lost frames would exceed the
|
||||
* buffer size. If just limiting the aggregate size, this would be
|
||||
* 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:
|
||||
* - TX: 1 or 18 or 81
|
||||
* 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.
|
||||
* The callback can sleep.
|
||||
@ -3388,9 +3467,7 @@ struct ieee80211_ops {
|
||||
int (*tx_last_beacon)(struct ieee80211_hw *hw);
|
||||
int (*ampdu_action)(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid, u16 *ssn,
|
||||
u8 buf_size, bool amsdu);
|
||||
struct ieee80211_ampdu_params *params);
|
||||
int (*get_survey)(struct ieee80211_hw *hw, int idx,
|
||||
struct survey_info *survey);
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @seq: buffer to receive the sequence data
|
||||
* @pn: PN to add
|
||||
*
|
||||
* This function allows a driver to retrieve the current TX IV/PN
|
||||
* for the given key. It must not be called if IV generation is
|
||||
* offloaded to the device.
|
||||
* Returns: pointer to the octet following IVs (i.e. beginning of
|
||||
* the packet payload)
|
||||
*
|
||||
* Note that this function may only be called when no TX processing
|
||||
* can be done concurrently, for example when queues are stopped
|
||||
* and the stop has been synchronized.
|
||||
* This function writes the tkip IV value to pos (which should
|
||||
* point to the crypto header)
|
||||
*/
|
||||
void ieee80211_get_key_tx_seq(struct ieee80211_key_conf *keyconf,
|
||||
struct ieee80211_key_seq *seq);
|
||||
u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key_conf *keyconf, u64 pn);
|
||||
|
||||
/**
|
||||
* 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,
|
||||
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
|
||||
*
|
||||
@ -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,
|
||||
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
|
||||
*
|
||||
@ -5371,6 +5447,21 @@ ieee80211_vif_type_p2p(struct ieee80211_vif *vif)
|
||||
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,
|
||||
int rssi_min_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 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 */
|
||||
|
@ -1727,6 +1727,8 @@ enum nl80211_commands {
|
||||
* underlying device supports these minimal RRM features:
|
||||
* %NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES,
|
||||
* %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
|
||||
* association request. In addition, it must also set the RRM capability
|
||||
* 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
|
||||
* between scans. The scan plans are executed sequentially.
|
||||
* 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
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
@ -2164,6 +2170,8 @@ enum nl80211_attrs {
|
||||
NL80211_ATTR_MAX_SCAN_PLAN_ITERATIONS,
|
||||
NL80211_ATTR_SCHED_SCAN_PLANS,
|
||||
|
||||
NL80211_ATTR_PBSS,
|
||||
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
@ -4396,12 +4404,18 @@ enum nl80211_feature_flags {
|
||||
/**
|
||||
* 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_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.
|
||||
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
|
||||
*/
|
||||
enum nl80211_ext_feature_index {
|
||||
NL80211_EXT_FEATURE_VHT_IBSS,
|
||||
NL80211_EXT_FEATURE_RRM,
|
||||
|
||||
/* add new features before the definition below */
|
||||
NUM_NL80211_EXT_FEATURES,
|
||||
|
@ -59,6 +59,8 @@ enum rfkill_type {
|
||||
* @RFKILL_OP_DEL: a device was removed
|
||||
* @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)
|
||||
* into a state, also updating the default state used for devices that
|
||||
* are hot-plugged later.
|
||||
*/
|
||||
enum rfkill_operation {
|
||||
RFKILL_OP_ADD = 0,
|
||||
|
@ -7,6 +7,7 @@
|
||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
||||
* Copyright 2007-2010, Intel Corporation
|
||||
* Copyright(c) 2015 Intel Deutschland GmbH
|
||||
*
|
||||
* 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
|
||||
@ -61,16 +62,25 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
|
||||
{
|
||||
struct ieee80211_local *local = sta->local;
|
||||
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);
|
||||
|
||||
tid_rx = rcu_dereference_protected(sta->ampdu_mlme.tid_rx[tid],
|
||||
lockdep_is_held(&sta->ampdu_mlme.mtx));
|
||||
|
||||
if (!tid_rx)
|
||||
if (!test_bit(tid, sta->ampdu_mlme.agg_session_valid))
|
||||
return;
|
||||
|
||||
RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL);
|
||||
__clear_bit(tid, sta->ampdu_mlme.agg_session_valid);
|
||||
|
||||
ht_dbg(sta->sdata,
|
||||
"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",
|
||||
(int)reason);
|
||||
|
||||
if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP,
|
||||
&sta->sta, tid, NULL, 0, false))
|
||||
if (drv_ampdu_action(local, sta->sdata, ¶ms))
|
||||
sdata_info(sta->sdata,
|
||||
"HW problem - can not stop rx aggregation for %pM tid %d\n",
|
||||
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,
|
||||
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);
|
||||
|
||||
/* 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 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;
|
||||
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 */
|
||||
if (buf_size > local->hw.max_rx_aggregation_subframes)
|
||||
buf_size = local->hw.max_rx_aggregation_subframes;
|
||||
params.buf_size = buf_size;
|
||||
|
||||
/* examine state machine */
|
||||
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,
|
||||
"unexpected AddBA Req from %pM on tid %u\n",
|
||||
sta->sta.addr, tid);
|
||||
@ -290,6 +316,16 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||
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 */
|
||||
tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL);
|
||||
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++)
|
||||
__skb_queue_head_init(&tid_agg_rx->reorder_buf[i]);
|
||||
|
||||
ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START,
|
||||
&sta->sta, tid, &start_seq_num, 0, false);
|
||||
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) {
|
||||
@ -341,6 +376,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||
tid_agg_rx->timeout = timeout;
|
||||
tid_agg_rx->stored_mpdu_num = 0;
|
||||
tid_agg_rx->auto_seq = auto_seq;
|
||||
tid_agg_rx->reorder_buf_filtered = 0;
|
||||
status = WLAN_STATUS_SUCCESS;
|
||||
|
||||
/* activate it for RX */
|
||||
@ -352,6 +388,8 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
|
||||
}
|
||||
|
||||
end:
|
||||
if (status == WLAN_STATUS_SUCCESS)
|
||||
__set_bit(tid, sta->ampdu_mlme.agg_session_valid);
|
||||
mutex_unlock(&sta->ampdu_mlme.mtx);
|
||||
|
||||
end_no_lock:
|
||||
|
@ -7,6 +7,7 @@
|
||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
||||
* Copyright 2007-2010, Intel Corporation
|
||||
* Copyright(c) 2015 Intel Deutschland GmbH
|
||||
*
|
||||
* 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
|
||||
@ -295,7 +296,14 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
||||
{
|
||||
struct ieee80211_local *local = sta->local;
|
||||
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;
|
||||
|
||||
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_LOCAL_REQUEST:
|
||||
case AGG_STOP_PEER_REQUEST:
|
||||
action = IEEE80211_AMPDU_TX_STOP_CONT;
|
||||
params.action = IEEE80211_AMPDU_TX_STOP_CONT;
|
||||
break;
|
||||
case AGG_STOP_DESTROY_STA:
|
||||
action = IEEE80211_AMPDU_TX_STOP_FLUSH;
|
||||
params.action = IEEE80211_AMPDU_TX_STOP_FLUSH;
|
||||
break;
|
||||
default:
|
||||
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);
|
||||
if (reason != AGG_STOP_DESTROY_STA)
|
||||
return -EALREADY;
|
||||
ret = drv_ampdu_action(local, sta->sdata,
|
||||
IEEE80211_AMPDU_TX_STOP_FLUSH_CONT,
|
||||
&sta->sta, tid, NULL, 0, false);
|
||||
params.action = IEEE80211_AMPDU_TX_STOP_FLUSH_CONT;
|
||||
ret = drv_ampdu_action(local, sta->sdata, ¶ms);
|
||||
WARN_ON_ONCE(ret);
|
||||
return 0;
|
||||
}
|
||||
@ -381,8 +388,7 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
|
||||
WLAN_BACK_INITIATOR;
|
||||
tid_tx->tx_stop = reason == AGG_STOP_LOCAL_REQUEST;
|
||||
|
||||
ret = drv_ampdu_action(local, sta->sdata, action,
|
||||
&sta->sta, tid, NULL, 0, false);
|
||||
ret = drv_ampdu_action(local, sta->sdata, ¶ms);
|
||||
|
||||
/* HW shall not deny going back to legacy */
|
||||
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 ieee80211_local *local = sta->local;
|
||||
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;
|
||||
|
||||
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();
|
||||
|
||||
start_seq_num = sta->tid_seq[tid] >> 4;
|
||||
|
||||
ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START,
|
||||
&sta->sta, tid, &start_seq_num, 0, false);
|
||||
params.ssn = sta->tid_seq[tid] >> 4;
|
||||
ret = drv_ampdu_action(local, sdata, ¶ms);
|
||||
if (ret) {
|
||||
ht_dbg(sdata,
|
||||
"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 */
|
||||
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,
|
||||
tid_tx->timeout);
|
||||
}
|
||||
@ -684,18 +695,24 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
|
||||
struct sta_info *sta, u16 tid)
|
||||
{
|
||||
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);
|
||||
|
||||
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",
|
||||
sta->sta.addr, tid);
|
||||
|
||||
drv_ampdu_action(local, sta->sdata,
|
||||
IEEE80211_AMPDU_TX_OPERATIONAL,
|
||||
&sta->sta, tid, NULL, tid_tx->buf_size,
|
||||
tid_tx->amsdu);
|
||||
drv_ampdu_action(local, sta->sdata, ¶ms);
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
iv32 = key->u.tkip.tx.iv32;
|
||||
iv16 = key->u.tkip.tx.iv16;
|
||||
pn64 = atomic64_read(&key->conf.tx_pn);
|
||||
iv32 = TKIP_PN_TO_IV32(pn64);
|
||||
iv16 = TKIP_PN_TO_IV16(pn64);
|
||||
|
||||
if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE &&
|
||||
!(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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
* 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,
|
||||
params->ht_capa, sta);
|
||||
|
||||
/* VHT can override some HT caps such as the A-MSDU max length */
|
||||
if (params->vht_capa)
|
||||
ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
|
||||
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))
|
||||
continue;
|
||||
|
||||
if (!sta->uploaded)
|
||||
if (!sta->uploaded || !test_sta_flag(sta, WLAN_STA_ASSOC))
|
||||
continue;
|
||||
|
||||
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(BEACON_TX_STATUS),
|
||||
FLAG(NEEDS_UNIQUE_STA_ADDR),
|
||||
FLAG(SUPPORTS_REORDERING_BUFFER),
|
||||
#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");
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
pn = atomic64_read(&key->conf.tx_pn);
|
||||
len = scnprintf(buf, sizeof(buf), "%08x %04x\n",
|
||||
key->u.tkip.tx.iv32,
|
||||
key->u.tkip.tx.iv16);
|
||||
TKIP_PN_TO_IV32(pn),
|
||||
TKIP_PN_TO_IV16(pn));
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
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,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid,
|
||||
u16 *ssn, u8 buf_size, bool amsdu)
|
||||
struct ieee80211_ampdu_params *params)
|
||||
{
|
||||
int ret = -EOPNOTSUPP;
|
||||
|
||||
@ -296,12 +294,10 @@ int drv_ampdu_action(struct ieee80211_local *local,
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return -EIO;
|
||||
|
||||
trace_drv_ampdu_action(local, sdata, action, sta, tid,
|
||||
ssn, buf_size, amsdu);
|
||||
trace_drv_ampdu_action(local, sdata, params);
|
||||
|
||||
if (local->ops->ampdu_action)
|
||||
ret = local->ops->ampdu_action(&local->hw, &sdata->vif, action,
|
||||
sta, tid, ssn, buf_size, amsdu);
|
||||
ret = local->ops->ampdu_action(&local->hw, &sdata->vif, params);
|
||||
|
||||
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,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid,
|
||||
u16 *ssn, u8 buf_size, bool amsdu);
|
||||
struct ieee80211_ampdu_params *params);
|
||||
|
||||
static inline int drv_get_survey(struct ieee80211_local *local, int idx,
|
||||
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 */
|
||||
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:
|
||||
changed = memcmp(&sta->sta.ht_cap, &ht_cap, sizeof(ht_cap));
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
||||
* Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
|
||||
* 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
|
||||
* 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;
|
||||
enum ieee80211_sta_rx_bandwidth bw = sta->sta.bandwidth;
|
||||
|
||||
ieee80211_ht_oper_to_chandef(channel,
|
||||
elems->ht_operation,
|
||||
&chandef);
|
||||
cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT);
|
||||
ieee80211_chandef_ht_oper(elems->ht_operation, &chandef);
|
||||
|
||||
memcpy(&htcap_ie, elems->ht_cap_elem, sizeof(htcap_ie));
|
||||
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_sta_vht_cap cap = sta->sta.vht_cap;
|
||||
|
||||
ieee80211_vht_oper_to_chandef(channel,
|
||||
elems->vht_operation,
|
||||
&chandef);
|
||||
ieee80211_chandef_vht_oper(elems->vht_operation,
|
||||
&chandef);
|
||||
memcpy(&cap_ie, elems->vht_cap_elem, sizeof(cap_ie));
|
||||
ieee80211_vht_cap_ie_to_sta_vht_cap(sdata, sband,
|
||||
&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");
|
||||
|
||||
num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy,
|
||||
&ifibss->chandef,
|
||||
channels,
|
||||
ARRAY_SIZE(channels));
|
||||
scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef);
|
||||
ieee80211_request_ibss_scan(sdata, ifibss->ssid,
|
||||
ifibss->ssid_len, channels, num,
|
||||
scan_width);
|
||||
|
||||
if (ifibss->fixed_channel) {
|
||||
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 {
|
||||
int interval = IEEE80211_SCAN_INTERVAL;
|
||||
|
||||
|
@ -716,7 +716,6 @@ struct ieee80211_if_mesh {
|
||||
* back to wireless media and to the local net stack.
|
||||
* @IEEE80211_SDATA_DISCONNECT_RESUME: Disconnect after resume.
|
||||
* @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 {
|
||||
IEEE80211_SDATA_ALLMULTI = BIT(0),
|
||||
@ -724,7 +723,6 @@ enum ieee80211_sub_if_data_flags {
|
||||
IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3),
|
||||
IEEE80211_SDATA_DISCONNECT_RESUME = BIT(4),
|
||||
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 sk_buff_head queue;
|
||||
unsigned long flags;
|
||||
unsigned long byte_cnt;
|
||||
|
||||
/* keep last! */
|
||||
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 &&
|
||||
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,
|
||||
@ -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_cur_vht_bw(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,
|
||||
struct sta_info *sta, u8 opmode,
|
||||
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);
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
@ -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);
|
||||
|
||||
/* channel management */
|
||||
void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
|
||||
const struct ieee80211_ht_operation *ht_oper,
|
||||
struct cfg80211_chan_def *chandef);
|
||||
void ieee80211_vht_oper_to_chandef(struct ieee80211_channel *control_chan,
|
||||
const struct ieee80211_vht_operation *oper,
|
||||
struct cfg80211_chan_def *chandef);
|
||||
bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
|
||||
struct cfg80211_chan_def *chandef);
|
||||
bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper,
|
||||
struct cfg80211_chan_def *chandef);
|
||||
u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c);
|
||||
|
||||
int __must_check
|
||||
|
@ -977,7 +977,11 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
|
||||
if (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);
|
||||
txqi->byte_cnt = 0;
|
||||
spin_unlock_bh(&txqi->queue.lock);
|
||||
|
||||
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);
|
||||
} 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)) {
|
||||
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);
|
||||
|
||||
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,
|
||||
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);
|
||||
|
||||
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,
|
||||
int tid, struct ieee80211_key_seq *seq)
|
||||
{
|
||||
|
@ -44,13 +44,17 @@ enum ieee80211_internal_tkip_state {
|
||||
};
|
||||
|
||||
struct tkip_ctx {
|
||||
u32 iv32; /* current iv32 */
|
||||
u16 iv16; /* current iv16 */
|
||||
u16 p1k[5]; /* p1k cache */
|
||||
u32 p1k_iv32; /* iv32 for which p1k computed */
|
||||
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_local *local;
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
@ -71,7 +75,7 @@ struct ieee80211_key {
|
||||
struct tkip_ctx tx;
|
||||
|
||||
/* last received RSC */
|
||||
struct tkip_ctx rx[IEEE80211_NUM_TIDS];
|
||||
struct tkip_ctx_rx rx[IEEE80211_NUM_TIDS];
|
||||
|
||||
/* number of 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)
|
||||
return false;
|
||||
|
||||
ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
|
||||
ie->ht_operation, &sta_chan_def);
|
||||
|
||||
ieee80211_vht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
|
||||
ie->vht_operation, &sta_chan_def);
|
||||
cfg80211_chandef_create(&sta_chan_def, sdata->vif.bss_conf.chandef.chan,
|
||||
NL80211_CHAN_NO_HT);
|
||||
ieee80211_chandef_ht_oper(ie->ht_operation, &sta_chan_def);
|
||||
ieee80211_chandef_vht_oper(ie->vht_operation, &sta_chan_def);
|
||||
|
||||
if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef,
|
||||
&sta_chan_def))
|
||||
|
@ -137,8 +137,6 @@ struct mesh_path {
|
||||
* @copy_node: function to copy nodes of the table
|
||||
* @size_order: determines size of the table, there will be 2^size_order hash
|
||||
* 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
|
||||
* 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);
|
||||
int (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl);
|
||||
int size_order;
|
||||
int mean_chain_len;
|
||||
struct hlist_head *known_gates;
|
||||
spinlock_t gates_lock;
|
||||
|
||||
|
@ -55,16 +55,21 @@ int mpp_paths_generation;
|
||||
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)
|
||||
{
|
||||
return rcu_dereference_protected(mesh_paths,
|
||||
lockdep_is_held(&pathtbl_resize_lock));
|
||||
return resize_dereference_paths(mesh_paths);
|
||||
}
|
||||
|
||||
static inline struct mesh_table *resize_dereference_mpp_paths(void)
|
||||
{
|
||||
return rcu_dereference_protected(mpp_paths,
|
||||
lockdep_is_held(&pathtbl_resize_lock));
|
||||
return resize_dereference_paths(mpp_paths);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -160,11 +165,10 @@ static int mesh_table_grow(struct mesh_table *oldtbl,
|
||||
int i;
|
||||
|
||||
if (atomic_read(&oldtbl->entries)
|
||||
< oldtbl->mean_chain_len * (oldtbl->hash_mask + 1))
|
||||
< MEAN_CHAIN_LEN * (oldtbl->hash_mask + 1))
|
||||
return -EAGAIN;
|
||||
|
||||
newtbl->free_node = oldtbl->free_node;
|
||||
newtbl->mean_chain_len = oldtbl->mean_chain_len;
|
||||
newtbl->copy_node = oldtbl->copy_node;
|
||||
newtbl->known_gates = oldtbl->known_gates;
|
||||
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);
|
||||
if (atomic_inc_return(&tbl->entries) >=
|
||||
tbl->mean_chain_len * (tbl->hash_mask + 1))
|
||||
MEAN_CHAIN_LEN * (tbl->hash_mask + 1))
|
||||
grow = 1;
|
||||
|
||||
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);
|
||||
if (atomic_inc_return(&tbl->entries) >=
|
||||
tbl->mean_chain_len * (tbl->hash_mask + 1))
|
||||
MEAN_CHAIN_LEN * (tbl->hash_mask + 1))
|
||||
grow = 1;
|
||||
|
||||
spin_unlock(&tbl->hashwlock[hash_idx]);
|
||||
@ -835,6 +839,29 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta)
|
||||
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,
|
||||
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
|
||||
* @addr: dst address (ETH_ALEN length)
|
||||
*
|
||||
* 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_path *mpath;
|
||||
@ -892,8 +922,7 @@ int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr)
|
||||
int hash_idx;
|
||||
int err = 0;
|
||||
|
||||
read_lock_bh(&pathtbl_resize_lock);
|
||||
tbl = resize_dereference_mesh_paths();
|
||||
tbl = resize_dereference_paths(rcu_tbl);
|
||||
hash_idx = mesh_table_hash(addr, sdata, tbl);
|
||||
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;
|
||||
enddel:
|
||||
mesh_paths_generation++;
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1076,7 +1146,6 @@ int mesh_pathtbl_init(void)
|
||||
return -ENOMEM;
|
||||
tbl_path->free_node = &mesh_path_node_free;
|
||||
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);
|
||||
if (!tbl_path->known_gates) {
|
||||
ret = -ENOMEM;
|
||||
@ -1092,7 +1161,6 @@ int mesh_pathtbl_init(void)
|
||||
}
|
||||
tbl_mpp->free_node = &mesh_path_node_free;
|
||||
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);
|
||||
if (!tbl_mpp->known_gates) {
|
||||
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))
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* new matching peer */
|
||||
event = OPN_ACPT;
|
||||
goto out;
|
||||
} else {
|
||||
if (!test_sta_flag(sta, WLAN_STA_AUTH)) {
|
||||
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;
|
||||
}
|
||||
|
||||
/* new matching peer */
|
||||
if (!sta) {
|
||||
event = OPN_ACPT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (ftype) {
|
||||
case WLAN_SP_MESH_PEERING_OPEN:
|
||||
if (!matches_local)
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2007, Michael Wu <flamingice@sourmilk.net>
|
||||
* 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
|
||||
* 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 */
|
||||
if (sta_ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
|
||||
switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
|
||||
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;
|
||||
}
|
||||
ieee80211_chandef_ht_oper(ht_oper, chandef);
|
||||
} else {
|
||||
/* 40 MHz (and 80 MHz) must be supported for VHT */
|
||||
ret = IEEE80211_STA_DISABLE_VHT;
|
||||
@ -219,35 +210,11 @@ ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
|
||||
goto out;
|
||||
}
|
||||
|
||||
vht_chandef.chan = channel;
|
||||
vht_chandef.center_freq1 =
|
||||
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:
|
||||
vht_chandef = *chandef;
|
||||
if (!ieee80211_chandef_vht_oper(vht_oper, &vht_chandef)) {
|
||||
if (!(ifmgd->flags & IEEE80211_STA_DISABLE_VHT))
|
||||
sdata_info(sdata,
|
||||
"AP VHT operation IE has invalid channel width (%d), disable VHT\n",
|
||||
vht_oper->chan_width);
|
||||
"AP VHT information is invalid, disable VHT\n");
|
||||
ret = IEEE80211_STA_DISABLE_VHT;
|
||||
goto out;
|
||||
}
|
||||
@ -592,7 +559,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
|
||||
struct ieee80211_sub_if_data *other;
|
||||
|
||||
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;
|
||||
break;
|
||||
}
|
||||
@ -600,7 +567,7 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata,
|
||||
if (disable_mu_mimo)
|
||||
cap &= ~IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
|
||||
else
|
||||
sdata->flags |= IEEE80211_SDATA_MU_MIMO_OWNER;
|
||||
sdata->vif.mu_mimo_owner = true;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct delayed_work *delayed_work =
|
||||
container_of(work, struct delayed_work, work);
|
||||
struct delayed_work *delayed_work = to_delayed_work(work);
|
||||
struct ieee80211_sub_if_data *sdata =
|
||||
container_of(delayed_work, struct ieee80211_sub_if_data,
|
||||
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->vht_capa, 0, sizeof(ifmgd->vht_capa));
|
||||
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;
|
||||
|
||||
@ -2536,7 +2509,8 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
|
||||
eth_zero_addr(sdata->u.mgd.bssid);
|
||||
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
|
||||
sdata->u.mgd.flags = 0;
|
||||
sdata->flags &= ~IEEE80211_SDATA_MU_MIMO_OWNER;
|
||||
sdata->vif.mu_mimo_owner = false;
|
||||
|
||||
mutex_lock(&sdata->local->mtx);
|
||||
ieee80211_vif_release_channel(sdata);
|
||||
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.vht_operation, bssid, &changed)) {
|
||||
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,
|
||||
WLAN_REASON_DEAUTH_LEAVING,
|
||||
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?
|
||||
* Let's make sure!
|
||||
*/
|
||||
wiphy_debug(local->hw.wiphy,
|
||||
"%s: No probe response from AP %pM"
|
||||
" after %dms, disconnecting.\n",
|
||||
sdata->name,
|
||||
bssid, probe_wait_ms);
|
||||
mlme_dbg(sdata,
|
||||
"No probe response from AP %pM after %dms, disconnecting.\n",
|
||||
bssid, probe_wait_ms);
|
||||
|
||||
ieee80211_sta_connection_lost(sdata, bssid,
|
||||
WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, false);
|
||||
@ -4536,6 +4511,9 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
|
||||
if (ifmgd->associated) {
|
||||
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,
|
||||
WLAN_REASON_UNSPECIFIED,
|
||||
false, frame_buf);
|
||||
@ -4604,6 +4582,9 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
|
||||
if (ifmgd->associated) {
|
||||
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,
|
||||
WLAN_REASON_UNSPECIFIED,
|
||||
false, frame_buf);
|
||||
|
@ -4,6 +4,7 @@
|
||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2007-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* 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
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@ -18,6 +19,7 @@
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <net/mac80211.h>
|
||||
#include <net/ieee80211_radiotap.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);
|
||||
|
||||
if (status->flag & (RX_FLAG_FAILED_FCS_CRC |
|
||||
RX_FLAG_FAILED_PLCP_CRC))
|
||||
RX_FLAG_FAILED_PLCP_CRC |
|
||||
RX_FLAG_ONLY_MONITOR))
|
||||
return true;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (!local->monitors) {
|
||||
if (!local->monitors || (status->flag & RX_FLAG_SKIP_MONITOR)) {
|
||||
if (should_drop_frame(origskb, present_fcs_len,
|
||||
rtap_vendor_space)) {
|
||||
dev_kfree_skb(origskb);
|
||||
@ -797,6 +800,26 @@ static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
|
||||
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,
|
||||
struct tid_ampdu_rx *tid_agg_rx,
|
||||
int index,
|
||||
@ -811,7 +834,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
|
||||
if (skb_queue_empty(skb_list))
|
||||
goto no_frame;
|
||||
|
||||
if (!ieee80211_rx_reorder_ready(skb_list)) {
|
||||
if (!ieee80211_rx_reorder_ready(tid_agg_rx, index)) {
|
||||
__skb_queue_purge(skb_list);
|
||||
goto no_frame;
|
||||
}
|
||||
@ -825,6 +848,7 @@ static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -865,7 +889,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
|
||||
|
||||
/* release the buffer until next missing frame */
|
||||
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) {
|
||||
/*
|
||||
* 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;
|
||||
for (j = (index + 1) % tid_agg_rx->buf_size; j != index;
|
||||
j = (j + 1) % tid_agg_rx->buf_size) {
|
||||
if (!ieee80211_rx_reorder_ready(
|
||||
&tid_agg_rx->reorder_buf[j])) {
|
||||
if (!ieee80211_rx_reorder_ready(tid_agg_rx, j)) {
|
||||
skipped++;
|
||||
continue;
|
||||
}
|
||||
@ -902,8 +925,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata,
|
||||
skipped) & IEEE80211_SN_MASK;
|
||||
skipped = 0;
|
||||
}
|
||||
} else while (ieee80211_rx_reorder_ready(
|
||||
&tid_agg_rx->reorder_buf[index])) {
|
||||
} else while (ieee80211_rx_reorder_ready(tid_agg_rx, index)) {
|
||||
ieee80211_release_reorder_frame(sdata, tid_agg_rx, index,
|
||||
frames);
|
||||
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;
|
||||
j = (j + 1) % tid_agg_rx->buf_size) {
|
||||
if (ieee80211_rx_reorder_ready(
|
||||
&tid_agg_rx->reorder_buf[j]))
|
||||
if (ieee80211_rx_reorder_ready(tid_agg_rx, j))
|
||||
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;
|
||||
|
||||
/* 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);
|
||||
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_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
|
||||
|
||||
if (status->flag & RX_FLAG_DUP_VALIDATED)
|
||||
return RX_CONTINUE;
|
||||
|
||||
/*
|
||||
* Drop duplicate 802.11 retransmissions
|
||||
* (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_queue_head_init(&frame_list);
|
||||
|
||||
if (skb_linearize(skb))
|
||||
return RX_DROP_UNUSABLE;
|
||||
|
||||
ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
|
||||
rx->sdata->vif.type,
|
||||
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_sub_if_data *sdata = rx->sdata;
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
u16 q, hdrlen;
|
||||
u16 ac, q, hdrlen;
|
||||
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
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);
|
||||
if (!ether_addr_equal(mppath->mpp, mpp_addr))
|
||||
memcpy(mppath->mpp, mpp_addr, ETH_ALEN);
|
||||
mppath->exp_time = jiffies;
|
||||
spin_unlock_bh(&mppath->state_lock);
|
||||
}
|
||||
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))
|
||||
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)) {
|
||||
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion);
|
||||
return RX_DROP_MONITOR;
|
||||
@ -2738,6 +2761,11 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
||||
opmode, status->band);
|
||||
goto handled;
|
||||
}
|
||||
case WLAN_VHT_ACTION_GROUPID_MGMT: {
|
||||
if (len < IEEE80211_MIN_ACTION_SIZE + 25)
|
||||
goto invalid;
|
||||
goto queue;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -3275,6 +3303,85 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
|
||||
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 */
|
||||
|
||||
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);
|
||||
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_sub_if_data *sdata = sta->sdata;
|
||||
struct station_info sinfo;
|
||||
struct station_info *sinfo;
|
||||
int err = 0;
|
||||
|
||||
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 */
|
||||
if (sta_info_get_bss(sdata, sta->sta.addr)) {
|
||||
err = -EEXIST;
|
||||
@ -530,14 +537,12 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
|
||||
/* accept BA sessions now */
|
||||
clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
|
||||
|
||||
ieee80211_recalc_min_chandef(sdata);
|
||||
ieee80211_sta_debugfs_add(sta);
|
||||
rate_control_add_sta_debugfs(sta);
|
||||
|
||||
memset(&sinfo, 0, sizeof(sinfo));
|
||||
sinfo.filled = 0;
|
||||
sinfo.generation = local->sta_generation;
|
||||
cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
|
||||
sinfo->generation = local->sta_generation;
|
||||
cfg80211_new_sta(sdata->dev, sta->sta.addr, sinfo, GFP_KERNEL);
|
||||
kfree(sinfo);
|
||||
|
||||
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);
|
||||
out_err:
|
||||
mutex_unlock(&local->sta_mtx);
|
||||
kfree(sinfo);
|
||||
rcu_read_lock();
|
||||
return err;
|
||||
}
|
||||
@ -898,7 +904,7 @@ static void __sta_info_destroy_part2(struct sta_info *sta)
|
||||
{
|
||||
struct ieee80211_local *local = sta->local;
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
struct station_info sinfo = {};
|
||||
struct station_info *sinfo;
|
||||
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_set_sinfo(sta, &sinfo);
|
||||
cfg80211_del_sta_sinfo(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
|
||||
sinfo = kzalloc(sizeof(*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);
|
||||
ieee80211_sta_debugfs_remove(sta);
|
||||
ieee80211_recalc_min_chandef(sdata);
|
||||
|
||||
cleanup_single_sta(sta);
|
||||
}
|
||||
@ -1808,14 +1816,17 @@ int sta_info_move_state(struct sta_info *sta,
|
||||
clear_bit(WLAN_STA_AUTH, &sta->_flags);
|
||||
break;
|
||||
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);
|
||||
else if (sta->sta_state == IEEE80211_STA_ASSOC)
|
||||
} else if (sta->sta_state == IEEE80211_STA_ASSOC) {
|
||||
clear_bit(WLAN_STA_ASSOC, &sta->_flags);
|
||||
ieee80211_recalc_min_chandef(sta->sdata);
|
||||
}
|
||||
break;
|
||||
case IEEE80211_STA_ASSOC:
|
||||
if (sta->sta_state == IEEE80211_STA_AUTH) {
|
||||
set_bit(WLAN_STA_ASSOC, &sta->_flags);
|
||||
ieee80211_recalc_min_chandef(sta->sdata);
|
||||
} else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) {
|
||||
if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
|
||||
(sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright 2002-2005, Devicescape Software, Inc.
|
||||
* 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
|
||||
* 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
|
||||
* 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
|
||||
* @session_timer: check if peer keeps Tx-ing on the TID (by timeout value)
|
||||
* @reorder_timer: releases expired frames from the reorder buffer.
|
||||
@ -194,6 +197,7 @@ struct tid_ampdu_tx {
|
||||
struct tid_ampdu_rx {
|
||||
struct rcu_head rcu_head;
|
||||
spinlock_t reorder_lock;
|
||||
u64 reorder_buf_filtered;
|
||||
struct sk_buff_head *reorder_buf;
|
||||
unsigned long *reorder_time;
|
||||
struct timer_list session_timer;
|
||||
@ -212,20 +216,21 @@ struct tid_ampdu_rx {
|
||||
/**
|
||||
* 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_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
|
||||
* RX timer expired until the work for it runs
|
||||
* @tid_rx_stop_requested: bitmap indicating which BA sessions per TID the
|
||||
* driver requested to close until the work for it runs
|
||||
* @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.
|
||||
* @agg_session_valid: bitmap indicating which TID has a rx BA session open on
|
||||
* @work: work struct for starting/stopping aggregation
|
||||
* @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 mutex mtx;
|
||||
@ -233,6 +238,7 @@ struct sta_ampdu_mlme {
|
||||
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_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
|
||||
unsigned long agg_session_valid[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
|
||||
/* tx */
|
||||
struct work_struct work;
|
||||
struct tid_ampdu_tx __rcu *tid_tx[IEEE80211_NUM_TIDS];
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright 2002-2004, Instant802 Networks, Inc.
|
||||
* Copyright 2005, Devicescape Software, Inc.
|
||||
* Copyright (C) 2016 Intel Deutschland GmbH
|
||||
*
|
||||
* 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
|
||||
@ -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
|
||||
* of the IV. Returns pointer to the octet following IVs (i.e., beginning of
|
||||
* 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, key->u.tkip.tx.iv16);
|
||||
*pos++ = (key->conf.keyidx << 6) | (1 << 5) /* Ext IV */;
|
||||
put_unaligned_le32(key->u.tkip.tx.iv32, pos);
|
||||
pos = write_tkip_iv(pos, TKIP_PN_TO_IV16(pn));
|
||||
*pos++ = (keyconf->keyidx << 6) | (1 << 5) /* Ext IV */;
|
||||
put_unaligned_le32(TKIP_PN_TO_IV32(pn), pos);
|
||||
return pos + 4;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ieee80211_tkip_add_iv);
|
||||
|
||||
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;
|
||||
int res;
|
||||
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)
|
||||
return -1;
|
||||
@ -265,37 +266,36 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm,
|
||||
if ((keyid >> 6) != key->conf.keyidx)
|
||||
return TKIP_DECRYPT_INVALID_KEYIDX;
|
||||
|
||||
if (key->u.tkip.rx[queue].state != TKIP_STATE_NOT_INIT &&
|
||||
(iv32 < key->u.tkip.rx[queue].iv32 ||
|
||||
(iv32 == key->u.tkip.rx[queue].iv32 &&
|
||||
iv16 <= key->u.tkip.rx[queue].iv16)))
|
||||
if (rx_ctx->ctx.state != TKIP_STATE_NOT_INIT &&
|
||||
(iv32 < rx_ctx->iv32 ||
|
||||
(iv32 == rx_ctx->iv32 && iv16 <= rx_ctx->iv16)))
|
||||
return TKIP_DECRYPT_REPLAY;
|
||||
|
||||
if (only_iv) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (key->u.tkip.rx[queue].state == TKIP_STATE_NOT_INIT ||
|
||||
key->u.tkip.rx[queue].iv32 != iv32) {
|
||||
if (rx_ctx->ctx.state == TKIP_STATE_NOT_INIT ||
|
||||
rx_ctx->iv32 != iv32) {
|
||||
/* 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 &&
|
||||
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;
|
||||
|
||||
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
|
||||
sdata = container_of(key->sdata->bss,
|
||||
struct ieee80211_sub_if_data, u.ap);
|
||||
drv_update_tkip_key(key->local, sdata, &key->conf, key->sta,
|
||||
iv32, key->u.tkip.rx[queue].p1k);
|
||||
key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED;
|
||||
iv32, rx_ctx->ctx.p1k);
|
||||
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);
|
||||
done:
|
||||
|
@ -13,8 +13,6 @@
|
||||
#include <linux/crypto.h>
|
||||
#include "key.h"
|
||||
|
||||
u8 *ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key);
|
||||
|
||||
int ieee80211_tkip_encrypt_data(struct crypto_cipher *tfm,
|
||||
struct ieee80211_key *key,
|
||||
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_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.
|
||||
@ -970,38 +986,25 @@ DEFINE_EVENT(local_only_evt, drv_tx_last_beacon,
|
||||
TRACE_EVENT(drv_ampdu_action,
|
||||
TP_PROTO(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
enum ieee80211_ampdu_mlme_action action,
|
||||
struct ieee80211_sta *sta, u16 tid,
|
||||
u16 *ssn, u8 buf_size, bool amsdu),
|
||||
struct ieee80211_ampdu_params *params),
|
||||
|
||||
TP_ARGS(local, sdata, action, sta, tid, ssn, buf_size, amsdu),
|
||||
TP_ARGS(local, sdata, params),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
LOCAL_ENTRY
|
||||
STA_ENTRY
|
||||
__field(u32, action)
|
||||
__field(u16, tid)
|
||||
__field(u16, ssn)
|
||||
__field(u8, buf_size)
|
||||
__field(bool, amsdu)
|
||||
VIF_ENTRY
|
||||
AMPDU_ACTION_ENTRY
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
LOCAL_ASSIGN;
|
||||
VIF_ASSIGN;
|
||||
STA_ASSIGN;
|
||||
__entry->action = action;
|
||||
__entry->tid = tid;
|
||||
__entry->ssn = ssn ? *ssn : 0;
|
||||
__entry->buf_size = buf_size;
|
||||
__entry->amsdu = amsdu;
|
||||
AMPDU_ACTION_ASSIGN;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " action:%d tid:%d buf:%d amsdu:%d",
|
||||
LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action,
|
||||
__entry->tid, __entry->buf_size, __entry->amsdu
|
||||
LOCAL_PR_FMT VIF_PR_FMT AMPDU_ACTION_PR_FMT,
|
||||
LOCAL_PR_ARG, VIF_PR_ARG, AMPDU_ACTION_PR_ARG
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -710,6 +710,10 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
|
||||
|
||||
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)
|
||||
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)
|
||||
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);
|
||||
|
||||
return;
|
||||
@ -1294,6 +1302,8 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
|
||||
if (!skb)
|
||||
goto out;
|
||||
|
||||
txqi->byte_cnt -= skb->len;
|
||||
|
||||
atomic_dec(&sdata->txqs_len[ac]);
|
||||
if (__netif_subqueue_stopped(sdata->dev, 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);
|
||||
}
|
||||
|
||||
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_header *rthdr =
|
||||
(struct ieee80211_radiotap_header *) skb->data;
|
||||
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,
|
||||
NULL);
|
||||
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 |
|
||||
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;
|
||||
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
|
||||
* 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 */
|
||||
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
|
||||
* 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 |
|
||||
IEEE80211_TX_CTL_INJECTED;
|
||||
|
||||
/* process and remove the injection radiotap header */
|
||||
if (!ieee80211_parse_tx_radiotap(skb))
|
||||
goto fail;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/*
|
||||
@ -1883,6 +1953,11 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
|
||||
goto fail_rcu;
|
||||
|
||||
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);
|
||||
rcu_read_unlock();
|
||||
|
||||
@ -2099,8 +2174,11 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata,
|
||||
mpp_lookup = true;
|
||||
}
|
||||
|
||||
if (mpp_lookup)
|
||||
if (mpp_lookup) {
|
||||
mppath = mpp_path_lookup(sdata, skb->data);
|
||||
if (mppath)
|
||||
mppath->exp_time = jiffies;
|
||||
}
|
||||
|
||||
if (mppath && mpath)
|
||||
mesh_path_del(mpath->sdata, mpath->dst);
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
|
||||
* Copyright 2007 Johannes Berg <johannes@sipsolutions.net>
|
||||
* 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
|
||||
* 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_TXPOWER;
|
||||
|
||||
if (sdata->vif.mu_mimo_owner)
|
||||
changed |= BSS_CHANGED_MU_GROUPS;
|
||||
|
||||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
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) {
|
||||
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;
|
||||
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;
|
||||
case NL80211_CHAN_WIDTH_80:
|
||||
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);
|
||||
}
|
||||
|
||||
void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
|
||||
const struct ieee80211_ht_operation *ht_oper,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
bool ieee80211_chandef_ht_oper(const struct ieee80211_ht_operation *ht_oper,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
enum nl80211_channel_type channel_type;
|
||||
|
||||
if (!ht_oper) {
|
||||
cfg80211_chandef_create(chandef, control_chan,
|
||||
NL80211_CHAN_NO_HT);
|
||||
return;
|
||||
}
|
||||
if (!ht_oper)
|
||||
return false;
|
||||
|
||||
switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
|
||||
case IEEE80211_HT_PARAM_CHA_SEC_NONE:
|
||||
@ -2414,42 +2426,66 @@ void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
|
||||
break;
|
||||
default:
|
||||
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,
|
||||
const struct ieee80211_vht_operation *oper,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
bool ieee80211_chandef_vht_oper(const struct ieee80211_vht_operation *oper,
|
||||
struct cfg80211_chan_def *chandef)
|
||||
{
|
||||
if (!oper)
|
||||
return;
|
||||
struct cfg80211_chan_def new = *chandef;
|
||||
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) {
|
||||
case IEEE80211_VHT_CHANWIDTH_USE_HT:
|
||||
break;
|
||||
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;
|
||||
case IEEE80211_VHT_CHANWIDTH_160MHZ:
|
||||
chandef->width = NL80211_CHAN_WIDTH_160;
|
||||
new.width = NL80211_CHAN_WIDTH_160;
|
||||
new.center_freq1 = cf1;
|
||||
break;
|
||||
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;
|
||||
default:
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
|
||||
chandef->center_freq1 =
|
||||
ieee80211_channel_to_frequency(oper->center_freq_seg1_idx,
|
||||
control_chan->band);
|
||||
chandef->center_freq2 =
|
||||
ieee80211_channel_to_frequency(oper->center_freq_seg2_idx,
|
||||
control_chan->band);
|
||||
if (!cfg80211_chandef_valid(&new))
|
||||
return false;
|
||||
|
||||
*chandef = new;
|
||||
return true;
|
||||
}
|
||||
|
||||
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];
|
||||
bitrate = sband->bitrates[status->rate_idx].bitrate;
|
||||
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);
|
||||
@ -3357,3 +3405,17 @@ void ieee80211_init_tx_queue(struct ieee80211_sub_if_data *sdata,
|
||||
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
|
||||
*
|
||||
* Portions of this file
|
||||
* Copyright(c) 2015 - 2016 Intel Deutschland GmbH
|
||||
*
|
||||
* 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
|
||||
* 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);
|
||||
|
||||
/* 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)
|
||||
@ -425,6 +445,43 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
|
||||
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,
|
||||
struct sta_info *sta, u8 opmode,
|
||||
enum ieee80211_band band)
|
||||
|
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright 2002-2004, Instant802 Networks, Inc.
|
||||
* 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
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
|
||||
{
|
||||
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);
|
||||
unsigned int hdrlen;
|
||||
int len, tail;
|
||||
u64 pn;
|
||||
u8 *pos;
|
||||
|
||||
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;
|
||||
|
||||
/* Increase IV for the frame */
|
||||
spin_lock(&key->u.tkip.txlock);
|
||||
key->u.tkip.tx.iv16++;
|
||||
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);
|
||||
pn = atomic64_inc_return(&key->conf.tx_pn);
|
||||
pos = ieee80211_tkip_add_iv(pos, &key->conf, pn);
|
||||
|
||||
/* hwaccel - with software IV */
|
||||
if (info->control.hw_key)
|
||||
|
@ -41,5 +41,4 @@ config RFKILL_GPIO
|
||||
default n
|
||||
help
|
||||
If you say yes here you get support of a generic gpio RFKILL
|
||||
driver. The platform should fill in the appropriate fields in the
|
||||
rfkill_gpio_platform_data structure and pass that to the driver.
|
||||
driver.
|
||||
|
@ -57,6 +57,8 @@ struct rfkill {
|
||||
|
||||
bool registered;
|
||||
bool persistent;
|
||||
bool polling_paused;
|
||||
bool suspended;
|
||||
|
||||
const struct rfkill_ops *ops;
|
||||
void *data;
|
||||
@ -233,29 +235,6 @@ static void rfkill_event(struct rfkill *rfkill)
|
||||
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
|
||||
*
|
||||
@ -285,7 +264,7 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked)
|
||||
spin_lock_irqsave(&rfkill->lock, flags);
|
||||
prev = rfkill->state & RFKILL_BLOCK_SW;
|
||||
|
||||
if (rfkill->state & RFKILL_BLOCK_SW)
|
||||
if (prev)
|
||||
rfkill->state |= RFKILL_BLOCK_SW_PREV;
|
||||
else
|
||||
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);
|
||||
if (err) {
|
||||
/*
|
||||
* Failed -- reset status to _prev, this may be different
|
||||
* from what set set _PREV to earlier in this function
|
||||
* Failed -- reset status to _PREV, which may be different
|
||||
* from what we have set _PREV to earlier in this function
|
||||
* if rfkill_set_sw_state was invoked.
|
||||
*/
|
||||
if (rfkill->state & RFKILL_BLOCK_SW_PREV)
|
||||
@ -323,6 +302,19 @@ static void rfkill_set_block(struct rfkill *rfkill, bool blocked)
|
||||
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
|
||||
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
|
||||
*
|
||||
* This function sets the state of all switches of given type,
|
||||
* unless a specific switch is claimed by userspace (in which case,
|
||||
* that switch is left alone) or suspended.
|
||||
* unless a specific switch is suspended.
|
||||
*
|
||||
* 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;
|
||||
|
||||
if (type == RFKILL_TYPE_ALL) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_RFKILL_TYPES; i++)
|
||||
rfkill_global_states[i].cur = blocked;
|
||||
} else {
|
||||
rfkill_global_states[type].cur = blocked;
|
||||
}
|
||||
|
||||
rfkill_update_global_state(type, blocked);
|
||||
list_for_each_entry(rfkill, &rfkill_list, node) {
|
||||
if (rfkill->type != type && type != RFKILL_TYPE_ALL)
|
||||
continue;
|
||||
@ -477,17 +460,28 @@ bool rfkill_get_global_sw_state(const enum rfkill_type type)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
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)
|
||||
return ret;
|
||||
|
||||
if (change)
|
||||
if (prev != blocked)
|
||||
schedule_work(&rfkill->uevent_work);
|
||||
|
||||
return ret;
|
||||
@ -582,6 +576,34 @@ void rfkill_set_states(struct rfkill *rfkill, bool sw, bool hw)
|
||||
}
|
||||
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,
|
||||
char *buf)
|
||||
{
|
||||
@ -591,38 +613,12 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr,
|
||||
}
|
||||
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,
|
||||
char *buf)
|
||||
{
|
||||
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);
|
||||
|
||||
@ -730,20 +726,12 @@ static ssize_t state_store(struct device *dev, struct device_attribute *attr,
|
||||
}
|
||||
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[] = {
|
||||
&dev_attr_name.attr,
|
||||
&dev_attr_type.attr,
|
||||
&dev_attr_index.attr,
|
||||
&dev_attr_persistent.attr,
|
||||
&dev_attr_state.attr,
|
||||
&dev_attr_claim.attr,
|
||||
&dev_attr_soft.attr,
|
||||
&dev_attr_hard.attr,
|
||||
NULL,
|
||||
@ -768,7 +756,7 @@ static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
if (error)
|
||||
return error;
|
||||
error = add_uevent_var(env, "RFKILL_TYPE=%s",
|
||||
rfkill_get_type_str(rfkill->type));
|
||||
rfkill_types[rfkill->type]);
|
||||
if (error)
|
||||
return error;
|
||||
spin_lock_irqsave(&rfkill->lock, flags);
|
||||
@ -786,6 +774,7 @@ void rfkill_pause_polling(struct rfkill *rfkill)
|
||||
if (!rfkill->ops->poll)
|
||||
return;
|
||||
|
||||
rfkill->polling_paused = true;
|
||||
cancel_delayed_work_sync(&rfkill->poll_work);
|
||||
}
|
||||
EXPORT_SYMBOL(rfkill_pause_polling);
|
||||
@ -797,6 +786,11 @@ void rfkill_resume_polling(struct rfkill *rfkill)
|
||||
if (!rfkill->ops->poll)
|
||||
return;
|
||||
|
||||
rfkill->polling_paused = false;
|
||||
|
||||
if (rfkill->suspended)
|
||||
return;
|
||||
|
||||
queue_delayed_work(system_power_efficient_wq,
|
||||
&rfkill->poll_work, 0);
|
||||
}
|
||||
@ -807,7 +801,8 @@ static int rfkill_suspend(struct device *dev)
|
||||
{
|
||||
struct rfkill *rfkill = to_rfkill(dev);
|
||||
|
||||
rfkill_pause_polling(rfkill);
|
||||
rfkill->suspended = true;
|
||||
cancel_delayed_work_sync(&rfkill->poll_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -817,12 +812,16 @@ static int rfkill_resume(struct device *dev)
|
||||
struct rfkill *rfkill = to_rfkill(dev);
|
||||
bool cur;
|
||||
|
||||
rfkill->suspended = false;
|
||||
|
||||
if (!rfkill->persistent) {
|
||||
cur = !!(rfkill->state & RFKILL_BLOCK_SW);
|
||||
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;
|
||||
}
|
||||
@ -1164,15 +1163,8 @@ static ssize_t rfkill_fop_write(struct file *file, const char __user *buf,
|
||||
|
||||
mutex_lock(&rfkill_global_mutex);
|
||||
|
||||
if (ev.op == RFKILL_OP_CHANGE_ALL) {
|
||||
if (ev.type == RFKILL_TYPE_ALL) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (ev.op == RFKILL_OP_CHANGE_ALL)
|
||||
rfkill_update_global_state(ev.type, ev.soft);
|
||||
|
||||
list_for_each_entry(rfkill, &rfkill_list, node) {
|
||||
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)
|
||||
{
|
||||
int error;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_RFKILL_TYPES; i++)
|
||||
rfkill_global_states[i].cur = !rfkill_default_state;
|
||||
rfkill_update_global_state(RFKILL_TYPE_ALL, !rfkill_default_state);
|
||||
|
||||
error = class_register(&rfkill_class);
|
||||
if (error)
|
||||
|
@ -27,8 +27,6 @@
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
#include <linux/rfkill-gpio.h>
|
||||
|
||||
struct rfkill_gpio_data {
|
||||
const char *name;
|
||||
enum rfkill_type type;
|
||||
@ -81,7 +79,6 @@ static int rfkill_gpio_acpi_probe(struct device *dev,
|
||||
if (!id)
|
||||
return -ENODEV;
|
||||
|
||||
rfkill->name = dev_name(dev);
|
||||
rfkill->type = (unsigned)id->driver_data;
|
||||
|
||||
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)
|
||||
{
|
||||
struct rfkill_gpio_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct rfkill_gpio_data *rfkill;
|
||||
struct gpio_desc *gpio;
|
||||
const char *type_name;
|
||||
int ret;
|
||||
|
||||
rfkill = devm_kzalloc(&pdev->dev, sizeof(*rfkill), GFP_KERNEL);
|
||||
if (!rfkill)
|
||||
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)) {
|
||||
ret = rfkill_gpio_acpi_probe(&pdev->dev, rfkill);
|
||||
if (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);
|
||||
@ -124,10 +124,8 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
|
||||
|
||||
rfkill->shutdown_gpio = gpio;
|
||||
|
||||
/* Make sure at-least one of the GPIO is defined and that
|
||||
* a name is specified for this instance
|
||||
*/
|
||||
if ((!rfkill->reset_gpio && !rfkill->shutdown_gpio) || !rfkill->name) {
|
||||
/* Make sure at-least one GPIO is defined for this instance */
|
||||
if (!rfkill->reset_gpio && !rfkill->shutdown_gpio) {
|
||||
dev_err(&pdev->dev, "invalid platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -50,8 +50,8 @@ config CFG80211_DEVELOPER_WARNINGS
|
||||
default n
|
||||
help
|
||||
This option enables some additional warnings that help
|
||||
cfg80211 developers and driver developers, but that can
|
||||
trigger due to races with userspace.
|
||||
cfg80211 developers and driver developers, but beware that
|
||||
they can also trigger due to races with userspace.
|
||||
|
||||
For example, when a driver reports that it was disconnected
|
||||
from the AP, but the user disconnects manually at the same
|
||||
@ -61,19 +61,6 @@ config CFG80211_DEVELOPER_WARNINGS
|
||||
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
|
||||
bool "cfg80211 certification onus"
|
||||
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
|
||||
to be an authorized master, i.e., with radar detection support and DFS
|
||||
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
|
||||
a channel due to this relaxation should not allow connection from
|
||||
non P2P clients.
|
||||
@ -148,7 +135,7 @@ config CFG80211_DEBUGFS
|
||||
depends on CFG80211
|
||||
depends on DEBUG_FS
|
||||
---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.
|
||||
|
||||
@ -159,7 +146,7 @@ config CFG80211_INTERNAL_REGDB
|
||||
---help---
|
||||
This option generates an internal data structure representing
|
||||
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.
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
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_mpath && !ops->del_mpath);
|
||||
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;
|
||||
|
||||
|
@ -711,7 +711,7 @@ EXPORT_SYMBOL(cfg80211_rx_mgmt);
|
||||
|
||||
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_chan_def chandef;
|
||||
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;
|
||||
int bandid, i;
|
||||
|
||||
delayed_work = container_of(work, struct delayed_work, work);
|
||||
rdev = container_of(delayed_work, struct cfg80211_registered_device,
|
||||
dfs_update_channels_wk);
|
||||
wiphy = &rdev->wiphy;
|
||||
|
@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
|
||||
* Copyright 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright 2015 Intel Deutschland GmbH
|
||||
* Copyright 2015-2016 Intel Deutschland GmbH
|
||||
*/
|
||||
|
||||
#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_SCHED_SCAN_DELAY] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_REG_INDOOR] = { .type = NLA_FLAG },
|
||||
[NL80211_ATTR_PBSS] = { .type = NLA_FLAG },
|
||||
};
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
params.pbss = nla_get_flag(info->attrs[NL80211_ATTR_PBSS]);
|
||||
if (params.pbss && !rdev->wiphy.bands[IEEE80211_BAND_60GHZ])
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
wdev_lock(wdev);
|
||||
err = rdev_start_ap(rdev, dev, ¶ms);
|
||||
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 (!(rdev->wiphy.features &
|
||||
NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) ||
|
||||
!(rdev->wiphy.features & NL80211_FEATURE_QUIET))
|
||||
if (!((rdev->wiphy.features &
|
||||
NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
|
||||
(rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
|
||||
!wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
NL80211_EXT_FEATURE_RRM))
|
||||
return -EINVAL;
|
||||
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 (!(rdev->wiphy.features &
|
||||
NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) ||
|
||||
!(rdev->wiphy.features & NL80211_FEATURE_QUIET)) {
|
||||
if (!((rdev->wiphy.features &
|
||||
NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) &&
|
||||
(rdev->wiphy.features & NL80211_FEATURE_QUIET)) &&
|
||||
!wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
NL80211_EXT_FEATURE_RRM)) {
|
||||
kzfree(connkeys);
|
||||
return -EINVAL;
|
||||
}
|
||||
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);
|
||||
err = cfg80211_connect(rdev, dev, &connect, connkeys, NULL);
|
||||
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_MCS] = { .align = 1, .size = 3, },
|
||||
[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
|
||||
*/
|
||||
|
@ -60,13 +60,6 @@
|
||||
#include "regdb.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
|
||||
* 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)
|
||||
goto out;
|
||||
|
||||
REG_DBG_PRINT("%s: device specific dfs_region "
|
||||
"(%s) disagrees with cfg80211's "
|
||||
"central dfs_region (%s)\n",
|
||||
dev_name(&wiphy->dev),
|
||||
reg_dfs_region_str(wiphy_regd->dfs_region),
|
||||
reg_dfs_region_str(regd->dfs_region));
|
||||
pr_debug("%s: device specific dfs_region (%s) disagrees with cfg80211's central dfs_region (%s)\n",
|
||||
dev_name(&wiphy->dev),
|
||||
reg_dfs_region_str(wiphy_regd->dfs_region),
|
||||
reg_dfs_region_str(regd->dfs_region));
|
||||
|
||||
out:
|
||||
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)
|
||||
{
|
||||
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();
|
||||
reg_crda_timeouts++;
|
||||
restore_regulatory_settings(true);
|
||||
@ -585,7 +576,7 @@ static int call_crda(const char *alpha2)
|
||||
|
||||
if (!is_world_regdom((char *) alpha2))
|
||||
pr_debug("Calling CRDA for country: %c%c\n",
|
||||
alpha2[0], alpha2[1]);
|
||||
alpha2[0], alpha2[1]);
|
||||
else
|
||||
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);
|
||||
|
||||
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,
|
||||
const struct ieee80211_reg_rule *reg_rule,
|
||||
const struct ieee80211_channel *chan)
|
||||
@ -1242,20 +1197,19 @@ static void handle_channel(struct wiphy *wiphy,
|
||||
if (lr->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
|
||||
request_wiphy && request_wiphy == wiphy &&
|
||||
request_wiphy->regulatory_flags & REGULATORY_STRICT_REG) {
|
||||
REG_DBG_PRINT("Disabling freq %d MHz for good\n",
|
||||
chan->center_freq);
|
||||
pr_debug("Disabling freq %d MHz for good\n",
|
||||
chan->center_freq);
|
||||
chan->orig_flags |= IEEE80211_CHAN_DISABLED;
|
||||
chan->flags = chan->orig_flags;
|
||||
} else {
|
||||
REG_DBG_PRINT("Disabling freq %d MHz\n",
|
||||
chan->center_freq);
|
||||
pr_debug("Disabling freq %d MHz\n",
|
||||
chan->center_freq);
|
||||
chan->flags |= IEEE80211_CHAN_DISABLED;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
regd = reg_get_regdomain(wiphy);
|
||||
chan_reg_rule_print_dbg(regd, chan, reg_rule);
|
||||
|
||||
power_rule = ®_rule->power_rule;
|
||||
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;
|
||||
|
||||
if (!lr) {
|
||||
REG_DBG_PRINT("Ignoring regulatory request set by %s "
|
||||
"since last_request is not set\n",
|
||||
reg_initiator_name(initiator));
|
||||
pr_debug("Ignoring regulatory request set by %s since last_request is not set\n",
|
||||
reg_initiator_name(initiator));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (initiator == NL80211_REGDOM_SET_BY_CORE &&
|
||||
wiphy->regulatory_flags & REGULATORY_CUSTOM_REG) {
|
||||
REG_DBG_PRINT("Ignoring regulatory request set by %s "
|
||||
"since the driver uses its own custom "
|
||||
"regulatory domain\n",
|
||||
reg_initiator_name(initiator));
|
||||
pr_debug("Ignoring regulatory request set by %s since the driver uses its own custom regulatory domain\n",
|
||||
reg_initiator_name(initiator));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1415,10 +1366,8 @@ static bool ignore_reg_update(struct wiphy *wiphy,
|
||||
if (wiphy_strict_alpha2_regd(wiphy) && !wiphy->regd &&
|
||||
initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
|
||||
!is_world_regdom(lr->alpha2)) {
|
||||
REG_DBG_PRINT("Ignoring regulatory request set by %s "
|
||||
"since the driver requires its own regulatory "
|
||||
"domain to be set first\n",
|
||||
reg_initiator_name(initiator));
|
||||
pr_debug("Ignoring regulatory request set by %s since the driver requires its own regulatory domain to be set first\n",
|
||||
reg_initiator_name(initiator));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1699,7 +1648,7 @@ static void reg_check_chans_work(struct work_struct *work)
|
||||
{
|
||||
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();
|
||||
|
||||
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)) {
|
||||
REG_DBG_PRINT("Disabling freq %d MHz as custom regd has no rule that fits it\n",
|
||||
chan->center_freq);
|
||||
pr_debug("Disabling freq %d MHz as custom regd has no rule that fits it\n",
|
||||
chan->center_freq);
|
||||
if (wiphy->regulatory_flags & REGULATORY_WIPHY_SELF_MANAGED) {
|
||||
chan->flags |= IEEE80211_CHAN_DISABLED;
|
||||
} else {
|
||||
@ -1792,8 +1741,6 @@ static void handle_channel_custom(struct wiphy *wiphy,
|
||||
return;
|
||||
}
|
||||
|
||||
chan_reg_rule_print_dbg(regd, chan, reg_rule);
|
||||
|
||||
power_rule = ®_rule->power_rule;
|
||||
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()) {
|
||||
/* Unless we're asked to ignore it and reset it */
|
||||
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[1] = '7';
|
||||
|
||||
@ -2534,24 +2481,24 @@ static void restore_alpha2(char *alpha2, bool reset_user)
|
||||
* back as they were for a full restore.
|
||||
*/
|
||||
if (!is_world_regdom(ieee80211_regdom)) {
|
||||
REG_DBG_PRINT("Keeping preference on module parameter ieee80211_regdom: %c%c\n",
|
||||
ieee80211_regdom[0], ieee80211_regdom[1]);
|
||||
pr_debug("Keeping preference on module parameter ieee80211_regdom: %c%c\n",
|
||||
ieee80211_regdom[0], ieee80211_regdom[1]);
|
||||
alpha2[0] = ieee80211_regdom[0];
|
||||
alpha2[1] = ieee80211_regdom[1];
|
||||
}
|
||||
} else {
|
||||
REG_DBG_PRINT("Restoring regulatory settings while preserving user preference for: %c%c\n",
|
||||
user_alpha2[0], user_alpha2[1]);
|
||||
pr_debug("Restoring regulatory settings while preserving user preference for: %c%c\n",
|
||||
user_alpha2[0], user_alpha2[1]);
|
||||
alpha2[0] = user_alpha2[0];
|
||||
alpha2[1] = user_alpha2[1];
|
||||
}
|
||||
} else if (!is_world_regdom(ieee80211_regdom)) {
|
||||
REG_DBG_PRINT("Keeping preference on module parameter ieee80211_regdom: %c%c\n",
|
||||
ieee80211_regdom[0], ieee80211_regdom[1]);
|
||||
pr_debug("Keeping preference on module parameter ieee80211_regdom: %c%c\n",
|
||||
ieee80211_regdom[0], ieee80211_regdom[1]);
|
||||
alpha2[0] = ieee80211_regdom[0];
|
||||
alpha2[1] = ieee80211_regdom[1];
|
||||
} else
|
||||
REG_DBG_PRINT("Restoring regulatory settings\n");
|
||||
pr_debug("Restoring regulatory settings\n");
|
||||
}
|
||||
|
||||
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);
|
||||
spin_unlock(®_requests_lock);
|
||||
|
||||
REG_DBG_PRINT("Kicking the queue\n");
|
||||
pr_debug("Kicking the queue\n");
|
||||
|
||||
schedule_work(®_work);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -2718,10 +2665,10 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
|
||||
if (!reg_beacon)
|
||||
return -ENOMEM;
|
||||
|
||||
REG_DBG_PRINT("Found new beacon on frequency: %d MHz (Ch %d) on %s\n",
|
||||
beacon_chan->center_freq,
|
||||
ieee80211_frequency_to_channel(beacon_chan->center_freq),
|
||||
wiphy_name(wiphy));
|
||||
pr_debug("Found new beacon on frequency: %d MHz (Ch %d) on %s\n",
|
||||
beacon_chan->center_freq,
|
||||
ieee80211_frequency_to_channel(beacon_chan->center_freq),
|
||||
wiphy_name(wiphy));
|
||||
|
||||
memcpy(®_beacon->chan, beacon_chan,
|
||||
sizeof(struct ieee80211_channel));
|
||||
@ -2800,8 +2747,7 @@ bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region)
|
||||
case NL80211_DFS_JP:
|
||||
return true;
|
||||
default:
|
||||
REG_DBG_PRINT("Ignoring uknown DFS master region: %d\n",
|
||||
dfs_region);
|
||||
pr_debug("Ignoring uknown DFS master region: %d\n", dfs_region);
|
||||
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.ssid,
|
||||
wdev->conn->params.ssid_len,
|
||||
IEEE80211_BSS_TYPE_ESS,
|
||||
wdev->conn_bss_type,
|
||||
IEEE80211_PRIVACY(wdev->conn->params.privacy));
|
||||
if (!bss)
|
||||
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);
|
||||
bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
|
||||
wdev->ssid, wdev->ssid_len,
|
||||
IEEE80211_BSS_TYPE_ESS,
|
||||
wdev->conn_bss_type,
|
||||
IEEE80211_PRIVACY_ANY);
|
||||
if (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,
|
||||
wdev->ssid_len,
|
||||
IEEE80211_BSS_TYPE_ESS, IEEE80211_PRIVACY_ANY);
|
||||
wdev->conn_bss_type, IEEE80211_PRIVACY_ANY);
|
||||
if (WARN_ON(!bss))
|
||||
return;
|
||||
|
||||
@ -1017,6 +1017,9 @@ int cfg80211_connect(struct cfg80211_registered_device *rdev,
|
||||
memcpy(wdev->ssid, connect->ssid, 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)
|
||||
err = cfg80211_sme_connect(wdev, connect, prev_bssid);
|
||||
else
|
||||
|
@ -393,9 +393,9 @@ unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *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 */
|
||||
switch (ae) {
|
||||
default:
|
||||
@ -407,21 +407,31 @@ unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
|
||||
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);
|
||||
|
||||
int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
|
||||
enum nl80211_iftype iftype)
|
||||
static int __ieee80211_data_to_8023(struct sk_buff *skb, struct ethhdr *ehdr,
|
||||
const u8 *addr, enum nl80211_iftype iftype)
|
||||
{
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
u16 hdrlen, ethertype;
|
||||
u8 *payload;
|
||||
u8 dst[ETH_ALEN];
|
||||
u8 src[ETH_ALEN] __aligned(2);
|
||||
struct {
|
||||
u8 hdr[ETH_ALEN] __aligned(2);
|
||||
__be16 proto;
|
||||
} payload;
|
||||
struct ethhdr tmp;
|
||||
u16 hdrlen;
|
||||
u8 mesh_flags = 0;
|
||||
|
||||
if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
|
||||
return -1;
|
||||
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
if (skb->len < hdrlen + 8)
|
||||
return -1;
|
||||
|
||||
/* convert IEEE 802.11 header + possible LLC headers into Ethernet
|
||||
* 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 1 RA TA DA SA
|
||||
*/
|
||||
memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN);
|
||||
memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN);
|
||||
memcpy(tmp.h_dest, ieee80211_get_DA(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 &
|
||||
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))
|
||||
return -1;
|
||||
if (iftype == NL80211_IFTYPE_MESH_POINT) {
|
||||
struct ieee80211s_hdr *meshdr =
|
||||
(struct ieee80211s_hdr *) (skb->data + hdrlen);
|
||||
/* make sure meshdr->flags is on the linear part */
|
||||
if (!pskb_may_pull(skb, hdrlen + 1))
|
||||
if (mesh_flags & MESH_FLAGS_AE_A4)
|
||||
return -1;
|
||||
if (meshdr->flags & MESH_FLAGS_AE_A4)
|
||||
return -1;
|
||||
if (meshdr->flags & MESH_FLAGS_AE_A5_A6) {
|
||||
if (mesh_flags & MESH_FLAGS_AE_A5_A6) {
|
||||
skb_copy_bits(skb, hdrlen +
|
||||
offsetof(struct ieee80211s_hdr, eaddr1),
|
||||
dst, ETH_ALEN);
|
||||
skb_copy_bits(skb, hdrlen +
|
||||
offsetof(struct ieee80211s_hdr, eaddr2),
|
||||
src, ETH_ALEN);
|
||||
tmp.h_dest, 2 * ETH_ALEN);
|
||||
}
|
||||
hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
|
||||
hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
|
||||
}
|
||||
break;
|
||||
case cpu_to_le16(IEEE80211_FCTL_FROMDS):
|
||||
if ((iftype != NL80211_IFTYPE_STATION &&
|
||||
iftype != NL80211_IFTYPE_P2P_CLIENT &&
|
||||
iftype != NL80211_IFTYPE_MESH_POINT) ||
|
||||
(is_multicast_ether_addr(dst) &&
|
||||
ether_addr_equal(src, addr)))
|
||||
(is_multicast_ether_addr(tmp.h_dest) &&
|
||||
ether_addr_equal(tmp.h_source, addr)))
|
||||
return -1;
|
||||
if (iftype == NL80211_IFTYPE_MESH_POINT) {
|
||||
struct ieee80211s_hdr *meshdr =
|
||||
(struct ieee80211s_hdr *) (skb->data + hdrlen);
|
||||
/* make sure meshdr->flags is on the linear part */
|
||||
if (!pskb_may_pull(skb, hdrlen + 1))
|
||||
if (mesh_flags & MESH_FLAGS_AE_A5_A6)
|
||||
return -1;
|
||||
if (meshdr->flags & MESH_FLAGS_AE_A5_A6)
|
||||
return -1;
|
||||
if (meshdr->flags & MESH_FLAGS_AE_A4)
|
||||
if (mesh_flags & MESH_FLAGS_AE_A4)
|
||||
skb_copy_bits(skb, hdrlen +
|
||||
offsetof(struct ieee80211s_hdr, eaddr1),
|
||||
src, ETH_ALEN);
|
||||
hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
|
||||
tmp.h_source, ETH_ALEN);
|
||||
hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
|
||||
}
|
||||
break;
|
||||
case cpu_to_le16(0):
|
||||
@ -498,33 +498,33 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
|
||||
break;
|
||||
}
|
||||
|
||||
if (!pskb_may_pull(skb, hdrlen + 8))
|
||||
return -1;
|
||||
skb_copy_bits(skb, hdrlen, &payload, sizeof(payload));
|
||||
tmp.h_proto = payload.proto;
|
||||
|
||||
payload = skb->data + hdrlen;
|
||||
ethertype = (payload[6] << 8) | payload[7];
|
||||
|
||||
if (likely((ether_addr_equal(payload, rfc1042_header) &&
|
||||
ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
|
||||
ether_addr_equal(payload, bridge_tunnel_header))) {
|
||||
if (likely((ether_addr_equal(payload.hdr, rfc1042_header) &&
|
||||
tmp.h_proto != htons(ETH_P_AARP) &&
|
||||
tmp.h_proto != htons(ETH_P_IPX)) ||
|
||||
ether_addr_equal(payload.hdr, bridge_tunnel_header)))
|
||||
/* remove RFC1042 or Bridge-Tunnel encapsulation and
|
||||
* replace EtherType */
|
||||
skb_pull(skb, hdrlen + 6);
|
||||
memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
|
||||
memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
|
||||
} else {
|
||||
struct ethhdr *ehdr;
|
||||
__be16 len;
|
||||
hdrlen += ETH_ALEN + 2;
|
||||
else
|
||||
tmp.h_proto = htons(skb->len);
|
||||
|
||||
skb_pull(skb, hdrlen);
|
||||
len = htons(skb->len);
|
||||
pskb_pull(skb, hdrlen);
|
||||
|
||||
if (!ehdr)
|
||||
ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
|
||||
memcpy(ehdr->h_dest, dst, ETH_ALEN);
|
||||
memcpy(ehdr->h_source, src, ETH_ALEN);
|
||||
ehdr->h_proto = len;
|
||||
}
|
||||
memcpy(ehdr, &tmp, sizeof(tmp));
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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,
|
||||
const u8 *addr, enum nl80211_iftype iftype,
|
||||
const unsigned int extra_headroom,
|
||||
bool has_80211_header)
|
||||
{
|
||||
unsigned int hlen = ALIGN(extra_headroom, 4);
|
||||
struct sk_buff *frame = NULL;
|
||||
u16 ethertype;
|
||||
u8 *payload;
|
||||
const struct ethhdr *eth;
|
||||
int remaining, err;
|
||||
u8 dst[ETH_ALEN], src[ETH_ALEN];
|
||||
int offset = 0, remaining, err;
|
||||
struct ethhdr eth;
|
||||
bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb);
|
||||
bool reuse_skb = false;
|
||||
bool last = false;
|
||||
|
||||
if (has_80211_header) {
|
||||
err = ieee80211_data_to_8023(skb, addr, iftype);
|
||||
err = __ieee80211_data_to_8023(skb, ð, addr, iftype);
|
||||
if (err)
|
||||
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;
|
||||
__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;
|
||||
|
||||
/* the last MSDU has no padding */
|
||||
remaining = skb->len - offset;
|
||||
if (subframe_len > remaining)
|
||||
goto purge;
|
||||
|
||||
skb_pull(skb, sizeof(struct ethhdr));
|
||||
offset += sizeof(struct ethhdr);
|
||||
/* 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;
|
||||
else {
|
||||
unsigned int hlen = ALIGN(extra_headroom, 4);
|
||||
/*
|
||||
* Allocate and reserve two bytes more for payload
|
||||
* alignment since sizeof(struct ethhdr) is 14.
|
||||
*/
|
||||
frame = dev_alloc_skb(hlen + subframe_len + 2);
|
||||
reuse_skb = true;
|
||||
} else {
|
||||
frame = __ieee80211_amsdu_copy(skb, hlen, offset, len,
|
||||
reuse_frag);
|
||||
if (!frame)
|
||||
goto purge;
|
||||
|
||||
skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2);
|
||||
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;
|
||||
}
|
||||
offset += len + padding;
|
||||
}
|
||||
|
||||
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;
|
||||
ethertype = (payload[6] << 8) | payload[7];
|
||||
|
||||
if (likely((ether_addr_equal(payload, rfc1042_header) &&
|
||||
ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
|
||||
ether_addr_equal(payload, bridge_tunnel_header))) {
|
||||
/* remove RFC1042 or Bridge-Tunnel
|
||||
* encapsulation and replace EtherType */
|
||||
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);
|
||||
eth.h_proto = htons(ethertype);
|
||||
skb_pull(frame, ETH_ALEN + 2);
|
||||
}
|
||||
|
||||
memcpy(skb_push(frame, sizeof(eth)), ð, sizeof(eth));
|
||||
__skb_queue_tail(list, frame);
|
||||
}
|
||||
|
||||
if (!reuse_skb)
|
||||
dev_kfree_skb(skb);
|
||||
|
||||
return;
|
||||
|
||||
purge:
|
||||
|
Loading…
Reference in New Issue
Block a user